构建自定义扩展UI

NOTE
本文假定您对软件开发工具有一定的了解。

此过程描述如何生成用户实际看到的屏幕,以及如何使用Fusion完成​连接(“握手”)

在此过程中,请务必记住,扩展在两个框架中运行:隐藏的​ 注册 ​框架和可见的​ UI ​框架。

有关与自定义扩展相关的框架的信息,请参阅UI扩展中包含的框架

有关构建注册框架的说明,请参阅创建用于UI扩展性的项目

在两个帧之间布线

两帧加载相同的index.html;小型前端路由器根据URL决定要显示的组件。

  1. web-src/src/components/App.js中设置路由。 关键部分是:

    code language-jsx
    import { HashRouter as Router, Routes, Route } from "react-router-dom";
    import ExtensionRegistration from "./ExtensionRegistration";
    import DashboardWidget from "./DashboardWidget";
    
    export default function App() {
      return (
        <Router>
          <Routes>
            {/* Background frame: registers the extension with Fusion */}
            <Route index element={<ExtensionRegistration />} />
            <Route path="index.html" element={<ExtensionRegistration />} />
    
            {/* Visible frame: the URL you returned from getWidget() */}
            <Route path="my-widget" element={<DashboardWidget />} />
          </Routes>
        </Router>
      );
    }
    

    这些路由将映射到以前的配置,如下所示:

    • 默认路由(index)呈现​ExtensionRegistration,即调用register(...)的隐藏帧。
    • my-widget路由呈现您可见的UI DashboardWidget。 这与您在上一页中从getWidget()返回的url: "/index.html#/my-widget"匹配。
    note
    NOTE
    路由和getWidget URL必须一致。 如果更改路由名称,请同时更改url,否则Fusion将加载空白页。
  2. 继续完成与attach的握手。

使用attach完成握手

这是可见UI中最重要的一行。 当Fusion打开您的UI框架时,将等待该框架“签入”。 您的代码通过调用attach({ id })签入。

如果省略,Fusion将超时,并出现错误,例如​“正在等待来自目标iframe的初始消息。”

  1. 将以下内容添加到web-src/src/components/DashboardWidget.js

    code language-jsx
    import { useEffect, useState } from "react";
    import { attach } from "@adobe/uix-guest";
    import { extensionId } from "./Constants";
    
    export default function DashboardWidget() {
      const [connection, setConnection] = useState(null);
    
      useEffect(() => {
        // Tell Fusion this UI frame is ready. Required.
        attach({ id: extensionId })
          .then(setConnection)
          .catch((e) => console.error("attach failed", e));
      }, []);
    
      if (!connection) {
        return <p>Connecting to Fusion...</p>;
      }
    
      return <h2>Hello from my Fusion extension!</h2>;
    }
    

    此代码执行以下操作:

    • Fusion响应后,attach({ id })将返回​连接对象。 我们建议保存此内容,因为您将在下一步中使用它来读取Fusion发送的上下文。
    • 在连接解析之前,出现一个简短的“Connecting…”(连接……) 将显示消息。
    • 使用您在Constants.js中设置的​相同extensionId

    此时,您拥有一个有效的扩展:该扩展注册、附加和显示消息。 之后的所有工作都是关于使用数据融合的。

  2. 继续读取上下文Fusion共享

读取上下文Fusion共享

在附加该连接后,该连接会公开一个​共享上下文,其中包含有关当前用户、组织和团队的信息。 您可以使用connection.sharedContext.get("<key>")读取单个值:

const orgId = connection.sharedContext.get("imsOrgId");
const organization = connection.sharedContext.get("organization"); // full Fusion org
const user = connection.sharedContext.get("user");                 // full Fusion user

此示例显示了一个完整的被动示例,当用户切换组织或团队时,该示例也会更新:

import { useEffect, useState } from "react";
import { attach } from "@adobe/uix-guest";
import { extensionId } from "./Constants";

const KEYS = ["imsOrgId", "imsUserId", "organization", "team", "user"];

function readContext(source) {
  // sharedContext behaves like a Map (.get); the change event gives a plain object.
  const get =
    typeof source.get === "function" ? (k) => source.get(k) : (k) => source[k];
  return Object.fromEntries(KEYS.map((k) => [k, get(k)]));
}

export default function DashboardWidget() {
  const [context, setContext] = useState(null);

  useEffect(() => {
    let cleanup = () => {};
    attach({ id: extensionId })
      .then((connection) => {
        // 1) initial values
        setContext(readContext(connection.sharedContext));

        // 2) react to org/team/user changes pushed by Fusion
        const onChange = (event) =>
          setContext(readContext(event?.detail?.context ?? connection.sharedContext));
        connection.addEventListener("contextchange", onChange);
        cleanup = () => connection.removeEventListener?.("contextchange", onChange);
      })
      .catch((e) => console.error("attach failed", e));
    return () => cleanup();
  }, []);

  if (!context) return <p>Connecting to Fusion...</p>;

  return (
    <div>
      <h2>{context.organization?.name ?? "No organization"}</h2>
      <p>Signed in as {context.user?.name} ({context.user?.email})</p>
      <p>IMS org: {context.imsOrgId}</p>
    </div>
  );
}

请记住以下内容:

  • 直接在attach之后从connection.sharedContext.get(key)中读取初始值
  • 订阅contextchange​以保持同步。 每当活动的组织、团队或用户发生更改时,Fusion都会触发此事件。 新值在event.detail.context到达。

有关键的完整列表以及每个键所包含的内容,均包含在Fusion上下文引用中。

要继续配置自定义扩展的过程,请转到Fusion上下文引用

recommendation-more-help
workfront-fusion-help-workfront-fusion