diff --git a/.changeset/6939-objectql-record-source-refinement.md b/.changeset/6939-objectql-record-source-refinement.md new file mode 100644 index 0000000000..d1e5f5fe6a --- /dev/null +++ b/.changeset/6939-objectql-record-source-refinement.md @@ -0,0 +1,33 @@ +--- +'@object-ui/types': patch +--- + +Repair the `object-map` and `object-gantt` mirrors: `objectName` is optional, +and a refinement requires that at least one of `data`, `staticData`, +`objectName` is present (objectui#6939, maintainer ruling recorded 2026-09-02 — +this is one of the eight groups on that card, dispatched as its own PR per the +ruling). + +Both renderers resolve their records from one of three keys, in this order — +`getDataConfig` in `plugin-map/src/ObjectMap.tsx` and +`plugin-gantt/src/ObjectGantt.tsx`: `data`, then `staticData`, then +`objectName`. Both mirrors required `objectName` alone, so a document authored +on `staticData` drew correctly and was refused by `safeValidateSchema` — six +catalog entries, three per component. + +- **`object-map`** / **`object-gantt`**: `objectName` becomes optional on the + mirror and on the TypeScript twin in the same stroke, and each member ends in + `requireRecordSource`, whose issue sits at the root path, carries + `params.code = 'RECORD_SOURCE_REQUIRED'` and names the three keys an author + can supply. +- **`object-gantt`** additionally declares `data` (as `ViewDataSchema`, the + spelling `object-map` already used): it is the FIRST key that resolver reads + and was undeclared on both faces, which would have left the refinement naming + a key the validator had never heard of. + +**patch, not minor: the accept set only widens toward what already renders.** +Every document that validated before still validates — `objectName` alone, +including an empty one, still parses, because presence is `!== undefined` and +not the renderer's truthiness. The one shape the refinement refuses (none of +the three) was refused before too, when `objectName` was required. Documents +the renderers already draw start validating. diff --git a/content/docs/plugins/plugin-gantt.mdx b/content/docs/plugins/plugin-gantt.mdx index fe63288a4a..358c2d95ca 100644 --- a/content/docs/plugins/plugin-gantt.mdx +++ b/content/docs/plugins/plugin-gantt.mdx @@ -118,9 +118,10 @@ const schema = { ```plaintext { type: 'object-gantt', - objectName?: string, // ObjectQL object name - staticData?: Array, // Static data array - data?: ViewData, // Advanced data configuration + objectName?: string, // ObjectQL object name (read third) + staticData?: Array, // Static data array (read second) + data?: ViewData, // Advanced data configuration (read first) + // At least one of data / staticData / objectName is required gantt?: GanttConfig, // Gantt-specific configuration viewMode?: 'day' | 'week' | 'month' | 'quarter' | 'year', readOnly?: boolean // disable every edit path diff --git a/content/docs/plugins/plugin-map.mdx b/content/docs/plugins/plugin-map.mdx index 3adcddbdc1..4482a0f31b 100644 --- a/content/docs/plugins/plugin-map.mdx +++ b/content/docs/plugins/plugin-map.mdx @@ -102,9 +102,10 @@ const schema = { ```plaintext { type: 'object-map', - objectName: string, // ObjectQL object name - staticData?: Array, // Static data array - data?: ViewData, // Advanced data configuration + objectName?: string, // ObjectQL object name (read third) + staticData?: Array, // Static data array (read second) + data?: ViewData, // Advanced data configuration (read first) + // At least one of data / staticData / objectName is required filter?: Array, // Query filter, sent as $filter sort?: string | SortConfig[], // Sort, sent as $orderby map?: ObjectMapConfig, // Map-specific configuration diff --git a/examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx b/examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx new file mode 100644 index 0000000000..752954415d --- /dev/null +++ b/examples/schema-catalog/test/objectql-record-source-render-identity-6939.test.tsx @@ -0,0 +1,174 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * objectui#6939, the `object-map` + `object-gantt` group — the GANTT half of + * the render pin. `ObjectGanttSchema` used to require `objectName`, a key the + * renderer reads THIRD (`getDataConfig` in `plugin-gantt/src/ObjectGantt.tsx`: + * `data`, then `staticData`, then `objectName`), so the three `staticData`-only + * catalog entries below drew correctly and were refused by `safeValidateSchema`. + * The repair makes `objectName` optional behind a refinement; the validator-side + * contract is pinned in `packages/types/src/__tests__/objectql-record-source- + * refinement-6939.test.ts`, and the `object-map` tiles are pinned in + * `packages/plugin-map/src/ObjectMap.catalogRecordSource-6939.test.tsx`. + * + * ## Why the render half is the discriminating half + * + * From objectui#6318's triage: a "correction" that renders identically proves + * the SCHEMA was wrong, not the fixture. So the repair has to clear the mirror + * image of that bar — the validator's verdict must change and the renderer's + * output must NOT. The numbers in `PRE_REPAIR` were measured on `origin/main` + * at `d88e20f55`, BEFORE the mirror was touched, through THIS file's harness. + * + * ## The harness, and why it is named + * + * A bare `SchemaRenderer` is not enough here: `ObjectGantt` calls + * `useSchemaContext`, so without a `SchemaRendererProvider` the tile is the + * error boundary — 4 elements reading `Component "object-gantt" failed to + * render` — and an identity pin over THAT is the vacuous pin this file must + * not be. Measured through the provider-wrapped bare renderer below, the three + * tiles draw 407 / 354 / 436 elements. The docs-gallery harness + * (`catalog-gallery-render.test.tsx`, provider + `SidebarProvider` + a padded + * wrapper) gives different absolute counts for the same tile; identity within + * ONE harness is the claim that discriminates. `Date` is frozen because the + * chart carries a Today marker and a date-stamped export name — the pin must + * not move with the calendar. + * + * Three readings per tile, because a count alone cannot tell a swapped element + * from an equal one: element count, a tag census, and the text — the visible + * text as a literal (the chart's own `