Controls: Load controls for composed-ref stories on direct deep-link#35402
Conversation
Fixes composed-ref Controls showing "No controls" on a direct deep-link. A ref's runtime story enrichment (args, argTypes, parameters, prepared) arrives via STORY_PREPARED but is not part of the ref's static story index, so `setRef` rebuilding the index wiped it — and on a deep-link the enrichment can arrive before the index is composed, so `updateStory` dropped it entirely. Cache the enrichment per ref (`ref.storyUpdates`) and re-apply it whenever the ref index is (re)built, making it order-independent. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
Fixes composed-ref Controls not showing when a ref story is opened via a direct deep-link by preserving and reapplying runtime story/doc enrichment (from STORY_PREPARED / DOCS_PREPARED) across ref index (re)composition.
Changes:
- Introduces
storyUpdateson composed refs to cache runtime enrichment (args,argTypes, etc.) and reapply it whensetRefrebuilds the ref index. - Updates ref-side story/docs update flows to persist runtime updates even if they arrive before the ref index exists.
- Adds/updates unit tests to cover the cached enrichment behavior and the updated
updateRefpayload shape.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| code/core/src/types/modules/api.ts | Adds storyUpdates to API_LoadedRefData / composed ref update type surface. |
| code/core/src/types/modules/api-stories.ts | Introduces API_RefStoryRuntimeData type for cached runtime enrichment. |
| code/core/src/manager-api/modules/stories.ts | Caches runtime enrichment into ref.storyUpdates when updates arrive for ref stories/docs. |
| code/core/src/manager-api/modules/refs.ts | Re-applies cached runtime enrichment onto freshly rebuilt ref indexes inside setRef. |
| code/core/src/manager-api/tests/stories.test.ts | Updates expectations to include storyUpdates in updateRef payload. |
| code/core/src/manager-api/tests/refs.test.ts | Adds regression test ensuring cached runtime enrichment survives index rebuilds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds ChangesRuntime Story Enrichment Persistence
Estimated code review effort: 3 (Moderate) | ~25 minutes ✨ Finishing Touches📝 Generate docstrings
Comment |
…mment Align the API_LoadedRefData.storyUpdates doc comment with the actual cached shape, which also includes initialArgs, per PR review feedback. Co-authored-by: Cursor <cursoragent@cursor.com>
Sidnioulz
left a comment
There was a problem hiding this comment.
Tested, it works!
When navigating to host story first, and then to composed story, we see a flash of "This story has no controls" whilst controls are loading, but I find that acceptable. I'd only suggest showing a loading state for composed stories' controls if we can reliably detect whether the loading mechanism introduced here has completed yet or not.
Closes #34553
What I did
Composed-ref Controls still didn't work when a ref story is opened via a direct deep-link (the exact way it gets QA'd): the panel shows "This story has no controls" even for stories that clearly have args.
Background / history
#34553reported that Controls never load for a story served from a composed Storybook ref. It went through a couple of rounds:ControlsPanelonly watched the host's globalpreviewInitialized, which staysfalsefor ref stories, so the args table was stuck on the loading skeleton forever. Shipped inv10.5.0-alpha.5.v10.5.0-alpha.6.During a secondary QA pass on
v10.5.0-alpha.11, composed-ref Controls still failed — but with a different symptom. #35050 correctly cleared the loading skeleton, so instead of "loading forever" the panel now renders the "No controls" empty state. Because the user still never sees controls, it read as "the same bug" and didn't pass QA. This was never a regression — it's a second, independent bug that was masked by the loading-skeleton bug and is present in10.4.xtoo.Root cause
A composed ref's story entries are enriched at runtime from the ref preview's
STORY_PREPAREDevent (args,argTypes,parameters,prepared). That enrichment is not part of the ref's static story index. Two things then conspire:setRefrebuilds the ref'sindexfrom the static story index (which has noargTypes), wiping any runtime enrichment on every (re)composition.STORY_PREPAREDbefore the ref index has been composed, soupdateStory'sif (index && index[storyId])guard fails and the enrichment is dropped outright.Since the ref preview already rendered the story, it doesn't re-emit
STORY_PREPARED, so the enrichment never comes back →useArgTypes()returns{}→ "No controls". (In-app navigation happened to work because the ref index was already composed before opening the story.)The fix
Cache the runtime enrichment on the ref itself (
ref.storyUpdates) and re-apply it whenever the ref index is (re)built, so it survives index rebuilds and works regardless of whether it arrives before or after the index is composed:updateStory/updateDocs(ref branch) merge each update intoref.storyUpdates(in addition to the live index entry when present).setRefre-appliesref.storyUpdatesonto the freshly builtindex/filteredIndex.API_RefStoryRuntimeData+API_LoadedRefData.storyUpdates.The
ControlsPanelfix from #35050 is left intact — it correctly handles the loading half. This change completes the other half.Checklist for Contributors
Testing
The changes in this PR are covered in the following automated tests:
Added a regression test in
refs.test.ts(cached runtime enrichment is re-applied whensetRefrebuilds the index) and updated theSTORY_ARGS_UPDATEDassertion instories.test.ts.Manual testing
refs(e.g. the composed-ref repro from [Bug]: Controls never load with two Storybooks (refs) if initial page is a ref story #34553, or point the internal Storybook UI — which composes theIconsref — at these changes).http://localhost:6006/?path=/story/icons_icons-arrowtoplefticon--default(hard reload).Checklist for Maintainers
When this PR is ready for testing, make sure to add
ci:normal,ci:mergedorci:dailyGH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli-storybook/src/sandbox-templates.tsDeclare whether manual QA will be needed for this PR during the next release, through
qa:neededorqa:skipMake sure this PR contains one of the labels below:
Available labels
bug: Internal changes that fixes incorrect behavior.maintenance: User-facing maintenance tasks.dependencies: Upgrading (sometimes downgrading) dependencies.build: Internal-facing build tooling & test updates. Will not show up in release changelog.cleanup: Minor cleanup style change. Will not show up in release changelog.documentation: Documentation only changes. Will not show up in release changelog.feature request: Introducing a new feature.BREAKING CHANGE: Changes that break compatibility in some way with current major version.other: Changes that don't fit in the above categories.🦋 Canary release
This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the
@storybookjs/coreteam here.core team members can create a canary release here or locally with
gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>Made with Cursor
Summary by CodeRabbit