Repository navigation
Commit 03069ca
fix(ui): object-form drawer and modal saves toast the record-named save message (#28204)
domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6Jao4bEiUw69ndedqMFX4DU3cu)_
Fixes #27453
Clause-②: yes (widening: @object-ui/i18n gains the public export
recordSaveMessage; no accept set moves)
Metadata-protocol: none
## 维护者速读
- 改了什么:`object-form` 块以抽屉或弹窗打开(`formType: 'drawer' | 'modal'`,含 React
页面里 `formType="drawer"` 的 `ObjectForm`)保存成功后,现在弹出点名记录的成功提示,如 `Task "Fix
login" updated`,与控制台记录对话框一致;提示文案改由 `@object-ui/i18n` 新导出的
`recordSaveMessage` 统一生成,控制台的两份手抄副本一并换成它。
- 为什么改:showcase
的任务台页面在抽屉里改任务、在弹窗里建任务,写入成功却没有任何反馈,违反「每次落地的写都要有点名记录的反馈」;React 页面的作用域里拿不到
toast,页面自己补不上,所以按分诊在平台补。
- 风险与回滚:只在块的抽屉/弹窗容器里加提示;控制台自己挂的
`ModalForm`、动作弹窗、设计器表单都不经过这个容器,不会双重提示(有用例钉住);带 `submitHandler`
的表单不提示;回滚即 revert 本 PR。
- 先看:`ui/packages/plugin-form/src/ObjectFormContainer.tsx` 的
`useContainerSaveFeedback`、`ui/packages/i18n/src/recordSaveMessage.ts`、`AppContent.tsx`
里改为调用共享构造器的 `recordSaveMessage`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/plugin-form/src/__tests__/containerSaveToastNamesRecord-27453.test.tsx`,预期
13 个用例全绿。
- 需要你做的:无,席位落地。
## What changes
The triage ruling (6523407987) asked for the console's named-save
feedback to become reachable from the platform: the drawer and modal
forms raise the same save feedback the record pages do, through one
exported helper rather than a second copy of `recordSaveMessage`, with
no change to the showcase page.
- **`@object-ui/i18n`** adds `recordSaveMessage(t, { label, objectDef,
saved, mode })`: the record-named message (`form.createdNamed` /
`form.updatedNamed`), or the object-label one (`form.createSuccess` /
`form.updateSuccess`) when the ADR-0079 resolver finds nothing nameable
(its `Record #ID` floor). It lives in `@object-ui/i18n` because its four
keys live in that package's packs, it already depends on
`@object-ui/core` (where `getRecordDisplayName` lives), and both
`@object-ui/plugin-form` and `@object-ui/app-shell` already depend on
it. No new dependency edge.
- **`@object-ui/app-shell`**: the console's record dialog
(`AppContent`'s `recordSaveMessage`) and the record form page
(`RecordFormPage`'s `handleSuccess`) each carried their own copy of that
logic; both now call the shared builder. Same keys, same floor, same
wording; the #27999 warning claim and `toastRecordSave` are untouched.
- **`@object-ui/plugin-form`**: `ObjectFormContainer`, the container the
`object-form` block supplies for `formType: 'drawer' | 'modal'`
(ADR-0050 Decision 4), now wraps the author's `onSuccess`: when the
container itself wrote (it has a data source and no `submitHandler`, in
`create` or `edit` mode) it toasts the record-named message, then runs
the author's `onSuccess`. A declared `successMessage` is used as
written. The object definition is read through `getObjectSchema`, which
the adapter has already cached for the form body. `DrawerForm` and
`ModalForm` themselves are unchanged, so a host that mounts them
directly (the console's record dialog, `useActionModal`, the designer's
object and field forms) keeps owning its feedback and is never toasted
twice.
`examples/app-showcase` is unchanged: its task-desk page's `afterWrite`
keeps closing the overlay and reloading, and the toast now comes from
the platform. No `packages/spec` edit.
## Tests
-
`ui/packages/plugin-form/src/__tests__/containerSaveToastNamesRecord-27453.test.tsx`
(new, 13 cases, each of the first six run for `drawer` and `modal`):
edit toasts `Task "Fix login" updated` before the author's `onSuccess`,
which still gets the record; create toasts `Task "Write release notes"
created`; a metadata-only block with no `onSuccess` is toasted; a record
with nothing nameable keeps `Task created successfully`; a declared
`successMessage` is the toast; a `submitHandler` form is not toasted; a
directly mounted `DrawerForm` with an `onSuccess` is not toasted.
- Existing suites that pin the console wording now run through the
shared builder unchanged: `AppContent.recordSaveToastNamesRecord-26172`,
`AppContent.recordSaveOneToast-27999` and every `RecordFormPage.*` suite
(14 files, 84 tests, all green).
**Ablation.** With `ObjectFormContainer`'s `toast.success(message)`
replaced by a no-op through `scripts/ablation-replace.mjs` (anchor 1 → 0
on disk), the new suite went 10 red / 3 green: every "toasts" row red,
the three "not toasted" rows green, as predicted before the run.
Restored by the tool: blob equal to `HEAD`'s, `git diff HEAD` empty.
## Acceptance notes
- **Where the toast is raised, and why not inside `DrawerForm` /
`ModalForm`.** The ruling allowed either the form variants or a
React-page toast hook; a hook would have needed the showcase page to
call it, which the ruling rules out. Inside `DrawerForm` / `ModalForm`
the toast would have fired for every host that mounts them directly and
toasts itself (the console's record dialog through `crud_success`,
`useActionModal`), so each would have needed an opt-out.
`ObjectFormContainer` is the one place where the `object-form` block is
the caller (ADR-0050 Decision 4), so the feedback sits there and the
direct hosts are untouched; the last test row pins that.
- **Advisory write warnings on this path are not folded into the
toast.** The console's dialog and record page claim their write's answer
warnings and carry them on the save toast (#27999, `claimAnswerWarnings`
in `@object-ui/app-shell`). The block container lives in
`@object-ui/plugin-form`, below app-shell, and has no claim, so a
warning from a drawer/modal save still arrives on the write-warning
channel's own toast, as it did before this change. Noted, not filed.
- **`successMessage` on a drawer/modal block was never shown before.**
It is now the toast when declared; previously neither container read it.
- **Showcase unchanged** (`examples/app-showcase`): its `afterWrite`
keeps closing the overlay and bumping the reload counter. Live
reproduction against the showcase backend was not run in this container;
the behaviour is pinned through the same `ObjectFormContainer` route the
React page's `ObjectForm` block takes.
- `@object-ui/app-shell` is `private: true`, so the changeset bumps only
`@object-ui/i18n` and `@object-ui/plugin-form`; the app-shell edit is a
refactor onto the shared builder with no wording change.
- **Double-toast survey (e8e2bcb).** Hosts that mount `ModalForm` /
`DrawerForm` directly and own their feedback: `AppContent` (record
dialog, via `crud_success`), `useActionModal`, the designer's
`FieldDesigner` and `ObjectManager`. None of them passes through
`ObjectFormContainer`, so none gets a second toast; the last test row
pins a direct `DrawerForm` mount. Pages that use the block's container
and gain a toast: the showcase task-desk page (drawer edit, modal
create) and the showcase renewals page (`ObjectForm formType="drawer"`).
Neither raised a toast of its own before, so neither is doubled.
## Verification
Head `e8e2bcbd` (the branch merged with `origin/main` `c48cd2c1`; the
four incoming commits touch no file under `ui/`).
- New suite: 13/13 green. Ablation as described above: 10 red / 3 green,
restored to `HEAD`.
- `pnpm --dir ui exec vitest run packages/plugin-form/ packages/i18n/`:
306 files. The first run had 2 failures in
`residue-namespaces-3546.test.tsx`, which pins `AppContent`'s fallback
spelling `t('common.record', { defaultValue: 'Record' })`; the spelling
is restored in `AppContent` and that file plus
`AppContent.recordSaveToastNamesRecord-26172` re-ran 52/52 green.
- `pnpm --dir ui exec vitest run` on
`AppContent.recordSaveToastNamesRecord-26172`,
`AppContent.recordSaveOneToast-27999` and
`packages/app-shell/src/views/RecordFormPage*`: 14 files, 84 tests,
green.
- `type-check` (with a real `.d.ts` build of the
`@object-ui/app-shell^...` closure): `@object-ui/i18n`,
`@object-ui/plugin-form`, `@object-ui/app-shell` exit 0.
- `eslint --no-inline-config` on the six touched source files: 0 errors.
`pnpm --dir ui run check:new-line-citations`: 0 new.
- Derived gates on `e8e2bcbd`, every line run with stdin from /dev/null,
exit codes on disk, reconciled with `dispatch-gates.mjs --ran`: 34
derived, 34 run, 0 NOT-MEASURED.
<details><summary>Derived gates (local, head e8e2bcb)</summary>
```text
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qiby8nyBCmFZV9NNymGG)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 49a078e commit 03069ca
7 files changed
Lines changed: 348 additions & 52 deletions
File tree
- .changeset
- ui/packages
- app-shell/src
- console
- views
- i18n/src
- plugin-form/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
20 | | - | |
| 19 | + | |
21 | 20 | | |
22 | 21 | | |
23 | 22 | | |
| |||
881 | 880 | | |
882 | 881 | | |
883 | 882 | | |
884 | | - | |
885 | | - | |
886 | | - | |
887 | | - | |
888 | | - | |
889 | | - | |
890 | | - | |
891 | | - | |
892 | | - | |
893 | | - | |
894 | | - | |
895 | | - | |
896 | | - | |
897 | | - | |
898 | | - | |
899 | | - | |
900 | | - | |
901 | | - | |
902 | | - | |
903 | | - | |
904 | | - | |
905 | | - | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
906 | 892 | | |
907 | 893 | | |
908 | 894 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
| 37 | + | |
39 | 38 | | |
40 | 39 | | |
41 | 40 | | |
| |||
166 | 165 | | |
167 | 166 | | |
168 | 167 | | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
178 | 173 | | |
179 | 174 | | |
180 | 175 | | |
| |||
197 | 192 | | |
198 | 193 | | |
199 | 194 | | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
211 | | - | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
216 | 201 | | |
217 | 202 | | |
218 | 203 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
85 | 88 | | |
86 | 89 | | |
87 | 90 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
27 | 34 | | |
28 | 35 | | |
29 | | - | |
| 36 | + | |
30 | 37 | | |
| 38 | + | |
| 39 | + | |
31 | 40 | | |
32 | 41 | | |
33 | 42 | | |
| |||
54 | 63 | | |
55 | 64 | | |
56 | 65 | | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
57 | 113 | | |
58 | 114 | | |
59 | 115 | | |
60 | 116 | | |
61 | 117 | | |
| 118 | + | |
62 | 119 | | |
63 | 120 | | |
64 | 121 | | |
| |||
88 | 145 | | |
89 | 146 | | |
90 | 147 | | |
| 148 | + | |
91 | 149 | | |
92 | 150 | | |
93 | 151 | | |
| |||
126 | 184 | | |
127 | 185 | | |
128 | 186 | | |
| 187 | + | |
129 | 188 | | |
130 | 189 | | |
131 | 190 | | |
| |||
0 commit comments