writing-settings-forms
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<!-- TIER:1 -->
<!-- TIER:1 -->
Writing Settings Forms
编写 Settings Forms
A settings form () is the form the Celigo UI renders to collect a resource's : which fields appear, their labels and choices, how they're grouped, and which show when. The values it collects are stored in the same resource's , and that's what steps read at run time -- in a template, in a script.
settingsFormsettingssettings{{settings.flow.region}}options.settings.flow.regionSeven places carry a form, each with its own : an integration, each of an integration's flow groups (), a flow, an export, an import, a connection, and an iClient. An Integration App's settings are a different mechanism, driven by the app's own code -- see managing-integrations > Integration Apps.
settingsflowGroupings[]What a form is not:
- Not validation. Only the UI renders the form and applies its rules. An API, CLI, or MCP write of stores the object it's given: a field the form marks
settingscan be missing, keys the form doesn't define are kept, and nothing checks types or choices.required - Not checked on save. A layout entry or a condition naming a field the form doesn't have is stored as sent. Only and
formare kept: any other top-level key ininitis dropped without an error.settingsForm - Not what steps read. Steps read , never the form. A new field gives steps nothing until its value is in
settings, so write the value along with the field.settings
设置表单()是 Celigo UI 渲染、用于收集资源 的表单:决定显示哪些字段、它们的标签和选项、如何分组,以及哪些字段在何时显示。表单收集的值存储在同一资源的 中,这正是 steps 在运行时读取的内容——在 template 中是 ,在 script 中是 。
settingsFormsettingssettings{{settings.flow.region}}options.settings.flow.region共有七类资源携带表单,每类资源都有自己的 :一个 integration、一个 integration 的各个 flow group()、一个 flow、一个 export、一个 import、一个 connection 和一个 iClient。Integration App 的 settings 采用另一套机制,由该 app 自身的代码驱动——参见 managing-integrations > Integration Apps。
settingsflowGroupings[]表单不是什么:
- 不是 validation。 只有 UI 会渲染表单并应用其规则。通过 API、CLI 或 MCP 写入 时,会原样存储传入的对象:表单标记为
settings的字段仍可能缺失,表单未定义的 key 也会保留,而且不会检查类型或选项。required - 保存时不会校验。 引用了表单中不存在字段的 layout entry 或 condition 会按发送内容存储。中仅保留
settingsForm和form:任何其他顶层 key 都会在不报错的情况下被丢弃。init - 不是 steps 读取的内容。 Steps 读取的是 ,绝不是表单。新增字段不会自动向 steps 提供任何值,除非该值已写入
settings,因此添加字段时必须同时写入值。settings
How to Run the Steps
如何运行 Steps
This skill names each step by what it reads or changes; the exact calls depend on how you reach the account. Read the one reference that matches your tools -- both follow the step numbers of How to Build a Settings Form, then How to Check a Form:
- Celigo MCP tools (,
list_integrations,upsert_integration,upsert_flow, ...) -- references/mcp.md. The deployed server writes forms only through the full-replaceupsert_exporttools, and can't run an init script or preview a dropdown's export.upsert_* - The CLI -- references/cli.md
celigo
Reading a resource only reads. Writing a form or its updates the resource, and a full update replaces the whole document: a body that leaves out or erases them.
settingssettingsFormsettings本 skill 根据每个 step 读取或更改的内容来命名;具体调用方式取决于访问 account 的方式。阅读与所用工具匹配的那份 reference——两者均遵循“如何构建 Settings Form”的步骤编号,然后阅读“如何检查表单”:
- Celigo MCP tools(、
list_integrations、upsert_integration、upsert_flow等)——references/mcp.md。已部署的 server 只能通过完整替换的upsert_exporttools 写入表单,无法运行 init script,也无法预览 dropdown 的 export。upsert_* - CLI——references/cli.md
celigo
读取资源只会执行读取。写入表单或其 会更新资源,而完整更新会替换整个 document:如果请求 body 未包含 或 ,它们就会被清除。
settingssettingsFormsettingsThe Seven Scopes
七种 Scope
| Scope | Form | Values | Steps read them as |
|---|---|---|---|
| Integration | | | |
| Flow group | | | |
| Flow | | | |
| Export (lookups too) | | | |
| Import | | | |
| Connection | | | |
| iClient | | | |
The scope key is literal: (no scope) and paths built from field labels or section names render empty. After the scope, the path follows the stored JSON -- a top-level value is , and each nested key adds a segment. Templates, filters, and Mapper 2.0 read these paths (writing-handlebars > Context Decision Matrix); scripts read (writing-scripts > Common Options).
{{settings.region}}settings.flow.regionoptions.settings.<scope>Which scopes a step sees depends on how it runs:
- A flow run gives the whole chain: integration, flow group, flow, connection, iClient, and the step's own scope.
- A step inside an API or a Tool gets only its own scope plus connection and iClient; integration, flow group, and flow resolve empty there.
- A step run on its own -- an export or import invoke with no parent -- gets only its own scope. An import invoke run as a step of a flow sees the flow's chain.
Pick the narrowest scope that every step reading the value shares: a whole integration, a flow group for flows that share a region or subsidiary, a flow, or a step's own form for a knob only that step uses.
| Scope | Form | Values | Steps read them as |
|---|---|---|---|
| Integration | | | |
| Flow group | integration 上的 | | |
| Flow | | | |
| Export(包括 lookups) | | | |
| Import | | | |
| Connection | | | |
| iClient | | | |
scope key 是字面量:(没有 scope)以及根据字段标签或 section 名称构建的路径都会渲染为空。在 scope 之后,路径遵循存储的 JSON——顶层 value 是 ,每增加一层嵌套 key 就增加一段路径。Templates、filters 和 Mapper 2.0 读取这些路径(writing-handlebars > Context Decision Matrix);scripts 读取 (writing-scripts > Common Options)。
{{settings.region}}settings.flow.regionoptions.settings.<scope>Step 能看到哪些 scopes 取决于其运行方式:
- Flow run 会获得完整链路:integration、flow group、flow、connection、iClient,以及该 step 自身的 scope。
- API 或 Tool 内的 step 只能获得自身 scope,以及 connection 和 iClient;在该处 integration、flow group 和 flow 都会解析为空。
- 单独运行的 step——没有父级的 export 或 import invoke——只能获得自身 scope。作为 flow 中一个 step 运行的 import invoke 则能看到该 flow 的完整链路。
选择所有读取该 value 的 steps 共享的最窄 scope:整个 integration、用于共享 region 或 subsidiary 的 flow group、flow,或仅供某个 step 使用的自身表单。
Quick Reference
快速参考
The Shape
结构
json
{
"settingsForm": {
"form": {
"fieldMap": {
"region": {
"id": "region", "name": "region", "type": "select", "label": "Region", "required": true,
"options": [{ "items": [{ "label": "United States", "value": "us" }, { "label": "Europe", "value": "eu" }] }]
},
"vatNumber": {
"id": "vatNumber", "name": "vatNumber", "type": "text", "label": "VAT number",
"visibleWhen": [{ "field": "region", "is": ["eu"] }]
},
"statusMap": {
"id": "statusMap", "name": "statusMap", "type": "staticMap", "label": "Order status map",
"keyName": "source", "keyLabel": "Source status", "valueName": "target", "valueLabel": "Destination status",
"valueOptions": [{ "label": "Open", "value": "open" }, { "label": "Closed", "value": "closed" }]
}
},
"layout": {
"type": "collapse",
"containers": [
{ "label": "General", "fields": ["region", "vatNumber"] },
{ "label": "Advanced", "type": "box", "containers": [{ "label": "Status mapping", "fields": ["statusMap"] }] }
]
}
}
},
"settings": { "region": "eu", "vatNumber": "EU123", "statusMap": [{ "source": "pending", "target": "open" }] }
}json
{
"settingsForm": {
"form": {
"fieldMap": {
"region": {
"id": "region", "name": "region", "type": "select", "label": "Region", "required": true,
"options": [{ "items": [{ "label": "United States", "value": "us" }, { "label": "Europe", "value": "eu" }] }]
},
"vatNumber": {
"id": "vatNumber", "name": "vatNumber", "type": "text", "label": "VAT number",
"visibleWhen": [{ "field": "region", "is": ["eu"] }]
},
"statusMap": {
"id": "statusMap", "name": "statusMap", "type": "staticMap", "label": "Order status map",
"keyName": "source", "keyLabel": "Source status", "valueName": "target", "valueLabel": "Destination status",
"valueOptions": [{ "label": "Open", "value": "open" }, { "label": "Closed", "value": "closed" }]
}
},
"layout": {
"type": "collapse",
"containers": [
{ "label": "General", "fields": ["region", "vatNumber"] },
{ "label": "Advanced", "type": "box", "containers": [{ "label": "Status mapping", "fields": ["statusMap"] }] }
]
}
}
},
"settings": { "region": "eu", "vatNumber": "EU123", "statusMap": [{ "source": "pending", "target": "open" }] }
}Field Properties
字段属性
| Property | Rules |
|---|---|
fieldMap key, | Use one string for all three. |
| The control -- see Field Types |
| The label beside the field, a line of text under it, and the help icon's text |
| Blocks the UI's Save while the field is empty (default |
| What the UI shows while |
| The choices of a |
| Conditions | |
| |
| 属性 | 规则 |
|---|---|
fieldMap key、 | 三者使用同一个字符串。 |
| 控件类型——参见 Field Types |
| 字段旁的标签、字段下方的一行文本,以及帮助图标的文本 |
| 字段为空时阻止 UI 保存(默认 |
| 当 |
| |
| Conditions | |
| 为 |
Field Types
字段类型
| Control | Saved value |
|---|---|---|
| Text input; | String (array with |
| Checkbox | Boolean |
| A switch between the entries of | The chosen entry's |
| Dropdown, radio buttons | The chosen item's |
| Dropdown allowing several choices | Array of |
| Date or date-and-time picker; | The picked date |
| Text input for a relative URI | String |
| Code editor; | The editor's content |
| Rows of two free-text inputs; | Array of |
| Two-column mapping table whose columns can offer choices | Array of |
| Dropdown whose options an export returns | The chosen option's |
| 控件 | 保存的 value |
|---|---|---|
| 文本输入; | String(使用 |
| Checkbox | Boolean |
| 在 | 所选 entry 的 |
| Dropdown、radio buttons | 所选 item 的 |
| 允许多选的 dropdown | |
| 日期或日期时间选择器; | 所选日期 |
| 相对 URI 的文本输入 | String |
| Code editor; | 编辑器中的内容 |
| 每行包含两个自由文本输入框; | |
| 可为列提供选项的双列映射表 | |
| 选项由 export 返回的 dropdown | 所选 option 的 |
Conditions
Conditions
A condition rule is (or ). Two set values compare as strings, so and both match a checked checkbox; match an unchecked one with .
{"field": "<field id>", "is": [<values>]}"isNot""is": ["true"]"is": [true][false]- shows the field while any rule matches;
visibleWhenwhile all of them do. With neither, the field always shows.visibleWhenAll - /
requiredWhenandrequiredWhenAll/disabledWhenmake the field required or read-only the same way.disabledWhenAll - A rule can hold nested or
"AND": [rules]in place of"OR": [rules].field - A rule naming a field the form doesn't have counts as matching for (the field always shows) and as not matching for
visibleWhenandrequiredWhen-- the save doesn't catch it.disabledWhen
条件规则为 (或使用 )。所有值都按字符串比较,因此 和 都会匹配已勾选的 checkbox;要匹配未勾选的 checkbox,则使用 。
{"field": "<field id>", "is": [<values>]}"isNot""is": ["true"]"is": [true][false]- 在任一规则匹配时显示字段;
visibleWhen在所有规则都匹配时显示。两者均未设置时,字段始终显示。visibleWhenAll - /
requiredWhen和requiredWhenAll/disabledWhen以相同方式将字段设为必填或只读。disabledWhenAll - 规则可以在 的位置包含嵌套的
field或"AND": [rules]。"OR": [rules] - 如果规则引用了表单中不存在的字段,则对于 视为匹配(字段始终显示),对于
visibleWhen和requiredWhen视为不匹配——保存操作不会发现此问题。disabledWhen
Layout
Layout
form.layoutfieldMap- A layout has a ,
type, and optionallycontainers(ids shown before the containers).fields - The layout's sets how its containers render:
typeside by side,columnas collapsible sections (closed until opened;collapseopens one),"collapsed": falseas bordered groups,boxas indented groups,indentandtabWithoutSaveas tabs.verticalTabWithoutSave - Each container has a (its heading) and
label, and can carry its ownfieldsandtypeto nest another level, as the Advanced container does in The Shape.containers
form.layoutfieldMap- 一个 layout 包含 、
type,并可选包含containers(显示在 containers 之前的 ids)。fields - Layout 的 决定其 containers 的渲染方式:
type为并排显示,column为可折叠 sections(默认关闭;collapse会打开某一项),"collapsed": false为带边框的 groups,box为缩进的 groups,indent和tabWithoutSave为 tabs。verticalTabWithoutSave - 每个 container 包含一个 (其标题)和
label,还可以拥有自己的fields和type来嵌套另一层,正如“结构”示例中的 Advanced container。containers
Init Scripts
Init Scripts
settingsForm.init{"_scriptId": "<scriptId>", "function": "<name>"}settingsForm.formsettingsjavascript
function initForm(options) {
var form = options.resource.settingsForm.form;
// add, remove, or change fields from the resource's own state
return form;
}- What the function gets: (the resource whose form it is -- for a flow group, the group:
options.resource,_id,name,settings),settingsForm, and on an integration and a flow group the parents: a flow group gets its integration asoptions.sandbox(and a parent integration asparentResource), a child integration gets its parent asgrandparentResource.parentResourceandoptions.licenseappear only in Integration Apps. Flows, exports, imports, and connections get onlyoptions.parentLicenseandresource.sandbox - The script must be the account's own. Any other is refused with 422 "Only a script owned by the user or a script shared by the Integration App can be used at settingsForm.init._scriptId" (on a flow group the path is
_scriptId).flowGroupings.<index>.settingsForm.init._scriptId - Not on iClients. The platform's form-init route serves integrations, flow groups, flows, exports, imports, and connections only, so an iClient form with an shows an error instead of the form -- and an iClient save stores any
initwithout checking it._scriptId - Testing: no CLI command or MCP tool calls the init route. Run the function through the JavaScript processor with an object you build -- see How to Check a Form.
options
settingsForm.init{"_scriptId": "<scriptId>", "function": "<name>"}settingsForm.formsettingsjavascript
function initForm(options) {
var form = options.resource.settingsForm.form;
// add, remove, or change fields from the resource's own state
return form;
}- 函数获得的内容:(表单所属的资源;对于 flow group,是该 group:
options.resource、_id、name、settings)、settingsForm;integration 和 flow group 还可获得父资源:flow group 的options.sandbox是其 integration(如果该 integration 本身还有父 integration,则后者是parentResource),child integration 的grandparentResource是其父级。parentResource和options.license仅出现在 Integration Apps 中。Flows、exports、imports 和 connections 仅获得options.parentLicense和resource。sandbox - Script 必须属于当前 account。 任何其他 都会被拒绝,并返回 422 “Only a script owned by the user or a script shared by the Integration App can be used at settingsForm.init._scriptId”(对于 flow group,路径为
_scriptId)。flowGroupings.<index>.settingsForm.init._scriptId - iClients 不支持。 平台的 form-init route 仅适用于 integrations、flow groups、flows、exports、imports 和 connections,因此带有 的 iClient form 会显示错误,而不是表单——而 iClient 保存时会存储任何
init,不会对其进行检查。_scriptId - **测试:**没有 CLI command 或 MCP tool 会调用 init route。请通过 JavaScript processor 运行该函数,并自行构建它所需的 对象——参见“如何检查表单”。
options
Schema Index
Schema Index
The form's full shape is the schema on the API reference's Integrations page (agent-readable markdown; exports and imports embed the same schema), and is a free-form object on every scope. Over MCP, returns it.
Formsettingsget_schema({ target: "resource", name: "common/form" })表单的完整结构是 API reference 的 Integrations 页面上的 schema(可供 agent 阅读的 markdown;exports 和 imports 嵌入相同 schema),而 在每个 scope 上都是 free-form object。通过 MCP, 会返回它。
Formsettingsget_schema({ target: "resource", name: "common/form" })Related Skills
Related Skills
- writing-handlebars > Context Decision Matrix -- reading settings values in templates
- writing-scripts > Common Options -- in hooks, and the init function point
options.settings - configuring-filters > Gotchas -- settings scopes in filter operands
- configuring-exports -- the export body an runs
exportSelect - managing-integrations > Organize the resources inside -- creating flow groups and putting flows in them
- managing-integrations > Integration Apps -- app settings, which the app's own code saves
- configuring-connections -- full updates of connections and iClients, which carry masked secrets
- writing-handlebars > Context Decision Matrix——在 templates 中读取 settings values
- writing-scripts > Common Options——hooks 中的 以及 init function point
options.settings - configuring-filters > Gotchas——filter operands 中的 settings scopes
- configuring-exports——运行的 export body
exportSelect - managing-integrations > Organize the resources inside——创建 flow groups 并在其中放入 flows
- managing-integrations > Integration Apps——由 app 自身代码保存的 app settings
- configuring-connections——connections 和 iClients 的完整更新,其中包含被遮蔽的 secrets
Dynamic Fields: exportSelect and staticMap
Dynamic Fields:exportSelect 和 staticMap
exportSelect
exportSelect
A dropdown whose options come from an export the form carries inline, in :
resource.virtualjson
"warehouse": {
"id": "warehouse", "name": "warehouse", "type": "exportSelect", "label": "Warehouse",
"resource": { "virtual": {
"_connectionId": "<connectionId>",
"adaptorType": "HTTPExport",
"http": { "relativeURI": "/v1/warehouses", "method": "GET", "formType": "http", "response": { "resourcePath": "warehouses" } },
"transform": { "type": "expression", "expression": { "version": "2", "rulesTwoDotZero": { "mode": "create", "mappings": [
{ "generate": "label", "extract": "$.name", "dataType": "string", "status": "Active" },
{ "generate": "value", "extract": "$.code", "dataType": "string", "status": "Active" } ] } } }
} }
}- The export is an export body, not a reference. There's no way to point at a saved export by id: put , its adaptor block, and an optional
adaptorTypeintransform. Withoutvirtualthe field shows "requires export resource."resource.virtualdefaults to the connection of the export or import the form is on; on any other scope, set it._connectionId - The UI previews the export when the form opens (and on Refresh) and lists the preview's -- the records after the transform, output filter, and preSavePage hook. Each record needs a
dataand avalue; a bare string or number serves as both. The preview reads at most 100 records: the UI sendslabel100 unless the export sets its own, which can't exceed 100. An HTTP export that finds no records answers without atest.limitlist, so the field shows "expecting array. try transform?" rather than an empty list -- as it does for any answer that isn't a list.data - allows several choices, saved as an array.
multiselect: true - renders the export body as a template before each preview (everything but
supportHandlebars: true,transform, andhooks). The template's context isn't the runtime's: the form's current values sit under the form's own scope name (filter,integration,flowGrouping,flow, orexport), beside the saved settings of the scopes above it and, on an export or import form, the whole document of the connection the export uses -- with noimportprefix:settings.,{{integration.accountId}}. Connection and iClient forms get an empty context. A templated list doesn't load on its own when the form opens: it loads through{{export.country}}orrefreshOptionsOnChangesTo, or when the user clicks Refresh.typeAheadSearch - loads the templated list once one of those fields has a value and reloads it whenever one changes -- a cascading dropdown. It works only with
refreshOptionsOnChangesTo: ["<field id>", ...].supportHandlebars - reloads it as the user types (300 ms after the last keystroke), with the typed text as this field's own value in the context; an empty box clears the list, and free text is accepted.
typeAheadSearch: true
一种 dropdown,其选项来自表单通过 内联携带的 export:
resource.virtualjson
"warehouse": {
"id": "warehouse", "name": "warehouse", "type": "exportSelect", "label": "Warehouse",
"resource": { "virtual": {
"_connectionId": "<connectionId>",
"adaptorType": "HTTPExport",
"http": { "relativeURI": "/v1/warehouses", "method": "GET", "formType": "http", "response": { "resourcePath": "warehouses" } },
"transform": { "type": "expression", "expression": { "version": "2", "rulesTwoDotZero": { "mode": "create", "mappings": [
{ "generate": "label", "extract": "$.name", "dataType": "string", "status": "Active" },
{ "generate": "value", "extract": "$.code", "dataType": "string", "status": "Active" } ] } } }
} }
}- 这个 export 是 export body,而不是引用。 无法通过 id 指向已保存的 export:需要在 中放置
virtual、对应的 adaptor block,以及可选的adaptorType。如果没有transform,字段会显示“requires export resource.”。resource.virtual默认使用该表单所属 export 或 import 的 connection;在其他 scope 上则必须显式设置。_connectionId - UI 会在表单打开时以及点击 Refresh 时预览该 export,并列出预览结果的 ——即经过 transform、output filter 和 preSavePage hook 处理后的 records。每条 record 都需要包含
data和value;裸字符串或数字可以同时充当两者。预览最多读取 100 条 records:除非 export 自行设置,否则 UI 会发送label100,而 export 自行设置的值不能超过 100。如果 HTTP export 未找到 records,响应中将没有test.limit列表,因此字段会显示“expecting array. try transform?”,而不是显示空列表;对于任何非列表形式的响应也是如此。data - 允许选择多个选项,并将其保存为数组。
multiselect: true - 会在每次预览前将 export body 渲染为 template(
supportHandlebars: true、transform和hooks除外)。该 template 的 context 与 runtime 不同:表单当前的 values 位于表单自身 scope name(filter、integration、flowGrouping、flow或export)下,与上级 scopes 已保存的 settings 并列;对于 export 或 import form,还包括该 export 所使用 connection 的完整 document,且没有import前缀:settings.、{{integration.accountId}}。Connection 和 iClient forms 得到空 context。带有 template 的列表不会在表单打开时自行加载:它通过{{export.country}}或refreshOptionsOnChangesTo加载,或者在用户点击 Refresh 时加载。typeAheadSearch - 会在指定字段之一已有 value 后加载 templated list,并在其中任一字段发生变化时重新加载——这就是 cascading dropdown。它仅在启用
refreshOptionsOnChangesTo: ["<field id>", ...]时有效。supportHandlebars - 会在用户输入时重新加载列表(最后一次按键后 300 ms),并将输入文本作为该字段自身的 value 放入 context;清空输入框会清除列表,同时允许使用自由文本。
typeAheadSearch: true
staticMap
staticMap
A two-column table, saved under the field's as an array of rows: .
name[{"source": "pending", "target": "open"}]- /
keyNamename the columns -- the keys of each saved row.valueName/keyLabelhead them.valueLabel - /
keyOptionsgive a column a suggestion list:valueOptionsitems ({label, value}and{id, text}work too). The cell still accepts typed values.[value, label] - /
keyResource--valueResource-- fill a column's suggestions from an inline export, previewed as for{"virtual": {<export body>}}(no templating). With either one set, both columns are required unless the field setsexportSelect, and the UI drops incomplete rows when it saves.keyValueRequired: false - Steps read the whole array: in a script, or
options.settings.flow.statusMap.find(r => r.source === status)over it in a template.#each
一种双列表格,以字段的 为 key 保存为行数组:。
name[{"source": "pending", "target": "open"}]- /
keyName用于命名各列,也就是每条保存记录中的 keys。valueName/keyLabel用作列标题。valueLabel - /
keyOptions为某一列提供建议列表:采用valueOptionsitems({label, value}和{id, text}格式也有效)。单元格仍接受手动输入的值。[value, label] - /
keyResource——valueResource——通过内联 export 为某一列填充建议值,其预览方式与{"virtual": {<export body>}}相同(不支持 templating)。设置其中任意一个后,两列都会成为必填项,除非字段设置了exportSelect;UI 保存时会丢弃不完整的行。keyValueRequired: false - Steps 会读取整个数组:在 script 中使用 ,或在 template 中对其执行
options.settings.flow.statusMap.find(r => r.source === status)。#each
How to Build a Settings Form
如何构建 Settings Form
1. Decide the scope
1. 决定 scope
Who reads the value? Put the form where every reader shares it (The Seven Scopes), and remember that steps in an API or a Tool see only their own scope plus connection and iClient. For a flow group, create the group first and put the flows in it (managing-integrations > Organize the resources inside).
谁会读取该 value?将表单放在所有读取者共享的位置(七种 Scope),并记住 API 或 Tool 中的 steps 只能看到自身 scope,以及 connection 和 iClient。对于 flow group,请先创建 group,再将 flows 放入其中(managing-integrations > Organize the resources inside)。
2. Read the resource
2. 读取资源
Read the whole resource: an existing to extend, the current , and everything else a full update must send back. On an integration, a flow group's form and values live in its entry.
settingsFormsettingsflowGroupings[]读取完整资源:需要扩展的现有 、当前 ,以及完整更新必须回传的所有其他内容。对于 integration,flow group 的表单和 values 位于其 entry 中。
settingsFormsettingsflowGroupings[]3. Write the fields
3. 编写字段
One entry per setting, with the same string as key, , and -- a plain key, no dots. Choose the (Field Types), give to choice fields, and a where the UI should suggest one. For a list of values the user picks from another system, use an ; for a value-to-value table, a (step 6).
fieldMapidnametypeoptionsdefaultValueexportSelectstaticMap每个 setting 对应一个 entry,其 key、 和 使用同一个字符串——普通 key,不含点号。选择 (Field Types),为选择类字段提供 ,并在 UI 应建议默认值时设置 。如果用户需要从另一个系统选择一组 values,请使用 ;如果需要 value-to-value table,请使用 (步骤 6)。
fieldMapidnametypeoptionsdefaultValueexportSelectstaticMap4. Lay the fields out
4. 排列字段布局
List every field in the layout exactly once. Choose the top-level , group related fields into labeled containers, and nest a container's own and for a second level.
typetypecontainers在 layout 中将每个字段恰好列出一次。选择顶层 ,将相关字段分组到带标签的 containers 中,并可嵌套 container 自身的 和 以形成第二层结构。
typetypecontainers5. Add conditions
5. 添加 conditions
Show, require, or lock fields with / / (or their forms), naming fields by id. Add to a field whose value shouldn't be saved while it's hidden.
visibleWhenrequiredWhendisabledWhen*AllomitWhenHidden: true使用 / / (或其 形式)显示、要求或锁定字段,并通过 id 引用字段。对于隐藏期间不应保存 value 的字段,添加 。
visibleWhenrequiredWhendisabledWhen*AllomitWhenHidden: true6. Build the dynamic fields
6. 构建动态字段
Write the inline export of each (or a column's / ) and preview it before you save the form: it must return / records -- shape them with a . Add and for a dropdown that depends on another field.
exportSelectstaticMapkeyResourcevalueResourcelabelvaluetransformsupportHandlebarsrefreshOptionsOnChangesTo编写每个 的内联 export(或某个 列的 / ),并在保存表单前进行预览:它必须返回包含 / 的 records——可使用 对其结构进行转换。对于依赖另一个字段的 dropdown,添加 和 。
exportSelectstaticMapkeyResourcevalueResourcelabelvaluetransformsupportHandlebarsrefreshOptionsOnChangesTo7. Add an init script (optional)
7. 添加 init script(可选)
When the form must change with the resource's state, write an init function that returns the form, test it (How to Check a Form), save the script, and set . The returned form replaces in the UI, so keep as the fallback the function starts from.
settingsForm.initsettingsForm.formform当表单必须随资源状态变化时,编写一个返回表单的 init function,对它进行测试(如何检查表单),保存 script,然后设置 。返回的表单会替代 ,因此应保留 作为函数开始执行时使用的 fallback。
settingsForm.initsettingsForm.formform8. Save the form and the values together
8. 同时保存表单和值
Send the form and the matching values in one update -- the full document, read in step 2 -- so steps have values before anyone opens the form. Keep every value steps read in the form: a save in the UI writes from the form's fields.
settingssettings在一次更新中发送表单及对应的 values——使用步骤 2 中读取的完整 document——从而确保在任何人打开表单之前,steps 就已经拥有所需的 values。保留 steps 会读取的每个 value:UI 保存时会根据表单字段写入 。
settingssettings9. Read the values in steps
9. 在 steps 中读取值
Reference each value through its scope key: in a template or filter operand, in a script, or in a Mapper 2.0 extract with the envelope input context (writing-mappings > Choose the input context).
{{settings.flowGrouping.region}}options.settings.export.batchLimit$.settings.flow.region通过各自的 scope key 引用 value:在 template 或 filter operand 中使用 ,在 script 中使用 ,或在带 envelope input context 的 Mapper 2.0 extract 中使用 (writing-mappings > Choose the input context)。
{{settings.flowGrouping.region}}options.settings.export.batchLimit$.settings.flow.regionHow to Check a Form
如何检查表单
- Read the resource back and compare and
settingsFormwith what you sent. A save never validates the form, so check it yourself: every layout id has asettingsentry, every field is in the layout once, every condition names an existing field, key =fieldMap=idon each field, and choice fields havename.options - Preview each inline export an or
exportSelectruns, withstaticMapadded the way the UI sends it -- a preview without it returns one record. Its"test": {"limit": 100}must be a list ofdata/labelrecords.value - Run the init function through the JavaScript processor, with the object it will receive (
options,resource, and the parents its scope gets). The reply'ssandboxis the form it returns; a throw comes back as 422 with the message.data - Render a template that reads the values with the Handlebars processor, with in its data (
settings), or preview the step with{"record": {...}, "settings": {"flow": {"region": "eu"}}}in the document. An import invoke writes to the destination; run one only against a test destination.settings - Open the form in the UI. Only the UI renders it -- the layout, the conditions, the dropdowns, and the init script's result.
- 重新读取资源,并将 和
settingsForm与发送的内容进行比较。保存操作绝不会校验表单,因此需要自行检查:每个 layout id 都有settingsentry,每个字段在 layout 中恰好出现一次,每个 condition 都引用现有字段,每个字段都满足 key =fieldMap=id,且选择类字段具有name。options - 预览每个内联 export,即 或
exportSelect运行的 export,并按照 UI 的方式添加staticMap——不带它进行预览只会返回一条 record。其"test": {"limit": 100}必须是包含data/label的 record 列表。value - 通过 JavaScript processor 运行 init function,并提供它将收到的 对象(
options、resource,以及其 scope 对应的父资源)。响应中的sandbox就是函数返回的表单;如果发生异常,则会以 422 和相应 message 返回。data - 渲染读取这些值的 template,通过 Handlebars processor 并在数据中提供 (
settings),或者在 document 中包含{"record": {...}, "settings": {"flow": {"region": "eu"}}}并预览该 step。Import invoke 会写入目标系统;仅可针对测试目标运行。settings - 在 UI 中打开表单。 只有 UI 会实际渲染它——包括 layout、conditions、dropdowns 和 init script 的结果。
Pre-Submit Checklist
提交前检查清单
- The form sits on the narrowest scope every reading step shares
- Each field's key,
fieldMap, andidare the same plain stringname - Every field appears in the layout once, and every layout id and condition names an existing field
- Choice fields have ; each
optionshasexportSelectwhose preview returnsresource.virtual/labelrecordsvalue - An names a script in this account, and the function was tested; not on an iClient
init._scriptId - holds a value for every field steps read, written in the same update as the form
settings - The update sent the complete document: ,
settingsForm, and everything else the resource hadsettings - Steps reference each value through its scope key
- 表单位于所有读取 steps 共享的最窄 scope
- 每个字段的 key、
fieldMap和id都是同一个普通字符串name - 每个字段在 layout 中恰好出现一次,且每个 layout id 和 condition 都引用现有字段
- 选择类字段具有 ;每个
options都有exportSelect,且其预览返回包含resource.virtual/label的 recordsvalue - 引用当前 account 中的 script,且该函数已经过测试;iClient 不得使用它
init._scriptId - 为每个供 steps 读取的字段保存了 value,并与表单在同一次更新中写入
settings - 更新发送了完整 document:、
settingsForm以及资源原有的所有其他内容settings - Steps 通过各自的 scope key 引用 value
Gotchas
Gotchas
- A full update erases what it omits. A body without or
settingsFormremoves them, and a body whosesettingshas nosettingsFormremoves the init script. Read the whole resource first, and change onlyinitwhen that's all you mean to change.settingsForm.form - Saves aren't checked against the form. A missing value, extra keys, wrong types, and dangling layout ids or conditions all save; only the UI enforces the form.
required - Only and
formare kept. Anything else at the top ofinitis dropped silently.settingsForm - Values sit directly under , keyed by
settings. A dottednamesaves as nested objects but reloads empty, and a value under any other key is invisible to the field.name - Steps need the scope key. renders empty; so does a path built from a field's label or a section heading.
{{settings.region}} - A step run on its own sees only its own scope. An export or import invoke without a parent renders ,
settings.integration, andsettings.flowGroupingempty -- run it as a step of the flow, or the flow itself, to see them.settings.flow - A hidden field is still saved unless it sets .
omitWhenHidden - A condition on a missing field fails open for visibility. naming a field that isn't there leaves the field always visible;
visibleWhenandrequiredWhennever apply.disabledWhen - The init script replaces the form. The UI shows what the function returns, not ; a throw replaces the form with the error message.
settingsForm.form - iClient forms can't use init, and an iClient save accepts any unchecked.
_scriptId - An exportSelect lists the preview's , at most 100 records. Records without
dataandlabeldon't make usable options, and an HTTP export that finds nothing shows an error instead of an empty list.value - Keep every value steps read in the form. A UI save writes from the form's fields, so a key you wrote over the API that the form doesn't define won't survive someone saving the form.
settings - Integration App settings are separate. An app's settings form is in its (
settings,settings.general), and changes go through the app's own save route -- see managing-integrations > Integration Apps.settings.sections
- 完整更新会清除未包含的内容。 未包含 或
settingsForm的 body 会将其移除,而settings中没有settingsForm的 body 会移除 init script。请先读取完整资源;如果只想修改init,就只修改它。settingsForm.form - 保存时不会根据表单进行检查。 缺失的 value、多余的 keys、错误的 types,以及悬空的 layout ids 或 conditions 全都可以保存;只有 UI 会执行表单规则。
required - 仅保留 和
form。init顶层的其他内容都会被静默丢弃。settingsForm - Values 直接位于 下,并以
settings为 key。 包含点号的name会被保存为嵌套对象,但重新加载时为空;任何使用其他 key 保存的 value 对字段都不可见。name - Steps 需要 scope key。 会渲染为空;根据字段标签或 section 标题构建的路径同样如此。
{{settings.region}} - 单独运行的 step 只能看到自身 scope。 没有父级的 export 或 import invoke 会将 、
settings.integration和settings.flowGrouping渲染为空——应将其作为 flow 中的 step 运行,或单独运行该 flow,才能看到这些值。settings.flow - 隐藏字段仍会被保存,除非它设置了 。
omitWhenHidden - 引用缺失字段的 condition 会在可见性判断时 fail open。 引用不存在的字段时,字段会始终可见;
visibleWhen和requiredWhen则不会生效。disabledWhen - Init script 会替代表单。 UI 显示函数返回的内容,而不是 ;发生异常时,错误信息会替代表单。
settingsForm.form - iClient forms 不能使用 init,并且 iClient 保存时会接受任何 ,不会进行检查。
_scriptId - exportSelect 最多列出预览中的 100 条 records。 缺少 和
label的 records 无法形成可用选项;如果 HTTP export 未找到内容,则会显示错误,而不是空列表。value - 保留 steps 会读取的每个 value。 UI 保存时会根据表单字段写入 ,因此通过 API 写入、但表单未定义的 key 不会在有人保存表单后继续保留。
settings - Integration App settings 是独立的。 App 的 settings form 位于其 中(
settings、settings.general),相关变更通过 app 自身的 save route 提交——参见 managing-integrations > Integration Apps。settings.sections
Common Errors
常见错误
| Error | Cause | Fix |
|---|---|---|
| 422 "Only a script owned by the user or a script shared by the Integration App can be used at settingsForm.init._scriptId" | | Use the |
| The form shows an error message instead of fields | The init function threw (or the form is on an iClient with an | Run the function through the JavaScript processor to see the error; remove |
| "requires export resource." under an exportSelect | No | Add the inline export body |
| "expecting array. try transform?" | The exportSelect's export found no records (an HTTP preview then has no | Preview the export with |
| An exportSelect's options are blank or can't be chosen | The records have no | Map them in the export's |
A field always shows despite | The rule names a field id that isn't in | Name the controlling field's id |
| A field reloads empty after saving | Its | Use one plain string for key, |
| No scope key, the wrong scope, the value isn't in | Check the path against The Seven Scopes and read |
A whole form or | A full update left it out | Write it back from your copy or the resource's audit log (an update's |
| 错误 | 原因 | 修复方法 |
|---|---|---|
| 422 “Only a script owned by the user or a script shared by the Integration App can be used at settingsForm.init._scriptId” | | 使用当前 account 中某个 script 的 |
| 表单显示错误消息而不是字段 | Init function 抛出异常,或者表单位于带 | 通过 JavaScript processor 运行该函数以查看错误;从 iClient 中移除 |
| exportSelect 下显示“requires export resource.” | 缺少 | 添加内联 export body |
| “expecting array. try transform?” | exportSelect 的 export 未找到 records(HTTP preview 因而没有 | 使用 |
| exportSelect 的 options 为空或无法选择 | Records 缺少 | 在 export 的 |
尽管设置了 | 规则引用了 | 引用控制字段的正确 id |
| 保存后字段重新加载时为空 | 其 | 对 key、 |
| 缺少 scope key、scope 错误、value 不在 | 对照“七种 Scope”检查路径,并重新读取 |
整个表单或 | 完整更新遗漏了这些内容 | 从你的副本或资源 audit log 中恢复(更新的 |