Skip to content

[WEB-4050] feat: breadcrumbs revamp#7188

Merged
sriramveeraghanta merged 24 commits intopreviewfrom
feat-breadcrumbs-revamp
Jun 19, 2025
Merged

[WEB-4050] feat: breadcrumbs revamp#7188
sriramveeraghanta merged 24 commits intopreviewfrom
feat-breadcrumbs-revamp

Conversation

@anmolsinghbhatia
Copy link
Collaborator

@anmolsinghbhatia anmolsinghbhatia commented Jun 9, 2025

Summary

This PR includes a complete revamp of the breadcrumbs component with the following enhancements:

  • Breadcrumb Redesign for better clarity and navigation
  • Project & Feature Switcher integrated into breadcrumbs
  • Improved UX & Micro-Interactions for smoother user experience and visual feedback

Reference

[WEB-4050]

Summary by CodeRabbit

  • New Features

    • Introduced enhanced and more flexible breadcrumb components, including dropdowns and search-enabled navigation within breadcrumbs.
    • Added reusable components for common project breadcrumbs and project feature navigation.
    • Breadcrumbs now support improved responsive layouts, tooltips, and modular subcomponents for better user experience.
    • Added dynamic quick actions and view switchers in workspace and project headers.
  • Refactor

    • Updated all breadcrumb usages across the app to use the new component structure and props, simplifying and standardizing breadcrumb rendering.
    • Replaced custom breadcrumb logic in headers with unified, reusable components for consistency.
    • Streamlined quick action menus in workspace views for easier interaction.
  • Bug Fixes

    • Improved loading states and accessibility for breadcrumb navigation.
    • Enhanced dropdown interactions and visual consistency across different screen sizes.
  • Documentation

    • Added Storybook stories to showcase new breadcrumb component usage and variations.

@anmolsinghbhatia anmolsinghbhatia self-assigned this Jun 9, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 9, 2025

Walkthrough

This update introduces a comprehensive refactor and enhancement of breadcrumb navigation components across the codebase. It standardizes breadcrumb item usage, introduces reusable components for project and feature breadcrumbs, and adds new dropdown and search-select capabilities for navigation. The changes also streamline header and quick action components, improve UI flexibility, and centralize navigation logic for project features.

Changes

Files/Group Change Summary
admin/core/components/auth-header.tsx, web/app/.../header.tsx, web/core/components/project/header.tsx, web/core/components/workspace-notifications/sidebar/header/root.tsx Replaced Breadcrumbs.BreadcrumbItem with Breadcrumbs.Item; switched from link/type props to component prop for breadcrumb items.
packages/constants/src/project.ts Added EProjectFeatureKey enum for project feature keys.
packages/ui/src/breadcrumbs/breadcrumbs.tsx Refactored and modularized Breadcrumbs component; added new subcomponents and improved responsive/loading behavior.
packages/ui/src/breadcrumbs/breadcrumbs.stories.tsx Added Storybook stories for Breadcrumbs component, demonstrating new features and variants.
packages/ui/src/breadcrumbs/navigation-dropdown.tsx, packages/ui/src/breadcrumbs/navigation-search-dropdown.tsx Enhanced dropdown components: added search, new props, improved state management, and styling.
packages/ui/src/breadcrumbs/index.ts Re-exported new dropdown modules for public API.
packages/ui/src/dropdowns/custom-search-select.tsx Ensured onOpen callback is invoked when opening dropdown; improved button class handling.
packages/ui/src/header/header.tsx Added flex-grow to LeftItem container for layout flexibility.
web/ce/components/breadcrumbs/common.tsx, web/ce/components/breadcrumbs/project-feature.tsx, web/ce/components/breadcrumbs/project.tsx Added CommonProjectBreadcrumbs and ProjectFeatureBreadcrumb components; refactored ProjectBreadcrumb for parameterization and dropdown navigation.
web/ce/components/breadcrumbs/index.ts Re-exported new breadcrumb components for broader usage.
web/ce/components/issues/header.tsx, web/ce/components/projects/settings/intake/header.tsx Switched to CommonProjectBreadcrumbs for standardized breadcrumb rendering.
web/ce/components/projects/navigation/helper.tsx, web/ce/components/projects/navigation/index.ts Added helper to generate project feature navigation items; re-exported helper.
web/core/components/common/breadcrumb-link.tsx Refactored BreadcrumbLink to use new Breadcrumbs.ItemWrapper; improved memoization and tooltip logic.
web/core/components/common/switcher-label.tsx Added SwitcherIcon component; refactored SwitcherLabel to use it for consistent icon rendering.
web/core/components/workspace/views/default-view-quick-action.tsx, web/core/components/workspace/views/quick-action.tsx, web/core/components/workspace/views/header.tsx Simplified quick action components; removed unused props and custom button logic; streamlined menu rendering.
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/.../header.tsx (multiple files) Refactored breadcrumbs to use CommonProjectBreadcrumbs and new dropdowns; improved navigation and removed manual item construction.
web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx Added view switcher dropdown and contextual quick actions to global issues header.
web/app/(all)/[workspaceSlug]/(projects)/workspace-views/[globalViewId]/page.tsx Removed unused GlobalViewsHeader import and usage.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Breadcrumbs
    participant CommonProjectBreadcrumbs
    participant ProjectFeatureBreadcrumb
    participant ProjectBreadcrumb
    participant Dropdown

    User->>Breadcrumbs: Render with items/components
    Breadcrumbs->>CommonProjectBreadcrumbs: Render with workspaceSlug, projectId, featureKey
    CommonProjectBreadcrumbs->>ProjectBreadcrumb: Render project breadcrumb (dropdown)
    CommonProjectBreadcrumbs->>ProjectFeatureBreadcrumb: (if featureKey) Render feature breadcrumb (dropdown)
    ProjectBreadcrumb->>Dropdown: Show project switch options
    ProjectFeatureBreadcrumb->>Dropdown: Show feature navigation options
    User->>Dropdown: Select item
    Dropdown->>Breadcrumbs: Trigger navigation to selected route
