Repository navigation
feat(console): an action's param dialog names its own submit verb (submitText drawn in place of Confirm) - #28392
Conversation
…bmitText Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
… form offers it Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
…-empty params Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
…row, translated Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
…he dialog and the resolver Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
… key Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
… description Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
📓 Docs Drift CheckThis PR changes 3 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 177 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 182b71038c2c39787453384f8ad4f7346d58080e && git checkout 182b71038c2c39787453384f8ad4f7346d58080e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin fa74b489308f0aded7d3434ebd65246519192022 9d549390e4cd47770852aece9585be4323f9a41c && git checkout -B drift-repro fa74b489308f0aded7d3434ebd65246519192022 && git merge --no-ff 9d549390e4cd47770852aece9585be4323f9a41c
node scripts/docs-audit/affected-docs.mjs --json fa74b489308f0aded7d3434ebd65246519192022
|
…on form's submitText row The positive-control count of translated metadata-form labels goes from 696 to 697: the action form now offers a `submitText` row, authored in all three translated locales. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzPbVCsG2npDkDqikd
|
domain:ui#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
domain:ui#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: Inputs: card #28158 (the consumer half of #27944: both handlers resolve ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Verdict reasoning. The card's two doors resolve the key in the order the i18n layer already uses for Implemented-by: VERDICT: PASS |
|
domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN 席位核对ACCEPT · seat 席位意见:操作弹出参数对话框时,提交按钮现在显示作者为该操作写的动词,例如「发送」「记录通话」,不再一律显示「确认」。没写时仍显示「确认」,上传文件期间仍显示「上传中」。翻译包里的译文优先,其次是行内多语言文本,最后是作者原文。命令行提取翻译时,只为带参数的操作生成这个键。规范只改说明文字,规则本身不变。
|
Requested by Tesla · project thread
Fixes #28158
Refs #27944
Clause-②: yes (widening:
@object-ui/typesUIActionSchemaand@object-ui/coreActionDefgain the optional membersubmitText, typed by derivation from the spec'sActionSchema;@object-ui/i18nuseObjectLabel()gains the resolveractionSubmitText; no key, route or error code is added)Metadata-protocol: none
维护者速读
submitText(如「发送」「记录通话」),没声明时仍是「确认」,上传文件时仍是「上传中…」。翻译包里的_actions.ACTION.submitText优先,其次是作者写的多语言文本(按当前语言取),最后是作者写的字符串。Studio 的动作表单也能填这个键了,os i18n extract会为带参数的动作生成它的翻译位。submitText已在 feat(spec): an action's param dialog can name its own submit verb —submitText#28188 写进 spec,但控制台一直画「确认」,作者写的按钮文字没人显示。submitText的动作完全不变。回滚即 revert 本 PR。ui/packages/app-shell/src/hooks/useConsoleActionRuntime.tsx与ui/packages/app-shell/src/views/RecordDetailView.tsx的paramCollectionHandler(新增的submitText解析);ui/packages/app-shell/src/views/ActionParamDialog.tsx提交按钮那一行;packages/spec/liveness/action.json的submitText行。pnpm --dir ui exec vitest run packages/app-shell/src/views/ActionParamDialog.submitText-28158.test.tsx packages/app-shell/src/hooks/__tests__/useConsoleActionRuntime.submitText-28158.test.tsx packages/app-shell/src/views/RecordDetailView.paramSubmitText-28158.test.tsx packages/i18n/src/__tests__/useObjectLabel-actionSubmitText-28158.test.tsx,预期 4 个文件、20 个测试全绿。What changes
The dialog (
ActionParamDialog.tsx).ParamDialogStategainssubmitText?: string, the already-resolved label. The submit button draws it, falls back toactionDialog.confirmwhen it is absent or empty, and still saysactionDialog.uploadingwhile a file param uploads.Both param-collection handlers (
useConsoleActionRuntime.tsx#paramCollectionHandler,RecordDetailView.tsx#paramCollectionHandler) resolve it the way they resolvedescription:actionSubmitText(keyObject, action.name, pickLocalized(action.submitText, language)). So the bundle'sobjects.OBJECT._actions.ACTION.submitText(globalActions.ACTION.submitTextfor an object-less action) comes first, then the authored inline locale map collapsed to the active language, then the authored string.The resolver (
@object-ui/i18nuseObjectLabel().actionSubmitText), the sibling ofactionDescription, on the sameactionSuffixesnode rule (a bound action never readsglobalActions). Its member-count pin inuseObjectLabel-identity-5564.test.tsxgoes from 28 to 29.Types.
UIActionSchema.submitText?: SpecAction['submitText']andActionDef.submitText?: SpecActionInput['submitText'], both derived.ACTION_DEF_KEYSlists it, and theSPEC_ACTION_KEYScomment no longer calls it inventory-only.The four action renderers (
action:button,action:icon,action:group,action:menu) forwardsubmitTextto the runner.check:action-forward-parity(ui) reds without this once the handlers read the key: the key would be dropped one hop before the dialog.action-forward-precedence.test.tsxlists it besidedescription.Spec rows.
liveness/action.jsonsubmitTextflipsplanned→livewith these read points, and dropsauthorWarn/authorHintin the same edit;state-counts/action.mdregenerates. Theaction/submitTextomit row leavesmetadata-form-zod-reconciliation.test.ts, andaction.form.tsgains a plainsubmitTextrow ("Submit button label"), not gated onparams, because the parse refuses the key beside an emptyparamsby name. Theplatform-objectsmetadata-forms bundles regenerate (node scripts/check-i18n-bundles.mjs --write); the zh-CN / ja-JP / es-ES values are hand-translated. The prose clause "(declared ahead of its console reader: no renderer shows it yet)" leavesActionSchema.submitText's.describe(), and "no renderer shows it yet" leaves the translation slot's;content/docs/references/**regenerates (check:generated --fix). The seat ruled that trim into this PR. Nothing else in the schema changes.os i18n extract(packages/cli/src/utils/i18n-extract.ts,pushActionSubmitText). It scaffoldssubmitTextunder an action's translation root only for an action with a non-emptyparams, the populationtranslateActionoverlays it onto. It is optional-not-derived likedescription, and there is no slot for a paramless action.Changeset
.changeset/28158-action-param-dialog-submit-text.md, allpatch(Metadata-protocol: none).Tests
ActionParamDialog.submitText-28158.test.tsx(5): the verb is drawn, the fallback is Confirm (also for''), the verb button submits, and Uploading wins while a file uploads.useConsoleActionRuntime.submitText-28158.test.tsx(5) andRecordDetailView.paramSubmitText-28158.test.tsx(5), one per reader: the authored string, the bundle winning, an inline map collapsed to the active language before it is offered as the fallback, the key object asked (global for an object-less action, the page object when the action declares none), and nothing handed over when nothing resolves.useObjectLabel-actionSubmitText-28158.test.tsx(5): the object node, the global node, no global read for a bound action (with a control), the miss answers.RecordDetailView.paramRuntimeParity-6431.test.tsx:submitTextjoinsDIALOG_READS, and the two runtimes write the same value.packages/cli/test/i18n-extract-action-submit-text.test.ts(7): top-level, global and inline actions; the seed-less slot; no slot without params; bundle seed and coverage gating; one fixture throughActionSchema→ extract →ObjectTranslationDataSchema.useObjectLabelpartially gain anactionSubmitTextpassthrough (overrideNotice,paramDialogTitle,paramRefusal-13161,oneToastPerRefusal-13340,flowRowGuard-13397).Acceptance notes
ui/packages/i18n(the resolver) orui/packages/components/src/renderers/action/*(the forward lines). Both are mechanical consequences of the read point, and the seat accepted both before this PR opened; the claim will be amended with them.ActionParamDialogconsumer,metadata-admin/MetadataTypeActions.tsx(metadata-type actions in Setup), passes neitherdescriptionnorsubmitText, so its button still says Confirm. The card names the two business-action handlers only. Noted, not filed.submitTextis not interpolated: it is a button verb, and no${…}hole is read in it, unlikedescription.Verification
Readings at head
5f1a6b33(after mergingorigin/mainat3ba52069), unless a line says otherwise.Derived gates — 112 derived, 112 run, all exit 0
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 112 families against this diff; each ran with stdin closed and its exit code recorded before any pipe. The record isui-seat-1/r2026-10-30/out/28158-gates-ran-5f1a6b33.listin the project files.dispatch-gates.mjs --ran: 112 run, 0 NOT-MEASURED, 0 UNRUN.ef504b2cthe same sweep had one exit 3,check-plugin-teardown-shape.mjs --self-test(the pinned fixture commit is absent from a shallow clone); aftergit fetch origin 621a4876… --depth=1it exits 0, and on5f1a6b33all 112 exit 0.env -u OS_SKIP_DTS pnpm exec turbo run build --filter='!@objectstack/docs', 116/116 tasks).node scripts/check-sdui-manifest.mjsexit 0 (derived); uicheck:action-forward-parityexit 0 (it reds before the four forward lines: 4 surfaces "does not forward 1 key the runtime reads:submitText"); uicheck:new-line-citations0 new, exit 0.Tests
5f1a6b33:pnpm --dir ui exec vitest runover the four new files,app-shell/src/hooks/__tests__/, the twoRecordDetailView.param*pins,i18n/,core/src/actions/,components/src/renderers/action/,types/→ 649 files, 13888 passed, 13 skipped.ef504b2c:ActionParamDialog*,RecordDetailView*,DeclaredActionsBar*→ 110 files, 819 passed.@object-ui/app-shell,components,core,i18n,types→ exit 0 each.pnpm --filter @objectstack/spec exec vitest run src/ui/ src/system/metadata-form-zod-reconciliation.test.ts src/system/translation.test.ts→ 170 files, 6236 passed.typecheckexit 0;vitest run --project unit test/i18n-extract→ 10 files, 87 passed.scripts/ablation-replace.mjs): replacing theparamsguard inpushActionSubmitText(anchor 1 → 0) reds "emits NO slot for an action without params" (1 failed | 6 passed); restored by the tool, blob == HEAD,git diff HEADempty.pnpm --filter @objectstack/spec check:livenessexit 0 aftergen:liveness-counts(theactionshard: one row planned → live).Generated by Claude Code