Repository navigation
Commit acc4328
fix(plugin-view): hand ObjectGallery the gallery block nested, so coverFit, cardSize and visibleFields take effect (objectui#12053) (#12069)
Fixes #12053
Clause-②: no
Implemented by the os-dev dispatched from seat `domain:ui#3`, session
`session_01CGZy1BGCjdN5cXqL9cnvB8`, on the claim in comment
`6086543001`.
## What changed
`generateViewSchema`'s gallery branch
(`packages/plugin-view/src/ObjectView.tsx`) now hands `ObjectGallery`
the gallery block **nested**, as the node's own `gallery`. That is the
shape `ListView` already hands the same renderer. Before, the branch
built a flat node that carried `imageField` (from `coverField`) and
`titleField` only, so a gallery view handed to plugin-view's
`ObjectView` lost `coverFit`, `cardSize` and `visibleFields`. That held
for the host `views` prop and for a named `listViews` entry alike.
- The keys are picked **by name** through a new module-local table,
`GALLERY_CONFIG_SPELLING`, with the existing `pickFlatMapConfig` helper.
The gantt and timeline branches already use this mechanism
(objectui#6152 round 14). The table is a `satisfies Record` keyed by
every `keyof` of the spec's gallery block (`SpecListView['gallery']`),
so a key the spec adds or drops fails `tsc` here. ⛔ No raw spread: an
undeclared key in the authored block does not reach the node, and a
block key named like a node key cannot override the node's own value.
- **One spelling per key.** The flat `imageField` and `titleField` are
gone from the node, because `ObjectGallery` reads the nested
`coverField` and `titleField` ahead of them (measured below). The
branch's existing `'name'` title floor moves into the block with the key
it floors, so an undeclared title still resolves to `name`.
- `ObjectGallery`, `ListView` and every other branch of
`generateViewSchema` are untouched. No export, prop, type member or
language-pack key changes. `GALLERY_CONFIG_SPELLING` is not exported.
## Dispatch zone 2: the three hypotheses, measured
1. **What `ObjectGallery` reads, and in what order.** These are the read
points in `packages/plugin-list/src/ObjectGallery.tsx`, in the block
under the comment `Resolve GalleryConfig with backwards-compatible
fallbacks`:
- `coverField`: `gallery?.coverField ?? schema.imageField ?? 'image'`
(nested first)
- `coverFit`: `gallery?.coverFit ?? 'cover'` (nested only)
- `cardSize`: `gallery?.cardSize ?? 'medium'` (nested only)
- `titleField`: `gallery?.titleField ?? schema.titleField` (nested
first)
- `visibleFields`: `gallery?.visibleFields` (nested only)
⇒ once the block is nested, the flat pair can only restate a nested
value, so it is dropped (one spelling per key).
2. **The declared set.** `@objectstack/spec` 17.7.0, as plugin-view
resolves it, declares `GalleryConfigSchema` (strict) as
`ListViewShapeSchema.gallery`. That shape feeds `ListViewSchema` and the
named-view `ObjectListViewSchema`. Its keys are `coverField`,
`coverFit`, `cardSize`, `titleField` and `visibleFields`.
`ObjectGallery` reads exactly these five off `schema.gallery`. No key is
on one side only, so this is not a stop. The objectui node type
`ObjectGallerySchema.gallery` is typed as the spec's `GalleryConfig`.
3. **Named `listViews`.** `canonicalViewKindBlocks.gallery` folds a
named view's `gallery` into the same `viewOptions.gallery` the host
`views` entry feeds, so both reach the same branch. Pinned: every route
pin in the new test file runs on both routes.
## End-to-end reading through the real `ObjectGallery`
This is a scratch probe and is not committed. It uses the real
`SchemaRenderer`, imports `@object-ui/plugin-list` (through the root
vitest alias) for its `object-gallery` registration, and mounts
plugin-view's `ObjectView` with the gallery block `{ coverField:
'photo', coverFit: 'contain', cardSize: 'small', visibleFields:
['stage'] }` and one row that carries a cover URL.
| route | before: the flat node (ablation A1 below) | after: HEAD |
| --- | --- | --- |
| host `views` prop | `object-cover` img, medium grid
(`lg:grid-cols-4`), no `stage` on the card | `object-contain` img, small
grid (`xl:grid-cols-6`), `stage` value shown |
| named `listViews` entry | same as the row above | same as the row
above |
**Why the probe is not committed:** plugin-view does not depend on
`@object-ui/plugin-list`, and its type-checked test program
(`tsconfig.test.json`, `paths: {}`) cannot resolve that package. The
committed pins read the generated node at the `SchemaRenderer` seam, as
every sibling file in this package does. The app-shell import-side run
below does reach the real `ObjectGallery` through this branch, with no
gallery block.
## Tests
- **New:**
`packages/plugin-view/src/__tests__/ObjectView.galleryBlockNested-12053.test.tsx`.
It holds triage's pins (comment `6080379082`). Each route pin runs on
the host `views` prop and on a named `listViews` entry:
- `coverFit: 'contain'` reaches `gallery.coverFit`;
- `cardSize` and `visibleFields` reach `gallery` the same way;
- every key the spec declares on the block, driven off
`ListViewSchema.shape.gallery`, reaches `gallery`;
- one spelling per key: no flat `imageField` or `titleField`;
- an undeclared title keeps the `name` floor inside the block;
- control: an undeclared key (and a block `objectName`) reaches neither
`gallery` nor the node.
- **Updated, re-spelled from flat to nested** (both pinned the flat
`imageField` this card retires):
- `ObjectView.readersRetired-6152.test.tsx`, section 3 and its header
bullet;
- `ObjectView.namedViewProtocolKeys-8980.test.tsx`, the `gallery` case.
- **Control route (`ListView`), unchanged:** plugin-list
`ListView.galleryOptionsBagCanonical-6152`,
`ListView.readersRetired-6152`, `ListView.test.tsx` and the twelve
`ObjectGallery.*` files: 15 files, 227 tests passed.
## Reverse verification (ablation)
Predictions were written before either run. The mutation went through
`ablation-replace.mjs` from the objectstack checkout (objectui has
none), in wrap mode, with blob-equal restores. The tests import
`../ObjectView` relatively, from source, and no alias or `dist/` is
involved, so no rebuild was needed. Runs were on HEAD `a31f6aa85`, the
fix commit.
- **A1, rebuild the flat node** (`imageField` from `coverField` plus a
flat `titleField`, no nested block). Predicted: all 11 new pins red,
both re-spelled pins red, the probe red on both routes. **Observed: 16
failed, 48 passed (64).** Exactly that set, and the probe readings in
the table above. Mutation landed: anchor 1 to 0, blob `5fae6dbb4b45` to
`abf92739b839`. Restored: blob equals HEAD (`5fae6dbb4b45`), `git diff
HEAD` empty.
- **A2, raw spread inside the nested block** (`...viewOptions.gallery`
in place of the pick). Predicted: the new control red, the round-14
gallery arm (`objectName` hijack) red, the retired-`imageField` pin red,
everything else green. **Observed: 3 failed, 61 passed (64).** Exactly
those three. Restored: blob equals HEAD, `git diff HEAD` empty.
## Gates (union run after the final commit, HEAD `c346c41f7`)
| command | exit | the gate's own verdict |
| --- | --- | --- |
| `pnpm exec vitest run packages/plugin-view/` | 0 | `Test Files 74
passed (74)`, `Tests 691 passed (691)` |
| plugin-list `ListView` / `ObjectGallery` control set | 0 | `Test Files
15 passed (15)`, `Tests 227 passed (227)` |
| import side: app-shell `PageView.refreshInPlace-10519` (drives
`defaultViewType: 'gallery'` through this branch into the real
`ObjectGallery`), app-shell `ObjectView.titleFieldConvergence`,
`examples/schema-catalog/test/catalog-gallery-render` | 0 | `Test Files
3 passed (3)`, `Tests 603 passed (603)` |
| `pnpm --filter @object-ui/plugin-view type-check` (after `pnpm
--workspace-concurrency=2 --filter '@object-ui/plugin-view^...' build`,
exit 0) | 0 | `tsc --noEmit && tsc -p tsconfig.test.json` clean;
`--listFiles` counts all three touched test files in the test program |
| `pnpm exec eslint` on the 4 touched source files | 0 | 0 errors, 101
warnings (`no-explicit-any` and kin; warnings carry no ratchet) |
| `pnpm check:control-bytes` | 0 | `check-control-bytes: OK` |
| `pnpm check:test-path-roots` | 0 | `check-test-path-roots: OK` |
| `pnpm check:changeset-claims` | 0 | `No pending changeset names a file
this change touches.` |
| `pnpm check:pending-changeset-literals` | 0 | `No test source names a
pending changeset.` |
| `pnpm check:new-line-citations` | 0 | `VERDICT
new-cross-file-line-citations: 0 new citation(s)` |
| `pnpm check:vi-mock-specifiers` / `check:vi-mock-inherit` /
`check:vi-mock-override-shape` | 0 / 0 / 0 | `OK` each |
| `pnpm check:shell-escape-residue` / `check:handler-key-reads` /
`check:unreferenced-sources` / `check:metadata-write-doors` | 0 each |
`OK` each |
| `node scripts/check-changeset-presence.mjs` /
`check-changeset-no-major.mjs` | 0 / 0 | presence satisfied by
`.changeset/12053-view-gallery-block.md` (patch); `No changeset declares
a major bump.` |
**The eslint narrowing is a measurement, not a skip.**
- Population: `eslint.config.js` lints `**/*.{ts,tsx}`.
- The JSON output counts 4 files, none ignored.
- Type-aware linting is off (no `parserOptions.project`, no
`projectService`), and no rule under `eslint-rules/` reads another file.
So this diff cannot move an untouched file's verdict.
The repo-wide `pnpm lint` is CI's.
**NOT MEASURED:**
- `check:eager-closure`, reason: it needs the console build and belongs
to CI. The diff adds one five-entry const and moves no import.
- i18n gates, reason: no language pack is touched.
- `check:readme-exports`, reason: no export changes.
## Acceptance notes
- **`ListView`'s gallery branch (out of scope here)** still builds its
nested block by spreading `schema.options?.gallery` and `schema.gallery`
whole. It also writes a flat `titleField` beside `gallery.titleField`,
so there are two spellings on that route. The undeclared keys it carries
are inert there: `ObjectGallery` reads five keys off the block, and
nested keys cannot override node keys. Observation only; there is no
wrong answer at a public door. Carrier: none.
- **The `name` title floor.** Both routes floor `titleField` at the
literal `'name'`, while `ObjectGallery`'s own ADR-0079 comment prefers
`getRecordDisplayName` to a literal `'name'` floor. This PR keeps the
floor as existing behaviour. Observation, not measured at a public door.
Carrier: none.
- No committed test drives the real `ObjectGallery` through
plugin-view's `ObjectView` (see the probe section for why). Carrier:
none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent d03b022 commit acc4328
5 files changed
Lines changed: 220 additions & 20 deletions
File tree
- .changeset
- packages/plugin-view/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
223 | 238 | | |
224 | 239 | | |
225 | 240 | | |
| |||
2349 | 2364 | | |
2350 | 2365 | | |
2351 | 2366 | | |
| 2367 | + | |
| 2368 | + | |
| 2369 | + | |
| 2370 | + | |
| 2371 | + | |
| 2372 | + | |
| 2373 | + | |
| 2374 | + | |
| 2375 | + | |
| 2376 | + | |
| 2377 | + | |
| 2378 | + | |
| 2379 | + | |
| 2380 | + | |
| 2381 | + | |
| 2382 | + | |
| 2383 | + | |
| 2384 | + | |
2352 | 2385 | | |
2353 | 2386 | | |
2354 | 2387 | | |
2355 | | - | |
2356 | | - | |
2357 | | - | |
2358 | | - | |
2359 | | - | |
2360 | | - | |
2361 | | - | |
2362 | | - | |
2363 | | - | |
2364 | | - | |
2365 | | - | |
2366 | | - | |
2367 | | - | |
| 2388 | + | |
| 2389 | + | |
| 2390 | + | |
| 2391 | + | |
2368 | 2392 | | |
2369 | 2393 | | |
2370 | 2394 | | |
| |||
Lines changed: 160 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 | + | |
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
201 | 201 | | |
202 | 202 | | |
203 | 203 | | |
204 | | - | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
205 | 207 | | |
206 | 208 | | |
207 | 209 | | |
| |||
Lines changed: 9 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
25 | | - | |
26 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| |||
151 | 152 | | |
152 | 153 | | |
153 | 154 | | |
154 | | - | |
| 155 | + | |
155 | 156 | | |
156 | | - | |
| 157 | + | |
157 | 158 | | |
158 | 159 | | |
159 | 160 | | |
160 | 161 | | |
161 | | - | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
162 | 165 | | |
163 | 166 | | |
0 commit comments