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 7bbc0b9
Browse filesBrowse the repository at this point in the historyBrowse files
fix(app-shell): pending changes folds platform-written system fields and derived keys into one collapsed line (#25984)
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi9CEUVquf4gyNp5rXBUzghZZ)_Fixes#25890
Clause-②: no
Metadata-protocol: none
## What changes
Studio's pending-changes drill-in (`DraftChangesPanel`) listed a new
object's platform-injected system columns (`created_at`, `created_by`,
`owner_id`, `updated_at`, `updated_by`) as fields the author added, and
its derived `nameField` under "Also changed", next to the one field the
author actually typed. Following the triage ruling ("Pending changes
lists what the author changed. Platform-provisioned system fields and
derived keys belong in a collapsed 'generated' group, not in the
author's diff."):
- **System fields fold.** In `computeChangeDetail`, a field this publish
adds or removes, where every definition the two bodies carry has
`system: true`, moves to a new `generated` list. `system: true` is the
spec's own mark (`FieldSchema.system`: "Auto-injected system/audit field
… Tools that surface system fields separately from author-declared
business fields should branch on this flag"). No name list is kept in
the panel. The read localises the injected columns' labels, so
byte-identity against `injectedSystemColumnDefs` cannot answer this on a
served body; the mark can.
- **Derived keys fold.** A top-level `nameField` goes to `generated`
when its value equals the `@objectstack/spec/data` `provisionPrimary`
derivation over the body without the pointer. That is the same test the
registry's write-side strip (`stripProvisionedPrimaryFrom`) uses. A
pointer naming a field the derivation would not pick is the author's
choice and stays an author row.
- **What stays an author row.** A system field whose definition
*differs* between the published and draft bodies (for example, the
author relabelled `owner_id`) stays an author row: the platform injects
the same definition on both reads, so a difference is an edit. The
objectui#13125 rule (`system` AND `hidden`, e.g. `__search`) still drops
those rows outright, unchanged.
- **The fold renders as one collapsed line**, "Generated by the platform
(N)" (「平台生成(N)」), with a toggle that shows those rows. It stays
collapsed in the confirm posture too.
- **A new item's keys are headed "Includes:"** (「包含:」) instead of "Also
changed:" (「其他变更:」). Every key of an item that does not exist yet is
part of it, not some other change.
- Two new i18n keys (`preview.changes.detailNewKeys`,
`preview.changes.generatedGroup`) are added to all ten packs, because
the key-parity test requires every pack.
- `scripts/sdui-manifest.record.json`: the registry-source hash is
re-recorded by `node scripts/gen-sdui-manifest-node.mjs`. The manifest
bytes did not change (sha256 `1f6e1ccb925a…`, 106 components).
The card's repro (new object 「报修工单」, OWD private) now expands to `+ 名称
name`, then `Includes: + label + name + sharingModel`, then one
collapsed `Generated by the platform (6)` line (the five system columns
plus `nameField`).
## Acceptance notes
- **Deviation from the dispatch's acceptance wording ("only the authored
field(s) plus one folded system-fields line").** The new object's
authored top-level keys `label`, `name` and `sharingModel` are still
listed, under "Includes:". The ruling folds *platform-provisioned*
fields and *derived* keys, and those three are authored in the create
dialog. A first cut dropped `name`/`label` for new items (the row
already shows them), but that reversed seven existing pins in four files
(`DraftChangesPanel.test.tsx` "classifies a NEW item",
`noChangeAndKeySplit-11807`, `posture-12517`,
`protectionEnvelope-12594`), which the dispatch asked to keep green. So
it was reverted. If the maintainer wants a new item's name/label hidden
as well, that is a follow-up with those pins rewritten deliberately.
- **One existing pin updated on purpose.** In
`DraftChangesPanel.fieldRows-13125.test.tsx`, `owner_id` and
`created_at` were "listed" controls ("this card does not widen the
rule"). They now assert placement in the generated group, and that the
drop rule still leaves them in the detail behind the toggle.
- The panel only sees served bodies, so an author who declares a column
that the platform also injects, with `system: true` on it, reads as
platform-written when added. That is the spec's stated meaning of the
mark.
## Tests
At head `f96a8519`:
- `pnpm exec vitest run --maxWorkers=2 packages/i18n/
packages/app-shell/src/preview/` (from `ui/`): **Test Files 120 passed
(120), Tests 1585 passed | 13 skipped**.
- New `DraftChangesPanel.generatedGroup-25890.test.tsx` (9 tests). It
pins the card's repro using the spec's real `injectedSystemColumnDefs`
with zh-localised labels, plus four controls: a system field the author
changed, an author-chosen `nameField`, a system field added on an
update, and an audit-shaped field without the mark.
- **Ablation, once.** I disabled the fold predicate through
`scripts/ablation-replace.mjs` (anchor 1 to 0, blob `6c92a1c5…` to
`805a4a90…`). The new suite went **4 failed | 5 passed**. The file was
restored to its HEAD blob `6c92a1c5…`. The suite resolves
`DraftChangesPanel` from source through the ui vitest alias, so no dist
rebuild was involved.
- `pnpm --filter @object-ui/i18n --filter @object-ui/app-shell run
type-check` (both `tsc --noEmit` and `tsconfig.test.json`): **Done /
Done**.
- `node scripts/check-i18n-call-site-keys.mjs` (ui): exit 0. eslint on
the touched files: 0 errors. The 6 warnings are all in code this PR does
not change.
## Gates
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `f96a8519` derived 46 families. All 46
ran with exit 0. `--ran` reconciliation: "46 derived famil(ies)
accounted for — 46 run, 0 NOT-MEASURED (a DERIVED zero …)". At the
earlier head `6577bce6`, `check-sdui-manifest` was red because the ui
source hash had moved. The regeneration commit fixed it, and the check
is green at `f96a8519`. CI families are left to the PR's check-runs.
Out of bounds and untouched: `ui/.github/**` and the root
`.github/workflows/ci.yml`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01P4aqt32BH9VTnLdDgkBUMx)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
fix(app-shell): pending changes folds what the platform wrote into one collapsed line
7
+
8
+
Clause-②: no
9
+
Metadata-protocol: none
10
+
11
+
Publishing a new object from Studio listed the platform's injected system columns (`created_at`, `created_by`, `owner_id`, `updated_at`, `updated_by`) as fields the author added, and the object's derived `nameField` under "Also changed", beside the one field the author typed.
12
+
13
+
- A field the publish adds or removes whose every definition carries `system: true` (the spec's mark for an auto-injected system/audit column), and a `nameField` equal to the registry's own `provisionPrimary` derivation, now fold into one collapsed "Generated by the platform (N)" line; opening it shows those rows. A system field whose definition differs between the published and draft bodies is an edit and stays an author row, as does a `nameField` the derivation would not pick.
14
+
- A new item's top-level keys are headed "Includes:" rather than "Also changed:": every key of an item that does not exist yet is part of it.
15
+
- The columns the platform injects and hides (`__search`, `organization_id`, `owning_business_unit_id`) are still not listed at all.
16
+
17
+
New strings `preview.changes.detailNewKeys` and `preview.changes.generatedGroup` ship in all ten locale packs.
0 commit comments