mcpField
E
editor-creator

editor-creator

github.com/datex开发92 次安装
代码仓库

关于 editor-creator

用于在 Datex Studio 分支上创建或修改编辑器配置的 skill,适合构建单实体查看与编辑界面。它强调数据源与实体字段绑定、查看/编辑模式,以及通过 CRUD action 保存。

主要功能

  1. 01创建或修改编辑器配置
  2. 02为单个实体绑定字段
  3. 03配置只读与编辑模式切换
  4. 04通过包装 function 调用 CRUD action
  5. 05验证配置后写回分支

适用场景

  1. 01为单条记录创建详情与编辑页面
  2. 02按实体属性配置编辑器字段
  3. 03为现有配置调整保存和编辑行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/datex/skills --skill editor-creator

安装后在 Claude Code 中输入/editor-creator确认已加载。

附带文件evals/evals.jsonreferences/editors.md

详细介绍

Editor Creator

在分支上创作或修改 Datex Studio 编辑器(configurationTypeId=4)——这是一个单实体查看/编辑屏幕,可加载一条记录,将字段与其属性一一绑定,在只读模式和编辑模式之间切换,并通过调用 CRUD 操作的封装函数保存更改。

参考资料

依赖项

  • requirements-gathering 技能 — 如果对话上下文中尚无需求简报,则调用此技能生成一份
  • form-creator / grid-creator 技能 — 当需求实际涉及临时收集输入(表单)或多记录列表(网格),而非单实体详情屏幕时调用
  • datasource-creator 技能 — 当编辑器所依赖的单结果流数据源需要作为独立配置创作时调用(较少见——通常使用嵌入式私有数据源)。要创作嵌入式数据源,请遵循 ../datasource-creator/references/datasources.md → 创建自有数据源 — generate-flow --single --get-flow 已会生成编辑器所需的结构,因此只需应用信封差异。
  • component-wiring-check 技能 — 推送前调用,以审核编辑器宿主(中心标签页 / 网格行操作 / 表单)上的 configParameters ↔ 目标 inParams 契约
  • type-definition-creator 技能 — 当编辑器绑定的实体接口或相关类型定义需要创作或扩展时调用(例如,向架构添加字段,而编辑器必须新增相应绑定)
  • tailoring-overlay 技能 — 当编辑器的客户专属扩展(添加字段、修改绑定)需要放入定制覆盖层,而非基础配置中时调用

CLI 生命周期

编辑器编写通过 dxs configuration 进行——这是一个适用于所有平台配置类型的通用 CRUD 基元。没有 dxs editor 子命令,也不支持字段级修补;你需要构建(或获取并提取)完整的 JSON 正文,编辑后再将其整体推回。CLI 中的类型标识符是 editor(小写,与 ConfigurationEndpoints.normalize_type 的输出一致),对应 configurationTypeId: 4。

创建新编辑器:

# 1. Build body.json from scratch (see references/editors.md → Minimal Valid Skeleton)
# 2. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI
dxs configuration validate editor -b <branchId> -D body.json
# 3. Create
dxs configuration upsert editor -b <branchId> -D body.json

编辑现有编辑器:

# 1. Fetch — note the envelope wrapper
dxs configuration get editor <configId> -b <branchId> -O envelope.json
# 2. EXTRACT THE INNER BODY (round-trip footgun guard — see "Round-trip rule" below)
jq .json envelope.json > body.json
# 3. Edit body.json
# 4. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI
dxs configuration validate editor -b <branchId> -D body.json
# 5. Push
dxs configuration upsert editor -b <branchId> -D body.json
往返规则(至关重要)

编辑现有配置时,切勿将 envelope.json 直接通过管道传给 dxs configuration upsert——这会在不报错的情况下破坏配置内容。上文修正后的步骤(在编辑前使用 jq 提取内部的 .json)适用于任何往返操作,不可省略。规范的往返流程和相关底层错误,参见 ../datex-studio-shared/configuration-roundtrip.md。

编辑器内容复杂——正文中会包含大量已填充内容,包括 toolbar、fieldsets、flows、datasourceConfig 和 datasources,并且每个嵌入的 flow 都带有 code 字段。在如此庞大的 JSON 中进行精细修改很容易出错;必须严格遵循往返流程(获取 → 使用 jq 提取 → 编辑 → 验证 → 推回),不能妥协。

工作流

