Repository navigation
Commit b65aa5e
fix(app-shell): both Create View doors build the persisted view through one builder, so "Save as view" saves a kanban the spec accepts (objectui#11581) (#11589)
Fixes #11581
Clause-②: no
Why no: the new symbols (`buildNewViewSpec` in the new
`packages/app-shell/src/views/newViewSpec.ts`, `buildAddViewSpec` in
`ObjectView.tsx`, `offeredViewTypes` in `CreateViewDialog.tsx`) are
module exports for the pins only. Nothing is added to
`packages/app-shell/src/index.ts` (the package exports only `.`), and
`views/index.ts` re-exports `CreateViewDialog` and `ObjectView` by name,
not these.
## What changed
The Create View dialog persists through two doors: "Save as view" on the
object data page, and the add-view door on the object page
(`handleViewCreate`: the tab bar's add button and the view-config
panel's create mode). They assembled the spec separately from the same
payload, and only the add-view door mirrored the columns into
`kanban.columns` / `gallery.visibleFields`. Measured on the cut
(`f1c9379`) with the installed `@objectstack/spec` 17.6.0: "Save as
view" with Kanban is refused, `invalid_type` at `kanban.columns`; every
other offered type parses at both doors, but a gallery from "Save as
view" carries no `visibleFields` while the same payload through the tab
bar does.
- **One builder:** `buildNewViewSpec(config, { fallbackColumns, filter
})`. It resolves `columns` (the payload's, else the door's fallback),
places `filter` (no rules, no key), and owns every type-specific rule
through `COLUMN_MIRRORS`, a TOTAL record over `ListViewVisualization`:
`kanban` (required `columns`), `gallery` (`visibleFields` when the
payload has none), `null` for the other seven, so a new visualization
fails the build until its block is decided.
- **Door 1** `buildSaveAsViewSpec(config, columns, urlFilters)` keeps
its signature and pins; it now resolves only its inputs (page columns,
URL triples folded to spec rules) and calls the builder.
- **Door 2** `handleViewCreate`'s inline body moves to
`buildAddViewSpec(config, objectDef)`, which supplies
`defaultListColumnsFromObject(objectDef, 5)` and calls the builder. This
door's body is byte-identical to before.
- `CreateViewDialog.offeredViewTypes()`: a pure read of the picker's
rows (`buildViewTypeMeta` with an identity translator), so the pin
enumerates at collection time.
- Behaviour change, "Save as view" only: a kanban now persists
`kanban.columns` (was a 422 at the view write door); a gallery now
persists `gallery.visibleFields` = the view's columns when it declares
none, as the tab-bar door always did, so its cards show those fields.
- objectui#11578's refusal toasts and the dialog's await, and
objectui#11576's chart dataset binding, are unchanged. The other write
sites objectui#11583 lists are not touched.
- One `@object-ui/app-shell` patch changeset:
`.changeset/11581-one-view-builder.md`.
## Pins
- `CreateViewDialog.viewTypeParse-11581.test.tsx`
- enumeration: `PARSE_ROWS` names exactly `offeredViewTypes()`, and
`offeredViewTypes()` is the type grid the dialog renders;
- one row per offered type (`it.each(offeredViewTypes())`): the real
dialog is rendered and submitted with that row's picks, the payload goes
through `buildSaveAsViewSpec` and `buildAddViewSpec`, each wrapped by
`viewEnvelope`; `ListViewSchema` must accept the envelope's `config` and
`ViewItemSchema` the envelope, at both doors (soft, so a row names every
refusing door), and the two doors must build the same envelope from the
same columns;
- the builder's mirror pins (`kanban.columns`, `gallery.visibleFields`
kept when declared, nothing for other types or a prototype-chain name);
- "Save as view" with Kanban through `ObjectDataPage`, against the
spec's view gate replayed at the network boundary: 200, `kanban.columns`
equal to the persisted `columns`, lands on the draft.
- `ObjectView.createKanbanView-11581.test.tsx`: the add-view door
through the real `ObjectView` and dialog; the saved body parses and
carries the mirror.
## Evidence
- **Red before** (`1a8dc9a`, the pin plus door 2 moved unchanged into
`buildAddViewSpec`, no builder): 3 failed, 10 passed. Kanban row: DOOR 1
refused, `invalid_type` at `kanban.columns`. Gallery row: "the two doors
built different bodies from one payload". Page case: `expected 422 to be
200`.
- **Green after** at `168f819`: the new file 17 passed; the door-2 page
pin 1 passed.
- **Ablation 1**, the kanban mirror set to `null` in the builder (anchor
1 to 0, injection 0 to 1, on disk): 5 failed, 13 passed. The kanban row
fails at BOTH doors, both schemas (`kanban.columns` /
`config.kanban.columns`, "expected array, received undefined"); both
builder kanban pins; both page cases. Restored with `git checkout HEAD`;
blob `accf26f1db91` equals the HEAD blob, `git diff HEAD` empty.
- **Ablation 2**, a fake type appended to `buildViewTypeMeta`'s record
(injection 0 to 1 on disk): 2 failed, 16 passed: the `PARSE_ROWS`
enumeration and the row `fake_ablation_type` ("no parse row for the
offered view type"). The rendered-grid check stays green, since the grid
and `offeredViewTypes()` both carry it. Restored; blob `aa96b493d04b`
equals the HEAD blob, `git diff HEAD` empty.
## Gates (head `168f819`)
- `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...'
build` (29 packages): exit 0.
- `pnpm --filter @object-ui/app-shell type-check` (`tsc --noEmit && tsc
-p tsconfig.test.json`, which includes `src/**/*.test.tsx`): exit 0.
- vitest, narrowed: the 75 test files that import a changed module by
name (`git grep` for `ObjectView`, `ObjectDataPage`, `CreateViewDialog`,
`runtime-metadata-persistence`, `newViewSpec` across `packages/**` and
`apps/**` tests, minus the 46 hits in `packages/plugin-view`, which
import that package's own `ObjectView`): 75 files, 857 tests passed. It
includes every `CreateViewDialog.*`, `ObjectDataPage.*` and
`ObjectView.create*` suite.
- eslint on the 7 changed `.ts`/`.tsx` files, `--no-inline-config
--format json`: 7 files, 0 errors. The narrowing is a measurement: the
population is the config's `**/*.{ts,tsx}` rule objects; the rule set is
`tseslint.configs.recommended` with no type-aware parser options, and no
`eslint-rules/*` rule reads another file, so the diff cannot move a
verdict on an untouched file.
- `check:control-bytes`, `check:new-line-citations` (0 new),
`check:changeset-claims` (2 pending bodies name `ObjectView.tsx` /
`ObjectDataPage.tsx`; both re-read and still true),
`check:pending-changeset-literals`, `check:metadata-write-doors`,
`check:vi-mock-specifiers`, `check:vi-mock-inherit`,
`check:vi-mock-override-shape`, `check:test-path-roots`,
`check:unreferenced-sources`, `check:self-import`,
`check:esm-specifiers`, `check:phantom-deps`, `check:unused-deps`,
`check-changeset-presence`, `check-changeset-no-major`,
`check-governed-queue-guard --test` (NOT GOVERNED): all exit 0.
- NOT MEASURED: the whole `packages/app-shell` suite (988 test files).
One run died with its process, without a verdict, about 20 minutes in,
at `--maxWorkers=2`; CI's `pnpm test` runs it. `check:eager-closure`:
PREREQUISITE NOT MET (it reads a built console bundle); CI owns it.
## Acceptance notes
- The `grid` type card's test id, `create-view-type-grid`, is also the
test id of the grid that holds the cards. The new pin reads cards by
tag. No user effect; noted, not filed (carrier: none).
- The dialog's key pattern accepts a one-character key, while the spec
`ListViewSchema` `name` needs two. Not reachable as a refusal:
`viewEnvelope` strips `name` from `config`, and the envelope's `name` is
the qualified object-dot-key, which `ViewItemSchema` accepts (measured
with a one-character key). Observation only.
- `origin/main` moved to `0c012a7` after the cut (objectui#10872's
README, objectui#11511's skills guide). Neither touches these files, so
the branch is not merged with it.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 5a2ca6b commit b65aa5e
8 files changed
Lines changed: 694 additions & 44 deletions
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
153 | 168 | | |
154 | 169 | | |
155 | 170 | | |
| |||
168 | 183 | | |
169 | 184 | | |
170 | 185 | | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
176 | 193 | | |
177 | 194 | | |
178 | 195 | | |
| |||
Lines changed: 349 additions & 0 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
68 | 69 | | |
69 | 70 | | |
70 | 71 | | |
| |||
168 | 169 | | |
169 | 170 | | |
170 | 171 | | |
171 | | - | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
172 | 180 | | |
173 | 181 | | |
174 | 182 | | |
175 | 183 | | |
176 | 184 | | |
177 | 185 | | |
178 | | - | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
187 | 190 | | |
188 | 191 | | |
189 | 192 | | |
| |||
Lines changed: 170 additions & 0 deletions
| 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 | + | |
| 64 | + | |
| 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 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
| |||
648 | 649 | | |
649 | 650 | | |
650 | 651 | | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
651 | 671 | | |
652 | 672 | | |
653 | 673 | | |
| |||
1523 | 1543 | | |
1524 | 1544 | | |
1525 | 1545 | | |
1526 | | - | |
1527 | | - | |
1528 | | - | |
1529 | | - | |
1530 | | - | |
1531 | | - | |
1532 | | - | |
1533 | | - | |
1534 | | - | |
1535 | | - | |
1536 | 1546 | | |
1537 | 1547 | | |
1538 | 1548 | | |
1539 | 1549 | | |
1540 | | - | |
1541 | | - | |
1542 | | - | |
1543 | | - | |
1544 | | - | |
1545 | | - | |
1546 | | - | |
1547 | | - | |
1548 | | - | |
1549 | | - | |
1550 | | - | |
1551 | | - | |
1552 | | - | |
1553 | | - | |
| 1550 | + | |
| 1551 | + | |
| 1552 | + | |
| 1553 | + | |
| 1554 | + | |
1554 | 1555 | | |
1555 | 1556 | | |
1556 | | - | |
1557 | | - | |
1558 | | - | |
| 1557 | + | |
| 1558 | + | |
1559 | 1559 | | |
1560 | 1560 | | |
1561 | 1561 | | |
| |||
0 commit comments