Skip to content

Fix dashboard stories schema and SchemaRenderer prop spreading#286

Merged
hotlong merged 3 commits intomainfrom
copilot/fix-storybook-dashboard-blank
Jan 30, 2026
Merged

Fix dashboard stories schema and SchemaRenderer prop spreading#286
hotlong merged 3 commits intomainfrom
copilot/fix-storybook-dashboard-blank

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 30, 2026

Fix Storybook Dashboard Component Blank Display

Problem

The Storybook dashboard component (storybook dashboard 组件) was displaying as blank due to two issues:

  1. Incorrect Schema Structure: The dashboard stories used children array instead of the widgets array required by the DashboardSchema type
  2. Incomplete Prop Spreading: The SchemaRenderer component in @object-ui/react only spread schema.props instead of the entire schema object, preventing components from receiving props like label and value

Root Cause Analysis

The DashboardRenderer expects a widgets array where each widget has:

  • id: Unique identifier
  • title: Optional title for the widget
  • component: The actual schema to render (e.g., metric, card)

The original stories incorrectly passed components directly as children, causing no widgets to be rendered.

Additionally, the SchemaRenderer was only spreading schema.props, but many components (like MetricWidget) expect their props directly on the schema object (e.g., { type: 'metric', label: 'Total Revenue', value: '$45,231.89' }).

Changes Made

1. Fixed packages/components/src/stories-json/dashboard.stories.tsx

  • ✅ Changed children array to widgets array
  • ✅ Wrapped each component in proper widget structure with id and component properties
  • ✅ Added widget titles for the "WithCards" story
  • ✅ Updated both "Default" and "WithCards" stories

2. Fixed packages/react/src/SchemaRenderer.tsx

  • ✅ Added spreading of schema properties while excluding metadata (first commit)
  • ✅ Fixed React error by properly filtering out schema metadata properties like children, body, type, etc. that should NOT be passed as React props (second commit)
  • ✅ Maintains backward compatibility with explicit props object
  • ✅ Allows components to receive props directly from schema (e.g., label, value)

Screenshots

Dashboard - Default Story (3 Metric Cards):
Dashboard Default

Page Story - Now Working Without Errors:
Page Story Fixed

Testing

  • ✅ Verified Default dashboard story displays three metric cards with correct labels and values
  • ✅ Verified WithCards dashboard story displays two titled cards with nested metrics
  • ✅ Verified Page story now renders without React errors
  • ✅ Manually tested in Storybook at http://localhost:6006
  • ✅ No security vulnerabilities found (CodeQL scan passed)

Files Changed

  • packages/components/src/stories-json/dashboard.stories.tsx (schema structure fix)
  • packages/react/src/SchemaRenderer.tsx (prop spreading fix with metadata filtering)

Security Summary

No security vulnerabilities discovered or introduced by these changes.

Original prompt

storybook dashboard 组件显示为空白


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Jan 30, 2026 5:03pm
objectui-components Ready Ready Preview, Comment Jan 30, 2026 5:03pm
objectui-crm-app Error Error Jan 30, 2026 5:03pm

Request Review

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix blank display in storybook dashboard component Fix dashboard stories schema and SchemaRenderer prop spreading Jan 30, 2026
Copilot AI requested a review from hotlong January 30, 2026 16:32
@hotlong
Copy link
Copy Markdown
Contributor

hotlong commented Jan 30, 2026

@copilot page story error:

Error: Minified React error #31; visit https://react.dev/errors/31?args[]=object%20with%20keys%20%7Btype%2C%20cols%2C%20gap%2C%20children%7D for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
at A (/assets/client-DrgYFpIW.js:8:39614)
at E (/assets/client-DrgYFpIW.js:8:40965)
at /assets/client-DrgYFpIW.js:8:43388
at dl (/assets/client-DrgYFpIW.js:8:67053)
at Hv (/assets/client-DrgYFpIW.js:8:82508)
at e1 (/assets/client-DrgYFpIW.js:8:116345)
at Rm (/assets/client-DrgYFpIW.js:8:115427)
at oc (/assets/client-DrgYFpIW.js:8:115265)
at Iv (/assets/client-DrgYFpIW.js:8:112105)
at s1 (/assets/client-DrgYFpIW.js:8:123742)
at _t (/assets/client-DrgYFpIW.js:1:1783)

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 30, 2026

@copilot page story error:

Error: Minified React error #31; visit https://react.dev/errors/31?args[]=object%20with%20keys%20%7Btype%2C%20cols%2C%20gap%2C%20children%7D for the full message or use the...

