关于 fcode-ui-triggers
fcode-ui-triggers 说明如何将 Factorial Code 流程呈现为 Factorial 页面中的按钮,面向配置流程入口的应用开发者。内容涵盖上下文传递、同步结果、表单、授权和本地化标签。
主要功能
- 01在 Factorial 位置配置流程按钮
- 02传递页面上下文和可信身份参数
- 03支持同步结果与排队执行
- 04在 Factorial 对话框中打开流程表单
- 05配置本地化标签和允许列表中的图标
适用场景
- 01在 Factorial 页面添加流程按钮
- 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 触发器会将 marketplace 应用的流程公开为 Factorial 内的按钮(页面标题栏、操作下拉菜单等)。Factorial 页面会声明 位置;已安装应用的流程认领某个位置后,Factorial 就会为每个认领该位置的流程渲染一个按钮。点击按钮会运行流程,或打开其表单。这是 Factorial Action 的一个入口:其设置位于流程 metadata.json 的 factorial.uiTrigger 子块中,awaitResult 位于 factorial 块顶层(整个块、旧版镜像以及 Factorial One / 后端入口见 fcode-factorial-actions;字段参考见 fcode-cli)。
注意事项
- 只有已安装的 marketplace 应用才会显示按钮。 Factorial 会从公司已安装应用的部署工作区读取并列出触发器。普通工作区中的流程不会显示;触发器要像应用的其他部分一样,通过发布版本从 dev → prod → deploy 到达客户。
- 位置 ID 必须来自拥有该页面的 Factorial 团队。 位置在 Factorial 代码中声明(例如
calendar.header.admin),不在平台上声明。平台接受任何非空白的locationId(≤ 200 个字符);未知位置会被静默地从列表中忽略,因此拼写错误意味着“没有按钮”,而不是报错。 - 由位置决定契约,而不是流程:哪些上下文参数会转发给流程、同步结果中的哪些键会传回页面,以及该位置是否为
single(一次只能有一个已安装应用)。除了 ID,也要询问这三项。 awaitResult位于factorial块中,默认值为true(同步)。 旧版uiTrigger.awaitResult的默认行为是触发后不等待;镜像会将新值复制覆盖旧值。因此,移入factorial的按钮会同步运行,除非你写入"awaitResult": false。只有在任务耗时较短(< 50 s),且用户必须看到结果时,才将其设为true;设为false时,点击会将执行加入队列,用户会看到“操作已开始”,并且永远不会显示返回值。- 启用了表单的流程会打开表单,而不是运行流程。 启用
factorial.form.enabled(或旧版form.enabled)后,按钮会在 Factorial 内的对话框中打开表单,并忽略awaitResult。 - 由触发器打开的表单会通过 Factorial,而不是直接连接平台。 对话框会读取架构,并通过 Factorial 自己的后端提交;该后端会携带点击用户的身份。表单自身的
authMode仍适用于通过其公开 URL 访问表单的用户(fcode-forms),但不适用于对话框。 company_id、triggered_from_location和access_id在两种路径中都可信。 Factorial 会在每次调用时于服务端注入这些字段,不论是否使用表单;位置转发的参数会覆盖浏览器发送的任何值。可以安全地基于这些字段进行授权。(旧表单路径并非如此,它会将这些字段作为客户端可编辑的预填字段传递。)- 谁可以点击由
requiredPolicies决定,并会强制执行。 Factorial 会在运行任何内容之前,根据点击用户检查factorial.requiredPolicies(fcode-factorial-actions);此外,还会按策略范围读取位置。未列出任何策略的操作,对任何能访问该按钮的人开放。 - 未捕获的错误会显示通用消息。 抛出异常或崩溃时,用户会看到“The action could not be completed”,不会看到详情。对于任何应向用户展示的内容,请返回
{ errors: [...] }。 - 更改最多需要五分钟才会显示——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)。
一个应用可在同一位置声明多个触发器,每个触发器都会显示为一个按钮;但在 Factorial 中标记为 single 的位置只允许安装一个应用:如果安装第二个声明了该位置的应用,安装会因冲突而失败,并指出第一个应用。若应用需要与其他应用共存,请勿声明 single 位置。
流程接收的内容
点击按钮会运行流程,并将 fcode.context.parameters 设为:
- 该位置的转发上下文参数,例如页面所显示记录的 ID(
cycle_id),具体包含哪些键取决于该位置的允许列表; company_id— 点击按钮的 Factorial 用户所属的公司(可信:在共享密钥下注入,会覆盖浏览器发送的任何内容);triggered_from_location— 位置 ID(可信,注入方式相同);access_id— Factorial 访问权限(即点击用户在该公司中的成员身份),以字符串形式传入(可信,注入方式相同)。
没有上下文的位置(例如未关联任何记录的页眉按钮)不会转发任何参数,只传递三个可信键。点击用户的区域设置会作为执行区域设置传入,因此流程中的 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 会为每个文件向平台申请上传授权,将文件直接 PUT 到 Factorial Code 存储,并将生成的 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 monolith 中:
- 位置是组件
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 />。它会为每个声明该位置的触发器绘制一个按钮(F0outline按钮,或用于legacy_ui位置的旧版设计系统按钮);加载期间或没有已安装的应用声明该位置时不渲染任何内容,并负责管理表单对话框。底层钩子(用于列表的useFactorialCodeTriggers,以及用于点击的useFactorialCodeTriggerActivation)也会导出,供下拉菜单等数据驱动的宿主使用。 - 点击会通过
FactorialCode::Interactors::InvokeAction处理:它会检查操作的requiredPolicies(RequiredPoliciesAuthorization,由多个 AND 组构成 OR),并在策略范围内读取该位置的resource;只转发forward_params;覆盖浏览器发送的任何同名值,注入company_id/access_id/triggered_from_location;并原样返回流程的答复。SPA 使用不透明的action_id标识操作;流程 slug 不会传到浏览器。所有功能均受 Factorial Code 功能标志控制。
应用开发者无需处理这些内容;只需从负责该页面的团队获取位置 ID 和约定即可。
发布前检查清单
- 与负责的 Factorial 团队确认位置 id、转发参数和是否为
single。 - 明确决定
factorial.awaitResult的取值——仅在结果快速且对用户可见时设为true(默认值),其他情况设为false。 - 填写
factorial.requiredPolicies;如果任何能够访问此按钮的人都可以使用,则有意留空。 - 基于表单的触发器声明其读取的预填键,且任何文件参数都带有
x-fcode-file。 - 先在 Factorial 的开发安装中测试,然后升级到
prod-并发布,以便部署工作区获取更新(fcode-release、fcode-ama)。