Skip to content

Conversation

@fpan225
Copy link
Contributor

@fpan225 fpan225 commented Oct 6, 2025

…CHANGE)

This is a Breaking Change since it will break current EUA preview page box ai sidebar.

Summary by CodeRabbit

  • New Features

    • Support for custom sidebar panels and tabs (titles, icons/tooltips, disabled states, navigation callbacks); Box AI can be provided as a custom panel.
  • Refactor

    • Replaced static Box AI handling with a flexible custom-panel mechanism and dynamic ordering/visibility that integrates custom panels with existing views.
  • Tests

    • Expanded coverage for multiple custom tabs/panels, ordering, states, and interactions.
  • Documentation

    • Removed Box AI-specific Storybook entries and updated the ContentSidebar story.

@fpan225 fpan225 requested review from a team as code owners October 6, 2025 17:41
@CLAassistant
Copy link

CLAassistant commented Oct 6, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Walkthrough

Adds public support for custom sidebar panels/tabs via new Flow types and props (customSidebarPanels/customTabs/customPanels), wires them through ContentSidebar → Sidebar → SidebarNav/SidebarPanels, makes BoxAI detection data-driven, updates tests for custom panels, and removes BoxAI-specific Storybook stories.

Changes

Cohort / File(s) Summary
Public API: ContentSidebar prop
src/elements/content-sidebar/ContentSidebar.js
Adds customSidebarPanels?: Array<CustomSidebarPanel> prop; imports CustomSidebarPanel; forwards prop to Sidebar.
Sidebar core wiring
src/elements/content-sidebar/Sidebar.js
Accepts customSidebarPanels?: Array<CustomSidebarPanel>; derives hasBoxAI from custom panels; forwards customTabs/customPanels to SidebarNav/SidebarPanels; removes prior hasBoxAI prop reliance.
Navigation tabs logic
src/elements/content-sidebar/SidebarNav.js
New customTabs?: Array<CustomSidebarPanel> prop; builds visibleTabs by combining defaults and custom tabs (BoxAI handled via custom tab id); dynamic icon/tooltip handling; filters falsy entries.
Panels routing and order
src/elements/content-sidebar/SidebarPanels.js
New customPanels?: Array<CustomSidebarPanel> prop; introduces panel ordering (getPanelOrder, DEFAULT_SIDEBAR_VIEWS), per-panel routes, lazy refs for custom panels, refresh propagation, and eligibility-based redirect using combined order.
Flow types
src/elements/content-sidebar/flowTypes.js
Adds and exports CustomSidebarPanel and CustomSidebarPanels Flow types (panel metadata, optional props).
Unit tests: nav
src/elements/content-sidebar/__tests__/SidebarNav.test.js
Removes old BoxAI-specific tests; adds comprehensive tests for customTabs, ordering (BoxAI priority), icons, disabled states, DOM order, and onPanelChange.
Unit tests: panels
src/elements/content-sidebar/__tests__/SidebarPanels.test.js
Tests updated to pass customPanels; adds helpers for BoxAI panel; coverage for multiple custom panels, ordering, disabled handling, fallbacks, and navigation behavior.
Storybook removals
src/elements/content-sidebar/stories/BoxAISideBar.mdx, .../stories/BoxAISidebar.stories.tsx, .../stories/tests/BoxAISidebar-visual.stories.tsx
Removes BoxAI-specific docs, stories, and visual-test story files and exports.
Storybook consolidation
src/elements/content-sidebar/stories/tests/ContentSidebar-visual.stories.tsx
Replaces BoxAI variants with a single ContentSidebar story; removes BoxAI feature toggles; updates imports/types and exported story name.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant ContentSidebar
  participant Sidebar
  participant SidebarNav
  participant SidebarPanels

  App->>ContentSidebar: render({ customSidebarPanels })
  ContentSidebar->>Sidebar: render({ customSidebarPanels })
  Sidebar->>Sidebar: hasBoxAI = customSidebarPanels.some(p => p.id == SIDEBAR_VIEW_BOXAI)
  Sidebar->>SidebarNav: render({ customTabs: customSidebarPanels })
  Sidebar->>SidebarPanels: render({ customPanels: customSidebarPanels })

  note over SidebarNav,SidebarPanels: Data-driven custom panels flow

  SidebarNav->>SidebarNav: build visibleTabs = defaults + customTabs (BoxAI handled)
  SidebarPanels->>SidebarPanels: compute panelOrder(defaults + customPanels)
  SidebarPanels->>SidebarPanels: register routes & refs for customPanels
  SidebarPanels-->>App: redirect/render first eligible panel
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

