Repository navigation
Commit 0858267
fix(app-shell): a blank dataset Field box writes no
Fixes #11402
Clause-②: no
## What changed
`DatasetDefaultInspector` no longer writes `field: ''` for a dataset row
whose Field box is blank.
- **New rows carry no `field` key.** "Add dimension" seeds `{ name: '',
type: 'string' }` and "Add measure" seeds `{ name: '', aggregate: 'sum'
}`. Neither writes an `id` default or any other field on the author's
behalf.
- **A blank Field value removes the key.** Both Field combos write
through `writeRowField`, which rebuilds the row without `field` when the
value is blank. It does not store `''` or `field: undefined`, so the
held draft and the saved body agree. A `count` measure with no field
saves the one spelling the spec has for count(*): the key is absent.
- **A dimension with a blank Field box is held as incomplete.** The
inspector reports each dimension whose `field` is absent or blank on its
`onBlockingIssuesChange` channel. That count includes a stored `field:
''`. The host already reads this channel for the default-inspector
family (objectui#4527, objectui#6900): it holds the Save button, the
autosave timer and the shortcut until a field is picked. While the box
is blank, that row's Field label also shows the designer's required
marker (`RequiredMarker`, objectui#10948). A complete row shows the
plain label. Measures are not held: a measure's `field` is optional, and
whether its aggregate may go without one is the spec's verdict at save.
## Rulings → where each lands (triage `5941542449`)
| Ruling | Where |
|---|---|
| New rows are seeded without a `field` key. | the two `onAdd` seeds;
pins `seeds a new measure row …`, `seeds a new dimension row …` |
| A measure with a blank Field box writes no `field`. | `writeRowField`
via `pickMeasureField`; pin `⭐ a measure added and saved with a blank
Field box carries no field, and the saved dataset parses under
DatasetSchema` |
| A dimension with a blank Field box shows as incomplete and is not
saved with `''`. | the blocking count plus the state-bound marker; pins
under `a blank-Field dimension is held as incomplete` |
| ⛔ No `id` default. | the seeds; the dimension seed pin uses
`toStrictEqual` |
## Which "incomplete" mechanism this reuses, and why it is licensed here
I measured what this inspector family has for "incomplete": the
`onBlockingIssuesChange` Save gate, the static `RequiredMarker`, and the
host's live Zod pass. The Zod pass does not exist for `dataset`:
`clientValidation.ts` registers no loader for it. Nothing new was
invented. The hold reuses the Save gate, and the marker reuses
`RequiredMarker`.
A reviewer should weigh one point. The host's note above
`blockingReport` in `ResourceEditPage` describes this channel as
carrying faults the server does **not** catch, and it keeps schema
verdicts advisory. The reason is that a client gate *stricter* than the
server would wedge Save on a body the server accepts.
- **A field-less dimension.** The installed spec (`@objectstack/spec`
17.5.0, `DatasetDimensionSchema.field` is a required string) refuses it
as well. So the hold is never stricter than the spec. A new pin, `the
hold is never stricter than the spec …`, asserts `DatasetSchema` refuses
that dimension at `dimensions.0.field` and accepts it once a field is
picked. It goes red if the key ever turns optional.
- **A stored `field: ''`.** This is the one row the hold refuses that
17.5.0 accepts. The ruling covers it ("not saved with `''`"), and the
Field box on screen repairs it, so it cannot wedge.
- **Without the hold**, dropping the `''` seed alone would send every
freshly added dimension to the server without a field. Autosave would
then draw a 422 on every "Add dimension" until a field is picked. This
is inferred, not measured against a live server:
`DatasetDimensionSchema.field` is required on 17.5.0, and `dataset` has
no client validator.
## Inherited vs re-run (this run resumed a killed one)
- **Inherited:** `93f85530` (the pin) and `200e91d8` (the fix). I did
not take either on trust.
- **Re-run, red first:** with the inspector put back to its `7728c67c`
bytes and the pin file unchanged, 8 tests failed and 1 passed (9 total)
at `44fa23cf`. Each failure is on the asserted fact: the seeds carry
`field: ''`, the held row has a `field` key, nothing is reported on the
blocking channel, and `writeRowField` is absent. The one pass is the
spec control, which asserts the spec rather than the inspector. The
restore used `git checkout HEAD -- PATH`. I proved it by comparing
hashes: the file's blob equals the HEAD blob `725de67b`, and `git diff
HEAD` is empty.
- **Found and repaired with new commits** (objectui forbids force-push):
- `93c6598c`: the inherited pin did not compile under `tsc -p
tsconfig.test.json`, the second leg of the package's `type-check`. A
field-less literal passed to `writeRowField` read as a weak type and
drew TS2353. The rows are now typed.
- `44fa23cf`: the inherited fix put the marker on every dimension's
Field label. That changed the label text on complete rows and turned
`inspectorStrings.i18n-10696`'s lit control red, because it finds the
Field combo by the label's exact text. The marker now renders only while
the box is blank. That is also closer to the ruling's "shows as
incomplete" than a static "required" mark on complete rows.
- `e98eb867`: the spec-control pin described above.
- **New here:** the changeset (`c5648ec6`).
## Tests and gates — all read at `44fa23cf`
Node v22.22.2 from `/opt/nvm` (the container's v22.22.0 is refused by
the engine-strict install).
- `pnpm --filter @object-ui/app-shell type-check && pnpm --filter
@object-ui/app-shell build` exited 0. Both `tsc` legs echoed, and the
build printed `✓ dist completeness: 1 package(s) complete`. `tsc -p
tsconfig.test.json --listFiles` lists the pin file. I built the
dependency closure first with `turbo run build
--filter=@object-ui/app-shell... --concurrency=2`: 29 of 29 tasks
succeeded.
- `pnpm exec vitest run --maxWorkers=2` over every suite in
`packages/app-shell/src/views/metadata-admin/inspectors/`, plus the
dataset readers `previews/DatasetPreview*`,
`DatasetPreview.dimensionLabels-8187` and `dataPreviews.i18n-10862-s3`:
`Test Files 125 passed (125)`, `Tests 1727 passed | 1 skipped (1728)`.
The skip is an existing `skipIf` on a spec version in
`flow-node-config.spec-reconciliation`.
- These gates each exited 0:
- `pnpm check:control-bytes`
- `pnpm check:new-line-citations` (`VERDICT … 0 new citation(s)`)
- `node scripts/check-changeset-presence.mjs`
- `pnpm changeset:check`
- `check:vi-mock-specifiers`, `check:vi-mock-inherit` and
`check:vi-mock-override-shape` (the pin mocks `./useDatasetFields`)
- `check:test-path-roots`
- `check:i18n-keys`
- `check:changeset-claims`
- `check:pending-changeset-literals`
- **Narrowed lint, a measurement rather than a skip.**
1. The population is the package's `eslint .` under the root
`eslint.config.js`. Both changed files are linted, not ignored.
2. `--format json` reports 2 files, 0 errors and 4 warnings. One warning
is new: `react-refresh/only-export-components` on the `writeRowField`
export, the same rule the file's existing `objectChangePatch` export
already draws. `lint.yml` sets no `--max-warnings`.
3. Invariance: `eslint.config.js` enables no type-aware linting, and no
rule under `eslint-rules/` reads the disk. So this diff cannot move a
verdict on an untouched file.
- The diff is not on the governed surface:
`check-governed-queue-guard.mjs --test` reports `NOT GOVERNED`.
## Readers of these rows (checked for an absent `field`)
`DatasetPreview` reads `String(x?.field ?? '')` and skips an empty one.
`ReportView`'s drill fallback reads `dimDef?.field || dim`.
`missingRelationship` takes `field: string | undefined`.
`useDatasetCatalog` never reads `field`. None of them breaks.
## Acceptance notes (observations, not filed)
- **A legacy measure stored with `field: ''`** (written by this
inspector before this change) is re-sent unchanged unless the author
edits it. The card records that a `count` measure carrying it answered
500 on the ObjectQL strategy (the objectstack dev's measurement, not
re-taken here). Under objectstack-ai/objectstack#21240 it is refused at
`measures.N.field`. The combo has no "clear" affordance, so the in-UI
repair is the Source tab. Repairing stored data was not asked for here.
- **Clearing a filled Field box.** `InspectorComboField` offers no way
to clear a picked value, so the inspector has no UI path to clear a
measure's Field box back to count(*). `writeRowField` covers a blank
value if one ever arrives.
- **Host comments are now narrower than the channel.**
`ResourceEditPage`'s Save-button comment and `inspectorBlocking` note
name CEL faults and the objectui#6900 refusal as what the channel
carries. The dataset dimension hold is now a third kind.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JG2jy8a9su7ia4Hx7zxv42)_
---------
Co-authored-by: Claude <noreply@anthropic.com>field key; a field-less dimension holds Save (objectui#11402) (#11408)1 parent 9547063 commit 0858267
3 files changed
Lines changed: 311 additions & 20 deletions
File tree
- .changeset
- packages/app-shell/src/views/metadata-admin/inspectors
| 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 | |
|---|---|---|---|
| |||
| 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 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
0 commit comments