Loading

Suggested labels

🌐frontend, ✨feature, 🧹chore, ready_to_merge

Suggested reviewers

  • prateekshourya29
  • sriramveeraghanta

Poem

Hopping through the code with glee,
Breadcrumbs now are clear to see!
Dropdowns sparkle, icons shine,
Navigation’s streamlined, oh so fine.
With every switch and every link,
This rabbit’s proud—what do you think?
🥕✨


📜 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 12f5be7 and 12b386c.

📒 Files selected for processing (3)
  • web/app/(all)/[workspaceSlug]/(projects)/analytics/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx (3 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/app/(all)/[workspaceSlug]/(projects)/analytics/header.tsx
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx
🔇 Additional comments (3)
web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx (3)

8-37: LGTM: Import statements are well-organized and support the new functionality.

The import additions properly support the breadcrumb revamp with necessary constants, types, UI components, and hooks.


167-190: Excellent breadcrumb refactor with enhanced navigation capabilities.

The new breadcrumb structure successfully integrates the view switcher dropdown and follows the new component patterns. The implementation properly handles navigation, labeling, and icons while maintaining good user experience.


234-239: Well-simplified quick actions with clean conditional rendering.

The refactored quick actions properly handle different view types with a simplified prop interface, maintaining responsive behavior and clean separation of concerns.

✨ 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.

@makeplane
Copy link

makeplane bot commented Jun 9, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

@anmolsinghbhatia anmolsinghbhatia marked this pull request as ready for review June 17, 2025 10:44
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: 8

🔭 Outside diff range comments (3)
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/archives/header.tsx (1)

69-75: Avoid unnecessary .toString() casts

workspaceSlug and projectId are already typed as string | undefined.
Calling .toString() on a possibly-undefined value risks converting undefined into the literal string "undefined" and leaking into URLs.

-<ProjectBreadcrumb workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()} />
+{workspaceSlug && projectId && (
+  <ProjectBreadcrumb workspaceSlug={workspaceSlug} projectId={projectId} />
+)}

Guarding also prevents the breadcrumb component from rendering with invalid params.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx (1)

42-60: Guard against undefined before mapping over projectPageIds.

getCurrentProjectPageIds() can legally return undefined while the data is loading.
Calling .map unconditionally will raise a runtime TypeError and break the header.

-  const switcherOptions = projectPageIds
+  const switcherOptions = (projectPageIds ?? [])

A tiny guard is enough and keeps the component resilient during the initial loading phase.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx (1)

143-154: Handle potential undefined cycle details

Similar to the workspace views file, the cycle details retrieval might return undefined values.

Apply this diff to handle undefined values properly:

 const switcherOptions = currentProjectCycleIds
   ?.map((id) => {
     const _cycle = id === cycleId ? cycleDetails : getCycleById(id);
-    if (!_cycle) return;
+    if (!_cycle) return null;
     return {
       value: _cycle.id,
       query: _cycle.name,
       content: <SwitcherLabel name={_cycle.name} LabelIcon={ContrastIcon} />,
     };
   })
-  .filter((option) => option !== undefined) as ICustomSearchSelectOption[];
+  .filter(Boolean) as ICustomSearchSelectOption[];
🧹 Nitpick comments (23)
packages/constants/src/project.ts (1)