Fixed in commit 7f6148e. The error was caused by spreading schema metadata properties like children, body, and type as React props. Updated SchemaRenderer to filter out these metadata properties before spreading.

Page Story - Now Working:
Page Story Fixed

Dashboard Story - Still Working:
Dashboard Working

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • storybook.js.org
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/objectui/objectui/node_modules/.bin/../storybook/bin/index.cjs dev -p 6006 --no-open (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@hotlong hotlong marked this pull request as ready for review January 30, 2026 16:44
Copilot AI review requested due to automatic review settings January 30, 2026 16:44
@hotlong hotlong merged commit eae026b into main Jan 30, 2026
4 of 7 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes two issues that were causing the Storybook dashboard component to display as blank:

  1. Dashboard Schema Structure: Updated the dashboard stories to use the correct widgets array structure with id and component properties, matching the DashboardSchema type definition
  2. SchemaRenderer Prop Spreading: Modified the SchemaRenderer to spread schema properties (like label, value) directly to components, in addition to explicit props object

Changes:

  • Fixed dashboard story schemas to use widgets array with proper nested structure (id, title, component)
  • Added prop spreading in SchemaRenderer to pass schema properties directly to components
  • Filtered out schema metadata properties to prevent them from being passed as React props

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
packages/react/src/SchemaRenderer.tsx Added destructuring to filter out schema metadata properties and spread remaining properties to components, enabling direct prop access (e.g., label, value)
packages/components/src/stories-json/dashboard.stories.tsx Corrected schema structure from flat children array to nested widgets array with id and component properties per DashboardSchema type
Comments suppressed due to low confidence (1)

packages/react/src/SchemaRenderer.tsx:82

  • The changes to SchemaRenderer's prop spreading behavior are significant and affect how all components receive their props. However, there don't appear to be any tests for the SchemaRenderer component itself (only LazyPluginLoader has tests in the tests directory).

According to Rule #2 (Documentation Driven Development) from the coding guidelines, when implementing or refactoring features, both code AND tests should be updated. This prop spreading change is a core behavior change that should be covered by tests to:

  1. Verify that schema properties like label and value are correctly passed to components
  2. Ensure metadata properties are properly filtered out
  3. Validate the precedence order of props (componentProps < evaluatedSchema.props < explicit props)
  4. Prevent regression if this behavior needs to change in the future

Consider adding test cases for SchemaRenderer that cover these scenarios.

  // Extract schema metadata properties that should NOT be passed as React props
  const {
    type: _type,
    children: _children,
    body: _body,
    schema: _schema,
    visible: _visible,
    visibleOn: _visibleOn,
    hidden: _hidden,
    hiddenOn: _hiddenOn,
    disabled: _disabled,
    disabledOn: _disabledOn,
    ...componentProps
  } = evaluatedSchema;

  return React.createElement(Component, {
    schema: evaluatedSchema,
    ...componentProps,  // Spread non-metadata schema properties as props
    ...(evaluatedSchema.props || {}),  // Override with explicit props if provided
    className: evaluatedSchema.className,
    'data-obj-id': evaluatedSchema.id,
    'data-obj-type': evaluatedSchema.type,
    ...props
  });

Comment on lines +60 to 79
const {
type: _type,
children: _children,
body: _body,
schema: _schema,
visible: _visible,
visibleOn: _visibleOn,
hidden: _hidden,
hiddenOn: _hiddenOn,
disabled: _disabled,
disabledOn: _disabledOn,
...componentProps
} = evaluatedSchema;

return React.createElement(Component, {
schema: evaluatedSchema,
...(evaluatedSchema.props || {}),
...componentProps, // Spread non-metadata schema properties as props
...(evaluatedSchema.props || {}), // Override with explicit props if provided
className: evaluatedSchema.className,
'data-obj-id': evaluatedSchema.id,
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The id property is not being filtered out in the destructuring (lines 60-71), which means it will be included in componentProps and spread on line 76. However, the schema's id is already being passed explicitly as data-obj-id on line 79.

This could cause issues:

  1. Components might receive both id and data-obj-id props
  2. The id prop might be used as the DOM element's id attribute, which could cause duplicate IDs if multiple instances of the same schema are rendered
  3. It's unclear which id value should take precedence if a component explicitly uses the id prop

Consider adding id to the exclusion list:

const {
  type: _type,
  id: _id,  // Add this
  children: _children,
  ...

The schema's id should only be used for the data-obj-id attribute (line 79), not passed as a direct prop to components.

Copilot uses AI. Check for mistakes.
Comment on lines +76 to 78
...componentProps, // Spread non-metadata schema properties as props
...(evaluatedSchema.props || {}), // Override with explicit props if provided
className: evaluatedSchema.className,
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential issue with the prop spreading order. The className property is spread twice:

  1. First in line 76 as part of componentProps (since className is not filtered out)
  2. Then explicitly in line 78

This means the explicit className on line 78 will always override any className in componentProps, and then the explicit props object can override it again. This creates a confusing precedence:

  • componentProps.className is spread but immediately overridden
  • evaluatedSchema.className takes precedence
  • evaluatedSchema.props.className takes final precedence

Consider either:

  1. Adding className to the destructuring exclusion list (lines 60-71) so it's not included in componentProps, OR
  2. Removing line 78 since className is already in componentProps and can be overridden by evaluatedSchema.props

The recommended approach is option 1 (add className to exclusions) to maintain explicit control over the prop precedence order.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +72
// Extract schema metadata properties that should NOT be passed as React props
const {
type: _type,
children: _children,
body: _body,
schema: _schema,
visible: _visible,
visibleOn: _visibleOn,
hidden: _hidden,
hiddenOn: _hiddenOn,
disabled: _disabled,
disabledOn: _disabledOn,
...componentProps
} = evaluatedSchema;
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The properties id, name, label, description, placeholder, data, testId, and ariaLabel are defined in the BaseSchema interface and should potentially be filtered out from the spread, as they are schema metadata rather than component props.

These properties are part of the schema protocol but may not be intended as direct React props for all components. For example:

  • id is already being passed as data-obj-id
  • name is typically for form fields specifically
  • data is schema metadata, not a component prop
  • testId should be transformed to data-testid
  • ariaLabel should be transformed to aria-label

Consider reviewing which BaseSchema properties should be:

  1. Filtered out entirely (like data)
  2. Transformed before passing (like testIddata-testid, ariaLabelaria-label)
  3. Passed through directly (like label, placeholder for input components)

The current implementation may pass unintended props to components that don't expect them, which could cause React warnings about unknown DOM attributes.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +77
const {
type: _type,
children: _children,
body: _body,
schema: _schema,
visible: _visible,
visibleOn: _visibleOn,
hidden: _hidden,
hiddenOn: _hiddenOn,
disabled: _disabled,
disabledOn: _disabledOn,
...componentProps
} = evaluatedSchema;

return React.createElement(Component, {
schema: evaluatedSchema,
...(evaluatedSchema.props || {}),
...componentProps, // Spread non-metadata schema properties as props
...(evaluatedSchema.props || {}), // Override with explicit props if provided
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The props property from the schema is not being filtered out in the destructuring (lines 60-71), which means it will be included in componentProps and spread on line 76, and then spread AGAIN on line 77.

This creates duplicate spreading:

...componentProps,  // includes evaluatedSchema.props
...(evaluatedSchema.props || {}),  // spreads it again

This is redundant and could cause confusion. The props property should be added to the exclusion list alongside other metadata properties:

const {
  type: _type,
  children: _children,
  body: _body,
  schema: _schema,
  visible: _visible,
  visibleOn: _visibleOn,
  hidden: _hidden,
  hiddenOn: _hiddenOn,
  disabled: _disabled,
  disabledOn: _disabledOn,
  props: _props,  // Add this
  ...componentProps
} = evaluatedSchema;

Then line 77 becomes the single source for spreading the explicit props object.

Copilot uses AI. Check for mistakes.
type: _type,
children: _children,
body: _body,
schema: _schema,
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The schema property is being filtered out on line 64, but this might cause issues because the entire schema object is already being passed explicitly as a prop on line 75: schema: evaluatedSchema.

Filtering out schema from componentProps is correct to avoid passing it twice, but the variable name _schema is misleading - it suggests this is the schema being filtered out, when actually it's a property NAMED 'schema' that might exist on the evaluatedSchema object.

For clarity, consider renaming this to indicate it's a property collision being avoided:

schema: _schemaProperty,  // Avoid collision with explicit schema prop

This makes it clear that we're filtering out any schema property that might exist on the object to avoid conflicting with the explicit schema prop being passed on line 75.

Suggested change
schema: _schema,
schema: _schemaProperty, // Avoid collision with explicit `schema` prop below

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants