Skip to content

Conversation

@Kunal1522
Copy link
Contributor

@Kunal1522 Kunal1522 commented Nov 8, 2025

Tasks

  • Improve the breadcrumbs component to display each project/chapter/user/etc page H1 header content
  • Added Fallback to BreadCrumbWrapper in case of some rendering issue
  • Removed the /repositories to appear in breadcrumb as the page does not really exist
  • Added Unit Testing for BreadCrumbs.tsx, BreadCrumbsWrapper.tsx

Resolves #1425


Proposed change

Display actual entity names in breadcrumbs instead of URL slugs.

Currently, breadcrumbs show URL-formatted text like "Bjornkimminich" instead of the real name "Björn Kimminich" from the database. This PR fixes that by having detail pages pass their GraphQL data to the breadcrumb system through a simple interface.

Pages now pass entity names like this:

The breadcrumb checks which field is set and displays that name. If no data is provided, it falls back to formatting the URL slug nicely.

Also refactored breadcrumb logic into reusable components (BreadCrumbs, BreadCrumbsWrapper, useBreadcrumbs hook) and added 72 tests.


Detailed PR

Problem
Breadcrumbs were showing URL slugs instead of actual entity names from the database.

Solution

  1. Created Reusable Breadcrumb System
    Three main pieces:

    • BreadCrumbs.tsx - Pure UI component that renders breadcrumb items.
    • BreadCrumbsWrapper.tsx - Renders breadcrumbs. It takes an array of items and displays them nicely with proper styling and navigation links.
    • useBreadcrumbs hook - Contains all the logic for building breadcrumbs. It handles both simple routes (/projects/zap) and nested routes (/organizations/x/repositories/y).
  2. Pages Pass Real Names via Props
    Each detail page already fetches GraphQL data. Now they pass the entity name to PageLayout:

    The interface accepts different entity types:

    The hook checks which field is present and uses it. If none is provided, it falls back to formatting the URL slug.

  3. Special Handling for Nested Routes
    Repository routes (/organizations/[org]/repositories/[repo]) get special detection. The breadcrumb displays actual org and repo names, and skips the "Repositories" segment since that page doesn't exist.

Testing
Added 72 tests covering rendering, auto-generation, real name display, fallbacks, and edge cases. All pass.

BEFORE

image

AFTER

image

BEFORE

image

AFTER

image


Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Implemented dynamic breadcrumb navigation system with automatic path-based trail generation and intelligent title formatting.
    • Enhanced repository navigation with improved organization-scoped context handling.
  • Tests

    • Added comprehensive test coverage for breadcrumb functionality and related utilities.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Replaces a path-parsing breadcrumb component with a context-driven system: adds BreadcrumbContext, useBreadcrumbs hook, BreadcrumbProvider/BreadcrumbRoot, a BreadCrumbsWrapper that renders current-path breadcrumbs, a BreadCrumbRenderer (items prop), PageLayout to register titles, utilities, tests, and updates many dynamic layouts to use PageLayout and cached metadata helpers.

Changes

Cohort / File(s) Summary
Renderer & Wrapper
frontend/src/components/BreadCrumbs.tsx, frontend/src/components/BreadCrumbsWrapper.tsx
Replaces the old BreadCrumbs export with BreadCrumbRenderer({ items }) and adds BreadCrumbsWrapper to derive and render the breadcrumb trail for the current pathname, handling links vs last-item text.
Context & Hook
frontend/src/contexts/BreadcrumbContext.tsx, frontend/src/hooks/useBreadcrumbs.ts, frontend/src/types/breadcrumb.ts
New breadcrumb registry and APIs: registerBreadcrumb, getBreadcrumbItems, useBreadcrumb, BreadcrumbProvider, BreadcrumbRoot, plus useBreadcrumbs hook and BreadcrumbItem type.
Layout & Provider
frontend/src/components/PageLayout.tsx, frontend/src/app/layout.tsx
New client PageLayout component that registers a breadcrumb item and wraps page content; root layout now wrapped with <BreadcrumbRoot> and uses BreadCrumbsWrapper.
Dynamic page layouts
frontend/src/app/chapters/.../layout.tsx, frontend/src/app/committees/.../layout.tsx, frontend/src/app/organizations/.../layout.tsx, frontend/src/app/organizations/.../repositories/.../layout.tsx, frontend/src/app/projects/.../layout.tsx, frontend/src/app/members/.../layout.tsx
Converted many layouts to async, added cached metadata helpers (React cache), compute/display titles, and wrap detail pages with PageLayout(title, path) when data exists.
Utilities
frontend/src/utils/breadcrumb.ts
New formatBreadcrumbTitle(text) utility to convert slugs to human-readable title case.
Tests — components & hooks
frontend/__tests__/unit/components/BreadCrumbs.test.tsx, frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx, frontend/__tests__/unit/components/PageLayout.test.tsx, frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx, frontend/__tests__/unit/utils/breadcrumb.test.ts
Updated/added tests covering BreadCrumbRenderer API, BreadCrumbsWrapper route behavior, PageLayout registration, useBreadcrumbs behavior (registration, auto-generation, hidden segments), and slug formatting.
Tests — pages
frontend/__tests__/unit/pages/ChapterDetails.test.tsx, frontend/__tests__/unit/pages/CommitteeDetails.test.tsx, frontend/__tests__/unit/pages/OrganizationDetails.test.tsx
Added/mocked usePathname in next/navigation mocks and adjusted assertions to role-based queries.
Test utilities & wrappers
frontend/src/wrappers/testUtil.tsx
Test wrapper now nests BreadcrumbRoot around test children to enable breadcrumb registration in tests.
Repository & query tweaks
frontend/src/components/RepositoryCard.tsx, frontend/src/server/queries/repositoryQueries.ts
RepositoryCard key/path now use optional chaining with organization login; GraphQL query adds organization.name field.
Minor formatting
frontend/src/app/projects/[projectKey]/page.tsx
Non-functional formatting change (blank line after import).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • BreadcrumbContext registry semantics (subscribe/unsubscribe ordering and root registration).
    • useBreadcrumbs path parsing, hidden-segments behavior, and precedence of registered items.
    • Async layout signature changes and cached helpers (params typing, SSR/SSG implications).
    • Tests relying on next/navigation mocks and lifecycle/unregister correctness.

Possibly related PRs

Suggested reviewers

  • kasya
  • arkid15r
  • aramattamara

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor: update breadcrumbs component to support dynamic title rende...' directly describes the main change: refactoring breadcrumbs to support dynamic title rendering from actual entity names instead of URL slugs.
Description check ✅ Passed The description thoroughly explains the changes, including the problem (URL slugs instead of entity names), the solution (reusable breadcrumb system with PageLayout integration), implementation details, and test coverage. It directly relates to the changeset.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #1425: displays actual entity names in breadcrumbs instead of URL slugs, implements reusable breadcrumb components, handles nested routes with special repository logic, provides prettified slug fallbacks, and includes comprehensive test coverage (72 tests).
Out of Scope Changes check ✅ Passed All changes are scoped to breadcrumb refactoring: new breadcrumb components (BreadCrumbs.tsx, BreadCrumbsWrapper.tsx), context (BreadcrumbContext.tsx), hooks (useBreadcrumbs), utilities (formatBreadcrumbTitle), PageLayout wrapper, layout updates across pages, and related tests. Minor changes to RepositoryCard.tsx and repositoryQueries.ts are directly related to supporting the breadcrumb system's entity-name requirements.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

🧹 Nitpick comments (3)
frontend/src/hooks/useBreadcrumbs.ts (1)

26-27: Consider making route pattern detection more maintainable.

The nested repository route detection uses a hardcoded check with magic values. Consider extracting this as a constant or pattern matcher for better maintainability.

+const NESTED_REPO_PATTERN = {
+  segments: 4,
+  positions: { organization: 0, repositories: 2 },
+  values: { organization: 'organizations', repositories: 'repositories' }
+}
+
 const isNestedRepoRoute =