152-160: Consider using a const object + union type instead of a runtime enum

TS enums emit extra JS at runtime; you only need a string-literal union for typing. A lighter pattern is:

export const PROJECT_FEATURE_KEY = {
  WORK_ITEMS: "work_items",
  CYCLES: "cycles",
  MODULES: "modules",
  VIEWS: "views",
  PAGES: "pages",
  INTAKE: "intake",
} as const;

export type EProjectFeatureKey = typeof PROJECT_FEATURE_KEY[keyof typeof PROJECT_FEATURE_KEY];

This keeps the ergonomics, removes runtime cost, and is fully tree-shakable.

web/core/components/common/switcher-label.tsx (1)

6-29: Accessibility nit: make alt text descriptive

alt="logo" gives screen-reader users no context. Consider deriving it from the entity name:

- alt="logo"
+ alt={name ? `${name} logo` : "logo"}

(You can pass name as a prop or compute it higher up.)

web/core/components/workspace/views/header.tsx (1)

40-40: Minor type-safety nit – avoid ?.toString() when value is already guaranteed

Both ViewTab and DefaultViewTab bail out early if !workspaceSlug, so at this point workspaceSlug is truthy and already a string.
Using optional-chaining plus toString() widens the type to string | undefined and is unnecessary.

-      <WorkspaceViewQuickActions workspaceSlug={workspaceSlug?.toString()} view={view} />
+      <WorkspaceViewQuickActions workspaceSlug={workspaceSlug} view={view} />

Apply the same change to the call on line 60. This keeps the prop strictly typed as string and removes superfluous conversions.

Also applies to: 60-60

web/core/components/project/header.tsx (1)

40-48: Localise the “Archived” label

All other labels in this header are wrapped in t(...). The hard-coded string here skips localisation and will surface in English for non-English users.

-{isArchived && <Breadcrumbs.Item component={<BreadcrumbLink label="Archived" />} />}
+{isArchived && (
+  <Breadcrumbs.Item
+    component={<BreadcrumbLink label={t("common.archived")} />}
+  />
+)}
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/archives/header.tsx (1)

80-87: Key prop missing for dynamically created breadcrumb

When activeTabBreadcrumbDetail is truthy, a new Breadcrumbs.Item is pushed into an array.
React will emit a warning in dev mode because neither Breadcrumbs.Item nor its wrapper is given a key prop.

-<Breadcrumbs.Item
+<Breadcrumbs.Item
+  key={`archives-${activeTab}`}
web/ce/components/breadcrumbs/common.tsx (2)

24-26: Eliminate redundant toString() conversions

workspaceSlug and projectId are already declared as string; converting them back to string is superfluous and can hide type problems upstream.

-  workspaceSlug={workspaceSlug?.toString()}
-  projectId={projectId?.toString()}
+  workspaceSlug={workspaceSlug}
+  projectId={projectId}

17-32: Consider memoising to avoid re-renders

CommonProjectBreadcrumbs is pure and relies only on scalar props.
Wrapping it in memo will prevent unnecessary reconciliations in large headers where breadcrumbs seldom change.

-export const CommonProjectBreadcrumbs: FC<TCommonProjectBreadcrumbProps> = (props) => {
+export const CommonProjectBreadcrumbs: FC<TCommonProjectBreadcrumbProps> = memo((props) => {
   ...
-};
+});

You’ll need to import memo from react.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/header.tsx (1)

43-47: Breadcrumb component already converts values to string

CommonProjectBreadcrumbs internally calls .toString() on every identifier (see common.tsx).
Calling ?.toString() here is therefore redundant and can be dropped to reduce noise.

-  workspaceSlug={workspaceSlug?.toString() ?? ""}
-  projectId={projectId?.toString() ?? ""}
+  workspaceSlug={workspaceSlug}
+  projectId={projectId}
web/ce/components/projects/settings/intake/header.tsx (1)

39-45: Unintended border utility may leak into layout

Adding border to the flex container changes the visual design of every
project-intake header. Confirm with design before merging, otherwise drop the class.

-<div className="flex items-center gap-4 flex-grow border">
+<div className="flex items-center gap-4 flex-grow">
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx (1)

16-16: Inconsistent import path for shared breadcrumb module

Other files import @/plane-web/components/breadcrumbs, here we use
@/plane-web/components/breadcrumbs/common. Pick one barrel/explicit
path and stick to it to avoid duplicate bundles and confused auto-imports.

web/ce/components/issues/header.tsx (2)

7-14: Prefer consistent alias import for CommonProjectBreadcrumbs.

