Skip to content

Conversation

@rafalmaksymiuk
Copy link
Contributor

@rafalmaksymiuk rafalmaksymiuk commented Jul 14, 2025

SidebarNav and SidebarNavTablist is now accepting routerDisabled prop and acts accordingly using routing handlers instead of ReactRouter. Tests were converted to RTL and expanded.

Summary by CodeRabbit

  • New Features

    • Sidebar navigation now supports both internal navigation and an option to disable routing, offering more flexible navigation control.
    • New data attributes have been added for improved testing and accessibility.
    • Added a new localization string for a metadata button in the sidebar.
  • Tests

    • Refactored sidebar navigation tests to use React Testing Library instead of Enzyme, improving test reliability and maintainability.
    • Enhanced test coverage for both routing-enabled and routing-disabled navigation scenarios.

@rafalmaksymiuk rafalmaksymiuk requested review from a team as code owners July 14, 2025 16:02
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 14, 2025

"""

Walkthrough

The changes introduce optional internal navigation and router disabling support to the SidebarNav and SidebarNavTablist components. Props and event handlers are updated to support both React Router-based and internal navigation. Related tests are refactored to use React Testing Library, replacing Enzyme and improving test structure and assertions. A new localization string for metadata was also added.

Changes

File(s) Change Summary
src/elements/content-sidebar/SidebarNav.js Added optional internalSidebarNavigation, internalSidebarNavigationHandler, and routerDisabled props; passed to children; added test IDs.
src/elements/content-sidebar/SidebarNavTablist.js Added optional internal navigation and router disabling props; split keyboard navigation logic; conditional export based on routerDisabled.
src/elements/content-sidebar/tests/SidebarNav.test.js Refactored tests to use React Testing Library; consolidated and parameterized tests; updated assertions to use test IDs and roles.
src/elements/content-sidebar/tests/SidebarNavTablist.test.js Refactored tests to use React Testing Library and MemoryRouter; split tests for router-enabled/disabled; added mock tab component.
i18n/en-US.properties Added localization string boxui.subHeader.metadata = Metadata.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SidebarNav
    participant SidebarNavTablist
    participant Router
    participant InternalNavHandler

    User->>SidebarNav: Interacts (e.g., keydown)
    SidebarNav->>SidebarNavTablist: Pass navigation props
    SidebarNavTablist->>SidebarNavTablist: handleKeyDown(event)
    alt routerDisabled = false
        SidebarNavTablist->>Router: history.push(newPath)
    else routerDisabled = true
        SidebarNavTablist->>InternalNavHandler: internalSidebarNavigationHandler(newView)
    end
Loading

Possibly related PRs

  • box/box-ui-elements#4156: Implements router-disabled and internal navigation handling for SidebarNavButton, complementing these changes for related sidebar navigation components.
  • box/box-ui-elements#4160: Extends sidebar components with optional internal navigation and routerDisabled support, mirroring the dual-mode navigation logic in this PR.
  • box/box-ui-elements#4152: Adds router-disabled and internal navigation support to VersionsSidebar and StaticVersionSidebar, paralleling the approach for different sidebar modules.

Suggested labels

ready-to-merge

Suggested reviewers

  • jankowiakdawid
  • kajarosz

Poem

In the sidebar’s cozy warren,
Navigation hops are born—
With routers on or routers off,
The tabs respond to every cough.
Testing burrows deeper still,
As rabbits code with nimble skill,
And leap ahead with every thrill! 🐇
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82ccbb6 and cec7d3e.

📒 Files selected for processing (2)
  • src/elements/content-sidebar/SidebarNavTablist.js (3 hunks)
  • src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/elements/content-sidebar/tests/SidebarNavTablist.test.js
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: rafalmaksymiuk
PR: box/box-ui-elements#4136
File: src/elements/common/types/SidebarNavigation.ts:16-26
Timestamp: 2025-06-11T16:30:10.431Z
Learning: `VersionSidebarView` intentionally uses the `versionId` field to stay consistent with current URL parameter naming; a potential rename to `fileVersionId` is deferred until React Router is removed.
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.
src/elements/content-sidebar/SidebarNavTablist.js (2)
Learnt from: rafalmaksymiuk
PR: box/box-ui-elements#4136
File: src/elements/common/types/SidebarNavigation.ts:16-26
Timestamp: 2025-06-11T16:30:10.431Z
Learning: `VersionSidebarView` intentionally uses the `versionId` field to stay consistent with current URL parameter naming; a potential rename to `fileVersionId` is deferred until React Router is removed.
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.
🪛 Biome (1.9.4)
src/elements/content-sidebar/SidebarNavTablist.js

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

TypeScript only syntax

(parse)


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

TypeScript only syntax

(parse)


[error] 21-23: Expected a statement but instead found ',
routerDisabled?: boolean,
}'.

Expected a statement here.

(parse)


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

TypeScript only syntax

(parse)


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

TypeScript only syntax

(parse)


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

TypeScript only syntax

(parse)


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

TypeScript only syntax

(parse)


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

TypeScript only syntax

(parse)


[error] 36-36: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 38-38: void is confusing outside a return type or a type parameter.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


[error] 68-68: void is confusing outside a return type or a type parameter.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


[error] 135-135: Type annotations 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). (2)
  • GitHub Check: lint_test_build
  • GitHub Check: Summary
🔇 Additional comments (8)
src/elements/content-sidebar/SidebarNavTablist.js (8)

12-12: LGTM! Clean type definitions for dual-mode navigation support.

The type imports and prop definitions correctly support both router-based and internal navigation modes. Making history optional and adding the new navigation props with proper Flow typing is well-structured.

Also applies to: 17-19, 22-22


25-34: LGTM! Component signature properly updated for new navigation props.

The destructuring includes all new props with appropriate default values. The routerDisabled = false default ensures backward compatibility.


36-37: LGTM! Safe children mapping with proper optional chaining.

The children mapping correctly extracts sidebarView props and uses optional chaining for safety.


38-66: LGTM! Well-structured router-based keyboard navigation handler.

The handler correctly:

  • Guards against missing history prop
  • Extracts current tab from pathname
  • Implements proper wrap-around navigation logic
  • Manages focus and prevents default behavior

The implementation is clean and follows established patterns.


68-98: LGTM! Consistent non-router keyboard navigation handler.

The handler properly mirrors the router version but uses internal navigation:

  • Guards against missing handler
  • Uses internal navigation state for current tab
  • Maintains consistent navigation logic
  • Calls the appropriate handler instead of history.push

The parallelism between the two handlers makes the code easy to understand and maintain.


100-100: LGTM! Clear handler selection logic.

The ternary operator provides a clean and readable way to select the appropriate keyboard handler based on the routing mode.


117-118: LGTM! Navigation props properly passed to child components.

The new navigation props and routerDisabled flag are correctly passed to child components, maintaining consistency in the component hierarchy.

Also applies to: 121-121


132-142: LGTM! Clever conditional router wrapper implementation.

The wrapper pattern elegantly handles the conditional application of withRouter:

  • When routerDisabled is true, returns the plain component without router dependencies
  • When routerDisabled is false, returns the router-wrapped component
  • Maintains backward compatibility and clean separation of concerns

This approach is both maintainable and efficient.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@rafalmaksymiuk rafalmaksymiuk changed the title Frofra 35 feat(router): optional router in SidebarNav Jul 14, 2025
@rafalmaksymiuk rafalmaksymiuk changed the title feat(router): optional router in SidebarNav feat(router): optional router in SidebarNav, SidebarNavTablist Jul 14, 2025
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: 0

🧹 Nitpick comments (1)
src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js (1)

49-49: Consider moving require() to top-level import

While the require() inside the component works, it's unconventional. Consider extracting the history hook to the top level.

-            const history = require('react-router-dom').useHistory();
+            const history = useHistory();

And add the import at the top:

-import { MemoryRouter } from 'react-router-dom';
+import { MemoryRouter, useHistory } from 'react-router-dom';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb27df9 and 17755b4.

📒 Files selected for processing (2)
  • src/elements/content-sidebar/__tests__/SidebarNav.test.js (3 hunks)
  • src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/elements/content-sidebar/tests/SidebarNav.test.js
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: rafalmaksymiuk
PR: box/box-ui-elements#4136
File: src/elements/common/types/SidebarNavigation.ts:16-26
Timestamp: 2025-06-11T16:30:10.431Z
Learning: `VersionSidebarView` intentionally uses the `versionId` field to stay consistent with current URL parameter naming; a potential rename to `fileVersionId` is deferred until React Router is removed.
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.
src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js (3)
Learnt from: rafalmaksymiuk
PR: box/box-ui-elements#4136
File: src/elements/common/types/SidebarNavigation.ts:16-26
Timestamp: 2025-06-11T16:30:10.431Z
Learning: `VersionSidebarView` intentionally uses the `versionId` field to stay consistent with current URL parameter naming; a potential rename to `fileVersionId` is deferred until React Router is removed.
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.
Learnt from: rafalmaksymiuk
PR: box/box-ui-elements#4156
File: src/elements/content-sidebar/SidebarNavButton.js:77-102
Timestamp: 2025-06-25T20:05:18.480Z
Learning: Rendering functions (functions that return JSX) are considered anti-patterns in React development because they create new function instances on every render, break React DevTools, interfere with reconciliation, and make testing more difficult.
🧬 Code Graph Analysis (1)
src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js (3)
src/elements/content-sidebar/versions/__tests__/VersionsSidebarContainer.rtl.test.js (1)
  • history (35-35)
src/elements/content-sidebar/SidebarNavTablist.js (1)
  • tablist (36-36)
src/elements/content-sidebar/__tests__/SidebarToggle.test.js (1)
  • mockInternalSidebarNavigationHandler (34-34)
⏰ 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). (2)
  • GitHub Check: lint_test_build
  • GitHub Check: Summary
🔇 Additional comments (7)
src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js (7)

2-3: LGTM: Proper RTL migration setup

The import changes correctly introduce React Testing Library utilities and MemoryRouter, which are appropriate for testing components with routing behavior.


13-31: Well-implemented MockTabComponent with proper forwardRef

The MockTabComponent is correctly implemented using React.forwardRef which is essential for focus management in keyboard navigation tests. The component accepts all necessary props and uses data-testid for reliable test queries.


37-39: Good practice: Mock cleanup in beforeEach

Clearing mocks before each test ensures test isolation and prevents side effects between tests.


41-63: Clever test helper with history capture

The custom render function with the HistoryCapture component is an elegant solution for testing router behavior. The pattern allows asserting on navigation changes while maintaining proper router context.


75-115: Comprehensive router-enabled navigation tests

The keyboard navigation tests properly simulate user interactions with userEvent.keyboard() and verify that router history updates correctly. The test structure with test.each is clean and covers both arrow up/down navigation and the edge case of arrow right not navigating.


117-178: Thorough router-disabled navigation tests

The internal navigation tests correctly verify that the internalSidebarNavigationHandler is called with the expected sidebar view when routerDisabled is true. The test structure mirrors the router-enabled tests for consistency and includes proper edge case testing.


81-93: Proper userEvent simulation for keyboard navigation

The use of userEvent.click() followed by userEvent.keyboard() correctly simulates the user workflow of focusing the tablist and then pressing keys. This is more realistic than directly dispatching keyboard events.

kajarosz
kajarosz previously approved these changes Jul 16, 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