From de1ad2929b3fc33405ad58503f2502e2db04c3dc Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 24 Jul 2026 14:28:25 +0000 Subject: [PATCH] fix: read spec-canonical keys for dashboard header title and field length rules Naming-drift closeouts (framework#1878 / framework#1891): - DashboardRenderer header falls back to spec-canonical `label` when the legacy `title` is absent (mirrors DashboardGridLayout, #2666). - Field validation rules read spec-canonical camelCase minLength/maxLength (what the server record-validator enforces), snake_case kept as fallback. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CMaDBhnZEUu1fcw8Rvo6Yq --- .../naming-drift-dashboard-label-field-length.md | 16 ++++++++++++++++ packages/fields/src/index.tsx | 15 ++++++++++----- .../plugin-dashboard/src/DashboardRenderer.tsx | 11 ++++++++--- 3 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 .changeset/naming-drift-dashboard-label-field-length.md diff --git a/.changeset/naming-drift-dashboard-label-field-length.md b/.changeset/naming-drift-dashboard-label-field-length.md new file mode 100644 index 000000000..6edbad34d --- /dev/null +++ b/.changeset/naming-drift-dashboard-label-field-length.md @@ -0,0 +1,16 @@ +--- +"@object-ui/plugin-dashboard": patch +"@object-ui/fields": patch +--- + +fix: read spec-canonical keys for dashboard header title and field length rules + +Two naming-drift closeouts (framework#1878 / framework#1891): + +- `DashboardRenderer` header now falls back to the spec-canonical `label` when + the legacy `title` is absent (mirrors the `DashboardGridLayout` fallback from + #2666) — a spec-compliant dashboard gets its header title. +- Field validation rules now read the spec-canonical camelCase + `minLength`/`maxLength` (what the server record-validator enforces) with the + legacy snake_case `min_length`/`max_length` kept as fallback — authored + length constraints reach the client form. diff --git a/packages/fields/src/index.tsx b/packages/fields/src/index.tsx index 2d961ad79..330a5d1a3 100644 --- a/packages/fields/src/index.tsx +++ b/packages/fields/src/index.tsx @@ -1966,18 +1966,23 @@ export function buildValidationRules(field: any): any { // vars); a field-authored `*_message` is a string and passes through as-is, // still winning over the localized default. See form.tsx `localizeRule`. - // Length validation for text fields - if (field.min_length) { + // Length validation for text fields. The spec-canonical keys are camelCase + // (`minLength`/`maxLength`, @objectstack/spec FieldSchema — what the server + // record-validator enforces); the snake_case pair is the legacy objectui + // spelling, kept as fallback (framework#1878/#1891 naming-drift closeout). + const minLength = (field as any).minLength ?? field.min_length; + if (minLength) { rules.minLength = { - value: field.min_length, + value: minLength, message: typeof field.min_length_message === 'string' ? field.min_length_message : undefined, messageKey: 'validation.minLength', }; } - if (field.max_length) { + const maxLength = (field as any).maxLength ?? field.max_length; + if (maxLength) { rules.maxLength = { - value: field.max_length, + value: maxLength, message: typeof field.max_length_message === 'string' ? field.max_length_message : undefined, messageKey: 'validation.maxLength', }; diff --git a/packages/plugin-dashboard/src/DashboardRenderer.tsx b/packages/plugin-dashboard/src/DashboardRenderer.tsx index 15a43873f..ebfe0cf3e 100644 --- a/packages/plugin-dashboard/src/DashboardRenderer.tsx +++ b/packages/plugin-dashboard/src/DashboardRenderer.tsx @@ -775,13 +775,18 @@ const DashboardRendererInner = forwardRef{renderedNode}; }; + // The spec-canonical dashboard display name is `label` (@objectstack/spec + // DashboardSchema); `title` is the legacy objectui spelling. Read both so + // spec-compliant dashboards get their header title (framework#1878/#1891; + // mirrors the DashboardGridLayout fallback from #2666). + const headerTitle = schema.title || schema.label; const headerSection = schema.header && (
- {!hideHeaderText && schema.header.showTitle !== false && schema.title && ( + {!hideHeaderText && schema.header.showTitle !== false && headerTitle && (

{dashName - ? dashboardLabel({ name: dashName, label: resolveLabel(schema.title) }) - : resolveLabel(schema.title)} + ? dashboardLabel({ name: dashName, label: resolveLabel(headerTitle) }) + : resolveLabel(headerTitle)}

)} {!hideHeaderText && schema.header.showDescription !== false && schema.description && (