Most files in this PR import the breadcrumbs helper via the barrel file ("@/plane-web/components/breadcrumbs").
Using the relative path here introduces avoidable path-divergence and makes large-scale refactors harder.

-import { CommonProjectBreadcrumbs } from "../breadcrumbs/common";
+import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs";

62-70: Pass the router.back handler by reference to avoid re-creating a closure each render.

-<Breadcrumbs onBack={() => router.back()} …
+<Breadcrumbs onBack={router.back} …

It’s a micro-optimisation, but it also aligns with the pattern used in other headers added in this PR.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/header.tsx (1)

13-13: Import path inconsistency

Everywhere else the barrel import ("@/plane-web/components/breadcrumbs") is used. Sticking to a single path avoids duplicate bundles after tree-shaking and keeps auto-imports predictable.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx (1)

186-197: Consider re-using CountChip for uniform badge styling

You hand-rolled the badge here whereas other headers rely on the shared CountChip component. Re-using the shared component avoids styling drift and keeps future design tweaks in one place.

-<span className="flex …">{workItemsCount}</span>
+<CountChip count={workItemsCount} />
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx (1)

24-27: showButton prop is declared but never used

IPagesHeaderProps exposes showButton, yet PageDetailsHeader doesn’t consume it
(or forward it). Either wire it up or drop it from the interface to keep the API clean.

web/ce/components/breadcrumbs/feature.tsx (1)

38-55: shouldRender filter may drop externally supplied items

additionalNavigationItems are blindly concatenated and then filtered by
item.shouldRender, yet external callers might not set this flag.
Consider defaulting to true when the property is absent:

- .filter((item) => item.shouldRender)
+ .filter((item) => item.shouldRender !== false)

Prevents accidental disappearance of valid navigation entries coming from the caller.

packages/ui/src/breadcrumbs/navigation-search-dropdown.tsx (2)

17-19: disableRootHover prop is unused

The prop is defined but never referenced, leading to dead code and misleading API
surface. Either implement the hover-disabling logic or remove the prop entirely
until there is a concrete use-case.


53-60: Missing type="button" on clickable element

Inside a form context this <button> will default to type="submit", causing
unexpected navigation when the dropdown lives inside a <form>.
Add an explicit type to future-proof:

- <button
+ <button
+   type="button"
packages/ui/src/breadcrumbs/breadcrumbs.stories.tsx (1)

201-212: Repeated identical key values in story data

feature-3 is reused for several items. Storybook warns on duplicate keys and it
obscures example behaviour. Give each entry a distinct key.

- { key: "feature-3", title: "Cycles", … }
- { key: "feature-3", title: "Modules", … }
- { key: "feature-3", title: "Views", … }
- { key: "feature-3", title: "Pages", … }
+ { key: "feature-cycles",   title: "Cycles",   … }
+ { key: "feature-modules",  title: "Modules",  … }
+ { key: "feature-views",    title: "Views",    … }
+ { key: "feature-pages",    title: "Pages",    … }
web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx (1)

136-138: Simplify options filtering logic

The current implementation filters twice - once implicitly in the map and once explicitly. This can be simplified.

Consider using flatMap for cleaner code:

-const switcherOptions = [...defaultOptions, ...workspaceOptions].filter(
-  (option) => option !== undefined
-) as ICustomSearchSelectOption[];
+const switcherOptions = [
+  ...defaultOptions,
+  ...currentWorkspaceViews?.flatMap((view) => {
+    const _view = getViewDetailsById(view);
+    return _view
+      ? [{
+          value: _view.id,
+          query: _view.name,
+          content: <SwitcherLabel name={_view.name} LabelIcon={Layers} />,
+        }]
+      : [];
+  }) ?? []
+] as ICustomSearchSelectOption[];
web/ce/components/breadcrumbs/project.tsx (1)

60-67: Unify route formatting

router.push is invoked with /issues (no trailing slash) in the dropdown but /issues/ (trailing slash) in the fallback click handler.
In Next.js this can trigger an extra redirect or cache miss. Pick one style (prefer the repo-wide convention) and use it consistently.

packages/ui/src/breadcrumbs/navigation-dropdown.tsx (1)

34-40: Allow handleOnClick for the last breadcrumb too

Current guard if (!isLast) { … handleOnClick?.() } silences the callback when this item is the tail of the trail.
There are valid cases (e.g., refresh current view) where the last item still needs a click handler. Consider removing the !isLast restriction or exposing a separate prop to control it.

packages/ui/src/breadcrumbs/breadcrumbs.tsx (1)

44-47: Remove redundant fragment

