From 02307d05b6748d4b9d6e8aff4d83566cce216d24 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 04:08:46 +0000 Subject: [PATCH 1/2] fix(spec): reportForm offers a joined block's dataset as the ref:dataset picker, marked required The "Joined blocks" repeater's `dataset` row declared only a label, so Studio's report inspector drew a free-text, unmarked cell for a key the joined arm of ReportSchema now refuses when absent (#21702). The row now declares `widget: 'ref:dataset'` (registered in objectui's WIDGETS at the console pin) and `required: true`, and a pin beside the refusal's own tests holds both. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude --- .../src/ui/report-joined-block-dataset.test.ts | 17 +++++++++++++++++ packages/spec/src/ui/report.form.ts | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/spec/src/ui/report-joined-block-dataset.test.ts b/packages/spec/src/ui/report-joined-block-dataset.test.ts index 71921e4d23f..73462b9739e 100644 --- a/packages/spec/src/ui/report-joined-block-dataset.test.ts +++ b/packages/spec/src/ui/report-joined-block-dataset.test.ts @@ -27,6 +27,7 @@ import { describe, expect, it } from 'vitest'; import { getMetadataTypeSchema } from '../kernel/metadata-type-schemas'; import { MIGRATIONS_BY_MAJOR, RETIRED_KEYS_BY_MAJOR } from '../migrations/registry'; import { ObjectStackDefinitionSchema, defineStack } from '../stack.zod'; +import { reportForm } from './report.form'; import { JoinedReportBlockSchema, ReportSchema, defineReport } from './report.zod'; const ENTRY_ID = 'ui-report-joined-block-dataset-required'; @@ -245,6 +246,22 @@ describe('the joined reports measured at the census parse unchanged', () => { }); }); +describe('the report form offers a block\'s `dataset` as the dataset picker, marked required (#21714)', () => { + it('the "Joined blocks" repeater\'s `dataset` row declares `widget: \'ref:dataset\'` and `required: true`', () => { + // Studio's report inspector renders this row spec: the widget hint picks + // the cell's control, and `required` draws the column's marker and the + // cell's `aria-required`. Without both, a new block is a free-text cell the + // refusal above rejects on save. + const blocks = (reportForm.sections as any[]) + .flatMap((s) => s.fields ?? []) + .find((f: any) => f?.field === 'blocks'); + expect(blocks?.type).toBe('repeater'); + const row = (blocks.fields as any[]).find((f) => f?.field === 'dataset'); + expect(row?.widget).toBe('ref:dataset'); + expect(row?.required).toBe(true); + }); +}); + describe('the ADR-0087 ledger', () => { it('registers one D3 entry at protocol 18, with no D2 conversion, prescribing the binding', () => { const entries = MIGRATIONS_BY_MAJOR[18]!.semantic.filter((e) => e.id === ENTRY_ID); diff --git a/packages/spec/src/ui/report.form.ts b/packages/spec/src/ui/report.form.ts index 37ef33194b0..8bc1038e361 100644 --- a/packages/spec/src/ui/report.form.ts +++ b/packages/spec/src/ui/report.form.ts @@ -82,7 +82,11 @@ export const reportForm = defineForm({ // A `chart` input sat here until #20161: the key was removed from // `JoinedReportBlockSchema` because no renderer ever drew a block // chart, so this control offered a setting that plotted nothing. - { field: 'dataset', label: 'Dataset' }, + // #21714: a joined report refuses a block that binds no `dataset` + // (#21702), so this column declares the `ref:dataset` picker the + // top-level binding declares, marked required: a block is bound + // in the form before save. + { field: 'dataset', label: 'Dataset', widget: 'ref:dataset', required: true }, { field: 'rows', label: 'Rows' }, { field: 'columns', label: 'Columns' }, { field: 'values', label: 'Values' }, From d7c811ff388c6d186ea81befa609885a4ff3f845 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 04:12:52 +0000 Subject: [PATCH 2/2] chore(changeset): spec patch for the joined-block dataset picker row Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude --- .../21714-report-form-joined-block-dataset-picker.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/21714-report-form-joined-block-dataset-picker.md diff --git a/.changeset/21714-report-form-joined-block-dataset-picker.md b/.changeset/21714-report-form-joined-block-dataset-picker.md new file mode 100644 index 00000000000..a1e18766ed5 --- /dev/null +++ b/.changeset/21714-report-form-joined-block-dataset-picker.md @@ -0,0 +1,11 @@ +--- +"@objectstack/spec": patch +--- + +`reportForm`: the "Joined blocks" repeater's `dataset` column now declares `widget: 'ref:dataset'` and `required: true`. Studio's report inspector draws a joined report's block `dataset` as the dataset picker, with the required marker, instead of a free-text cell with no marker. + +Clause-②: no + +- **Why.** A `joined` report refuses a block that binds no `dataset`, at `blocks.N.dataset`. The form offered that column as plain text and did not mark it, so a newly added block failed on save. +- **Which renderer honours it.** The pinned console registers `ref:dataset` in its widget registry. Its repeater takes each column's widget and `required` from the row spec, in both the grid and the card layout. +- ⛔ Only this one form row changes. No schema, parse, export or accept-set change: `JoinedReportBlockSchema.dataset` stays optional on the block shape, and the joined arm's refusal is unchanged.