Skip to content

Core: Only show modified/affected icons on components and groups#34429

Closed
ghengeveld wants to merge 2 commits into
nextfrom
component-level-status
Closed

Core: Only show modified/affected icons on components and groups#34429
ghengeveld wants to merge 2 commits into
nextfrom
component-level-status

Conversation

@ghengeveld
Copy link
Copy Markdown
Member

@ghengeveld ghengeveld commented Apr 1, 2026

What I did

Showing a "modified" or "affected" icon on a story can be confusing, because when only a single story is changed, all siblings will be marked "modified" as well, due to the fact that change detection is file-based. By hiding the status dot on the story level, we avoid this confusion.

Screenshot 2026-04-01 at 13 33 13

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make 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/core team 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>

Summary by CodeRabbit

  • Bug Fixes

    • Story and docs statuses previously shown as "modified" or "affected" now display as "Unknown" in the sidebar tree.
  • Refactor

    • Reworked status mapping and display logic so icons, colors, labels, and branch-status visibility reflect the remapped status.
    • Simplified component control flow around context menu setup and display checks for better maintainability.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 1, 2026

View your CI Pipeline Execution ↗ for commit 4b9f32e

Command Status Duration Result
nx run-many -t compile,check,knip,test,lint,fmt... ❌ Failed 10m 18s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-01 12:05:54 UTC

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

Consolidated type imports in Tree.tsx, added HIDDEN_STORY_STATUSES and getDisplayStatus() to remap certain story/docs statuses to unknown, and updated Node rendering and context-menu hook ordering to use the derived display status across icons, labels, and branch-status visibility.

Changes

Cohort / File(s) Summary
Status remapping & rendering
code/core/src/manager/components/sidebar/Tree.tsx
Added HIDDEN_STORY_STATUSES and getDisplayStatus(itemType, status) to remap status-value:modified/status-value:affectedunknown for story/docs. Updated Node rendering to use displayedStatus for status icon/color (getStatus), StatusButton props (status and ariaLabel), and branch-status visibility. Consolidated type-only imports into a single import type block.
Context menu / control flow
code/core/src/manager/components/sidebar/Tree.tsx
Reordered hook usage: compute contextMenu via useContextMenu(item, statusLinks, api) unconditionally (then stub for non-internal refs) before performing the isDisplayed early return; removed conditional hook call inside a ternary.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
code/core/src/manager/components/sidebar/Tree.tsx (1)

265-268: Consider skipping useContextMenu() for non-internal refs.

This now instantiates the full hook for every rendered node and then immediately replaces it with a noop object when refId !== 'storybook_internal'. Since useContextMenu() subscribes to context and sets up several memoized branches, that adds avoidable render work to large composed sidebars.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/manager/components/sidebar/Tree.tsx` around lines 265 - 268,
Currently the component always calls the useContextMenu hook and then overwrites
its result for non-internal refs, causing unnecessary hook work; change the API
so useContextMenu receives refId (call it from Tree.tsx as useContextMenu(item,
statusLinks, api, refId)) and inside the hook immediately return the noop object
({ node: null, onMouseEnter: () => {} }) when refId !== 'storybook_internal'
before subscribing to contexts or running memoized logic, so the Tree.tsx code
can use the hook directly without creating then replacing its result.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/core/src/manager/components/sidebar/Tree.tsx`:
- Around line 216-222: The helper getDisplayStatus currently only remaps
HIDDEN_STORY_STATUSES for itemType === 'story', leaving docs able to show
'modified'/'affected'; update the condition to include docs (e.g., itemType ===
'story' || itemType === 'docs') so that when status is in HIDDEN_STORY_STATUSES
you return { status: 'status-value:unknown', label: 'Unknown' for docs as well;
ensure you reference getDisplayStatus, Item['type'], HIDDEN_STORY_STATUSES and
preserve the existing fallback formatting for other types/statuses.

---

Nitpick comments:
In `@code/core/src/manager/components/sidebar/Tree.tsx`:
- Around line 265-268: Currently the component always calls the useContextMenu
hook and then overwrites its result for non-internal refs, causing unnecessary
hook work; change the API so useContextMenu receives refId (call it from
Tree.tsx as useContextMenu(item, statusLinks, api, refId)) and inside the hook
immediately return the noop object ({ node: null, onMouseEnter: () => {} }) when
refId !== 'storybook_internal' before subscribing to contexts or running
memoized logic, so the Tree.tsx code can use the hook directly without creating
then replacing its result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8fa00af4-7076-4af8-b3be-c669d529aae8

📥 Commits

Reviewing files that changed from the base of the PR and between 4ffc041 and a3e4502.

📒 Files selected for processing (1)
  • code/core/src/manager/components/sidebar/Tree.tsx

Comment thread code/core/src/manager/components/sidebar/Tree.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
code/core/src/manager/components/sidebar/Tree.tsx (1)

265-272: Good fix for React hooks rules, but consider performance for external refs.

The restructuring correctly addresses the React hooks rule violation—hooks are now called unconditionally before any early returns. However, useContextMenu is now invoked for every node including external-ref items, even though the result is immediately discarded. Per context snippet 4, the hook creates internal state (3× useState), subscribes to StatusContext, and calls api.getShortcutKeys() on every mount.

For storybooks composing large external refs, this could accumulate unnecessary subscriptions and state. Consider passing a skip flag or similar to useContextMenu to short-circuit internal work when the menu won't be used.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/manager/components/sidebar/Tree.tsx` around lines 265 - 272,
The hook useContextMenu is being invoked for every node (including external
refs) causing unnecessary state, subscriptions, and api.getShortcutKeys() calls;
modify calls in Tree.tsx so you pass a short-circuit flag (e.g., skip or
isExternalRef) when refId === 'storybook_internal' is false, and update
useContextMenu to early-return a lightweight { node: null, onMouseEnter: () =>
{} } when skip is true, avoiding creation of useState hooks, StatusContext
subscription, and api.getShortcutKeys() work for external-ref items.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/core/src/manager/components/sidebar/Tree.tsx`:
- Around line 265-272: The hook useContextMenu is being invoked for every node
(including external refs) causing unnecessary state, subscriptions, and
api.getShortcutKeys() calls; modify calls in Tree.tsx so you pass a
short-circuit flag (e.g., skip or isExternalRef) when refId ===
'storybook_internal' is false, and update useContextMenu to early-return a
lightweight { node: null, onMouseEnter: () => {} } when skip is true, avoiding
creation of useState hooks, StatusContext subscription, and
api.getShortcutKeys() work for external-ref items.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 80dce32b-e377-408c-a351-542eb2307eb8

📥 Commits

Reviewing files that changed from the base of the PR and between 4ffc041 and 4b9f32e.

📒 Files selected for processing (1)
  • code/core/src/manager/components/sidebar/Tree.tsx

@ghengeveld
Copy link
Copy Markdown
Member Author

Already done in #34346

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant