カスタム拡張機能UIの構築

NOTE
この記事は、ソフトウェア開発ツールに精通していることを前提としています。

この手順では、ユーザーが実際に表示する画面を構築し、Fusionで​ 接続(「ハンドシェイク」) ​を完了する方法について説明します。

このプロセスでは、拡張機能が、非表示の​登録 フレームと表示される​UI フレームの2つのフレームで実行されていることを確認することが重要です。

カスタム拡張機能に関連するフレームについて詳しくは、UI拡張機能に含まれるフレーム ​を参照してください。

登録フレームの作成手順については、UI拡張機能のプロジェクトの作成を参照してください。

2つのフレーム間のルート

両方のフレームで同じ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)は、register(...)を呼び出す非表示フレーム ExtensionRegistration​をレンダリングします。
    • 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>;
    }
    

    このコードでは、次の操作を行います。

    • attach({ id })は、Fusionが応答すると​ 接続オブジェクト ​を返します。 これは、次の手順でFusionが送信するコンテキストを読み取るために使用するため、保存することをお勧めします。
    • 接続が解決するまで、短い「Connecting…」 メッセージが表示されます。
    • Constants.jsで設定した​ 同じextensionId ​を使用します。

    この時点で、動作する拡張機能があります。これは、メッセージを登録、添付、表示します。 この後はすべて、Fusionが提供するデータの使用に関するものです。

  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