You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 84ce59c
Browse filesBrowse the repository at this point in the historyBrowse files
feat(core): show a holeless confirmText / successMessage as written (objectui#13476) (#13482)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} -->
_Requested by **Elon** · [project
thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9DYL5YEa1zRjoXpJH1JbeMbZ)_Fixes#13476
Clause-②: no
Metadata-protocol: narrowed
## Summary
objectui#13367 kept one transitional reading in `ActionRunner`: a
`confirmText` or `successMessage` sentence with no `{{ }}` hole still
had its `${…}` tokens filled. This PR removes both branches, so a
holeless sentence is shown exactly as written, the same as any other
copy with no hole. It is the objectui half of
#25702; #25709
(warning to error, delete `ACTION_COPY_DOLLAR_TRANSITION_ROOTS`) waits
for objectstack's `.objectui-sha` to carry this merge.
## Changes
- `confirmMessage`: the `!hasTemplateHoles(text)` branch returns `text`
instead of `templates.evaluate(text)`. The method no longer takes the
evaluator; the param dialog's `interpolate` (still the `${…}` evaluator,
out of scope) now builds it right where it is used.
- `composeSuccessMessage`: a holeless `successMessage` returns
`successCopy` instead of running `substituteScopeTokens`.
- Docblocks updated: `ActionDef.confirmText`,
`ActionDef.successMessage`, the `RUNNER_TEXT` note,
`composeSuccessMessage`, `confirmMessage`, `templateEvaluatorFor`,
`interpolateTarget`'s note and `substituteScopeTokens` (the grammar's
one toast caller is now `outcomeMessages`), plus `hasTemplateHoles` in
`actionCopyTemplate.ts`.
- Docs: `content/docs/core/enhanced-actions.mdx` "Post-success
behaviour" now says `outcomeMessages` reads `${result.*}` and
`successMessage` reads `{{ result.* }}` / `{{ record.* }}`; the
complex-action example's `confirmText` uses a `{{ record.customer_name
}}` hole.
- Changeset `.changeset/13476-holeless-action-copy.md`:
`@object-ui/core` minor (a narrowing; objectui marks breaking changes
`minor`).
**Untouched, per the card:** `outcomeMessages` keeps its `${result.*}`
reading through `substituteScopeTokens`; `errorMessage` is still shown
as written.
The claim's file surface was amended by the seat (card comment
6391456644) for `actionCopyTemplate.ts`, the docs page, and the
app-shell test. Two more test files outside it also drove the old
reading end to end and are converted here:
`packages/plugin-grid/src/__tests__/rowActionRecordHole-12967.test.tsx`
and
`packages/app-shell/src/views/ObjectView.toolbarScriptSelection-12331.test.tsx`,
plus
`packages/react/src/hooks/__tests__/useActionTextLocalizer.outcomeMessages-11344.test.tsx`.
## Tests
Every fixture that fed the runner a holeless `${…}` `confirmText` /
`successMessage` now authors the `{{ }}` hole the runner reads, and
three rows pin the new behaviour:
- `ActionRunner.copyTemplate-13367`: "a `${…}` token in a sentence with
no hole is text, not an expression" (header door and row door), and "a
`${result.*}` token in a sentence with no hole is text, not filled".
- `ActionRunner.outcomeMessages-11344`: "rung 2 — a `${result.*}` token
in a successMessage with no hole is text". The "reads the `result` scope
only" row moves to an `outcomeMessages` entry, the one toast rung that
still uses the `${…}` grammar.
- `ActionRunner.rowRecordTemplates-12967`: the row-less control now
reads `Pause ?` (an unbound `{{ record.* }}` root prints empty) where
the evaluator left `${record.display_name}` raw.
Runs, at head `55dfcfd`, from the repo root:
- `pnpm exec vitest run packages/core/src/actions/`: 41 files, 625 tests
passed.
- Converted and neighbouring suites (app-shell invite feedback, toolbar
script selection, `onSuccess.navigate` hosts, param-dialog record holes,
`consoleServerAction`, components `renderers/action/`, element-button
i18n copy, plugin-grid row-action record hole, console registry parity,
react `hooks/`, app-shell `hooks/__tests__/`, record-alert, ListView).
The first sweep (44 files, 968 tests) failed 3 rows in
`rowActionRecordHole-12967` and `toolbarScriptSelection-12331`, which
still authored `${…}`; after converting them, those 2 files pass (11
tests). The second sweep: 120 files, 1233 tests passed.
- `pnpm --filter @object-ui/core type-check`: exit 0, after building the
core dependency closure.
**Ablation** (commit first, then mutate, trap-restored): with
`ActionRunner.ts` reverted to `origin/main`, the three new rows fail
(`Tests 3 failed | 45 passed (48)`); restored, `git diff HEAD` is empty
and the blob hash matches HEAD.
## Gates (local subset)
- `check:new-line-citations`, `check:control-bytes`, `check:doc-fences`,
`check:doc-types`, `check:changeset-claims`,
`check:pending-changeset-literals`, `check:action-forward-parity`: exit
0.
- `node scripts/check-changeset-presence.mjs`: passes, 1 changeset
declared.
- NOT MEASURED locally: `check:doc-snippets` and `check:doc-examples`
(exit 2, precondition: the doc-snippet build closure is not built here).
CI runs both; the docs edit changes one string literal inside a typed
snippet.
- Full `pnpm test` and `pnpm lint` are CI's.
## Acceptance notes
- No in-tree producer authors the holeless `${…}` shape: no non-test
`confirmText` / `successMessage` in this repo carries `${`, and
objectstack's measurement (card) found none in examples,
`platform-objects`, `plugin-approvals` or HotCRM.
- Fixtures left as `${…}` on purpose: `element-button-i18nCopy-12757`
and `action-outcomeMessages-forward-11344` (components) only pin that
copy reaches the runner unchanged, or never reach rung 2; the react
localizer's `outcomeMessages` fixtures are rung 1, which keeps
`${result.*}`.
- `ActionParamDialog.tsx`'s `interpolate` docblock still says it fills
`${...}` "in the template scope the runner reads `confirmText` in". The
record binding is still shared; the dialect differs now. Carrier: none,
noted only.
- [x] Adds no product-specific widget, dialog, hook or string (see
AGENTS.md › Product-neutral renderer)
---
_Generated by [Claude
Code](https://claude.ai/code/session_01P5j5dvWsBeNZNp2qLwwRqH)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
An action's `confirmText` or `successMessage` with no `{{ }}` hole is now shown exactly as written (objectui#13476).
9
+
10
+
objectui#13367 kept one transitional reading: a sentence with no `{{ }}` hole still had its `${…}` tokens filled, `${record.*}` in the confirm dialog and `${result.*}` in the success toast. That reading is gone. A `${…}` token in either text is now plain text, the same as in any other copy with no hole. To put a value into the sentence, write a `{{ }}` hole: `Archive {{ record.name }}?`, `Invitation sent to {{ result.email }}`.
11
+
12
+
No in-tree producer writes the holeless `${…}` shape. objectstack's measurement of its examples, `platform-objects`, `plugin-approvals` and HotCRM found none. objectstack's lint already warns on the shape and refuses every other `${…}` token in this copy (objectstack#25702). The paired objectstack card turns the warning into an error once its objectui pin carries this change.
13
+
14
+
`outcomeMessages` entries are unchanged: they still fill `${result.*}`. `errorMessage` is unchanged: it is shown as written.
0 commit comments