ready-to-merge

Suggested reviewers

  • greg-in-a-box
  • jpan-box
  • bfoxx1906

Poem

I pity the fool who hard-coded tabs,
Now custom panels strut with swagger and jabs.
BoxAI bows when data gives the cue,
Routes reorder, and the nav says "ooh!" 😎
Ship it now — the sidebar’s lookin' new.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning I pity the fool who submits a PR description that only calls out a breaking change without explaining what’s actually being changed. The current description merely notes that it will break the EUA preview page box AI sidebar but omits any summary of added props, updated components, removed story files, or the overall purpose of the change. Without details on the customSidebarPanels API, SidebarNav and SidebarPanels updates, or storybook deletions, reviewers cannot assess the scope or impact of this work. Please expand the description with a clear summary of all major changes, including the introduction of the customSidebarPanels prop, updates to Sidebar and its subcomponents, new flow type exports, and the removal of BoxAI-related storybook stories. Also explain why this constitutes a breaking change and any migration steps required for consumers. I pity the fool who leaves reviewers guessing about the PR’s purpose.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Title Check ✅ Passed I pity the fool who claims this title is vague when it clearly and concisely describes the feature of adding support for custom sidebar panels in the content-sidebar and follows conventional commit style.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch custom-sidebar-panels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/elements/content-sidebar/SidebarNav.js (1)

82-105: Make that Box AI focus check respect custom paths, fool!

Right now the click handler only fires focusPrompt() when sidebarview === SIDEBAR_VIEW_BOXAI. With the new API, the Box AI panel can ship with an alternate path, so the button will stop focusing the prompt even though the tab ID is still boxai. I pity the fool who ships a regression like that! Key the check off the actual Box AI tab metadata so custom paths still trigger the focus.