-  segments.length === 4 && segments[0] === 'organizations' && segments[2] === 'repositories'
+  segments.length === NESTED_REPO_PATTERN.segments &&
+  segments[0] === NESTED_REPO_PATTERN.values.organization &&
+  segments[2] === NESTED_REPO_PATTERN.values.repositories
frontend/src/components/BreadCrumbsWrapper.tsx (1)

19-78: LGTM! Solid implementation with good edge case handling.

The BreadCrumbsWrapper component correctly:

  • ✅ Returns null for home page and PageLayout-managed routes
  • ✅ Generates breadcrumb items from path segments with proper formatting (upperFirst + dash replacement)
  • ✅ Builds progressive paths for each breadcrumb link
  • ✅ Renders with consistent styling using HeroUI and FontAwesome

The logic aligns well with the useBreadcrumbs fallback behavior and has comprehensive test coverage.

Optional future refactor: The rendering logic (lines 36-77) is nearly identical to BreadCrumbRenderer (lines 10-53 in frontend/src/components/BreadCrumbs.tsx). Consider extracting the common rendering logic to reduce duplication:

// Shared base component
function BreadcrumbsBase({ items }: { items: BreadCrumbItem[] }) {
  return (
    <div className="mt-16 w-full pt-4">
      {/* ... shared rendering logic ... */}
    </div>
  )
}

// BreadCrumbsWrapper would then:
export default function BreadCrumbsWrapper() {
  // ... route detection and item generation ...
  return <BreadcrumbsBase items={items} />
}

This would centralize the styling and structure, making future updates easier.

frontend/__tests__/unit/components/BreadCrumbs.test.tsx (1)

37-43: Update the last-item test to assert current-page semantics.

Once the renderer stops using isDisabled, this case should verify the breadcrumb exposes aria-current="page" (and rename the test accordingly) rather than asserting it’s disabled. That keeps the test aligned with the accessibility contract we want. (heroui.com)

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6ca282 and 7a1353d.

