Repository navigation
feat(core,react,app-shell): action confirmText, successMessage and errorMessage read the template envelope and fill {{ }} holes (objectui#13367) - #13409
Conversation
…{ }} holes
ActionRunner reads confirmText, successMessage and errorMessage as a
string or a { dialect: 'template', source } envelope, and fills {{ }}
holes through @objectstack/formula's templateEngine: confirmText over
record and params, successMessage over result and record, errorMessage
verbatim. A sentence with no {{ }} hole keeps the ${...} reading.
useActionTextLocalizer keeps the envelope instead of collapsing it to
its first string value.
Claude-Session: https://claude.ai/code/session_0159TkE3rFbrKwMs3mWhnniW
Co-authored-by: Claude <noreply@anthropic.com>
flowSuccessCopy read the invoking action's successMessage only as a string, so an envelope fell to the flow's own copy. It now reads it through core's actionCopySource, and FlowRunner's actionSuccessMessage takes the same two shapes as ActionDef.successMessage. Claude-Session: https://claude.ai/code/session_0159TkE3rFbrKwMs3mWhnniW Co-authored-by: Claude <noreply@anthropic.com>
…tion-copy-template
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Face: the ① Derived judgmentsThe diff widens one public interface and adds one public module. No existing member is narrowed.
② Semver levelThe changeset declares ③ Boundary flags
Implemented-by: VERDICT: PASS |
席位核对ACCEPT — objectui#13367 (p3, M, card thread), head Seat: domain:ui#1 · Clause-②: yes(合同复核见本 PR 上的
|
Requested by Sales · project thread
Fixes #13367
The renderer half of objectstack-ai/objectstack#24814 (ruling A): an action's
confirmText,successMessageanderrorMessageread thetemplateenvelope and fill{{ }}holes, before the spec types the three slots astemplateslots. Claim: #13367 comment6369803045.What changes
ActionRunner(@object-ui/core) reads each key as a string or{ dialect?: 'template', source? }:confirmText:{{ }}holes overrecord(the record the action runs against; on a list, the clicked row, the same rule astemplateEvaluatorFor) andparams(the action's static params object, without the stashed row; the collected values do not exist yet when the confirmation shows);successMessage:{{ }}holes overresult(the payload${result.*}reads) andrecord;errorMessage: no root is declared yet, so the text shows as written.@objectstack/formula'stemplateEngine, the one the flow notifications render with and the one list bulk actionconfirmText: fill the template slot's declared holes —{{count}}first, the action's params second (the renderer half of objectstack#24798 ruling B) objectstack#25942's ruling names. It is exported at this repo's.objectstack-shapin and already a dependency of@object-ui/core. No engine and no hole grammar is written here.{{ }}hole keeps today's reading (${…}throughExpressionEvaluatorforconfirmText,${result.*}forsuccessMessage), so the platform objects'${result.email}sentences keep working until the spec card converts them.{{ }}hole goes through the template engine only. A record value that happens to contain${…}is never evaluated after it was filled into a hole.sourcegives''to the confirm handler (the declared confirmation still gates the run), the default text to the success toast, and the action's own error to the error toast.useActionTextLocalizer(@object-ui/react) kept the three keys asI18nLabelmaps and collapsed them withpickLocalized, which turns{ dialect: 'template', source }into its first string value: the wordtemplate. It now hands the envelope on, and a bundle entry replaces itssource(i18next leaves a missing{{ }}variable in place, measured on the installed version).@object-ui/app-shell):flowSuccessCopyread the invoking action'ssuccessMessageonly as a string, so an envelope fell to the flow's own copy. It now reads it throughactionCopySource.FlowRunner'sactionSuccessMessagetakes the same two shapes (the type widening made app-shell's type-check red at the two launch sites otherwise).@object-ui/coreexports the reader:ActionCopyTemplate,isActionCopyEnvelope,actionCopySource,hasTemplateHoles,fillTemplateHoles.Clause-②: yes (the claim said
no;ActionDef's three keys widen and core gains five exports, so this declares the widening)Metadata-protocol: none
Tests
packages/core/src/actions/__tests__/ActionRunner.copyTemplate-13367.test.ts(28): a plain string and an envelope per key; each root (recordfrom the header and from a row,paramswithout_rowRecord,result); a formatter; an undeclared root prints empty;${…}still filled forconfirmTextandsuccessMessage; one dialect per sentence for both; a refused source shown as written; an envelope with no source for each key;outcomeMessagesstill outranks; an envelope counts as declared copy for a navigation (objectui#12755); the reader helpers.packages/react/src/hooks/__tests__/useActionTextLocalizer.templateEnvelope-13367.test.tsx(5): nameless and named actions keep the envelope, a bundle entry replacessource, a sourceless envelope passes through, strings and maps unchanged.packages/app-shell/src/utils/__tests__/flowResponse.test.ts: 3 new cases for the envelope on a flow action.f25bc24): the localizer'scollapseCopyput back topickLocalized, and the success rung put back to string-only: 9 failed (5 runner, 4 localizer); restored withgit checkout HEAD -- packages,git diff --quiet HEADclean.pnpm exec vitest run --maxWorkers=2 packages/core/ packages/react/→ 331 files, 5566 passed.packages/components/src/renderers/action/ packages/app-shell/src/hooks/__tests__/ packages/app-shell/src/utils/ packages/plugin-grid/→ 391 files, 3995 passed. After the app-shell commit: app-shell hooks, utils and flow views → 141 files, 1427 passed. After mergingorigin/main(889d028): core actions, react hooks, flowResponse and the objectui#13379 navigator pins → 84 files, 1097 passed.NODE_OPTIONS=--max-old-space-size=8192 pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/console→ 37/37. A first run over app-shell, console, components and the plugin packages went red on the two launch sites above, which the second commit fixes.check:new-line-citations,check:control-bytes,check:spec-symbols,check:changeset-claims,check:pending-changeset-literals,check:unreferenced-sources,check:test-path-roots,check:action-forward-parity,check:handler-key-reads,check:phantom-deps,check:self-import,check:esm-specifiers,check:component-surface-parity,check:vi-mock-specifiers,check:comment-mask-corpus,scripts/check-changeset-presence.mjs.check:readme-exportsneeds every package built and was left to CI.Order
This PR → objectstack's
.objectui-shamoves past it → objectstack-ai/objectstack#24814 types the slots (it carriesBlocked-by: objectstack-ai/objectui#13367).Serial
objectui#13395 (objectui#13384) also edits
ActionRunner.ts, in other hunks (a refusal inserted just above the confirm read, and theRUNNER_TEXTdocblock, whose last sentence this PR rewords). Whichever lands second merges main.Acceptance notes
{{ }}formatters render inen-US: the runner has no language (its docblocks say so), so{{ amount | currency }}does not follow the user's locale yet. Noted, not filed.FlowRunner's terminal toast after a paused flow shows the action's copy as written: neither{{ }}nor${result.*}is filled there, before or after this PR. Noted, not filed.The Studio action inspector and preview (
ActionDefaultInspector,ActionPreview) read the three keys asI18nLabelmaps, so an envelope would show there astemplate. Authoring surface, outside the runner; noted, not filed.list bulk action
confirmText: fill the template slot's declared holes —{{count}}first, the action's params second (the renderer half of objectstack#24798 ruling B) objectstack#25942 (bulkconfirmTextfill step,baozhoutao) can call the samefillTemplateHolesover{ count, … }; this PR does not touch plugin-grid.Adds no product-specific widget, dialog, hook or string (see AGENTS.md › Product-neutral renderer)
Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_0159TkE3rFbrKwMs3mWhnniW