From b1b1002f663cb09b3cfe4fdb383abc8a42c444e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=85=E5=91=A8=E6=B6=9B?= Date: Mon, 22 Jun 2026 11:57:18 +0800 Subject: [PATCH] fix(spec): make GanttConfigSchema forward-compatible via .passthrough() The gantt renderer (objectui plugin-gantt) keeps adding view-config knobs (lockField, defaultCollapsedDepth, ...) ahead of this schema. The console validates the view config against a bundled copy of GanttConfigSchema before handing it to the renderer, so any field not declared here is stripped -- every new renderer knob otherwise needs a spec release + console rebuild to take effect. .passthrough() lets unknown fields reach the renderer, decoupling renderer releases from spec releases. Known fields keep their validation. Adds a forward-compat test asserting unknown fields survive parse. --- .changeset/gantt-config-passthrough.md | 15 +++++++++++++++ packages/spec/src/ui/view.test.ts | 14 ++++++++++++++ packages/spec/src/ui/view.zod.ts | 6 +++++- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 .changeset/gantt-config-passthrough.md diff --git a/.changeset/gantt-config-passthrough.md b/.changeset/gantt-config-passthrough.md new file mode 100644 index 0000000000..3959f029a6 --- /dev/null +++ b/.changeset/gantt-config-passthrough.md @@ -0,0 +1,15 @@ +--- +"@objectstack/spec": patch +--- + +fix(spec): make `GanttConfigSchema` forward-compatible via `.passthrough()`. + +The gantt renderer (objectui plugin-gantt) keeps adding view-config knobs +(e.g. `lockField`, `defaultCollapsedDepth`) ahead of this schema. Without +passthrough, the console — which validates the view config against a bundled +copy of this schema before handing it to the renderer — strips any field not +declared here, so every new renderer knob needs a spec release + console +rebuild before it can take effect. Adding `.passthrough()` lets unknown fields +flow through to the renderer, decoupling renderer releases from spec releases. +Known fields keep their validation; the renderer still only reads what it +understands. diff --git a/packages/spec/src/ui/view.test.ts b/packages/spec/src/ui/view.test.ts index cb39c124f8..646f40d5ec 100644 --- a/packages/spec/src/ui/view.test.ts +++ b/packages/spec/src/ui/view.test.ts @@ -237,6 +237,20 @@ describe('GanttConfigSchema', () => { expect(() => GanttConfigSchema.parse(config)).not.toThrow(); expect(GanttConfigSchema.parse(config)).toMatchObject({ parentField: 'parent_id', typeField: 'row_type' }); }); + + it('should passthrough unknown renderer fields ahead of this schema', () => { + const config = { + startDateField: 'start_date', + endDateField: 'end_date', + titleField: 'name', + // Newer renderer knobs not yet declared here (e.g. objectui plugin-gantt). + lockField: 'is_locked', + defaultCollapsedDepth: 2, + }; + + expect(() => GanttConfigSchema.parse(config)).not.toThrow(); + expect(GanttConfigSchema.parse(config)).toMatchObject({ lockField: 'is_locked', defaultCollapsedDepth: 2 }); + }); }); describe('ListViewSchema', () => { diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts index f769f86898..7c5e5261c5 100644 --- a/packages/spec/src/ui/view.zod.ts +++ b/packages/spec/src/ui/view.zod.ts @@ -427,7 +427,11 @@ export const GanttConfigSchema = lazySchema(() => z.object({ ])).optional().describe('Fields to surface in the hover tooltip, in display order'), quickFilters: z.array(GanttQuickFilterSchema).optional().describe('Multi-select filter dropdowns rendered above the chart'), autoZoomToFilter: z.boolean().optional().describe('When true (default), filtering zooms the range to the filtered tasks'), -})); +// Forward-compatible: the gantt renderer (objectui plugin-gantt) keeps adding +// config knobs (e.g. lockField / defaultCollapsedDepth) ahead of this schema. +// Passthrough lets those extra fields reach the renderer instead of being +// stripped here, so a renderer release no longer has to wait on a spec release. +}).passthrough()); /** * Navigation Mode Enum