editor-creator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Editor Creator

编辑器创作工具

Author or modify a Datex Studio editor (configurationTypeId=4) on a branch — a single-entity view/edit screen that hydrates one record, binds fields 1:1 to its properties, toggles between read-only and edit mode, and persists changes through a wrapping function that calls a CRUD action.
在分支上创作或修改Datex Studio编辑器(configurationTypeId=4)——这是一种单实体查看/编辑界面,可加载单条记录,字段与实体属性1:1绑定,支持只读与编辑模式切换,并通过调用CRUD操作的包装函数保存修改。

References

参考资料

  • ../datex-studio-shared/branch-setup.md — Branch/connection selection (shared across skills)
  • references/editors.md — Authoritative editor authoring reference: file shape, runtime globals, invocation contract, common patterns, pre-flight checklist
  • ../datex-studio-conventions/file-format.md
    configurationTypeId
    table and TypeScript-expression encoding rules
  • ../datex-studio-conventions/naming-conventions.md
    _editor
    suffix, filename stem matching, display-name rule
  • ../datex-studio-runtime/runtime-globals.md — platform-injected globals available in editor code (
    $editor
    ,
    $flows
    ,
    $shell
    ,
    $utils
    , ...)
  • ../datex-studio-runtime/calling-conventions.md — UI-tier calling rules (call functions, never actions; CRUD via
    $apis.<Package>.FootprintApi.extendedActions.<action_name>
    )
  • ../form-creator/references/forms.md — sibling component for transient input collection (the editor-vs-form decision)
  • ../grid-creator/references/grids.md — typical host for editors via row-click / row-action flows
  • ../datasource-creator/references/flow-datasources.md — single-result shape required for editor-backing datasources
  • ../component-wiring-check/references/component-wiring.md — host reference contracts, vars-must-be-declared rule, moduleId rule
  • ../datex-studio-shared/branch-setup.md — 分支/连接选择(各技能通用)
  • references/editors.md — 编辑器创作权威参考:文件结构、运行时全局变量、调用约定、通用模式、预检查清单
  • ../datex-studio-conventions/file-format.md
    configurationTypeId
    对照表与TypeScript表达式编码规则
  • ../datex-studio-conventions/naming-conventions.md
    _editor
    后缀、文件名主干匹配规则、显示名称规则
  • ../datex-studio-runtime/runtime-globals.md — 平台注入到编辑器代码中的全局变量(
    $editor
    $flows
    $shell
    $utils
    等)
  • ../datex-studio-runtime/calling-conventions.md — UI层调用规则(仅调用函数,不直接调用操作;通过
    $apis.<Package>.FootprintApi.extendedActions.<action_name>
    执行CRUD)
  • ../form-creator/references/forms.md — 用于临时输入收集的同级组件(编辑器与表单的选择判断)
  • ../grid-creator/references/grids.md — 通常通过行点击/行操作流程唤起编辑器的宿主组件
  • ../datasource-creator/references/flow-datasources.md — 编辑器绑定数据源所需的单结果结构
  • ../component-wiring-check/references/component-wiring.md — 宿主引用约定、变量必须声明规则、moduleId规则

Dependencies

依赖项

  • requirements-gathering
    skill — invoked to produce a requirements brief if one doesn't already exist in the conversation context
  • form-creator
    /
    grid-creator
    skills — invoked when the requirement is actually transient input collection (form) or a multi-record list (grid), not a single-entity detail screen
  • datasource-creator
    skill — invoked when the single-result flow datasource backing the editor needs to be authored as a standalone config (rare — the embedded private datasource is the usual shape)
  • component-wiring-check
    skill — invoked to audit
    configParameters
    ↔ target
    inParams
    contracts on the editor's host (hub tab / grid row action / form) before push
  • type-definition-creator
    skill — invoked when the editor's bound entity interface or a related type definition needs authoring or extension (e.g. adding a field to the schema that the editor must mirror with a new binding)
  • tailoring-overlay
    skill — invoked when customer-specific extensions to the editor (added fields, modified bindings) need to live in a tailored overlay rather than the base config
  • requirements-gathering
    技能 — 若对话上下文无需求说明文档,将调用该技能生成需求简报
  • form-creator
    /
    grid-creator
    技能 — 若实际需求为临时输入收集(表单)或多记录列表(表格)而非单实体详情界面,将调用对应技能
  • datasource-creator
    技能 — 若编辑器绑定的单结果流数据源需作为独立配置创作(少见,通常使用嵌入式私有数据源),将调用该技能
  • component-wiring-check
    技能 — 在推送前,用于审核编辑器宿主(中心标签页/表格行操作/表单)的
    configParameters
    与目标
    inParams
    约定
  • type-definition-creator
    技能 — 若编辑器绑定的实体接口或相关类型定义需创作或扩展(例如为编辑器新增字段绑定而修改 schema),将调用该技能
  • tailoring-overlay
    技能 — 若需为编辑器添加客户特定扩展(新增字段、修改绑定)并使其位于定制覆盖层而非基础配置中,将调用该技能

CLI Lifecycle

CLI生命周期

Editor authoring goes through
dxs configuration
— the generic CRUD primitive over every platform configuration type. There is no
dxs editor
subcommand and no field-level patching; you build (or fetch + extract) the whole JSON body, edit it, and push the whole thing back. The type identifier in the CLI is
editor
(lowercase, matches
ConfigurationEndpoints.normalize_type
output), mapping to
configurationTypeId: 4
.
Create a new editor:
bash
undefined
编辑器创作通过
dxs configuration
完成——这是针对所有平台配置类型的通用CRUD原语。不存在
dxs editor
子命令,也不支持字段级补丁;需构建(或获取并提取)完整JSON内容,编辑后重新推送完整内容。CLI中的类型标识符为**
editor
**(小写,与
ConfigurationEndpoints.normalize_type
输出一致),对应
configurationTypeId: 4
创建新编辑器:
bash
undefined