[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:设置与需求
  1. 按照 ../datex-studio-shared/branch-setup.md 选择分支和连接。切勿假定分支 ID——请让用户确认。
  2. 检查对话上下文中是否已存在需求简报(由 requirements-gathering 或其他调用技能生成)。
    • 已有简报——使用该简报。简报应说明正在编辑的实体(以及宿主传入哪个键)、哪些字段可见或可编辑、仅查看与编辑模式的行为、保存语义(哪个 CRUD 操作会持久化更改),以及同一个编辑器是否也处理创建模式。
    • 没有简报——先调用 requirements-gathering 技能。预先明确实体结构和保存语义,可避免后续进行繁琐的往返操作。
阶段 2:选择编辑器、表单或网格

编写前请参阅 references/editors.md → 用途与适用场景。这不是风格上的选择——编辑器、表单和网格承担不同的作用,不能互换。

在以下情况选择编辑器:

  • 用户查看或修改由键标识的单个实体。
  • 字段级输入与该实体的属性一一对应。
  • UX 需要在不同视图模式(只读)和编辑模式(输入已解锁、保存已启用)之间切换。
  • 工作流通过 CRUD 操作(crud_create_entity / crud_update_entity)持久化更改。

在以下情况改用表单:

  • 工作是临时收集输入,与已存储的记录无关。
  • 对话框将 outParams 返回给调用方;不会隐式持久化任何内容。
  • 对话框仅用于创建,尚无实体可供填充。

在以下情况改用网格:

  • 用户以表格布局查看或操作多条记录。

如果答案是表单,请停止并调用 form-creator。如果答案是网格,请停止并调用 grid-creator。编辑器可以通过 $editor.entity.isNew 处理创建模式,但只有在同一个组件同时处理同一实体类型的创建和编辑时,这种做法才合理——纯创建对话框通常更适合使用表单。

阶段 3:编写编辑器正文

根据 references/editors.md → 最小有效骨架中的骨架构建 body.json。要点如下:

  1. 文件基础要求。 遵循下方的预检清单和 ../datex-studio-conventions/universal-checklist.md;-editor.json 文件格式参见 references/editors.md → 文件位置与命名。

  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/references/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)。缺少绑定会导致导入失败。架构新增字段时,编辑器应在同一次修改中添加相应绑定;如果实际 UX 尚未就绪,可以使用 removed: true 的存根绑定。对于对象数组子树,请使用按钮 + $editor.vars.<var> + set_config 合并模式。请参阅 references/editors.md → EditorFields 要求为每个架构字段提供绑定以及序列化配置 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。

阶段 4:验证并推送
# Validate the body locally against the branch. Exit 1 = validation found errors
# (read validation_errors, fix body.json, re-run) — not a broken CLI. Do not push on exit 1.
dxs configuration validate editor -b <branchId> -D body.json

# For a new editor
dxs configuration upsert editor -b <branchId> -D body.json

# For modify-existing (round-trip — never skip the jq extract)
dxs configuration get editor <configId> -b <branchId> -O envelope.json
jq .json envelope.json > body.json
# ... edit body.json ...
dxs configuration upsert editor -b <branchId> -D body.json

验证会在推送前发现缺失的必填字段、格式错误的参数描述符结构、EditorFields 一致性违规以及引用错误。它不会发现 onInit 与 onDataLoaded 之间的切换、未声明的 $editor.vars.<id> 写入,或未加包裹的 TypeScript 表达式槽位 — 这些属于行为问题,只会在运行时暴露。推送前请逐项检查 references/editors.md → 预检清单。

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

通过常规调用路径以对话框形式打开编辑器(例如 hub 标签页工具栏按钮、网格行操作,或会链接到编辑器的表单):

  • 数据填充成功 — 运行 onDataLoaded 时,$editor.entity 已填充;字段显示已加载的值。
  • 编辑模式切换正常 — 编辑按钮将 edit_mode = true;保存和取消按钮出现;字段变为可编辑。
  • 保存成功提交 — 根据 $editor.entity.isNew 正确分支;外层 CRUD 操作成功;对话框关闭或切回只读状态。
  • 取消后恢复原始值 — 编辑前快照仍可用(或数据源可重新获取数据且正常)。
  • 对于创建模式(isNew: true),嵌入式数据源会生成空白实体;保存路径进入创建分支。
  • 只有 onFormValidateFlowConfig 报告 is_valid 后,保存按钮才会启用。

如果无法运行应用,请重新获取配置(使用修正后的 jq .json 提取模式),并与 body.json 对比,确认推送已生效。

推送前检查清单

推送前,请完整检查 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 进行审查。

常见错误

错误修正方法
在 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变量未声明,写入会静默失败或触发运行时错误。声明每个变量。
新架构字段缺少字段绑定EditorFields 类型错误:Property 'foo__bar' is missing... but required in type 'EditorFields'。在同一次编辑中添加绑定;如果用户体验尚未就绪,可使用 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 缺少 isOwned: trueisOwned 是唯一用于将引用路由到嵌入式 datasources[],而非跨应用查找的设置。若未设置,平台会根据 configId + moduleId 在其他应用中解析,解析失败后报告 Invalid contract. Referenced configuration <name> does not exist or has been renamed。设置 isOwned: true。移除 moduleId 无法解决此问题——对于自有引用,系统不会读取 moduleId。参见 ../datasource-creator/references/datasources.md → Resolving an Owned Reference。
嵌入式数据源缺少 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 结尾,或与文件名主体不匹配导入 / 查找会失败。使用 snake_case,以 _editor 结尾,并确保与文件名主体一致。
宿主的引用集合中,moduleId 被设为宿主的包,而不是编辑器的包跨组件引用规则:moduleId 始终指向目标的包。参见 ../component-wiring-check/references/component-wiring.md。
编辑完成后,请调用 post-edit-verification,以发现描述、JSON 或架构违规。进行最终审核时,请调用 component-validator。

评论

支持 Markdown