The fragment adds no semantic value and triggers the noUselessFragments lint error.

-              return (
-                <>
-                  <BreadcrumbItemLoader />
-                </>
-              );
+              return <BreadcrumbItemLoader />;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 75f89c4 and b3a9670.

📒 Files selected for processing (44)
  • admin/core/components/auth-header.tsx (2 hunks)
  • packages/constants/src/project.ts (1 hunks)
  • packages/ui/src/breadcrumbs/breadcrumbs.stories.tsx (1 hunks)
  • packages/ui/src/breadcrumbs/breadcrumbs.tsx (3 hunks)
  • packages/ui/src/breadcrumbs/index.ts (1 hunks)
  • packages/ui/src/breadcrumbs/navigation-dropdown.tsx (3 hunks)
  • packages/ui/src/breadcrumbs/navigation-search-dropdown.tsx (1 hunks)
  • packages/ui/src/dropdowns/custom-search-select.tsx (2 hunks)
  • packages/ui/src/header/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/active-cycles/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/analytics/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/browse/[workItem]/header.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/drafts/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/profile/[userId]/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/archives/header.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/archives/issues/(detail)/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx (3 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(list)/header.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/draft-issues/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx (3 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/header.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx (3 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(detail)/[viewId]/header.tsx (4 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/header.tsx (2 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/stickies/header.tsx (1 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/workspace-views/[globalViewId]/page.tsx (0 hunks)
  • web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx (3 hunks)
  • web/ce/components/breadcrumbs/common.tsx (1 hunks)
  • web/ce/components/breadcrumbs/feature.tsx (1 hunks)
  • web/ce/components/breadcrumbs/index.ts (1 hunks)
  • web/ce/components/breadcrumbs/project.tsx (1 hunks)
  • web/ce/components/issues/header.tsx (3 hunks)
  • web/ce/components/projects/navigation/helper.tsx (1 hunks)
  • web/ce/components/projects/navigation/index.ts (1 hunks)
  • web/ce/components/projects/settings/intake/header.tsx (2 hunks)
  • web/core/components/common/breadcrumb-link.tsx (1 hunks)
  • web/core/components/common/switcher-label.tsx (2 hunks)
  • web/core/components/project/header.tsx (1 hunks)
  • web/core/components/workspace-notifications/sidebar/header/root.tsx (1 hunks)
  • web/core/components/workspace/views/default-view-quick-action.tsx (2 hunks)
  • web/core/components/workspace/views/header.tsx (2 hunks)
  • web/core/components/workspace/views/quick-action.tsx (3 hunks)
💤 Files with no reviewable changes (1)
  • web/app/(all)/[workspaceSlug]/(projects)/workspace-views/[globalViewId]/page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (12)
web/app/(all)/[workspaceSlug]/(projects)/active-cycles/header.tsx (2)
packages/i18n/src/store/index.ts (1)
  • t (211-232)
web/ce/components/workspace/upgrade-badge.tsx (1)
  • UpgradeBadge (11-30)
web/core/components/workspace/views/header.tsx (2)
web/core/components/workspace/views/quick-action.tsx (1)
  • WorkspaceViewQuickActions (24-126)
web/core/components/workspace/views/default-view-quick-action.tsx (1)
  • DefaultWorkspaceViewQuickActions (20-97)
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/header.tsx (2)
web/core/hooks/use-app-router.tsx (1)
  • useAppRouter (4-4)
web/ce/components/breadcrumbs/common.tsx (1)
  • CommonProjectBreadcrumbs (17-32)
web/core/components/workspace/views/default-view-quick-action.tsx (1)
packages/types/src/workspace-views.d.ts (1)
  • TStaticViewTypes (35-39)
web/app/(all)/[workspaceSlug]/(projects)/browse/[workItem]/header.tsx (3)
packages/ui/src/breadcrumbs/breadcrumbs.tsx (1)
  • Breadcrumbs (190-190)
web/ce/components/breadcrumbs/common.tsx (1)
  • CommonProjectBreadcrumbs (17-32)
web/core/store/router.store.ts (1)
  • projectId (85-87)
web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx (8)
web/core/hooks/use-app-router.tsx (1)
  • useAppRouter (4-4)
packages/constants/src/workspace.ts (1)
  • DEFAULT_GLOBAL_VIEWS_LIST (228-248)
web/core/components/common/switcher-label.tsx (1)
  • SwitcherLabel (38-46)
web/core/store/global-view.store.ts (1)
  • currentWorkspaceViews (67-76)
packages/types/src/common.d.ts (1)
  • ICustomSearchSelectOption (30-36)
packages/ui/src/breadcrumbs/navigation-search-dropdown.tsx (1)
  • BreadcrumbNavigationSearchDropdown (21-96)
web/core/components/workspace/views/quick-action.tsx (1)
  • WorkspaceViewQuickActions (24-126)
web/core/components/workspace/views/default-view-quick-action.tsx (1)
  • DefaultWorkspaceViewQuickActions (20-97)
packages/ui/src/breadcrumbs/breadcrumbs.tsx (1)
packages/ui/src/tooltip/tooltip.tsx (1)
  • Tooltip (36-110)
web/ce/components/projects/settings/intake/header.tsx (1)
web/ce/components/breadcrumbs/common.tsx (1)
  • CommonProjectBreadcrumbs (17-32)
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/header.tsx (3)
web/ce/components/breadcrumbs/common.tsx (1)
  • CommonProjectBreadcrumbs (17-32)
packages/ui/src/breadcrumbs/navigation-search-dropdown.tsx (1)
  • BreadcrumbNavigationSearchDropdown (21-96)
web/core/components/common/switcher-label.tsx (1)
  • SwitcherIcon (13-29)
web/core/components/common/switcher-label.tsx (2)
packages/types/src/common.d.ts (1)
  • TLogoProps (13-24)
apiserver/plane/db/models/workspace.py (1)
  • logo_url (145-153)
web/ce/components/projects/navigation/helper.tsx (2)
web/core/store/router.store.ts (1)
  • projectId (85-87)
web/core/components/workspace/sidebar/project-navigation.tsx (1)
  • TNavigationItem (19-28)
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/header.tsx (1)
web/ce/components/breadcrumbs/common.tsx (1)
  • CommonProjectBreadcrumbs (17-32)
🪛 Biome (1.9.4)
packages/ui/src/breadcrumbs/breadcrumbs.tsx

[error] 40-56: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (27)
packages/ui/src/dropdowns/custom-search-select.tsx (1)

100-106: Readable class-name merge looks good

Switching to cn improves clarity and keeps disabled/hover styles consistent.

web/core/components/common/switcher-label.tsx (1)

42-42: Good extraction of icon logic

Replacing the inline ternary with SwitcherIcon centralises icon decisions and keeps SwitcherLabel tidy.

packages/ui/src/header/header.tsx (1)

41-44: flex-grow may overflow on very long breadcrumb sets

flex-grow together with max-w-[80%] generally works, but check narrow viewports: long labels could still push the right-hand actions off-screen. If that happens, consider min-w-0 on the grow element or wrapping crumbs in an overflow-auto container.

web/ce/components/projects/navigation/index.ts (1)

1-1: Index barrel looks fine

Simple re-export keeps import paths clean.

packages/ui/src/breadcrumbs/index.ts (1)

3-3: Barrel update is clear and correct

navigation-search-dropdown is now surfaced through the public API – makes sense and won’t introduce tree-shaking issues.

web/app/(all)/[workspaceSlug]/(projects)/drafts/header.tsx (1)

44-49: Nice migration to Breadcrumbs.Item

Adopts the new component prop cleanly and keeps the JSX concise. No issues spotted.

web/ce/components/breadcrumbs/index.ts (1)

1-3: ```shell
#!/bin/bash
echo "Listing all export statements in each module for manual inspection:"
for f in web/ce/components/breadcrumbs/{common,feature,project}.tsx; do
echo -e "\n=== $f ==="
rg -n 'export ' "$f"
done


</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/active-cycles/header.tsx (1)</summary>

`17-27`: **Breadcrumb refactor LGTM**  

Implementation matches the new API, icon & translation hook usage are consistent.

</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/header.tsx (1)</summary>

`31-36`: **Correct adoption of new breadcrumb API**  

Clean swap to `Breadcrumbs.Item` with no regressions noted.

</details>
<details>
<summary>admin/core/components/auth-header.tsx (1)</summary>

`70-78`: **Breadcrumb API migration looks correct**  

The switch to `Breadcrumbs.Item` with the `component` prop is consistent with the updated UI package and compiles cleanly – nothing else needed here.  



Also applies to: 82-85

</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/profile/[userId]/header.tsx (1)</summary>

`55-63`: **Breadcrumb refactor applied flawlessly**  

The new `Breadcrumbs.Item` usage together with `BreadcrumbLink` is fully aligned with the refactored breadcrumbs API. No issues spotted.

</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/analytics/header.tsx (1)</summary>

`42-49`: **Analytics header crumbs migrated correctly**  

Implementation matches the new API and keeps translations & icons intact – looks good.

</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/stickies/header.tsx (1)</summary>

`28-35`: **Stickies breadcrumb update looks good**  

The conversion to `Breadcrumbs.Item` with a `BreadcrumbLink` component is correct and preserves icon styling.

</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/draft-issues/header.tsx (1)</summary>

`95-106`: ```shell
#!/bin/bash
set -e

echo "=== Looking for Props definition in BreadcrumbLink ==="
rg -nE "^(type|interface) Props" -C5 web/core/components/common/breadcrumb-link.tsx || echo "No Props type found"

echo -e "\n=== Searching for href handling in component implementation ==="
rg -n "<(Link|a)" -C5 web/core/components/common/breadcrumb-link.tsx || echo "No anchor or Link usage detected"

echo -e "\n=== Showing first 200 lines of the component for manual inspection ==="
sed -n '1,200p' web/core/components/common/breadcrumb-link.tsx
web/core/components/workspace-notifications/sidebar/header/root.tsx (1)

29-37: Breadcrumb refactor looks good

The migration to Breadcrumbs.Item with the new component prop is correct and consistent with the revamped breadcrumbs API. No further action required.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(list)/header.tsx (1)

22-23: ```shell
#!/bin/bash

Locate and print the beginning of the header.tsx file where useParams is used

find . -type f -name header.tsx -path "/modules/" -print -exec sed -n '1,200p' {} ;


</details>
<details>
<summary>web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(list)/header.tsx (1)</summary>

`58-65`: ```bash
#!/bin/bash
set -e

# Locate only the header.tsx files under any "(list)" directory
paths=$(find web/app -type f | grep "/(list)/header\.tsx" || true)
if [ -z "$paths" ]; then
  echo "No list header.tsx files found under web/app"
  exit 1
fi

for file in $paths; do
  echo "---- Inspecting: $file ----"
  # Print lines 50–90 to capture the snippet around lines 58–65
  sed -n '50,90p' "$file"
  echo
done
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/views/(list)/header.tsx (1)

26-31: Empty-string fall-back may leak into the generated URL

CommonProjectBreadcrumbs receives workspaceSlug={workspaceSlug?.toString() ?? ""} and the same for projectId.
If either param is still undefined on first render, the component will receive an empty string and generate routes like "/projects//views", which later stick in the history stack.

Consider short-circuiting the render (as you did in other headers) or guarding the breadcrumb call:

{workspaceSlug && projectId && (
  <CommonProjectBreadcrumbs  />
)}
web/app/(all)/[workspaceSlug]/(projects)/browse/[workItem]/header.tsx (1)

36-50: Minor: keep the back-handler style consistent

Other headers pass router.back directly; this one wraps it in onBack={router.back} already — good.
No action needed, just highlighting for future consistency reviews.

web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx (1)

173-180: Guard against undefined route params when pushing module switch

router.push(\/${workspaceSlug}/projects/${projectId}/modules/${value}`) will emit/undefined/projects/undefined/modules/…` on the first couple of renders when the params are not yet populated.

Either:

  1. Wrap the call in a param check, or
  2. Pre-compute workspaceSlug?.toString() and projectId?.toString() once the params are available and skip rendering the dropdown until then.

This avoids broken navigation entries in the history stack.

web/app/(all)/[workspaceSlug]/(projects)/workspace-views/header.tsx (1)

208-213: Extract view type detection logic

The view rendering logic correctly handles both workspace and default views.

web/ce/components/projects/navigation/helper.tsx (1)

1-78: Well-structured navigation helper implementation

The helper function is well-implemented with:

  • Proper typing and consistent structure
  • Clear separation of concerns
  • Appropriate use of feature flags for conditional rendering
  • Correct permission mapping
web/core/components/workspace/views/quick-action.tsx (1)

82-123: Clean refactor to CustomMenu implementation

The refactor successfully:

  • Simplifies the component interface by removing unused props
  • Implements proper event handling with preventDefault and stopPropagation
  • Uses consistent styling with the ellipsis button pattern
  • Maintains proper conditional rendering based on permissions
web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx (2)

169-193: Clean breadcrumb implementation with feature key

The breadcrumb implementation properly uses:

  • CommonProjectBreadcrumbs with appropriate feature key
  • BreadcrumbNavigationSearchDropdown for cycle selection
  • Proper icon and styling integration

194-207: Well-implemented work items count display

The tooltip implementation for work items count is well done with:

  • Proper mobile responsiveness check
  • Clear tooltip content with singular/plural handling
  • Appropriate styling and positioning
web/core/components/common/breadcrumb-link.tsx (2)

16-46: Excellent use of memoization for performance

The refactor demonstrates best practices:

  • Proper use of React.memo for preventing unnecessary re-renders
  • Clear component names with displayName for debugging
  • Modular sub-components for better maintainability
  • Efficient memoization of props and content

47-74: Clean implementation with proper conditional rendering

The main component implementation is well-structured:

  • Proper memoization of computed values
  • Clean conditional rendering based on href presence
  • Correct integration with the new Breadcrumbs.ItemWrapper
  • Good handling of tooltip behavior for mobile devices

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: 3

🧹 Nitpick comments (4)
web/ce/components/breadcrumbs/project-feature.tsx (2)

36-40: Memoise and de-duplicate allNavigationItems

Every render allocates a new array and can re-create dropdown items even if neither props nor store values changed. In MobX observers this is easy to miss because reactive changes trigger re-renders often.

-  const allNavigationItems = [...(additionalNavigationItems || []), ...navigationItems];
+  const allNavigationItems = useMemo(() => {
+    // Prevent duplicate keys while preserving caller order.
+    const map = new Map<string, TNavigationItem>();
+    [...(additionalNavigationItems ?? []), ...navigationItems].forEach((i) => {
+      if (!map.has(i.key)) map.set(i.key, i);
+    });
+    return Array.from(map.values());
+  }, [additionalNavigationItems, navigationItems]);

This avoids unnecessary allocations and removes potential key collisions that would break React’s list diffing.


64-65: Separator visibility should respect isLast

showSeparator={false} is hard-coded, so non-last items lose the chevron separator. Prefer:

-        showSeparator={false}
+        showSeparator={!isLast}

This keeps visual continuity for intermediate crumbs.

web/core/components/common/breadcrumb-link.tsx (2)

64-72: Missing passHref/prefetch options & anchor semantics

next/link no longer injects href into non-anchor children after v13 when legacyBehavior is off. Wrapping a non-anchor component without passHref can break semantics & prefetching:

-  <Link href={href}>
+  <Link href={href} passHref>
     <ItemWrapper {...itemWrapperProps}>{content}</ItemWrapper>
   </Link>

Consider adding prefetch={false} where prefetching large pages is undesirable.


17-25: Accessibility: mark purely decorative icons

When the breadcrumb shows both icon + label, the icon should be hidden from screen readers to avoid duplicate announcements.

-  <div className="flex size-4 items-center justify-center overflow-hidden !text-[1rem]">{icon}</div>
+  <div
+    aria-hidden={label ? true : undefined}
+    className="flex size-4 items-center justify-center overflow-hidden !text-[1rem]"
+  >
+    {icon}
+  </div>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 08f47b5 and 16652a6.

📒 Files selected for processing (4)
  • web/ce/components/breadcrumbs/common.tsx (1 hunks)
  • web/ce/components/breadcrumbs/index.ts (1 hunks)
  • web/ce/components/breadcrumbs/project-feature.tsx (1 hunks)
  • web/core/components/common/breadcrumb-link.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/ce/components/breadcrumbs/index.ts
  • web/ce/components/breadcrumbs/common.tsx
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
web/ce/components/breadcrumbs/project-feature.tsx (1)

47-55: Unsafe as FC<ISvgIcons> cast

item.icon is blindly asserted to FC<ISvgIcons>. If any navigation item carries a plain JSX element or a string, TypeScript will not warn but runtime will break when React.createElement receives an invalid type. Consider narrowing the type at source or gracefully falling back:

- icon: item.icon as FC<ISvgIcons>,
+ icon:
+   typeof item.icon === "function"
+     ? (item.icon as FC<ISvgIcons>)
+     : undefined,

@sriramveeraghanta sriramveeraghanta merged commit 2b7a17b into preview Jun 19, 2025
5 of 6 checks passed
@sriramveeraghanta sriramveeraghanta deleted the feat-breadcrumbs-revamp branch June 19, 2025 11:47
lifeiscontent pushed a commit that referenced this pull request Aug 18, 2025
* chore: project feature enum added

* feat: revamp breadcrumb and add navigation dropdown component

* chore: custom search select component refactoring

* chore: breadcrumb stories added

* chore: switch label and breadcrumb link component refactor

* chore: project navigation helper function added

* chore: common breadcrumb component added

* chore: breadcrumb refactoring

* chore: code refactor

* chore: code refactor

* fix: build error

* fix: nprogress and button tooltip

* chore: code refactor

* chore: workspace view breadcrumb improvements

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

---------

Co-authored-by: vamsikrishnamathala <matalav55@gmail.com>
@coderabbitai coderabbitai bot mentioned this pull request Aug 23, 2025
1 task
@coderabbitai coderabbitai bot mentioned this pull request Nov 23, 2025
3 tasks
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.

5 participants