1. Build body.json from scratch (see references/editors.md → Minimal Valid Skeleton)

1. 从零构建body.json(参考references/editors.md → 最小有效骨架)

2. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI

2. 验证 — 作为推送前置检查。退出码1表示发现错误(查看validation_errors,修复后重新运行),并非CLI故障

dxs configuration validate editor -b <branchId> -D body.json
dxs configuration validate editor -b <branchId> -D body.json

3. Create

3. 创建

dxs configuration upsert editor -b <branchId> -D body.json

**Edit an existing editor:**

```bash
dxs configuration upsert editor -b <branchId> -D body.json

**编辑现有编辑器:**

```bash

1. Fetch — note the envelope wrapper

1. 获取 — 注意信封包装

dxs configuration get editor <configId> -b <branchId> -O envelope.json
dxs configuration get editor <configId> -b <branchId> -O envelope.json

2. EXTRACT THE INNER BODY (round-trip footgun guard — see "Round-trip rule" below)

2. 提取内部内容(往返操作防坑规则 — 见下文“往返规则”)

jq .json envelope.json > body.json
jq .json envelope.json > body.json

3. Edit body.json

3. 编辑body.json

4. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI

4. 验证 — 作为推送前置检查。退出码1表示发现错误(查看validation_errors,修复后重新运行),并非CLI故障

dxs configuration validate editor -b <branchId> -D body.json
dxs configuration validate editor -b <branchId> -D body.json

5. Push

5. 推送

dxs configuration upsert editor -b <branchId> -D body.json
undefined
dxs configuration upsert editor -b <branchId> -D body.json
undefined

Round-trip rule (critical)

往返规则(关键)

When editing an existing config, never pipe the envelope.json directly into
dxs configuration upsert
— it silently destroys configuration content. The corrected sequence above (extract inner
.json
with
jq
before editing) is mandatory for any round-trip. See ../datex-studio-shared/configuration-roundtrip.md for the canonical round-trip and the underlying bug.
Editors are dense — the body carries
toolbar
,
fieldsets
,
flows
,
datasourceConfig
, and
datasources
substantially populated, with a
code
field on every embedded flow. Surgical edits in this much JSON are error-prone; round-trip discipline (fetch → jq-extract → edit → validate → push) is non-negotiable.
编辑现有配置时,切勿直接将envelope.json管道输入
dxs configuration upsert
——这会静默破坏配置内容。上述正确流程(编辑前用
jq
提取内部
.json
)是所有往返操作的强制要求。有关标准往返流程及底层问题,详见../datex-studio-shared/configuration-roundtrip.md
编辑器内容密集——body包含大量
toolbar
fieldsets
flows
datasourceConfig
datasources
配置,每个嵌入式流程都有
code
字段。在如此复杂的JSON中进行精准编辑易出错;往返操作规范(获取→jq提取→编辑→验证→推送)必不可少。

Workflow

工作流程

[Phase 1: Setup + Requirements]
Follow branch-setup.md for branch/connection selection
        |
[requirements brief in context?]
  +-----+-----+
  |            |
 YES          NO -> invoke `requirements-gathering`
  |            |
  +-----+------+
        |
[Phase 2: Editor vs Form vs Grid decision]
Consult references/editors.md → "Purpose & When to Use":
  - single hydrated entity, view/edit toggle, persist via CRUD -> editor
  - transient input collection, returns outParams, no entity -> form
  - multi-record tabular view -> grid
If form -> invoke `form-creator` instead and stop here.
If grid -> invoke `grid-creator` instead and stop here.
Create-only dialogs are usually forms, not editors.
        |