-        if (sidebarview === SIDEBAR_VIEW_BOXAI) {
+        if (boxAiTab && sidebarview === boxAiTab.path) {
             focusPrompt();
         }
src/elements/content-sidebar/SidebarPanels.js (1)

146-156: Remove unused Box AI sidebar cache and ref, fool
I pity the fool who lets dead code linger: boxAiSidebarCache is never accessed, and the boxAISidebar ref + refresh block are redundant with customSidebars. Drop the state field (lines 146–156), remove the ref & its refresh() (lines 209–212), and update SidebarPanels.test.js to remove 'boxAISidebar' from the sidebar list and assertions.

🧹 Nitpick comments (5)
src/elements/content-sidebar/SidebarPanels.js (4)

327-360: Drop redundant component existence checks; Flow’s got your back, fool!

CustomSidebarPanel.component is required by type. Remove !CustomPanelComponent guard and the ternary. Cleaner, less noise.

Apply:

-                        if (isDisabled || !CustomPanelComponent) {
+                        if (isDisabled) {
                             return null;
                         }

                         return (
                             <Route
                                 exact
                                 key={customPanelId}
                                 path={`/${customPanelPath}`}
                                 render={() => {
                                     this.handlePanelRender(customPanelPath);
-                                    return CustomPanelComponent ? (
-                                        <CustomPanelComponent
-                                            elementId={elementId}
-                                            key={file.id}
-                                            fileExtension={file.extension}
-                                            hasSidebarInitialized={isInitialized}
-                                            ref={this.getCustomSidebarRef(customPanelId)}
-                                        />
-                                    ) : null;
+                                    return (
+                                        <CustomPanelComponent
+                                            elementId={elementId}
+                                            key={file.id}
+                                            fileExtension={file.extension}
+                                            hasSidebarInitialized={isInitialized}
+                                            ref={this.getCustomSidebarRef(customPanelId)}
+                                        />
+                                    );
                                 }}
                             />
                         );

Based on learnings


186-196: Refs won’t attach to function components without forwardRef — don’t get played, sucka!

You pass ref={this.getCustomSidebarRef(customPanelId)} to arbitrary custom components. Unless they use React.forwardRef (and ideally useImperativeHandle to expose refresh()), ref.current stays null and your custom refresh loop won’t hit them. Add a note to the CustomSidebarPanel contract/docs requiring forwardRef for refresh support, or switch to a callback/imperative prop.

Also applies to: 349-355


237-254: Panel ordering logic looks right; Box AI included when not default — solid work, fool.

Else-branch now includes all custom panels (including Box AI). Nice fix versus earlier exclusion. One caveat: if a custom panel path collides with a built-in (e.g., “metadata”), it can override eligibility/order. Add a reserved-name guard or validate uniqueness of panel.path.

Example guard (conceptual):

  • Reserved: {docgen, skills, activity, details, metadata}
  • Warn or skip any custom with a reserved path

292-308: Avoid key collisions in eligibility map, jive turkey!

Keys for custom eligibility are paths that can overwrite built-ins if they collide. Consider validating custom path against reserved names before merging, or namespace custom keys to prevent accidental overrides.

src/elements/content-sidebar/__tests__/SidebarPanels.test.js (1)

663-819: Consider a refresh test for custom panels — show me the receipts, sucka!

Add a test where a custom panel uses forwardRef to expose refresh(), mount, call instance.refresh(), and assert your custom ref’s refresh is called via the customSidebars loop.

I can draft the test with a forwardRef custom component and verify refresh invocation. Want me to add it?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6937b60 and 59c10df.

📒 Files selected for processing (11)
  • src/elements/content-sidebar/ContentSidebar.js (4 hunks)
  • src/elements/content-sidebar/Sidebar.js (6 hunks)
  • src/elements/content-sidebar/SidebarNav.js (4 hunks)
  • src/elements/content-sidebar/SidebarPanels.js (8 hunks)
  • src/elements/content-sidebar/__tests__/SidebarNav.test.js (4 hunks)
  • src/elements/content-sidebar/__tests__/SidebarPanels.test.js (19 hunks)
  • src/elements/content-sidebar/flowTypes.js (2 hunks)
  • src/elements/content-sidebar/stories/BoxAISideBar.mdx (0 hunks)
  • src/elements/content-sidebar/stories/BoxAISidebar.stories.tsx (0 hunks)
  • src/elements/content-sidebar/stories/tests/BoxAISidebar-visual.stories.tsx (0 hunks)
  • src/elements/content-sidebar/stories/tests/ContentSidebar-visual.stories.tsx (2 hunks)
💤 Files with no reviewable changes (3)
  • src/elements/content-sidebar/stories/BoxAISidebar.stories.tsx
  • src/elements/content-sidebar/stories/tests/BoxAISidebar-visual.stories.tsx
  • src/elements/content-sidebar/stories/BoxAISideBar.mdx
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-09-03T18:30:44.447Z
Learnt from: fpan225
PR: box/box-ui-elements#4239
File: src/elements/content-sidebar/SidebarPanels.js:0-0
Timestamp: 2025-09-03T18:30:44.447Z
Learning: In the CustomSidebarPanel type, the component field is required (React.ComponentType<any>), so runtime checks for component existence are unnecessary since Flow will catch missing components at compile time. User fpan225 prefers to rely on the type system rather than adding redundant runtime checks.

Applied to files:

  • src/elements/content-sidebar/SidebarPanels.js
  • src/elements/content-sidebar/Sidebar.js
  • src/elements/content-sidebar/flowTypes.js
  • src/elements/content-sidebar/ContentSidebar.js
  • src/elements/content-sidebar/SidebarNav.js
📚 Learning: 2025-09-23T21:14:20.232Z
Learnt from: fpan225
PR: box/box-ui-elements#4239
File: src/elements/content-sidebar/SidebarPanels.js:0-0
Timestamp: 2025-09-23T21:14:20.232Z
Learning: User fpan225 clarified that Box AI is included in customPanels if it exists, but the current getPanelOrder function logic in the else branch still excludes Box AI from the returned order when shouldBoxAIBeDefaultPanel is false, since otherCustomPanelPaths specifically filters out Box AI panels.

Applied to files:

  • src/elements/content-sidebar/SidebarPanels.js
  • src/elements/content-sidebar/__tests__/SidebarPanels.test.js
📚 Learning: 2025-06-17T13:30:02.172Z
Learnt from: rafalmaksymiuk
PR: box/box-ui-elements#4144
File: src/elements/content-sidebar/versions/VersionsList.js:24-33
Timestamp: 2025-06-17T13:30:02.172Z
Learning: In the box-ui-elements codebase, Flow components use .flow.js type definition files, not TypeScript .ts files. The InternalSidebarNavigation type is a union type where different variants may have different properties like versionId, and proper type safety is ensured through conditional checks in methods like getSelectedVersionId.

Applied to files:

  • src/elements/content-sidebar/Sidebar.js
  • src/elements/content-sidebar/flowTypes.js
  • src/elements/content-sidebar/ContentSidebar.js
📚 Learning: 2025-09-03T18:24:37.905Z
Learnt from: fpan225
PR: box/box-ui-elements#4239
File: src/elements/content-sidebar/SidebarPanels.js:0-0
Timestamp: 2025-09-03T18:24:37.905Z
Learning: User fpan225 prefers to keep the original `customPanels` variable name rather than normalizing it to a different variable name (like `panels`) for better code readability. They use `if (hasCustomPanels && customPanels)` pattern to satisfy Flow type checking instead of creating a normalized array.

Applied to files:

  • src/elements/content-sidebar/__tests__/SidebarPanels.test.js
📚 Learning: 2025-07-11T14:43:02.677Z
Learnt from: jpan-box
PR: box/box-ui-elements#4166
File: src/elements/content-sidebar/SidebarNav.js:126-126
Timestamp: 2025-07-11T14:43:02.677Z
Learning: In the box-ui-elements repository, there's a file-type-based pattern for internationalization: TypeScript files (.tsx) predominantly use the modern useIntl hook (41 vs 15 files), while JavaScript files (.js) predominantly use the legacy injectIntl HOC (64 vs 5 files). New TypeScript components should use useIntl, while existing JavaScript components typically continue using injectIntl for consistency.

Applied to files:

  • src/elements/content-sidebar/SidebarNav.js
🧬 Code graph analysis (4)
src/elements/content-sidebar/SidebarPanels.js (2)
src/elements/content-sidebar/ContentSidebar.js (4)
  • Props (226-226)
  • Props (275-275)
  • Props (320-320)
  • Props (352-385)
src/elements/content-sidebar/Sidebar.js (4)
  • Props (294-319)
  • hasSkills (324-324)
  • hasActivity (321-321)
  • hasMetadata (323-323)
src/elements/content-sidebar/__tests__/SidebarNav.test.js (1)
src/elements/content-sidebar/SidebarNav.js (1)
  • boxAiTab (90-90)
src/elements/content-sidebar/__tests__/SidebarPanels.test.js (1)
src/elements/content-sidebar/Sidebar.js (1)
  • hasBoxAI (326-328)
src/elements/content-sidebar/SidebarNav.js (4)
src/elements/content-sidebar/ContentSidebar.js (4)
  • Props (226-226)
  • Props (275-275)
  • Props (320-320)
  • Props (352-385)
src/elements/content-sidebar/Sidebar.js (5)
  • Props (294-319)
  • hasActivity (321-321)
  • hasDetails (322-322)
  • hasSkills (324-324)
  • hasMetadata (323-323)
src/elements/content-sidebar/SidebarNavButton.js (1)
  • SidebarNavButton (32-32)
src/elements/common/interactionTargets.js (2)
  • SIDEBAR_NAV_TARGETS (2-11)
  • SIDEBAR_NAV_TARGETS (2-11)
🪛 Biome (2.1.2)
src/elements/content-sidebar/SidebarPanels.js

[error] 44-44: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 136-136: return types can only be used in TypeScript files

remove this type annotation

(parse)


[error] 186-186: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 186-186: return type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 237-237: optional parameters are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 237-237: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 237-237: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 237-237: return type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 310-310: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)

src/elements/content-sidebar/Sidebar.js

[error] 31-31: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 32-32: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 33-33: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 34-34: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 35-35: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 37-37: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)

src/elements/content-sidebar/flowTypes.js

[error] 45-46: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)

src/elements/content-sidebar/ContentSidebar.js

[error] 49-49: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)

src/elements/content-sidebar/SidebarNav.js

[error] 32-32: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 33-33: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 35-35: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint_test_build
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Summary

@fpan225 fpan225 force-pushed the custom-sidebar-panels branch from 59c10df to df9a123 Compare October 6, 2025 23:11
@fpan225 fpan225 changed the title feat(content-sidebar): implement for custom sidebar panels (BREAKING … feat(content-sidebar): implement for custom sidebar panels Oct 14, 2025
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.

3 participants