fcode-ui-triggers について
fcode-ui-triggersは、Factorial CodeのプロセスをFactorialページ内のボタンとして公開する方法を説明します。コンテキスト転送、同期結果、フォーム、認可、ローカライズされたラベルを設定するアプリ開発者向けです。
主な機能
- 01Factorialのロケーションにプロセスボタンを設定
- 02ページコンテキストと信頼された識別情報を転送
- 03同期結果とキュー実行に対応
- 04Factorialのダイアログでプロセスフォームを表示
- 05ローカライズラベルと許可リスト内のアイコンを設定
活用シーン
- 01Factorialページにプロセスボタンを追加
- 02表示中のレコードIDをプロセスへ渡す
- 03ページ操作からプロセスフォームを開く
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ factorialco/ factorial-code-skills --skill fcode-ui-triggersインストール後、Claude Code で/fcode-ui-triggersを入力して読み込まれたか確認します。
詳細
Factorial Code — UI トリガー
UI トリガーを使うと、マーケットプレイスアプリのプロセスを Factorial 内のボタン(ページヘッダー、アクションのドロップダウンなど)として公開できます。Factorial のページでは ロケーション が宣言されます。インストール済みアプリのプロセスがロケーションを指定すると、Factorial はそのロケーションを指定したプロセスごとにボタンを表示します。クリックするとプロセスが実行されるか、フォームが開きます。これは Factorial Action のエントリーポイントの 1 つです。設定はプロセスの metadata.json にある factorial.uiTrigger サブブロックと、factorial ブロックのトップレベルにある awaitResult に記述します(ブロック全体、レガシーミラー、Factorial One/バックエンドのエントリーポイントについては fcode-factorial-actions、フィールドのリファレンスについては fcode-cli を参照してください)。
注意点
- ボタンが表示されるのは、インストール済みのマーケットプレイスアプリだけです。 Factorial は、会社がインストールしたアプリのトリガーを、そのアプリのデプロイワークスペースから読み取って一覧表示します。通常のワークスペースにあるプロセスは表示されません。また、トリガーが顧客に届く流れはアプリ本体と同じです。リリースを通じて dev → prod → deploy と進みます。
- ロケーション ID は、そのページを所有する Factorial チームから取得する必要があります。 ロケーションはプラットフォームではなく、Factorial のコード(例:
calendar.header.admin)で宣言されています。プラットフォームは空白でないlocationId(≤ 200 文字)を受け付けますが、存在しない ID は一覧から黙って除外されます。つまり、入力ミスをするとエラーではなく「ボタンが表示されない」状態になります。 - コントラクトを決めるのはプロセスではなくロケーションです。 プロセスに転送されるコンテキストパラメーター、同期実行の結果のうちページに渡されるキー、ロケーションが
single(一度にインストールできるアプリは 1 つ)かどうかが決まります。ID とあわせて、これら 3 点を確認してください。 awaitResultはfactorialブロックにあり、デフォルトはtrue(同期)です。 レガシーのuiTrigger.awaitResultのデフォルトはファイア・アンド・フォーゲットでしたが、ミラーには新しい値がコピーされます。そのため、ボタンをfactorialに移すと、"awaitResult": falseを指定しない限り同期実行されます。結果をユーザーに表示する必要があり、処理が速い(< 50 s)場合に限ってtrueにしてください。falseの場合、クリックすると実行がキューに登録され、ユーザーには「アクションを開始しました」と表示されます。戻り値は表示されません。- フォームが有効なプロセスでは、実行の代わりにフォームが開きます。
factorial.form.enabled(またはレガシーのform.enabled)が有効な場合、ボタンをクリックすると Factorial 内のダイアログにフォームが開き、awaitResultは無視されます。 - トリガーから開いたフォームは、プラットフォームに直接送信されるのではなく、Factorial を経由します。 ダイアログはスキーマを読み込み、クリックしたユーザーの ID を付与する Factorial 独自のバックエンドを通じて送信します。フォーム独自の
authModeは、公開 URL からアクセスした場合(fcode-forms)には引き続き適用されますが、ダイアログには適用されません。 - どちらの経路でも、
company_id、triggered_from_location、access_idは信頼できます。 フォームの有無にかかわらず、Factorial は呼び出しのたびにこれらをサーバー側で挿入します。また、ロケーションから転送されるパラメーターは、ブラウザーから送信された値を上書きします。これらの値に基づく認可は安全です。(以前のフォーム経路では、これらの値はクライアントが編集できる事前入力フィールドとして渡されていたため、そうではありませんでした。) - クリックできるユーザーは
requiredPoliciesで決まり、確実に適用されます。 Factorial は、アクションを実行する前に、クリックしたユーザーに対してfactorial.requiredPolicies(fcode-factorial-actions)を検証します。また、ロケーションのリソースもポリシーの範囲内で読み取ります。ポリシーが設定されていないアクションは、ボタンにアクセスできるすべてのユーザーが実行できます。 - 捕捉されないエラーは、汎用メッセージとして表示されます。 例外やクラッシュが発生すると、詳細は表示されず、ユーザーには「アクションを完了できませんでした」と表示されます。ユーザーに読ませる内容は
{ errors: [...] }を返してください。 - 変更が反映されるまで最大 5 分かかります。 Factorial はブラウザー内でトリガー一覧をキャッシュします。
トリガーを宣言する
processes/<slug>/metadata.json で設定してから、fcode push を実行します(または、コンソールのプロセスページにある Trigger from
Factorial セクションで設定します)。
{
"name": "Sync report",
"tags": ["acme"],
"factorial": {
"enabled": true,
"uiTrigger": {
"enabled": true,
"locationId": "compensations.cycle.header",
"label": "Sync to Acme",
"icon": "Refresh"
}
}
}
| フィールド | 意味 |
|---|---|
factorial.enabled | アクション全体のマスタースイッチです。ボタンを使うにはオンにする必要があります |
factorial.awaitResult | デフォルトは true です。同期実行して結果を表示します。処理を待たずに実行する場合は false を指定します |
uiTrigger.enabled | ボタンを有効にします。true の場合、locationId が必要です |
uiTrigger.locationId | ボタンを表示する Factorial のロケーションです。ページを所有するチームから指定されます |
uiTrigger.label | ボタンのテキストです。プレーンテキスト、または fcode.i18n("key") トークン(後述)を指定します。このブロックで i18n が適用されるフィールドはこれだけです |
uiTrigger.icon | 許可リストにある名前(後述)のいずれかを指定します。テキストのみのボタンにする場合は省略します |
従来のトップレベルの uiTrigger ブロック(enabled、locationId、label、
icon、awaitResult)も引き続き読み書きでき、factorial.uiTrigger と
ミラーリングされます。古いファイルも引き続き動作し、fcode pull は引き続きすべてのプロセスに "uiTrigger": { "enabled": false } を書き込みます。新しく設定する場合は factorial を使用してください。両方が存在する場合、fcode push は factorial を送信します(ミラーリングのルールについては
fcode-factorial-actions を参照してください)。
1 つのロケーションに複数のトリガーを宣言できます。それぞれ個別のボタンとして表示されます。ただし、Factorial で single と指定されたロケーションにインストールできるアプリは 1 つだけです。2 つ目のアプリをインストールしようとすると、先にインストールされたアプリの名前を示す競合エラーが発生します。他のアプリとの共存を想定したアプリから、single のロケーションを使用しないでください。
プロセスが受け取る内容
クリックすると、fcode.context.parameters に次の値が設定されてプロセスが実行されます。
- ロケーションの 転送されるコンテキストパラメーター。たとえば、ページに表示されているレコードの ID(
cycle_id)です。ロケーションで許可リストに登録されたキーだけが渡されます。 company_id— クリックしたユーザーが所属する Factorial の会社です(信頼できる値です。共有シークレットを使用して挿入され、ブラウザーから送信された値は上書きされます)。triggered_from_location— ロケーション ID です(同じ方法で渡される信頼できる値です)。access_id— Factorial のアクセス権(クリックしたユーザーの、その会社におけるメンバーシップ)を文字列で表したものです(同じ方法で渡される信頼できる値です)。
コンテキストのないロケーション(対象レコードのないヘッダーボタン)からは、パラメーターは一切渡されず、信頼できる 3 つのキーだけが渡されます。クリックしたユーザーのロケールは実行ロケールとして渡されるため、プロセス内の fcode.i18n はユーザーの言語で動作します(fcode-i18n)。
const { company_id, access_id, triggered_from_location, cycle_id } = fcode.context.parameters;
if (!cycle_id) throw new Error("cycle_id is required");
結果を返す(同期トリガー)
awaitResult: true の場合、Factorial は実行が終わるまで待ち、返された値を変更せずそのままページに渡します。値を包むためのエンベロープは不要で、途中で除外される情報もありません。
// Success — the whole object reaches the page's onSuccess handler.
return { synced: 42, report_url: "https://acme.example/reports/7" };
- 成功ステータスは、本文の内容にかかわらず常に成功です。
errorsキーを含むオブジェクトを返しても、失敗にはなりません。 - 想定される失敗は、本文ではなくエラーステータスで通知してください。
fcode.error(...)をスローするか、HTTP 形式のプロセスからエラーステータスを返します。本文はそのまま渡されるため、ページ側でメッセージを読み取れます。 - メッセージのないスロー、または同期実行の制限時間(約 50 秒)を超えた場合(実行はバックグラウンドで完了する可能性があります)→ ユーザーが対処できない一般的なエラーになります。
エントリーポイントが想定する形式に合わせるのは、プロセス作成者の役割です。フォームは独自の規約(message、formErrors、nextProcessId)を読み取りますが、通常のボタンはトーストを表示するだけです。そのため、両方から呼び出せるプロセスでも、どちらにも通用する結果形式はありません。ロケーションの result_keys は参考情報で、ページ側が読み取る予定の内容を示すだけです。この値によるフィルタリングはありません。
awaitResult を無効にすると、戻り値を確認できるのは実行ログだけです。時間のかかる処理は実行ログ側で行うか、短時間の同期トリガーから fcode.processes.run(...) を呼び出してください(fcode-javascript / fcode-python を参照)。
フォーム連携トリガー
通常どおりフォーム(fcode-forms)を有効にすると、ボタンを押したときに Factorial 内でダイアログが開き、f0 テーマで表示され、転送されたパラメーターがあらかじめ入力されます。クリック時にダイアログを開くかプロセスを実行するかは、アクションのエントリーポイントによって決まります。form と uiTrigger の両方を宣言するとフォームが開き、uiTrigger のみを宣言するとプロセスが実行されます。
送信は Factorial のバックエンドを経由し、company_id、triggered_from_location、access_id がサーバー側で注入されます。プロセスでこれらを読み取る場合は、parametersSchema.json で宣言してください(hidden ウィジェット)。結果はフォームの規約(message、formErrors、nextProcessId、…)に従います。複数ステップのフォームでは、同じダイアログ内で各ステップの nextProcessId に従って進みます。
{
"name": "Export cycle",
"factorial": {
"enabled": true,
"form": { "enabled": true },
"uiTrigger": { "enabled": true, "locationId": "compensations.cycle.header", "label": "Export…", "icon": "Download" }
}
}
トリガーフォーム内のファイル
ファイルフィールドを使用できます。ファイルは Factorial を経由しません。パラメーターを x-fcode-file で宣言し、対応する拡張子を列挙してください。
"msj_file": {
"title": "FIE file",
"type": "string",
"x-fcode-file": { "accept": [".msj"] },
"ui": { "ui:widget": "file", "ui:options": { "accept": ".msj" } }
}
送信時に Factorial はファイルごとにプラットフォームへアップロード許可を要求し、ファイルを Factorial Code のストレージに直接 PUT して、結果の fcode.storage:// パスをパラメーター値として送信します。プロセスは保存済みの他のファイルと同様に読み取ります(fcode-javascript / fcode-python)。
- アップロード許可が発行されるのは、スキーマの取得時ではなく送信時です。プラットフォームが実際のファイル名を
acceptと照合して、コンテンツタイプに署名しますが、ユーザーがファイルを選択するまでは、どちらもわかりません。acceptに含まれない名前のファイルは、その時点で拒否されます。 - アップロードされたファイルは、48 時間経過すると削除されます。プロセスでそれより長く必要なものは、別の場所にコピーしてください。
ラベルと i18n
label には fcode.i18n("key") トークンを埋め込めます。フォームスキーマで使用するものと同じトークンで、ワークスペースのロケールファイルから各ユーザーのロケールに応じて解決され、主要ロケールへのフォールバックも行われるため、ラベルが空になることはありません(モデル、ファイル、構文については fcode-i18n を参照してください)。
"factorial": {
"enabled": true,
"uiTrigger": { "enabled": true, "locationId": "calendar.header.admin", "label": "fcode.i18n(\"acme.sync.button\")" }
}
アイコン
Factorial が表示するのは次の名前のみです(大文字と小文字は区別されません)。それ以外はテキストのみのボタンにフォールバックし、コンソールにも同じ一覧がピッカーとして表示されます。
Bell、Calendar、Chart、Document、Download、ExternalLink、Globe、
Graph、Link、Play、Refresh、Send、Settings、Sparkles、Star、
Upload。
Factorial での表示方法(Factorial エンジニア向け)
Factorial 側は汎用的な実装で、アプリごとのコードはありません。factorial モノリスでは、次のようになっています。
- ロケーションは、コンポーネントの
app/fcode_locations/配下にある YAML ファイルです(id、任意のresourceと、対象レコードを示すparam_key、forward_params、result_keys、single、legacy_ui)。CI の仕様によって検証されます。calendar/header_admin.ymlが参考例です。 - ページは
frontend/src/modules/factorialCode/components/FactorialCodeTriggerの<FactorialCodeTrigger locationId="…" params={{ cycle_id }} onSuccess onError />をレンダリングします。要求された各トリガーにつきボタンを 1 つ表示し(F0 のoutlineボタン、またはlegacy_uiロケーションでは従来のデザインシステムのボタン)、読み込み中や、ロケーションを要求するインストール済みアプリがない場合は何も表示せず、フォームダイアログを管理します。基盤となるフック(一覧表示用のuseFactorialCodeTriggers、クリック用のuseFactorialCodeTriggerActivation)は、ドロップダウンメニューなど、データ駆動型のホスト向けにエクスポートされています。 - クリックは
FactorialCode::Interactors::InvokeActionを経由します。この処理は、アクションのrequiredPolicies(RequiredPoliciesAuthorization。AND グループの OR)と、ロケーションのresourceに対するポリシー適用範囲内の読み取りをチェックします。forward_paramsのみを転送し、ブラウザーから送られた値より優先してcompany_id/access_id/triggered_from_locationを注入し、プロセスの応答を変更せずに返します。SPA は不透明なaction_idでアクションを指定します。プロセスのスラッグがブラウザーに届くことはありません。すべての機能は Factorial Code のフィーチャーフラグによって制御されます。
アプリ開発者はこれらに触れる必要はありません。ページを所有するチームから、ロケーションの ID と仕様を入手してください。
リリース前のチェックリスト
- ロケーション ID、転送されるパラメーター、
singleかどうかを、担当の Factorial チームと確認します。 factorial.awaitResultを明示的に決定します。高速でユーザーに表示される結果の場合のみtrue(デフォルト)にし、それ以外はfalseにします。factorial.requiredPoliciesを設定するか、ボタンに到達できる人なら誰でも利用できるため意図的に空のままにします。- フォームに基づくトリガーでは、読み取る事前入力済みのキーを宣言し、ファイルパラメーターには
x-fcode-fileを指定します。 - Factorial の開発用インストール環境でテストしてから、
prod-に昇格させてリリースし、デプロイワークスペースに反映させます(fcode-release、fcode-ama)。