[Phase 3: Author editor body]
Build body.json:
  - File shape (configurationTypeId=4, *-editor.json suffix,
    referenceName ends _editor)
  - Embedded single-result private datasource in datasources[]
    (configurationTypeId=6, type=flows, accessModifier=private,
    getFlow populated; getListFlow/getByKeysFlow null;
    resultIsCollection=false; outParams[0].isCollection=false)
  - Flow shape: getFlow populated; getListFlow and getByKeysFlow null
    (editors call .get() — code left in getListFlow silently breaks hydration)
  - Entity shape mirrored: datasources[0].outParams[0].objectTypeDef
    == datasourceConfig.configOutParameters.result.objectTypeDef
  - onInitFlowConfig (pre-hydration; no $editor.entity reads)
    vs onDataLoadedFlowConfig (post-hydration; entity-derived defaults)
  - View/edit toggle via $editor.vars.edit_mode (declared in vars[])
  - Save branches on $editor.entity.isNew (crud_create vs crud_update)
  - onFormValidateFlowConfig gates $editor.toolbar.<save>.control.readOnly
  - EditorFields parity: every entity-interface field has a binding
    (stub with removed:true when UX isn't ready)
  - Invoke `datasource-creator` if a standalone datasource is missing
  - Invoke `component-wiring-check` to audit host's configParameters
        |
[Phase 4: Validate + push]
dxs configuration validate editor -b <branchId> -D body.json
        |
   +----+----+
   |         |
  CREATE   MODIFY-EXISTING
   |         |
   |         use the corrected round-trip
   |         (get -O envelope -> jq .json -> body)
   |         |
   +----+----+
        |
        v
dxs configuration upsert editor -b <branchId> -D body.json
   (upsert creates or updates by referenceName — one command for both)
        |
[Phase 5: Verify in Studio (optional)]
Open the editor as a dialog (from its host hub/grid); confirm
hydration, toggle into edit mode, save commits, cancel restores
        |
[invoke `post-edit-verification`; then `component-validator`]
[阶段1:设置 + 需求]
遵循branch-setup.md完成分支/连接选择
        |
[上下文是否存在需求简报?]
  +-----+-----+
  |            |
  是          否 → 调用`requirements-gathering`
  |            |
  +-----+------+
        |
[阶段2:编辑器、表单、表格的选择判断]
参考references/editors.md → “用途与适用场景”:
  - 单实体加载、查看/编辑模式切换、通过CRUD保存 → 编辑器
  - 临时输入收集、返回outParams、无实体关联 → 表单
  - 多记录表格视图 → 表格
若选择表单 → 调用`form-creator`并终止当前流程
若选择表格 → 调用`grid-creator`并终止当前流程
仅创建功能的对话框通常使用表单而非编辑器
        |
[阶段3:创作编辑器内容]
构建body.json:
  - 文件结构(configurationTypeId=4,后缀*-editor.json,
    referenceName以_editor结尾)
  - datasources[]中包含嵌入式单结果私有数据源
    (configurationTypeId=6,type=flows,accessModifier=private,
    getFlow已填充;getListFlow/getByKeysFlow为null;
    resultIsCollection=false; outParams[0].isCollection=false)
  - 流程结构:getFlow已填充;getListFlow和getByKeysFlow为null
    (编辑器调用.get() — getListFlow中遗留代码会破坏加载逻辑)
  - 实体结构镜像:datasources[0].outParams[0].objectTypeDef
    == datasourceConfig.configOutParameters.result.objectTypeDef
  - onInitFlowConfig(加载前;不可读取$editor.entity)
    与onDataLoadedFlowConfig(加载后;基于实体设置默认值)的区分
  - 通过$editor.vars.edit_mode实现查看/编辑模式切换(需在vars[]中声明)
  - 根据$editor.entity.isNew分支处理保存逻辑(crud_create vs crud_update)
  - 通过onFormValidateFlowConfig控制$editor.toolbar.<save>.control.readOnly
  - EditorFields一致性:实体接口的每个字段都有绑定
    (若UX未就绪,可使用removed:true作为占位)
  - 若缺少独立数据源,调用`datasource-creator`
  - 调用`component-wiring-check`审核宿主的configParameters
        |
[阶段4:验证 + 推送]
dxs configuration validate editor -b <branchId> -D body.json
        |
   +----+----+
   |         |
  创建新编辑器   修改现有编辑器
   |         |
   |         使用正确的往返流程
   |         (get -O envelope → jq .json → body)
   |         |
   +----+----+
        |
        v
dxs configuration upsert editor -b <branchId> -D body.json
   (upsert通过referenceName创建或更新 — 同一命令适用于两种场景)
        |
[阶段5:在Studio中验证(可选)]
通过正常调用路径(中心标签页工具栏按钮、表格行操作或链式表单)打开编辑器对话框;确认
加载成功、可切换编辑模式、保存提交生效、取消恢复原始值
        |
[调用`post-edit-verification`;随后调用`component-validator`]

Phase Details

阶段详情

Phase 1: Setup + Requirements

阶段1:设置 + 需求

  1. Follow ../datex-studio-shared/branch-setup.md for branch and connection selection. Never assume a branch ID — ask the user to confirm.
  2. Check whether a requirements brief already exists in the conversation context (produced by
    requirements-gathering
    or another calling skill).
    • Brief exists — use it. The brief should establish the entity being edited (and which key the host passes in), which fields are visible/editable, view-only-vs-edit-mode behavior, save semantics (which CRUD action persists changes), and whether the same editor handles create mode.
    • No brief — invoke the
      requirements-gathering
      skill first. Getting the entity shape and save semantics right up front avoids the dense round-trip that follows.
  1. 遵循../datex-studio-shared/branch-setup.md完成分支和连接选择。切勿假设分支ID——请用户确认。
  2. 检查对话上下文是否已存在需求简报(由
    requirements-gathering
    或其他调用技能生成)。
    • 存在简报 — 使用该简报。简报应明确待编辑的实体(及宿主传入的键)、可见/可编辑字段、只读与编辑模式行为、保存语义(通过哪个CRUD操作保存修改),以及同一编辑器是否支持创建模式。
    • 无简报 — 先调用
      requirements-gathering
      技能。提前明确实体结构和保存语义可避免后续复杂的往返操作。

Phase 2: Editor vs Form vs Grid decision

阶段2:编辑器、表单、表格的选择判断

Consult references/editors.md → Purpose & When to Use before authoring. The choice is not stylistic — editors, forms, and grids serve different roles and aren't interchangeable.
Pick an editor when:
  • The user views or modifies a single entity identified by a key.
  • Field-level inputs map 1:1 to properties of that entity.
  • The UX wants a distinct view-mode (read-only) and edit-mode (inputs unlocked, save active) toggle.
  • The flow persists changes through a CRUD action (
    crud_create_entity
    /
    crud_update_entity
    ).
Pick a form instead when:
  • The work is transient input collection that doesn't correspond to a stored record.
  • The dialog returns
    outParams
    to the caller; nothing persists implicitly.
  • The dialog is creation-only and no entity yet exists to hydrate.
Pick a grid instead when:
  • The user views or operates on multiple records in a tabular layout.
If the answer is form, stop and invoke
form-creator
. If the answer is grid, stop and invoke
grid-creator
. Editors can handle create mode via
$editor.entity.isNew
, but that path is justified only when the same component handles both create and edit for the same entity type — pure create dialogs are usually a better fit for a form.
创作前参考references/editors.md → 用途与适用场景。选择并非风格问题——编辑器、表单和表格各司其职,不可互换。
选择编辑器的场景:
  • 用户查看或修改由键标识的单个实体
  • 字段级输入与该实体属性1:1映射。
  • UX需要区分查看模式(只读)和编辑模式(输入解锁、保存激活)。
  • 流程通过CRUD操作(
    crud_create_entity
    /
    crud_update_entity
    )保存修改。
选择表单的场景:
  • 工作内容为临时输入收集,不对应存储记录。
  • 对话框向调用者返回
    outParams
    ;无隐式持久化逻辑。
  • 对话框仅用于创建,尚无实体可加载。
选择表格的场景:
  • 用户查看或操作表格布局中的多条记录
若选择表单,终止当前流程并调用
form-creator
。若选择表格,终止当前流程并调用
grid-creator
。编辑器可通过
$editor.entity.isNew
支持创建模式,但仅当同一组件处理同一实体类型的创建和编辑时才合理——纯创建对话框通常更适合使用表单。

Phase 3: Author editor body

阶段3:创作编辑器内容

Build
body.json
from the skeleton in references/editors.md → Minimal Valid Skeleton. Key points:
  1. File basics. Per the Pre-Flight Checklist below + ../datex-studio-conventions/universal-checklist.md; see references/editors.md → File Location & Naming for the
    -editor.json
    file shape.
  2. Embedded single-result datasource. Each editor embeds exactly one private, single-result flow datasource in
    datasources[]
    . Required shape:
    configurationTypeId: 6
    ,
    type: "flows"
    ,
    accessModifier: "private"
    ,
    getFlow
    populated,
    getListFlow: null
    ,
    getByKeysFlow: null
    ,
    resultIsCollection: false
    ,
    outParams[0].isCollection: false
    . A collection-returning datasource breaks the editor reference —
    datasourceConfig.get({...})
    can't hydrate
    $editor.entity
    from a list. See references/editors.md → Embedded Private Datasource and ../datasource-creator/references/flow-datasources.md → Single-Result Shape. If the editor needs to share a datasource with other components (rare), invoke
    datasource-creator
    to author a standalone version. The branch's server-side usage gate independently enforces this at contract-validation time — it blocks publish if the editor's datasource doesn't implement
    get
    on a single, non-collection result.
  3. Entity shape mirror.
    datasources[0].outParams[0].objectTypeDef
    (the datasource side) must mirror
    datasourceConfig.configOutParameters.result.objectTypeDef
    (the editor's consumer side) field-for-field. Any entity-shape change touches both places in the same edit. The
    datasourceKeyDef
    on
    datasourceConfig
    matches the embedded datasource's
    keyDef
    exactly and matches the
    inParams
    shape the host passes.
  4. onInitFlowConfig
    vs
    onDataLoadedFlowConfig
    .
    The single most common editor bug is flipping these.
    onInit
    fires before the datasource resolves —
    $editor.entity
    is not yet populated; reading it yields undefined. Use
    onInit
    for var setup, defaulting
    edit_mode
    on
    isNew
    , or logic independent of entity data.
    onDataLoaded
    fires after the entity hydrates — use it for entity-derived defaults, stashing pre-edit snapshots, and populating UI-only state from entity fields. See references/editors.md → onInitFlowConfig vs onDataLoadedFlowConfig.
  5. View/edit mode toggle. Declare
    edit_mode
    in top-level
    vars[]
    (every
    $editor.vars.<id>
    written in flow code must be declared — see ../component-wiring-check/references/component-wiring.md). Edit button visible when
    !edit_mode
    ; Save + Cancel visible when
    edit_mode
    . Field
    readOnly
    bound to
    !edit_mode
    (or computed per-field when some stay locked). Cancel restores original entity values — re-call the datasource or stash pre-edit values in
    $editor.vars
    during
    onDataLoaded
    .
  6. Save branches on
    $editor.entity.isNew
    .
    When new →
    crud_create_entity
    (or the equivalent create action wrapped in a function); when existing →
    crud_update_entity
    . Neither branch hardcoded. The UI-tier calling rule applies: editor code calls functions via
    $flows.<Package>.<fn>
    ; the function wraps the CRUD action call as
    $apis.<Package>.FootprintApi.extendedActions.<action_name>({...})
    . See ../datex-studio-runtime/calling-conventions.md.
  7. Save button gated by validation.
    onFormValidateFlowConfig
    runs whenever any field changes. Compute
    is_valid
    from field values (often via
    $utils.isDefinedTrimmed
    for required strings), then set
    $editor.toolbar.<save_button>.control.readOnly = !is_valid
    . Optionally push per-field messages to
    control.validationMessage
    . See references/editors.md → Save Button Gated by onFormValidateFlowConfig.
  8. EditorFields parity. The platform auto-generates an
    EditorFields
    TypeScript type from the bound entity's interface. The editor must declare a
    controlConfig
    -bearing binding for every field on that interface — nested paths flatten with
    __
    (e.g.
    replenishments.rules
    → field id
    replenishments__rules
    ). Missing a binding fails import. When the schema gains a field, the editor adds the binding in the same edit; a stub binding with
    removed: true
    is acceptable if real UX isn't ready. For array-of-object sub-trees, use the button +
    $editor.vars.<var>
    +
    set_config
    -merge pattern. See references/editors.md → EditorFields Requires a Binding for Every Schema Field and the serialized-config-JSON section for the wrapper-entity case.
  9. TypeScript-expression encoding on every declarative-string slot. Every
    tooltip
    ,
    placeholder
    ,
    value
    ,
    format
    , button
    label
    (when bound to a var) is inlined verbatim into generated TS. Wrap display text in backticks (
    "`Manage rules…`"
    ), wrap plain-string literals in TS quotes (
    "'MM/DD/YYYY'"
    ), leave raw expressions unwrapped (
    "$editor.vars.foo"
    ). An unwrapped tooltip like
    "Manage rules."
    compiles to bare TS tokens and breaks the build. See ../datex-studio-conventions/file-format.md → Declarative String Values Are TypeScript Expressions.
  10. No custom-enum FQNs in
    vars
    /
    inParams
    /
    outParams
    .
    Editors can't resolve
    $types.<Package>.e_<enum>
    in param declarations — declare those fields as primitive (
    string
    for string-valued enums,
    number
    for numeric) and cast at usage inside flow code.
  11. onCustomization*
    slots stay
    null
    unless customization hooks are explicitly needed — they're platform-extension points for tailored overlays (
    tailoring-overlay
    ), not everyday editor wiring.
  12. Host contract audit. The hub tab, grid row action, or form that opens this editor as a dialog must declare a full
    configParameters
    contract — every
    inParam
    the editor declares gets an entry on the host, including unused ones with
    value: null
    . Invoke
    component-wiring-check
    to audit reference contracts before push. See ../component-wiring-check/references/component-wiring.md.
基于references/editors.md → 最小有效骨架构建
body.json
。关键点:
  1. 文件基础。遵循下文预检查清单 + ../datex-studio-conventions/universal-checklist.md;文件结构参考references/editors.md → 文件位置与命名中的
    -editor.json
    规则。
  2. 嵌入式单结果数据源。每个编辑器在
    datasources[]
    中嵌入恰好一个私有单结果流数据源。必填结构:
    configurationTypeId: 6
    type: "flows"
    accessModifier: "private"
    getFlow
    已填充、
    getListFlow: null
    getByKeysFlow: null
    resultIsCollection: false
    outParams[0].isCollection: false
    。返回集合的数据源会破坏编辑器引用——
    datasourceConfig.get({...})
    无法从列表中加载
    $editor.entity
    。详见references/editors.md → 嵌入式私有数据源../datasource-creator/references/flow-datasources.md → 单结果结构。若编辑器需与其他组件共享数据源(少见),调用
    datasource-creator
    创作独立版本。分支的服务器端使用限制会在合约验证时独立强制执行——若编辑器数据源未实现单结果
    get
    操作,将阻止发布。
  3. 实体结构镜像
    datasources[0].outParams[0].objectTypeDef
    (数据源端)必须与
    datasourceConfig.configOutParameters.result.objectTypeDef
    (编辑器消费端)字段完全匹配。任何实体结构变更需同时修改两处内容。
    datasourceConfig
    上的
    datasourceKeyDef
    需与嵌入式数据源的
    keyDef
    完全匹配,且与宿主传入的
    inParams
    结构一致。
  4. onInitFlowConfig
    onDataLoadedFlowConfig
    的区分
    。最常见的编辑器错误就是混淆两者。
    onInit
    数据源解析前触发——
    $editor.entity
    尚未填充;读取会返回undefined。
    onInit
    用于变量设置、在
    isNew
    时默认
    edit_mode
    ,或与实体数据无关的逻辑。
    onDataLoaded
    实体加载后触发——用于基于实体设置默认值、存储编辑前快照,以及从实体字段填充仅UI状态。详见references/editors.md → onInitFlowConfig与onDataLoadedFlowConfig
  5. 查看/编辑模式切换。在顶层
    vars[]
    中声明
    edit_mode
    (流程代码中写入的每个
    $editor.vars.<id>
    都必须声明——详见../component-wiring-check/references/component-wiring.md)。当
    !edit_mode
    时显示编辑按钮;当
    edit_mode
    时显示保存+取消按钮。字段
    readOnly
    绑定到
    !edit_mode
    (或按字段计算,部分字段保持锁定)。取消操作恢复原始实体值——在
    onDataLoaded
    期间重新调用数据源或在
    $editor.vars
    中存储编辑前快照。
  6. 根据
    $editor.entity.isNew
    分支处理保存逻辑
    。新建实体时调用
    crud_create_entity
    (或包装在函数中的等效创建操作);现有实体时调用
    crud_update_entity
    。两者均不可硬编码。需遵循UI层调用规则:编辑器代码通过
    $flows.<Package>.<fn>
    调用函数;函数通过
    $apis.<Package>.FootprintApi.extendedActions.<action_name>({...})
    包装CRUD操作调用。详见../datex-studio-runtime/calling-conventions.md
  7. 保存按钮受验证控制
    onFormValidateFlowConfig
    在任何字段变更时触发。根据字段值计算
    is_valid
    (通常对必填字符串使用
    $utils.isDefinedTrimmed
    ),然后设置
    $editor.toolbar.<save_button>.control.readOnly = !is_valid
    。可选择将字段级消息推送到
    control.validationMessage
    。详见references/editors.md → 保存按钮受onFormValidateFlowConfig控制
  8. EditorFields一致性。平台会根据绑定实体的接口自动生成
    EditorFields
    TypeScript类型。编辑器必须为该接口的每个字段声明带有
    controlConfig
    的绑定——嵌套路径用
    __
    扁平化(例如
    replenishments.rules
    → 字段ID
    replenishments__rules
    )。缺少绑定会导致导入失败。当schema新增字段时,编辑器需在同一编辑操作中添加绑定;若UX未就绪,可使用
    removed: true
    作为占位绑定。对于对象数组子树,使用按钮 +
    $editor.vars.<var>
    +
    set_config
    合并模式。详见references/editors.md → EditorFields要求每个schema字段都有绑定和序列化配置JSON部分的包装实体案例。
  9. 每个声明式字符串插槽的TypeScript表达式编码。每个
    tooltip
    placeholder
    value
    format
    、按钮
    label
    (绑定到变量时)都会直接内联到生成的TS中。显示文本用反引号包裹(
    "`Manage rules…`"
    ),纯字符串字面量用TS引号包裹(
    "'MM/DD/YYYY'"
    ),原始表达式无需包裹(
    "$editor.vars.foo"
    )。未包裹的提示文本如
    "Manage rules."
    会编译为裸TS标记,导致构建失败。详见../datex-studio-conventions/file-format.md → 声明式字符串值为TypeScript表达式
  10. vars
    /
    inParams
    /
    outParams
    中无自定义枚举FQN
    。编辑器无法解析参数声明中的
    $types.<Package>.e_<enum>
    ——将这些字段声明为原始类型(字符串枚举用
    string
    ,数值枚举用
    number
    ),并在流程代码中使用时进行类型转换。
  11. onCustomization*
    插槽保持
    null
    ,除非明确需要自定义钩子——它们是平台为定制覆盖层(
    tailoring-overlay
    )提供的扩展点,并非日常编辑器配置所需。
  12. 宿主合约审核。将此编辑器作为对话框打开的中心标签页、表格行操作或表单必须声明完整的
    configParameters
    合约——编辑器声明的每个
    inParam
    都需在宿主中有对应条目,包括未使用的条目(
    value: null
    )。推送前调用
    component-wiring-check
    审核引用合约。详见../component-wiring-check/references/component-wiring.md

Phase 4: Validate + push

阶段4:验证 + 推送

bash
undefined
bash
undefined

Validate the body locally against the branch. Exit 1 = validation found errors

针对分支本地验证内容。退出码1表示验证发现错误

(read validation_errors, fix body.json, re-run) — not a broken CLI. Do not push on exit 1.

(查看validation_errors,修复body.json后重新运行)——并非CLI故障。退出码1时请勿推送。

dxs configuration validate editor -b <branchId> -D body.json
dxs configuration validate editor -b <branchId> -D body.json

For a new editor

针对新编辑器

dxs configuration upsert editor -b <branchId> -D body.json
dxs configuration upsert editor -b <branchId> -D body.json

For modify-existing (round-trip — never skip the jq extract)

针对修改现有编辑器(往返操作 — 切勿跳过jq提取步骤)

dxs configuration get editor <configId> -b <branchId> -O envelope.json jq .json envelope.json > body.json
dxs configuration get editor <configId> -b <branchId> -O envelope.json jq .json envelope.json > body.json

... edit body.json ...

... 编辑body.json ...

dxs configuration upsert editor -b <branchId> -D body.json

Validation surfaces missing required fields, malformed parameter-descriptor shapes, `EditorFields` parity violations, and reference errors before push. It does **not** catch the `onInit`-vs-`onDataLoaded` flip, undeclared `$editor.vars.<id>` writes, or unwrapped TypeScript-expression slots — those are behavioral and only surface at runtime. Walk the [references/editors.md → Pre-Flight Checklist](references/editors.md#pre-flight-checklist) before push.
dxs configuration upsert editor -b <branchId> -D body.json

验证会在推送前发现缺失的必填字段、格式错误的参数描述结构、EditorFields一致性违规和引用错误。但它**无法**检测`onInit`与`onDataLoaded`混淆、未声明的`$editor.vars.<id>`写入或未包裹的TypeScript表达式插槽——这些属于行为问题,仅在运行时暴露。推送前请浏览[references/editors.md → 预检查清单](references/editors.md#pre-flight-checklist)。

Phase 5: Verify in Studio (optional)

阶段5:在Studio中验证(可选)

Open the editor as a dialog through its normal invocation path (a hub tab toolbar button, a grid row action, or a form that chains into it):
  • Hydration succeeds —
    $editor.entity
    is populated when
    onDataLoaded
    runs; fields display the loaded values.
  • Edit-mode toggle works — Edit button flips
    edit_mode = true
    ; Save + Cancel appear; fields become editable.
  • Save commits — branches correctly on
    $editor.entity.isNew
    ; the wrapping CRUD action succeeds; the dialog closes or flips back to read-only.
  • Cancel restores original values — pre-edit snapshot survives (or the datasource re-fetches cleanly).
  • For create mode (
    isNew: true
    ), the embedded datasource synthesizes a blank entity; the save path takes the create branch.
  • Save button stays disabled until
    onFormValidateFlowConfig
    reports
    is_valid
    .
If the running app isn't available, re-fetch the config (using the corrected
jq .json
extract pattern) and diff against
body.json
to confirm the push landed.
通过正常调用路径(中心标签页工具栏按钮、表格行操作或链式表单)打开编辑器对话框:
  • 加载成功 —
    onDataLoaded
    触发时
    $editor.entity
    已填充;字段显示加载的值。
  • 编辑模式切换正常 — 编辑按钮将
    edit_mode
    设为
    true
    ;显示保存+取消按钮;字段变为可编辑。
  • 保存提交生效 — 根据
    $editor.entity.isNew
    正确分支;包装的CRUD操作成功;对话框关闭或切换回只读模式。
  • 取消恢复原始值 — 编辑前快照保留(或数据源重新获取干净数据)。
  • 创建模式(
    isNew: true
    )下,嵌入式数据源生成空白实体;保存路径走创建分支。
  • 保存按钮在
    onFormValidateFlowConfig
    报告
    is_valid
    前保持禁用。
若运行应用不可用,重新获取配置(使用正确的
jq .json
提取模式)并与
body.json
对比,确认推送已生效。

Pre-Flight Checklist

预检查清单

Before push, walk the full checklist in references/editors.md → Pre-Flight Checklist. The fast version:
  1. File basics.
    configurationTypeId: 4
    , suffix
    -editor.json
    ,
    referenceName
    ends
    _editor
    — plus the universal checks (../datex-studio-conventions/universal-checklist.md).
  2. Exactly one embedded datasource
    accessModifier: "private"
    ,
    type: "flows"
    , single-result shape (
    getFlow
    populated;
    getListFlow
    +
    getByKeysFlow
    null;
    resultIsCollection: false
    ;
    outParams[0].isCollection: false
    ).
  3. Entity shape mirrored
    datasourceConfig.configOutParameters.result.objectTypeDef
    field-for-field matches
    datasources[0].outParams[0].objectTypeDef
    .
    datasourceKeyDef
    matches the embedded datasource's
    keyDef
    and the host's
    inParams
    shape.
  4. Init-hook split correct
    onInitFlowConfig
    does not read
    $editor.entity
    ; entity-dependent defaults and pre-edit snapshots live in
    onDataLoadedFlowConfig
    .
  5. Save branches on
    $editor.entity.isNew
    crud_create_entity
    when new,
    crud_update_entity
    when existing. Neither branch hardcoded.
  6. onFormValidateFlowConfig
    gates
    $editor.toolbar.<save>.control.readOnly
    on field validity.
  7. $editor.vars
    declared
    — every var written in flow code (
    edit_mode
    , snapshots, in-progress arrays) is in top-level
    vars[]
    .
  8. EditorFields parity — every entity-interface field has a binding (stub
    removed: true
    if UX isn't ready). Array-of-object sub-trees use the button +
    $editor.vars
    +
    set_config
    -merge pattern.
  9. Calling-tier compliance — editor code calls functions via
    $flows.<Package>.<fn>
    ; the function wraps CRUD actions via
    $apis.<Package>.FootprintApi.extendedActions.<action_name>({...})
    ; no direct action calls from the editor.
  10. TypeScript-expression strings wrapped correctly — display text in backticks; raw expressions unwrapped; plain literals quoted.
  11. onCustomization*
    slots
    null
    unless customization is intentional.
  12. No
    $types.<Package>.e_<enum>
    in
    vars
    /
    inParams
    /
    outParams
    — primitives only at the param layer; cast at usage.
  13. Host carries a full
    configParameters
    contract
    — every inParam the editor declares has an entry; unused ones use
    value: null
    . Audit via
    component-wiring-check
    .
推送前,请浏览references/editors.md → 预检查清单完整内容。简化版本:
  1. 文件基础
    configurationTypeId: 4
    、后缀
    -editor.json
    referenceName
    _editor
    结尾 — 加上通用检查项(../datex-studio-conventions/universal-checklist.md)。
  2. 恰好一个嵌入式数据源
    accessModifier: "private"
    type: "flows"
    、单结果结构(
    getFlow
    已填充;
    getListFlow
    +
    getByKeysFlow
    为null;
    resultIsCollection: false
    outParams[0].isCollection: false
    )。
  3. 实体结构镜像
    datasourceConfig.configOutParameters.result.objectTypeDef
    datasources[0].outParams[0].objectTypeDef
    字段完全匹配。
    datasourceKeyDef
    与嵌入式数据源的
    keyDef
    及宿主的
    inParams
    结构一致。
  4. 初始化钩子区分正确
    onInitFlowConfig
    不读取
    $editor.entity
    ;依赖实体的默认值和编辑前快照放在
    onDataLoadedFlowConfig
    中。
  5. 根据
    $editor.entity.isNew
    分支处理保存逻辑
    — 新建时调用
    crud_create_entity
    ,现有时调用
    crud_update_entity
    。两者均未硬编码。
  6. onFormValidateFlowConfig
    根据字段有效性控制
    $editor.toolbar.<save>.control.readOnly
  7. $editor.vars
    已声明
    — 流程代码中写入的每个变量(
    edit_mode
    、快照、进行中的数组)都在顶层
    vars[]
    中声明。
  8. EditorFields一致性 — 实体接口的每个字段都有绑定(UX未就绪时可用
    removed: true
    占位)。对象数组子树使用按钮 +
    $editor.vars
    +
    set_config
    合并模式。
  9. 调用层合规 — 编辑器代码通过
    $flows.<Package>.<fn>
    调用函数;函数通过
    $apis.<Package>.FootprintApi.extendedActions.<action_name>({...})
    包装CRUD操作;编辑器不直接调用操作。
  10. TypeScript表达式字符串包裹正确 — 显示文本用反引号;原始表达式无需包裹;纯字面量用引号。
  11. onCustomization*
    插槽为
    null
    ,除非有意进行自定义。
  12. vars
    /
    inParams
    /
    outParams
    中无
    $types.<Package>.e_<enum>
    — 参数层仅使用原始类型;使用时在流程代码中进行类型转换。
  13. 宿主携带完整
    configParameters
    合约
    — 编辑器声明的每个inParam都有对应条目;未使用的条目设为
    value: null
    。通过
    component-wiring-check
    审核。

Common Mistakes

常见错误

MistakeFix
Reading
$editor.entity
inside
onInitFlowConfig
Entity isn't hydrated yet — yields undefined. Move entity-derived defaults and pre-edit snapshots to
onDataLoadedFlowConfig
.
Embedded datasource returns a collection (
resultIsCollection: true
or
outParams[0].isCollection: true
)
Editor can't hydrate
$editor.entity
from a list. Switch to single-result shape —
getFlow
populated,
getListFlow
/
getByKeysFlow
null.
datasources[0].outParams[0].objectTypeDef
and
datasourceConfig.configOutParameters.result.objectTypeDef
drift apart
Editor reference breaks at runtime. They mirror each other — any entity-shape change touches both.
Save path hardcoded to
crud_update_entity
(or
crud_create_entity
)
Breaks the other mode. Branch on
$editor.entity.isNew
.
$editor.vars.edit_mode = true
written in flow code without declaring
edit_mode
in top-level
vars[]
Var is undeclared — write fails silently or runtime error. Declare every var.
Missing field binding for a new schema field
EditorFields
type error:
Property 'foo__bar' is missing... but required in type 'EditorFields'
. Add the binding in the same edit; stub with
removed: true
if UX isn't ready.
Mutating
$editor.entity.<field>
directly when the entity is a serialized-config wrapper
Type error —
entity
exposes the wrapper, not the parsed config. Parse via
JSON.parse($editor.entity.config)
in
set_state
; reassemble in
set_config
; post
$editor.vars.new_config
via the CRUD action.
Array-of-object sub-tree authored as a flat field binding
id__path
flattening doesn't fit arrays. Use the button +
$editor.vars.<array_var>
+
set_config
-merge pattern (or a
codeBox
for power-user admin tooling).
Editor code calls an action directlyUI-tier rule: editor calls functions only. The function wraps the action via
$apis.<Package>.FootprintApi.extendedActions.<action_name>({...})
.
Unwrapped declarative-string slot (
"Manage rules."
instead of
"`Manage rules.`"
)
Inlined verbatim into generated TS — bare tokens break the build. Backticks for display text; quotes for plain literals; raw expressions unwrapped.
$types.<Package>.e_<enum>
in
vars
/
inParams
/
outParams
Custom-enum FQN doesn't resolve at the param layer. Declare as primitive (
string
/
number
); cast at usage inside flow code.
datasourceConfig.configOutParameters
authored as an object keyed by param name (
{"result": {...}}
)
It is an array of parameter descriptors mirroring the embedded datasource's
outParams
[{"id":"result","type":"object","objectTypeDef":[...],"isCollection":false}]
. The object form fails validation with a raw
Cannot deserialize ... into type 'IList<VarConfig>'
dump that names no field.
Embedded datasource given a
moduleId
on
datasourceConfig
An embedded (private) editor datasource carries no
moduleId
;
datasourceConfig
sets
isOwned: true
instead. With a
moduleId
the platform reports
Invalid contract. Referenced configuration <name> does not exist or has been renamed
, which points at the wrong problem entirely.
Embedded datasource missing
hasKey
/
hasResult
/
queryOptionsObjectTypeDef
All three are required.
queryOptionsObjectTypeDef
repeats the entity shape (the same array as
outParams[0].objectTypeDef
) and is the fifth entity-shape typedef site — the one most often missed. Omitting it fails with the bare, undiagnostic message
Entity definition is required
.
Piping
dxs configuration get -O envelope.json
directly into
dxs configuration upsert -D envelope.json
Silently destroys config content. Always
jq .json envelope.json > body.json
before editing. See "Round-trip rule" above.
description
exceeds 100 chars
SQL column limit — push will fail validation. Tighten.
referenceName
doesn't end in
_editor
or doesn't match filename stem
Import / lookup breaks. Snake_case,
_editor
suffix, filename stem matches.
moduleId
on the host's reference set to the host's package instead of the editor's
Cross-component reference rule —
moduleId
is always the target's package. See
../component-wiring-check/references/component-wiring.md
.
After your edit, invoke
post-edit-verification
to surface description/JSON/schema violations. For a final review, invoke
component-validator
.
错误修复方案
onInitFlowConfig
中读取
$editor.entity
实体尚未加载 — 返回undefined。将依赖实体的默认值和编辑前快照移至
onDataLoadedFlowConfig
嵌入式数据源返回集合(
resultIsCollection: true
outParams[0].isCollection: true
编辑器无法从列表中加载
$editor.entity
。切换为单结果结构 —
getFlow
已填充,
getListFlow
/
getByKeysFlow
为null。
datasources[0].outParams[0].objectTypeDef
datasourceConfig.configOutParameters.result.objectTypeDef
不一致
运行时编辑器引用失效。两者需完全镜像 — 任何实体结构变更需同时修改两处。
保存路径硬编码为
crud_update_entity
(或
crud_create_entity
破坏另一模式的功能。根据
$editor.entity.isNew
分支处理。
流程代码中写入
$editor.vars.edit_mode = true
但未在顶层
vars[]
中声明
edit_mode
变量未声明 — 写入操作静默失败或触发运行时错误。声明所有变量。
新增schema字段后缺少字段绑定
EditorFields
类型错误:
Property 'foo__bar' is missing... but required in type 'EditorFields'
。在同一编辑操作中添加绑定;UX未就绪时可用
removed: true
占位。
实体为序列化配置包装器时直接修改
$editor.entity.<field>
类型错误 —
entity
暴露的是包装器,而非解析后的配置。在
set_state
中通过
JSON.parse($editor.entity.config)
解析;在
set_config
中重新组装;通过CRUD操作提交
$editor.vars.new_config
对象数组子树作为扁平字段绑定创作
id__path
扁平化不适用于数组。使用按钮 +
$editor.vars.<array_var>
+
set_config
合并模式(或为高级用户管理工具使用
codeBox
)。
编辑器代码直接调用操作UI层规则:编辑器仅调用函数。函数通过
$apis.<Package>.FootprintApi.extendedActions.<action_name>({...})
包装操作调用。
未包裹的声明式字符串插槽(
"Manage rules."
而非
"`Manage rules.`"
直接内联到生成的TS中 — 裸标记导致构建失败。显示文本用反引号;纯字面量用引号;原始表达式无需包裹。
vars
/
inParams
/
outParams
中使用
$types.<Package>.e_<enum>
参数层无法解析自定义枚举FQN。声明为原始类型(
string
/
number
);使用时在流程代码中进行类型转换。
datasourceConfig.configOutParameters
创作为由参数名称作为键的对象(
{"result": {...}}
它是参数描述数组,需与嵌入式数据源的
outParams
镜像 —
[{"id":"result","type":"object","objectTypeDef":[...],"isCollection":false}]
。对象形式会导致验证失败,返回原始错误信息
Cannot deserialize ... into type 'IList<VarConfig>'
且不指明字段。
datasourceConfig
为嵌入式数据源设置
moduleId
嵌入式(私有)编辑器数据源
moduleId
datasourceConfig
需设置**
isOwned: true
**。设置
moduleId
后平台会报错
Invalid contract. Referenced configuration <name> does not exist or has been renamed
,指向错误问题。
嵌入式数据源缺少
hasKey
/
hasResult
/
queryOptionsObjectTypeDef
三者均为必填项。
queryOptionsObjectTypeDef
重复实体结构(与
outParams[0].objectTypeDef
相同的数组),是最常遗漏的第五个实体结构类型定义位置。省略它会返回无诊断信息的错误
Entity definition is required
dxs configuration get -O envelope.json
直接管道输入
dxs configuration upsert -D envelope.json
静默破坏配置内容。编辑前始终执行
jq .json envelope.json > body.json
。见上文“往返规则”。
description
超过100字符
SQL列限制 — 推送会验证失败。精简内容。
referenceName
不以
_editor
结尾或与文件名主干不匹配
导入/查找失效。使用蛇形命名、
_editor
后缀,文件名主干需匹配。
宿主引用的
moduleId
设为宿主包而非编辑器包
跨组件引用规则 —
moduleId
始终为目标组件的包。详见
../component-wiring-check/references/component-wiring.md
编辑完成后,调用
post-edit-verification
发现描述/JSON/schema违规。最终审核请调用
component-validator