⛔ Files ignored due to path filters (1)
  • frontend/src/types/__generated__/repositoryQueries.generated.ts is excluded by !**/__generated__/**
📒 Files selected for processing (20)
  • cspell/custom-dict.txt (3 hunks)
  • frontend/__tests__/unit/components/BreadCrumbs.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/PageLayout.test.tsx (1 hunks)
  • frontend/__tests__/unit/hooks/useBreadcrumbs.test.ts (1 hunks)
  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/CommitteeDetails.test.tsx (2 hunks)
  • frontend/__tests__/unit/pages/OrganizationDetails.test.tsx (2 hunks)
  • frontend/src/app/chapters/[chapterKey]/page.tsx (2 hunks)
  • frontend/src/app/committees/[committeeKey]/page.tsx (2 hunks)
  • frontend/src/app/layout.tsx (2 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
  • frontend/src/app/organizations/[organizationKey]/page.tsx (2 hunks)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (3 hunks)
  • frontend/src/app/projects/[projectKey]/page.tsx (2 hunks)
  • frontend/src/components/BreadCrumbs.tsx (2 hunks)
  • frontend/src/components/BreadCrumbsWrapper.tsx (1 hunks)
  • frontend/src/components/PageLayout.tsx (1 hunks)
  • frontend/src/hooks/useBreadcrumbs.ts (1 hunks)
  • frontend/src/server/queries/repositoryQueries.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS is actively used in frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx for program editing functionality and cannot be removed. It serves a different purpose than GET_PROGRAM_ADMIN_DETAILS, providing comprehensive program information needed for editing.

Applied to files:

  • frontend/src/app/committees/[committeeKey]/page.tsx
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/unit/components/PageLayout.test.tsx
  • frontend/__tests__/unit/pages/OrganizationDetails.test.tsx
  • frontend/__tests__/unit/pages/CommitteeDetails.test.tsx
  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx
  • frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx
  • frontend/__tests__/unit/components/BreadCrumbs.test.tsx
📚 Learning: 2025-07-13T07:31:06.511Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.

Applied to files:

  • frontend/__tests__/unit/pages/OrganizationDetails.test.tsx
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx
  • frontend/__tests__/unit/pages/CommitteeDetails.test.tsx
  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx
  • frontend/src/components/BreadCrumbs.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.

Applied to files:

  • frontend/src/components/BreadCrumbsWrapper.tsx
  • frontend/__tests__/unit/pages/CommitteeDetails.test.tsx
  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx
  • frontend/src/components/BreadCrumbs.tsx
  • frontend/src/components/PageLayout.tsx
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details. These queries cannot be removed or merged as they serve different use cases in the application.

Applied to files:

  • frontend/src/server/queries/repositoryQueries.ts
🧬 Code graph analysis (13)
frontend/src/app/committees/[committeeKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
frontend/__tests__/unit/components/PageLayout.test.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
frontend/src/app/projects/[projectKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
frontend/__tests__/unit/hooks/useBreadcrumbs.test.ts (1)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • useBreadcrumbs (18-64)
frontend/src/app/members/[memberKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx (1)
frontend/src/components/BreadCrumbsWrapper.tsx (1)
  • BreadCrumbsWrapper (19-78)
frontend/src/app/layout.tsx (1)
frontend/src/components/BreadCrumbsWrapper.tsx (1)
  • BreadCrumbsWrapper (19-78)
frontend/src/components/BreadCrumbs.tsx (1)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • BreadCrumbItem (4-7)
frontend/src/components/PageLayout.tsx (2)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • useBreadcrumbs (18-64)
frontend/src/components/BreadCrumbs.tsx (1)
  • BreadCrumbRenderer (11-54)
frontend/__tests__/unit/components/BreadCrumbs.test.tsx (1)
frontend/src/components/BreadCrumbs.tsx (1)
  • BreadCrumbRenderer (11-54)
frontend/src/app/organizations/[organizationKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
frontend/src/app/chapters/[chapterKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
🔇 Additional comments (18)
cspell/custom-dict.txt (1)

9-9: Verify the necessity of both Cyclonedx and cyclonedx casing variants.

All four new dictionary entries are correctly placed in alphabetical order. However, the addition of both Cyclonedx (line 9, capitalized) and cyclonedx (line 58, lowercase) appears redundant if both are intended to match the same tool name. Most spell-checkers handle case-insensitive matching, so a single entry may be sufficient.

Additionally, the standard spelling is CycloneDX (mixed case), not Cyclonedx. If this tool is referenced in the breadcrumb-related code, consider whether the dictionary entries match the actual casing used there.

Please confirm:

  1. Whether both casing variants are necessary for the spell-checker configuration in this project.
  2. Whether these words are actually used in the breadcrumb component changes, tests, or documentation, and if so, in what casing.

Also applies to: 17-17, 48-48, 58-58

frontend/__tests__/unit/components/PageLayout.test.tsx (1)

1-137: LGTM! Comprehensive test coverage.

The test suite provides excellent coverage of the PageLayout component functionality, including:

  • Children rendering
  • Breadcrumb positioning in the DOM
  • Various breadcrumbData field types (projectName, memberName, chapterName, committeeName, orgName/repoName)
  • Edge cases (undefined breadcrumbData, mismatched field types)

The use of compareDocumentPosition to verify breadcrumb placement is a solid approach.

frontend/src/app/layout.tsx (1)

9-9: LGTM! Clean component swap.

The replacement of BreadCrumbs with BreadCrumbsWrapper aligns with the broader breadcrumb refactoring described in the PR objectives.

Also applies to: 77-77

frontend/src/server/queries/repositoryQueries.ts (1)

34-34: LGTM! Supports breadcrumb display names.

Adding organization.name to the query enables breadcrumbs to display the full organization name instead of relying on the slug-formatted login field.

frontend/src/app/projects/[projectKey]/page.tsx (1)

21-21: LGTM! Consistent PageLayout integration.

The wrapping of DetailsCard with PageLayout and the passing of breadcrumbData={{ projectName: project.name }} follows the established pattern and enables proper breadcrumb rendering with the actual project name.

Also applies to: 93-113

frontend/__tests__/unit/pages/CommitteeDetails.test.tsx (1)

25-25: LGTM! Improved test robustness.

The changes adapt the test for the PageLayout integration:

  1. Mocking usePathname supports the breadcrumb generation logic
  2. Using getByRole('heading', { name: 'Test Committee' }) is more semantically correct and resilient than text-based queries

Also applies to: 56-56

frontend/src/app/members/[memberKey]/page.tsx (1)

29-29: LGTM! Proper fallback handling.

The PageLayout integration is clean and includes a sensible fallback: memberName: user?.name || user?.login ensures the breadcrumb displays either the user's full name or their login if no name is set.

Also applies to: 235-249

frontend/__tests__/unit/pages/OrganizationDetails.test.tsx (1)

31-31: LGTM! Consistent test improvements.

The changes mirror the pattern in CommitteeDetails.test.tsx:

  1. usePathname mock enables breadcrumb generation
  2. Role-based heading query is more robust than text matching

Also applies to: 74-74

frontend/src/hooks/useBreadcrumbs.ts (1)

50-58: The current breadcrumbData logic is correct and intentional.

The OR-chaining behavior in lines 50-58 is explicitly tested and expected. The test "handles partial breadcrumbData (uses first matching field)" at line 212 in useBreadcrumbs.test.ts validates that when a breadcrumbData field is provided, the first truthy value from the OR-chain is used regardless of route type. The same scenario is tested in PageLayout.test.tsx at line 125 under the title "handles partial breadcrumbData (wrong field for route type)," confirming this is intentional design.

Additionally, the codebase design prevents the problematic scenario from occurring: every page passes only the appropriate field for its route type (e.g., projectName for project routes, memberName for member routes). No instances exist where multiple conflicting fields are passed simultaneously.

frontend/src/app/committees/[committeeKey]/page.tsx (1)

84-94: LGTM!

The PageLayout integration is clean and consistent with the breadcrumb system. The committeeName is correctly passed from the GraphQL-fetched data, and the early return at lines 48-55 ensures committee is not null.

frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1)

31-31: LGTM!

Adding the usePathname mock is necessary for the PageLayout integration in ChapterDetailsPage, as the useBreadcrumbs hook (used by PageLayout) depends on usePathname to generate breadcrumb items. The mocked path /chapters/test-chapter correctly matches the chapterKey from the existing useParams mock.

frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx (1)

1-148: LGTM! Comprehensive test coverage.

The test suite provides excellent coverage of BreadCrumbsWrapper functionality:

  • ✅ Route detection logic (hiding on home and detail pages)
  • ✅ Breadcrumb rendering on list pages
  • ✅ Auto-generation logic (capitalization, dash replacement)
  • ✅ Progressive path building for links
  • ✅ Edge cases (trailing slashes, special characters)

The test structure is clear with well-organized describe blocks, and the assertions properly validate both visibility and rendering behavior.

frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (1)

113-145: PageLayout integration looks good.

The PageLayout wrapper is correctly implemented with appropriate fallback chains for organization and repository names. The optional chaining at lines 116-118 properly handles cases where repository.organization might be null.

frontend/src/app/chapters/[chapterKey]/page.tsx (1)

64-77: LGTM!

The PageLayout integration is clean and follows the established pattern. The chapterName is correctly passed from the GraphQL-fetched chapter data.

frontend/src/components/PageLayout.tsx (1)

1-28: LGTM! Clean component design.

The PageLayout component follows React best practices:

  • ✅ Proper separation of concerns (delegates breadcrumb logic to useBreadcrumbs hook)
  • ✅ Client component correctly marked with 'use client' directive (required for Next.js 15 app router with usePathname)
  • ✅ Fragment wrapper avoids unnecessary DOM nesting
  • ✅ Composition pattern with children prop for flexible page content

The interface design is pragmatic, allowing optional breadcrumb data fields that are resolved by the useBreadcrumbs hook based on the current route.

frontend/src/components/BreadCrumbsWrapper.tsx (1)

10-17: Route pattern matching looks correct.

The ROUTES_WITH_PAGE_LAYOUT patterns properly identify detail pages that use PageLayout component and should not show path-based breadcrumbs. The regex patterns correctly match:

  • Single-segment detail pages: /members/[key], /projects/[key], etc.
  • Nested repository pages: /organizations/[key]/repositories/[key]

This prevents double breadcrumb rendering on pages that have entity-specific breadcrumbs from PageLayout.

frontend/src/app/organizations/[organizationKey]/page.tsx (1)

117-131: Verify TypeScript satisfaction and type safety across state/useEffect.

The code logic is correct at runtime: the guard at line 54 prevents reaching the return statement unless graphQLData?.organization exists, which triggers setOrganization() in the useEffect. However, TypeScript may not recognize this connection because organization is a separate state variable initialized as null (line 21), and the guard checks graphQLData?.organization rather than directly narrowing the organization state variable.

The type-safety concern raised in the original review is valid—accessing organization.name, organization.description, and organization.stats at lines 117-131 could trigger TypeScript errors depending on the configuration and how state narrowing is handled.

Manual verification needed: Confirm whether TypeScript reports any errors for organization property access at lines 67-70, 79-91, and 115-131 in a proper build environment with TypeScript configured for the project.

frontend/__tests__/unit/hooks/useBreadcrumbs.test.ts (1)

14-241: Great coverage of breadcrumb scenarios.

The suite hits every branch of the hook, including nested repo routes, fallbacks, and trailing-slash handling. That gives strong confidence in the refactor.

@Kunal1522
Copy link
Contributor Author

@coderabbitai generate docstrings

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

Warning

Docstrings generation - IN PROGRESS

Generating docstrings for this pull request

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

…rmatting

- Replace isDisabled with aria-current="page" for proper accessibility
- Use consistent split/map/join capitalization for repository names
…rmatting

- Replace isDisabled with aria-current="page" for proper accessibility
- Use consistent split/map/join capitalization for repository names
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a1353d and ef1cfb8.

📒 Files selected for processing (1)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-13T07:31:06.511Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.

Applied to files:

  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx
🧬 Code graph analysis (1)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (19-28)
🔇 Additional comments (3)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (3)

10-10: LGTM!

The import is correctly placed and used for formatting breadcrumb names.


20-20: LGTM!

The PageLayout import is correctly placed and consistent with the breadcrumb refactoring across other detail pages.


130-146: LGTM!

The DetailsCard props are correctly preserved, and wrapping it in PageLayout successfully adds breadcrumb functionality without affecting the existing detail page content.

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)
frontend/src/components/BreadCrumbs.tsx (1)

11-57: Consider adding a guard for empty items.

While the parent components should ensure items is never empty, a defensive check would make the component more resilient:

 export default function BreadCrumbRenderer({ items }: BreadCrumbRendererProps) {
+  if (items.length === 0) {
+    return null
+  }
+
   return (
     <div className="mt-16 w-full pt-4">

This is optional since the useBreadcrumbs hook should always provide at least a Home item according to the PR objectives.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef1cfb8 and 0e96f26.

📒 Files selected for processing (1)
  • frontend/src/components/BreadCrumbs.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-13T07:31:06.511Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.

Applied to files:

  • frontend/src/components/BreadCrumbs.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.

Applied to files:

  • frontend/src/components/BreadCrumbs.tsx
🧬 Code graph analysis (1)
frontend/src/components/BreadCrumbs.tsx (1)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • BreadCrumbItem (4-7)
🔇 Additional comments (2)
frontend/src/components/BreadCrumbs.tsx (2)

1-9: LGTM! Clean imports and interface definition.

The type-only import on line 4 follows TypeScript best practices, and the rename of BreadcrumbItem to HeroUIBreadcrumbItem on line 3 properly avoids naming collisions with the custom BreadCrumbItem type. The interface is focused and well-typed.


30-52: Excellent refactor—previous accessibility issue properly resolved.

The component now correctly implements breadcrumb semantics:

  • Last item uses aria-current="page" (line 38) instead of the previous aria-disabled="true"
  • No isDisabled prop on HeroUIBreadcrumbItem (line 34)
  • Clean separation of concerns with logic moved to the useBreadcrumbs hook
  • Key using item.path is appropriate since breadcrumb paths are unique by nature

The refactor transforms this into a focused, pure renderer component.

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)
frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1)

34-144: Consider adding a breadcrumb rendering test.

While the breadcrumb system is tested elsewhere, you might consider adding a test in this suite to verify that the chapter name appears in the breadcrumbs when rendered through PageLayout. This would provide integration-level coverage for the breadcrumb feature in the chapter details context.

Example test structure:

test('renders chapter name in breadcrumbs', async () => {
  render(<ChapterDetailsPage />)
  await waitFor(() => {
    // Verify breadcrumb contains chapter name from mockChapterDetailsData
    expect(screen.getByText(mockChapterDetailsData.chapter.name)).toBeInTheDocument()
  })
})
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0e96f26 and cd1417d.

📒 Files selected for processing (2)
  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/app/members/[memberKey]/page.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-13T07:31:06.511Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.

Applied to files:

  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.

Applied to files:

  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx
🔇 Additional comments (1)
frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1)

31-31: LGTM! Mock addition supports breadcrumb integration.

The usePathname mock is correctly added to support the new breadcrumb system that PageLayout uses when wrapping ChapterDetailsPage. The returned path '/chapters/test-chapter' is consistent with the test data's chapterKey.

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

Thank you @Kunal1522 !
It works as expected for most part.. but I do have some concerns for the code. Left a few comments below ⬇️

Comment on lines 26 to 27
const isNestedRepoRoute =
segments.length === 4 && segments[0] === 'organizations' && segments[2] === 'repositories'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where is this 4 coming from? What if we have more then 4 nested items? 🤔
We want to make it as dynamic as possible

path: string
}

interface BreadcrumbData {
Copy link
Collaborator

Choose a reason for hiding this comment

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

BreadcrumbData interface is duplicated in two files, violating DRY.
It's added here and in PageLayout.tsx.

Also, we are trying to get away from using interface and want to use type instead. Please move this into types/ folder and use where needed to avoid code duplication

if (isNestedRepoRoute) {
breadcrumbs.push({ title: 'Organizations', path: '/organizations' })

const orgTitle = breadcrumbData?.orgName || upperFirst(segments[1]).replaceAll('-', ' ')
Copy link
Collaborator

Choose a reason for hiding this comment

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

I can see you use the same logic several times. Can we move this into a function instead? Lines 32, 38, 48.

Comment on lines 10 to 17
const ROUTES_WITH_PAGE_LAYOUT = [
/^\/members\/[^/]+$/,
/^\/projects\/[^/]+$/,
/^\/chapters\/[^/]+$/,
/^\/committees\/[^/]+$/,
/^\/organizations\/[^/]+$/,
/^\/organizations\/[^/]+\/repositories\/[^/]+$/,
]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm also not super happy with these hardcoded values. If we ever change our project structure - this might fail. Is there a better way to find a match? 🤔

import Link from 'next/link'
import { usePathname } from 'next/navigation'

const ROUTES_WITH_PAGE_LAYOUT = [
Copy link
Collaborator

Choose a reason for hiding this comment

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

I also think this route detection logic is somewhat duplicated: regex patterns in here vs string matching in useBreadcrumbs 🤔

})

test('returns null for member detail pages', () => {
;(usePathname as jest.Mock).mockReturnValue('/members/bjornkimminich')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use users/project names that we already added to cspell to not add new items? Or just some fake ones, that would be even better.

@kasya
Copy link
Collaborator

kasya commented Nov 13, 2025

@Kunal1522 I pushed some changes to address issues I found while reviewing your PR. The one I noticed was not connected to your changes, but other 2 were from running make check.

Could you also address 5 newly added issues found by SonarQube? Here's the list

@kasya
Copy link
Collaborator

kasya commented Nov 15, 2025

@Kunal1522 Hi! Are you planning to address the comments in this PR? The deadline for this issue passed a while ago (Nov 8th). If the updates aren’t made within the next day, I’ll need to reassign the issue to someone else. Thanks!

@Kunal1522
Copy link
Contributor Author

Hi, I’m sorry for the late reply. I have my end-term exams going on right now, so I won’t be able to contribute until 25th November.

However I went through the PR comments and completed all the requested changes, including the SonarQube ones.

Before committing, the only part I wanted to improve was making the breadcrumbs more dynamic and easier to extend.

Right now, the only path that appears in the breadcrumb but does not actually exist is: organisations/[slug]/repositories. I had to hard-code it, but similar cases may be added in the future.

One solution I found is to run a script at build time that walks through the app directory and stores all existing routes in a JSON file. This JSON can be checked whenever needed. This would help in two ways:

validating multi-level slugged routes,(so i would not need regex pattern matching )
preventing breadcrumbs for paths that do not actually exist (paths without a page.tsx or layout.tsx).

To make things more extensible, I also moved the configuration to a types file. So if more pages are added later, we can just update the types, and everything will adjust automatically.
image

Please assign this issue to someone else if they volunteer otherwise i will fix this after 26th November.

@Kunal1522 Kunal1522 marked this pull request as draft November 16, 2025 09:38
@kasya
Copy link
Collaborator

kasya commented Nov 26, 2025

@Kunal1522 I haven't reassigned this to anyone else. It's Nov 26th so let me know if you can get back to this tomorrow. Otherwise, I'll reassign! Hope the exams went well.
Thanks!

@Kunal1522
Copy link
Contributor Author

thanks i appreciate that .yeah i have started reworking on it now maybe will raise pr in 1-2 days

…x patterns, and simplify dynamic/static route handling
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: 2

🧹 Nitpick comments (8)
frontend/src/components/RepositoryCard.tsx (2)

25-31: Composite key is an improvement; consider fallback collisions

Using ${repository.organization?.login ?? 'unknown'}-${repository.key} is a good step toward more stable keys, especially if repository.key is scoped per organization. If there’s any chance of multiple repositories with missing organization appearing in the same list, they’ll all share the 'unknown' prefix, so you might still get duplicate keys. If available, consider a globally unique field (e.g., repository.id) or extending the composite key to avoid that edge case.


40-43: Guard against missing organization when constructing the navigation URL

details.organization?.login can evaluate to undefined; interpolated in a template literal this becomes the string "undefined", so the click could navigate to /organizations/undefined/repositories/${details.key} instead of a valid org route. If details.organization is guaranteed to be present for this component, it’s safer to reflect that in the type (make organization.login required here) and drop the optional chaining. Otherwise, add a guard before calling router.push (or render a non-clickable title when the organization is missing) to avoid broken links.

frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx (1)

67-90: Address SonarQube issues: consolidate push calls and reduce nesting depth.

The static analysis flags two issues in this test:

  1. Multiple Array#push() calls (lines 69-77) should be consolidated
  2. Nesting depth exceeds 4 levels due to forEach inside act() (line 89)

Apply this diff to address both issues:

-      const unregisterFns: (() => void)[] = []
-      act(() => {
-        unregisterFns.push(
-          registerBreadcrumb({ title: 'Test Organization', path: '/organizations/test-org' })
-        )
-        unregisterFns.push(
-          registerBreadcrumb({
-            title: 'Test Repository',
-            path: '/organizations/test-org/repositories/test-repo',
-          })
-        )
-      })
+      let unregisterOrg: () => void
+      let unregisterRepo: () => void
+      act(() => {
+        unregisterOrg = registerBreadcrumb({ title: 'Test Organization', path: '/organizations/test-org' })
+        unregisterRepo = registerBreadcrumb({
+          title: 'Test Repository',
+          path: '/organizations/test-org/repositories/test-repo',
+        })
+      })

       // Note: 'repositories' segment is hidden (in HIDDEN_SEGMENTS)
       expect(result.current).toEqual([
         { title: 'Home', path: '/' },
         { title: 'Organizations', path: '/organizations' },
         { title: 'Test Organization', path: '/organizations/test-org' },
         { title: 'Test Repository', path: '/organizations/test-org/repositories/test-repo' },
       ])

       act(() => {
-        unregisterFns.forEach((fn) => fn())
+        unregisterOrg()
+        unregisterRepo()
       })
frontend/src/hooks/useBreadcrumbs.ts (2)

6-6: Use export...from syntax for cleaner re-export.

Per SonarCloud suggestion, prefer direct re-export syntax.

-export type { BreadcrumbItem }
+export type { BreadcrumbItem } from 'types/breadcrumb'

Then remove the import on line 3:

-import type { BreadcrumbItem } from 'types/breadcrumb'

8-8: Use Set for HIDDEN_SEGMENTS for efficient lookup.

Set.has() is O(1) compared to Array.includes() which is O(n). While the performance difference is negligible for a single-element collection, using Set is idiomatic and aligns with the SonarCloud suggestion.

-const HIDDEN_SEGMENTS = ['repositories']
+const HIDDEN_SEGMENTS = new Set(['repositories'])

And update line 31:

-    if (HIDDEN_SEGMENTS.includes(segment)) {
+    if (HIDDEN_SEGMENTS.has(segment)) {
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (1)

34-40: Mark props as read-only per SonarCloud recommendation.

The component props should be marked as Readonly for immutability and consistency with React best practices.

 export default async function RepositoryDetailsLayout({
   children,
   params,
-}: {
+}: Readonly<{
   children: React.ReactNode
   params: Promise<{ repositoryKey: string; organizationKey: string }>
-}) {
+}>) {
frontend/src/contexts/BreadcrumbContext.tsx (2)

57-69: Mark props as read-only per static analysis.

SonarCloud correctly flags that BreadcrumbProviderProps should be marked read-only to match the pattern used elsewhere (e.g., BreadCrumbRendererProps).

Additionally, the [item] dependency could cause re-registration on every render if the parent creates a new object reference. Consider stabilizing with useMemo at call sites or using primitive values.

Apply this diff:

-type BreadcrumbProviderProps = {
+type BreadcrumbProviderProps = Readonly<{
   item: BreadcrumbItem
   children: ReactNode
-}
+}>

71-78: Mark inline props type as read-only.

Per SonarCloud and project conventions, wrap the inline props type in Readonly<>.

Apply this diff:

-export function BreadcrumbRoot({ children }: { children: ReactNode }) {
+export function BreadcrumbRoot({ children }: Readonly<{ children: ReactNode }>) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 536119e and 2f14e42.

📒 Files selected for processing (22)
  • frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/PageLayout.test.tsx (1 hunks)
  • frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx (1 hunks)
  • frontend/__tests__/unit/utils/breadcrumb.test.ts (1 hunks)
  • frontend/src/app/chapters/[chapterKey]/layout.tsx (1 hunks)
  • frontend/src/app/chapters/[chapterKey]/page.tsx (2 hunks)
  • frontend/src/app/committees/[committeeKey]/page.tsx (2 hunks)
  • frontend/src/app/layout.tsx (2 hunks)
  • frontend/src/app/members/[memberKey]/layout.tsx (2 hunks)
  • frontend/src/app/organizations/[organizationKey]/layout.tsx (3 hunks)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (2 hunks)
  • frontend/src/app/projects/[projectKey]/layout.tsx (0 hunks)
  • frontend/src/app/projects/[projectKey]/page.tsx (1 hunks)
  • frontend/src/components/BreadCrumbs.tsx (2 hunks)
  • frontend/src/components/BreadCrumbsWrapper.tsx (1 hunks)
  • frontend/src/components/PageLayout.tsx (1 hunks)
  • frontend/src/components/RepositoryCard.tsx (2 hunks)
  • frontend/src/contexts/BreadcrumbContext.tsx (1 hunks)
  • frontend/src/hooks/useBreadcrumbs.ts (1 hunks)
  • frontend/src/types/breadcrumb.ts (1 hunks)
  • frontend/src/utils/breadcrumb.ts (1 hunks)
  • frontend/src/wrappers/testUtil.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/app/projects/[projectKey]/layout.tsx
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/app/chapters/[chapterKey]/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/tests/unit/components/PageLayout.test.tsx
  • frontend/src/app/projects/[projectKey]/page.tsx
  • frontend/src/app/chapters/[chapterKey]/page.tsx
  • frontend/src/components/PageLayout.tsx
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-11-17T17:30:42.139Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:169-171
Timestamp: 2025-11-17T17:30:42.139Z
Learning: In the OWASP/Nest frontend tests (PR #2671 context), wrapper functions like `expectChaptersCountEqualsThree` that simply call another helper with a fixed parameter (e.g., `expectChaptersCountEquals(3)`) are intentionally used to avoid arrow function callbacks in `waitFor` calls. This pattern prevents adding nesting depth that would trigger rule typescript:S2004. Example: `await waitFor(expectChaptersCountEqualsThree)` avoids the extra nesting from `await waitFor(() => expectChaptersCountEquals(3))`.

Applied to files:

  • frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS is actively used in frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx for program editing functionality and cannot be removed. It serves a different purpose than GET_PROGRAM_ADMIN_DETAILS, providing comprehensive program information needed for editing.

Applied to files:

  • frontend/src/app/committees/[committeeKey]/page.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.

Applied to files:

  • frontend/src/components/BreadCrumbsWrapper.tsx
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx
📚 Learning: 2025-11-17T16:47:05.578Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:427-427
Timestamp: 2025-11-17T16:47:05.578Z
Learning: In the frontend test files for the OWASP/Nest repository, `expect(true).toBe(true)` no-op assertions may be intentionally added as workarounds when ESLint rule jest/expect-expect doesn't detect expectations inside helper functions or waitFor callbacks. These can be resolved by configuring the ESLint rule's assertFunctionNames option to recognize custom assertion helpers instead of flagging them as redundant.

Applied to files:

  • frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx
🧬 Code graph analysis (13)
frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx (2)
frontend/src/contexts/BreadcrumbContext.tsx (2)
  • BreadcrumbRoot (71-78)
  • registerBreadcrumb (20-28)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • useBreadcrumbs (49-54)
frontend/src/types/breadcrumb.ts (1)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • BreadcrumbItem (6-6)
frontend/src/app/committees/[committeeKey]/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
backend/apps/owasp/api/internal/queries/committee.py (1)
  • committee (14-28)
frontend/src/wrappers/testUtil.tsx (1)
frontend/src/contexts/BreadcrumbContext.tsx (1)
  • BreadcrumbRoot (71-78)
frontend/src/contexts/BreadcrumbContext.tsx (2)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • BreadcrumbItem (6-6)
frontend/src/types/breadcrumb.ts (1)
  • BreadcrumbItem (1-4)
frontend/src/app/members/[memberKey]/layout.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/utils/structuredData.ts (1)
  • generateProfilePageStructuredData (30-76)
frontend/src/components/BreadCrumbs.tsx (2)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • BreadcrumbItem (6-6)
frontend/src/types/breadcrumb.ts (1)
  • BreadcrumbItem (1-4)
frontend/src/components/BreadCrumbsWrapper.tsx (2)
frontend/src/hooks/useBreadcrumbs.ts (1)
  • useBreadcrumbs (49-54)
frontend/src/types/link.ts (1)
  • Link (1-7)
frontend/src/hooks/useBreadcrumbs.ts (3)
frontend/src/types/breadcrumb.ts (1)
  • BreadcrumbItem (1-4)
frontend/src/utils/breadcrumb.ts (1)
  • formatBreadcrumbTitle (3-9)
frontend/src/contexts/BreadcrumbContext.tsx (1)
  • useBreadcrumb (39-55)
frontend/__tests__/unit/utils/breadcrumb.test.ts (1)
frontend/src/utils/breadcrumb.ts (1)
  • formatBreadcrumbTitle (3-9)
frontend/src/app/layout.tsx (2)
frontend/src/contexts/BreadcrumbContext.tsx (1)
  • BreadcrumbRoot (71-78)
frontend/src/components/BreadCrumbsWrapper.tsx (1)
  • BreadCrumbsWrapper (10-58)
frontend/src/app/organizations/[organizationKey]/layout.tsx (3)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/organizationQueries.generated.ts (1)
  • GetOrganizationMetadataDocument (20-20)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/components/RepositoryCard.tsx (1)
backend/apps/github/api/internal/queries/repository.py (1)
  • repository (14-35)
🪛 GitHub Check: SonarCloud Code Analysis
frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx

[warning] 72-72: Do not call Array#push() multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09-t0qdgqZFlSEh&open=AZrZo09-t0qdgqZFlSEh&pullRequest=2573


[failure] 89-89: Refactor this code to not nest functions more than 4 levels deep.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09-t0qdgqZFlSEi&open=AZrZo09-t0qdgqZFlSEi&pullRequest=2573

frontend/src/contexts/BreadcrumbContext.tsx

[warning] 62-62: Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09Yt0qdgqZFlSEe&open=AZrZo09Yt0qdgqZFlSEe&pullRequest=2573


[warning] 71-71: Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09Yt0qdgqZFlSEf&open=AZrZo09Yt0qdgqZFlSEf&pullRequest=2573

frontend/src/hooks/useBreadcrumbs.ts

[warning] 6-6: Use export…from to re-export BreadcrumbItem.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09Ht0qdgqZFlSEc&open=AZrZo09Ht0qdgqZFlSEc&pullRequest=2573


[warning] 8-8: HIDDEN_SEGMENTS should be a Set, and use HIDDEN_SEGMENTS.has() to check existence or non-existence.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09Ht0qdgqZFlSEd&open=AZrZo09Ht0qdgqZFlSEd&pullRequest=2573

frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx

[warning] 34-40: Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo03ft0qdgqZFlSEb&open=AZrZo03ft0qdgqZFlSEb&pullRequest=2573

frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx

[warning] 18-18: Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrZo09qt0qdgqZFlSEg&open=AZrZo09qt0qdgqZFlSEg&pullRequest=2573

🔇 Additional comments (21)
frontend/src/types/breadcrumb.ts (1)

1-4: LGTM!

The BreadcrumbItem type is well-defined with appropriate use of Readonly for immutability. The structure is clean and suitable for breadcrumb data.

frontend/src/utils/breadcrumb.ts (1)

3-9: LGTM!

The formatBreadcrumbTitle function correctly transforms hyphenated slugs into human-readable titles. The use of upperFirst preserves acronyms (e.g., "OWASP-ZAP" → "OWASP ZAP") which is appropriate for breadcrumb display.

frontend/src/wrappers/testUtil.tsx (1)

8-12: LGTM!

Wrapping the test renderer with BreadcrumbRoot ensures that breadcrumb context is consistently available across all tests, which aligns well with the new breadcrumb system architecture.

frontend/src/app/committees/[committeeKey]/page.tsx (1)

84-94: LGTM!

The PageLayout wrapper correctly integrates breadcrumb functionality while preserving all existing component behavior. Using committee.name as the title appropriately displays the real entity name instead of the URL slug.

frontend/src/app/members/[memberKey]/layout.tsx (1)

59-59: LGTM!

The title fallback chain data?.user?.name || data?.user?.login || '' is appropriate. Note that the empty string fallback is technically unreachable due to the guard clause on line 54, but it serves as a defensive safeguard.

frontend/__tests__/unit/utils/breadcrumb.test.ts (1)

3-37: Test coverage is comprehensive.

The test suite covers all important edge cases including empty input, single/multiple hyphens, numbers, and case preservation. Good work on the thorough testing.

However, per previous feedback from kasya, consider using test data that's either already in cspell or generic fake names. Line 19 uses 'OWASP-ZAP' which might require adding to cspell. The other test values like 'test-org-repo' and 'test-multi-word-slug-example' appear generic enough.

frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx (1)

26-62: LGTM!

The test suite provides good coverage of the core BreadCrumbsWrapper functionality:

  • Conditional rendering based on route
  • Breadcrumb registration and display
  • Title override behavior

The test structure is clean and the assertions are appropriate.

frontend/src/app/organizations/[organizationKey]/layout.tsx (1)

103-108: Reconsider the duplicate query concern — Apollo Client deduplicates in-flight queries by default.

Apollo Client has queryDeduplication enabled by default and will automatically prevent duplicate network requests for identical in-flight queries (same operation and variables). The primary concern should be whether these queries execute simultaneously during server rendering.

If both generateMetadata and the layout component execute during the same server render cycle, Apollo Client's deduplication will likely handle the duplicate. However, if they execute sequentially or at different times, a manual deduplication approach using React's cache() helper is worth considering for clarity and guaranteed deduplication at the server-side request level.

The suggested approaches (React cache(), passing data down) remain valid for explicit control over data fetching, but verify the actual execution order and Apollo Client configuration in your setup before refactoring.

frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx (2)

41-60: Good test coverage for registered title precedence.

The test correctly verifies that registered titles override auto-generated ones, and properly cleans up by calling unregister() in the teardown. This ensures no state leakage between tests.


94-113: Edge cases well covered.

Tests for null pathname fallback and hyphenated URL formatting are essential for robustness. Good coverage of the formatBreadcrumbTitle integration.

frontend/src/components/BreadCrumbsWrapper.tsx (2)

10-14: Minor redundancy in root path check.

The pathname === '/' check is likely redundant since useBreadcrumbs() returns only [{ title: 'Home', path: '/' }] for root, making items.length <= 1 sufficient. However, keeping both provides explicit intent and negligible overhead.


16-56: Clean breadcrumb rendering implementation.

Good use of HeroUI Breadcrumbs with proper accessibility (aria-label), dark mode support, and the last-item non-clickable pattern using isDisabled combined with a span. The separator styling is consistent.

frontend/src/hooks/useBreadcrumbs.ts (1)

10-47: Well-structured breadcrumb building logic.

The buildBreadcrumbItems function is pure, handles null pathname gracefully, and correctly merges registered items with auto-generated fallbacks. The use of a Map for O(1) lookups is appropriate.

frontend/src/app/layout.tsx (1)

75-84: Clean integration of breadcrumb context and wrapper.

The BreadcrumbRoot correctly wraps the layout content to provide the breadcrumb registry context, and BreadCrumbsWrapper is positioned appropriately after the Header. This structure ensures all child routes can register their breadcrumbs.

frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (2)

46-48: Verify necessity of formatBreadcrumbTitle on repository name.

formatBreadcrumbTitle converts hyphenated slugs to title case (e.g., "test-repo" → "Test Repo"). If data.repository.name already contains the proper display name from the backend (e.g., "Test Repository"), applying this transformation may be unnecessary or even incorrect for names with intentional casing like "OWASP ZAP".

Consider conditionally applying formatting only to the fallback:

-  const repoName = data?.repository?.name
-    ? formatBreadcrumbTitle(data.repository.name)
-    : formatBreadcrumbTitle(repositoryKey)
+  const repoName = data?.repository?.name ?? formatBreadcrumbTitle(repositoryKey)

42-45: Duplicate Apollo Client query execution.

The same GetRepositoryMetadataDocument query executes in both generateMetadata and the layout function. Unlike Next.js's automatic deduplication of fetch() requests, Apollo Client queries do not benefit from this built-in mechanism and will result in two separate network calls during the same server render.

Consider extracting the query into a function wrapped with React.cache() to ensure a single execution per render, or leverage Apollo's normalized cache with an appropriate cache policy.

frontend/src/components/BreadCrumbs.tsx (2)

7-9: Props type correctly marked as readonly.

The BreadCrumbRendererProps type properly uses Readonly<> wrapper and readonly modifier for the items array, ensuring immutability.


30-52: Breadcrumb rendering logic is well-implemented.

The component correctly handles the distinction between navigable items (rendered as Link) and the current page (rendered as span with aria-current="page"). Using item.path as the key is appropriate since paths should be unique within a breadcrumb trail.

frontend/src/contexts/BreadcrumbContext.tsx (3)

11-28: Registry pattern is well-suited for client-side breadcrumb management.

The module-level singleton with Map-based storage and listener notification follows an external store pattern that works well with React's useSyncExternalStore semantics. Using path as the key naturally prevents duplicate breadcrumbs for the same route.


30-37: Sorting by path length works for typical hierarchical routes.

The sorting logic correctly prioritizes the root path and then orders by path length, which aligns with typical URL hierarchies where parent routes have shorter paths. For cases where paths have equal length but different depths (e.g., /a/b vs /x/y), the order would be arbitrary, but this is unlikely to be an issue in practice for breadcrumbs on the same page.


39-55: Subscription pattern in useBreadcrumb is implemented correctly.

The hook properly uses a lazy initializer for useState, adds the listener immediately, syncs on mount, and cleans up on unmount. This follows the recommended pattern for subscribing to external stores in React.

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

🧹 Nitpick comments (1)
frontend/src/hooks/useBreadcrumbs.ts (1)

8-8: Consider making hidden segments configurable.

The HIDDEN_SEGMENTS set is currently hardcoded with 'repositories'. If additional segments need hiding in the future, this requires code changes.

Consider accepting hidden segments as a parameter or loading from a config:

// Option 1: Parameter (if different routes need different rules)
function buildBreadcrumbItems(
  pathname: string | null,
  registeredItems: BreadcrumbItem[],
  hiddenSegments: ReadonlySet<string> = HIDDEN_SEGMENTS
): BreadcrumbItem[] {
  // ... use hiddenSegments instead of HIDDEN_SEGMENTS
}

// Option 2: Centralized config file
// config/breadcrumbs.ts
export const BREADCRUMB_CONFIG = {
  hiddenSegments: ['repositories'] as const,
} as const
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f14e42 and e529474.

📒 Files selected for processing (5)
  • frontend/__tests__/unit/components/BreadCrumbsWrapper.test.tsx (1 hunks)
  • frontend/__tests__/unit/hooks/useBreadcrumbs.test.tsx (1 hunks)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (2 hunks)
  • frontend/src/contexts/BreadcrumbContext.tsx (1 hunks)
  • frontend/src/hooks/useBreadcrumbs.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/tests/unit/hooks/useBreadcrumbs.test.tsx
  • frontend/tests/unit/components/BreadCrumbsWrapper.test.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/hooks/useBreadcrumbs.ts (3)
frontend/src/types/breadcrumb.ts (1)
  • BreadcrumbItem (1-4)
frontend/src/utils/breadcrumb.ts (1)
  • formatBreadcrumbTitle (3-9)
frontend/src/contexts/BreadcrumbContext.tsx (1)
  • useBreadcrumb (39-55)
frontend/src/contexts/BreadcrumbContext.tsx (1)
frontend/src/types/breadcrumb.ts (1)
  • BreadcrumbItem (1-4)
🔇 Additional comments (2)
frontend/src/hooks/useBreadcrumbs.ts (1)

1-54: Implementation looks solid.

The breadcrumb building logic correctly handles pathname parsing, registered item lookup, hidden segment filtering, and fallback formatting. The hook properly integrates with Next.js navigation and the breadcrumb context.

frontend/src/contexts/BreadcrumbContext.tsx (1)

1-79: Well-designed breadcrumb registry system.

The implementation follows solid patterns:

  • Pub/sub with Map/Set for efficient lookups and notifications
  • Proper cleanup functions that capture correct references
  • Lazy state initialization in useBreadcrumb to optimize initial renders
  • Dependency array [item.path, item.title] correctly addresses the inline object re-registration concern from past reviews

The registry correctly handles registration/unregistration lifecycle, sorting prioritizes root, and listeners are notified synchronously on changes.

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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e529474 and 05f171a.

📒 Files selected for processing (4)
  • frontend/src/app/chapters/[chapterKey]/layout.tsx (2 hunks)
  • frontend/src/app/committees/[committeeKey]/layout.tsx (2 hunks)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (3 hunks)
  • frontend/src/app/projects/[projectKey]/layout.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (4)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/repositoryQueries.generated.ts (1)
  • GetRepositoryMetadataDocument (22-22)
frontend/src/utils/breadcrumb.ts (1)
  • formatBreadcrumbTitle (3-9)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/app/projects/[projectKey]/layout.tsx (3)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/projectQueries.generated.ts (1)
  • GetProjectMetadataDocument (37-37)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/app/chapters/[chapterKey]/layout.tsx (3)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/app/projects/[projectKey]/layout.tsx (1)
  • generateMetadata (17-36)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/app/committees/[committeeKey]/layout.tsx (9)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/committeeQueries.generated.ts (1)
  • GetCommitteeMetadataDocument (20-20)
frontend/src/app/chapters/[chapterKey]/layout.tsx (1)
  • generateMetadata (17-34)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (1)
  • generateMetadata (18-38)
frontend/src/app/projects/[projectKey]/layout.tsx (1)
  • generateMetadata (17-36)
frontend/src/app/members/[memberKey]/layout.tsx (1)
  • generateMetadata (13-36)
frontend/src/app/organizations/[organizationKey]/layout.tsx (1)
  • generateMetadata (12-34)
frontend/src/app/snapshots/[id]/layout.tsx (1)
  • generateMetadata (7-27)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
🪛 GitHub Check: SonarCloud Code Analysis
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx

[warning] 3-3: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKW4Hht1b1BiGEsOc&open=AZraKW4Hht1b1BiGEsOc&pullRequest=2573


[warning] 2-2: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKW4Hht1b1BiGEsOb&open=AZraKW4Hht1b1BiGEsOb&pullRequest=2573

frontend/src/app/projects/[projectKey]/layout.tsx

[warning] 3-3: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKW3xht1b1BiGEsOa&open=AZraKW3xht1b1BiGEsOa&pullRequest=2573


[warning] 2-2: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKW3xht1b1BiGEsOZ&open=AZraKW3xht1b1BiGEsOZ&pullRequest=2573

frontend/src/app/chapters/[chapterKey]/layout.tsx

[warning] 3-3: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKWwVht1b1BiGEsOY&open=AZraKWwVht1b1BiGEsOY&pullRequest=2573


[warning] 2-2: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKWwVht1b1BiGEsOX&open=AZraKWwVht1b1BiGEsOX&pullRequest=2573

frontend/src/app/committees/[committeeKey]/layout.tsx

[warning] 2-2: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKW45ht1b1BiGEsOd&open=AZraKW45ht1b1BiGEsOd&pullRequest=2573


[warning] 3-3: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZraKW45ht1b1BiGEsOe&open=AZraKW45ht1b1BiGEsOe&pullRequest=2573

🔇 Additional comments (5)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (2)

10-16: Good use of cache() for request deduplication.

Wrapping the Apollo query in React's cache() ensures generateMetadata and the layout component share a single request per render cycle, addressing the duplicate query concern.


49-60: Inconsistent fallback behavior compared to other layouts.

This layout always renders PageLayout with a fallback title (formatted URL slug), whereas projects, chapters, and committees layouts return bare children when data is missing. Consider aligning the approach for consistency—either all layouts should provide PageLayout with fallback titles, or all should skip it when data is unavailable.

frontend/src/app/projects/[projectKey]/layout.tsx (1)

9-15: LGTM on the cached data fetch pattern.

The cache() wrapper properly deduplicates the GraphQL query between generateMetadata and the layout component. The async layout pattern and conditional PageLayout wrapping are correct.

Also applies to: 38-53

frontend/src/app/chapters/[chapterKey]/layout.tsx (1)

9-15: Implementation looks good.

Correctly uses cache() for query deduplication. The async layout pattern with conditional PageLayout wrapping matches the project layout approach.

Also applies to: 36-51

frontend/src/app/committees/[committeeKey]/layout.tsx (1)

9-15: Implementation is correct and consistent.

The cached data fetching and async layout pattern align well with the other detail layouts (projects, chapters). Query deduplication via cache() ensures efficient data loading.

Also applies to: 36-51

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

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/app/committees/[committeeKey]/layout.tsx (1)

25-32: Return empty object instead of null for metadata.

While null is technically valid, Next.js best practices recommend returning an empty object {} when metadata cannot be generated.

Apply this diff:

   return committee
     ? generateSeoMetadata({
         canonicalPath: `/committees/${committeeKey}`,
         description: committee.summary ?? `${committee.name} details`,
         keywords: ['owasp', 'security', 'committee', committeeKey, committee.name],
         title: committee.name,
       })
-    : null
+    : {}
♻️ Duplicate comments (1)
frontend/src/app/chapters/[chapterKey]/layout.tsx (1)

2-2: LGTM! Duplicate import resolved.

The consolidated import addresses the previous SonarCloud warning and reduces redundancy.

🧹 Nitpick comments (1)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (1)

2-7: Optional: switch to type-only React import for cleaner bundle.

Since React 19 with the modern JSX transform doesn’t require React at runtime, you can avoid a runtime react import by using a type-only import for ReactNode and a named import for cache:

-import React, { cache } from 'react'
+import type { ReactNode } from 'react'
+import { cache } from 'react'-export default async function RepositoryDetailsLayout({
-  children,
+export default async function RepositoryDetailsLayout({
+  children,
   params,
 }: Readonly<{
-  children: React.ReactNode
+  children: ReactNode
   params: Promise<{ repositoryKey: string; organizationKey: string }>
 }>) {

This keeps types intact while trimming an unnecessary runtime dependency.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05f171a and 6e9666b.

📒 Files selected for processing (4)
  • frontend/src/app/chapters/[chapterKey]/layout.tsx (2 hunks)
  • frontend/src/app/committees/[committeeKey]/layout.tsx (2 hunks)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (3 hunks)
  • frontend/src/app/projects/[projectKey]/layout.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/app/projects/[projectKey]/layout.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/app/chapters/[chapterKey]/layout.tsx (3)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/chapterQueries.generated.ts (1)
  • GetChapterMetadataDocument (20-20)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (4)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/repositoryQueries.generated.ts (1)
  • GetRepositoryMetadataDocument (22-22)
frontend/src/utils/breadcrumb.ts (1)
  • formatBreadcrumbTitle (3-9)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
🔇 Additional comments (5)
frontend/src/app/committees/[committeeKey]/layout.tsx (2)

2-2: Duplicate import resolved.

The duplicate React import issue from the previous review has been correctly addressed by consolidating into a single import statement.


49-49: Verify PageLayout accepts title prop.

Ensure that the PageLayout component correctly accepts and handles the title prop, and that this integration properly feeds into the breadcrumb system as intended by the PR objectives.

frontend/src/app/chapters/[chapterKey]/layout.tsx (1)

45-47: Verify the fallback behavior when chapter data is absent.

When !data?.chapter, the layout returns children directly without wrapping in PageLayout. This means breadcrumbs won't be displayed for non-existent chapters. Please confirm this is the intended behavior for 404 or error scenarios.

If breadcrumbs should still appear (e.g., showing a generic "Chapter" label), consider providing a fallback:

  if (!data?.chapter) {
-   return children
+   return <PageLayout title="Chapter">{children}</PageLayout>
  }
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (2)

9-15: Good use of cache to deduplicate repository metadata queries.

Wrapping the Apollo query in getRepositoryMetadata with React’s cache and reusing it in both generateMetadata and the layout cleanly eliminates duplicate network requests per render and centralizes the fetch logic. The argument list (organizationKey, repositoryKey) is a stable cache key, and returning only data keeps call sites simple.

Also applies to: 26-27, 47-47


39-59: Layout integration with PageLayout and breadcrumb title logic looks solid.

Deriving repoName from data.repository.name and falling back to a prettified repositoryKey via formatBreadcrumbTitle, then passing { title: repoName, path: /organizations/${organizationKey}/repositories/${repositoryKey} } into PageLayout, matches the new breadcrumb design (real entity names with sensible slug fallback) and keeps the route path explicit for the breadcrumb provider.

Also applies to: 48-50

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 1, 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 (2)
frontend/src/app/projects/[projectKey]/layout.tsx (1)

41-56: LGTM, but consider extracting the shared layout pattern.

The async layout with conditional PageLayout wrapping works correctly. However, this exact pattern (cached data fetch → conditional PageLayout wrapper) is duplicated across projects, committees, chapters, and repositories layouts. Consider abstracting this into a reusable higher-order component or utility function to reduce duplication and simplify future maintenance.

Example abstraction:

// utils/createEntityLayout.tsx
export function createEntityLayout<T>({
  getMetadata,
  extractName,
}: {
  getMetadata: (key: string) => Promise<T | null>
  extractName: (data: T) => string
}) {
  return async function EntityLayout({ children, params, ... }: LayoutProps) {
    const { key } = await params
    const data = await getMetadata(key)
    
    if (!data) return children
    
    return <PageLayout title={extractName(data)}>{children}</PageLayout>
  }
}
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (1)

52-64: Consider standardizing title formatting and path prop usage.

This layout differs from projects/committees/chapters layouts in two ways:

  1. Title formatting: Uses formatBreadcrumbTitle to convert repository names to Title Case (e.g., "my-repo" → "My Repo"), while other layouts use raw entity names directly.
  2. Explicit path prop: Passes path to PageLayout, while other layouts rely on PageLayout's internal usePathname() fallback.

These inconsistencies may lead to:

  • Different breadcrumb title casing across entity types (formatted repositories vs. raw project/chapter/committee names)
  • Potential confusion about when explicit paths are needed

Recommendation: Establish a consistent pattern:

  • Either apply formatBreadcrumbTitle to all entity layouts (if names can contain dashes/special characters), or remove it from repositories (if GraphQL names are already formatted).
  • Document when explicit path props are necessary (e.g., for nested routes that need non-standard breadcrumb paths) vs. when usePathname() suffices.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e9666b and 0058b28.

📒 Files selected for processing (4)
  • frontend/src/app/chapters/[chapterKey]/layout.tsx (2 hunks)
  • frontend/src/app/committees/[committeeKey]/layout.tsx (2 hunks)
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (3 hunks)
  • frontend/src/app/projects/[projectKey]/layout.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-30T12:52:32.214Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2155
File: frontend/graphql-codegen.ts:52-52
Timestamp: 2025-08-30T12:52:32.214Z
Learning: When using GraphQL Codegen with async configuration that needs to fetch data (like CSRF tokens), export the async function directly instead of using top-level await: `export default async function()` rather than `export default await function()`.

Applied to files:

  • frontend/src/app/chapters/[chapterKey]/layout.tsx
🧬 Code graph analysis (2)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (4)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/repositoryQueries.generated.ts (1)
  • GetRepositoryMetadataDocument (22-22)
frontend/src/utils/breadcrumb.ts (1)
  • formatBreadcrumbTitle (3-9)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
frontend/src/app/chapters/[chapterKey]/layout.tsx (9)
frontend/src/server/apolloClient.ts (1)
  • apolloClient (36-37)
frontend/src/types/__generated__/chapterQueries.generated.ts (1)
  • GetChapterMetadataDocument (20-20)
frontend/src/app/committees/[committeeKey]/layout.tsx (1)
  • generateMetadata (20-37)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (1)
  • generateMetadata (21-41)
frontend/src/app/projects/[projectKey]/layout.tsx (1)
  • generateMetadata (20-39)
frontend/src/app/members/[memberKey]/layout.tsx (1)
  • generateMetadata (13-36)
frontend/src/app/organizations/[organizationKey]/layout.tsx (1)
  • generateMetadata (12-34)
frontend/src/app/snapshots/[id]/layout.tsx (1)
  • generateMetadata (7-27)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (13-18)
🔇 Additional comments (4)
frontend/src/app/projects/[projectKey]/layout.tsx (1)

8-18: LGTM: Cached metadata helper follows React 19/Next.js 15 best practices.

The getProjectMetadata helper correctly uses React's cache to deduplicate requests across generateMetadata and the layout component, and the try-catch ensures graceful degradation when data fetching fails.

frontend/src/app/committees/[committeeKey]/layout.tsx (1)

8-54: LGTM: Implementation matches the established pattern.

The cached helper and conditional layout wrapping are correctly implemented, consistent with the projects layout. The same code duplication opportunity noted in frontend/src/app/projects/[projectKey]/layout.tsx applies here.

frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx (1)

9-19: LGTM: Cached helper follows best practices.

The getRepositoryMetadata implementation correctly uses React's cache with proper error handling, consistent with the pattern established in other entity layouts.

frontend/src/app/chapters/[chapterKey]/layout.tsx (1)

8-54: LGTM: Implementation follows the established pattern.

The cached helper and async layout are correctly implemented, consistent with projects and committees layouts. Note the code duplication opportunity mentioned in frontend/src/app/projects/[projectKey]/layout.tsx and the title formatting inconsistency flagged in frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/layout.tsx.

@Kunal1522 Kunal1522 marked this pull request as ready for review December 1, 2025 14:44
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.

Improve breadcrumbs component

2 participants