Skip to content

About page for OWASP Nest #1197

Merged
arkid15r merged 11 commits intoOWASP:mainfrom
Dishant1804:about_page
Mar 30, 2025
Merged

About page for OWASP Nest #1197
arkid15r merged 11 commits intoOWASP:mainfrom
Dishant1804:about_page

Conversation

@Dishant1804
Copy link
Contributor

Resolves #1158

  • Implement the /about page with structured sections.
  • Update the footer to link to the new About page.
  • Integrate text from the GitHub README About section.
  • Add leader profile links.
  • Dynamically fetch and display top contributors.
  • Add a roadmap section.
  • Display badges at the bottom of the page.
  • Ensure responsiveness and accessibility.
2025-03-28.18-40-01.mp4

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 28, 2025

Summary by CodeRabbit

  • New Features

    • Launched a new About page that showcases detailed project information, including history, leader profiles, top contributors, roadmap, and dynamic statistics.
    • Updated the site’s navigation by redirecting the footer link to direct users seamlessly to the new About page.
  • Style

    • Enhanced the appearance of user cards through customizable styling options.
    • Integrated an external icon font library to enrich the visual elements on the site.

Walkthrough

This pull request introduces a new "About" page for the application, accessible at /about. It includes end-to-end and unit tests to validate the page’s rendering, behavior, and interactions. New mock data and constants for the page content are provided. Additionally, the footer link is updated to point to the internal About page, and the UserCard component is enhanced with a configurable className property, along with corresponding updates to type definitions.

Changes

File(s) Change Summary
frontend/__tests__/e2e/.../About.spec.ts, frontend/__tests__/unit/.../About.test.tsx, frontend/__tests__/unit/.../mockAboutData.ts Added new end-to-end and unit tests along with mock data to validate the About page’s sections, interactions, and data loading.
frontend/src/App.tsx, frontend/src/pages/About.tsx Introduced a new About page component and added a route (/about) to navigate to it.
frontend/src/components/UserCard.tsx, frontend/src/pages/Users.tsx Modified the UserCard component to accept an additional className prop and updated its usage in the Users page for flexible styling.
frontend/src/types/card.ts, frontend/src/types/project.ts Enhanced the UserCardProps interface with an optional className property and added an issues_count property to the ProjectTypeAlgolia interface.
frontend/src/utils/aboutData.ts, frontend/src/utils/constants.ts Created new constants (aboutText and roadmap) for the About page content and updated the footer’s About link to a relative path (/about/).

Assessment against linked issues

Objective Addressed Explanation
Implement /about page with structured sections (including leaders, top contributors, roadmap) and update the footer link (#1158)
Display project badges from README on the About page (#1158) Badge display functionality is not implemented.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

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.

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 (13)
frontend/__tests__/unit/data/mockAboutData.ts (1)

1-24: Well-structured mock data for testing the About page.

The mock data provides a comprehensive representation of project information including metrics, metadata, and contributor data. The use of Array.from to generate multiple contributors is a clean approach for testing.

A small enhancement could be to vary the mock contributor data more realistically:

-    top_contributors: Array.from({ length: 15 }, (_, i) => ({
-      avatar_url: `https://example.com/avatar${i + 1}.jpg`,
-      contributions_count: 30 - i,
-      login: `contributor${i + 1}`,
-      name: `Contributor ${i + 1}`,
-    })),
+    top_contributors: Array.from({ length: 15 }, (_, i) => ({
+      avatar_url: `https://example.com/avatar${i + 1}.jpg`,
+      contributions_count: Math.floor(Math.random() * 100) + 20,
+      login: `contributor${i + 1}`,
+      name: `Contributor ${i + 1}`,
+    })),
frontend/__tests__/unit/pages/About.test.tsx (2)

21-29: Test should verify more specific content.

While the test checks for section headings, it doesn't verify that the actual content from aboutText or project data is rendered correctly.

test('renders project data after loading', async () => {
  render(<About />)
  await waitFor(() => {
    expect(screen.getByText('About')).toBeInTheDocument()
    expect(screen.getByText('Project history')).toBeInTheDocument()
    expect(screen.getByText('Leaders')).toBeInTheDocument()
    expect(screen.getByText('Roadmap')).toBeInTheDocument()
+   // Verify project data is rendered
+   expect(screen.getByText('Test Project')).toBeInTheDocument()
+   // Verify stats are displayed
+   expect(screen.getByText(/1200\+/)).toBeInTheDocument()
  })
})

1-50: Add test for API error handling.

There's no test for how the component behaves when the API call fails with an error.

+ test('handles API error gracefully', async () => {
+   (fetchAlgoliaData as jest.Mock).mockRejectedValue(new Error('API error'))
+   render(<About />)
+   await waitFor(() => {
+     expect(screen.getByText('No data available.')).toBeInTheDocument()
+   })
+ })
frontend/src/utils/aboutData.ts (2)

1-2: Consider storing large text content in a separate markdown file.

The long string with embedded HTML and markdown would be easier to maintain if extracted to a separate .md file and imported.

You could use a webpack loader to import markdown files directly:

-export const aboutText =
-  "OWASP Nest OWASPs **originally created by Arkadii Yakovets** (Ark) to address challenges in navigating OWASP projects. The project was **built from scratch based on Ark's ideas and discussions with Starr Brown** (Starr), ensuring a well-structured system design aligned with OWASP's ecosystem. Ark, an experienced software development professional with over 10 years of expertise in Python, Django, Django REST Framework (DRF), and related backend technologies, led the development of the backend using widely adopted Python **open-source frameworks and libraries**, including DRF, django-filter, OpenAI, Algolia Search, slack-bolt, PyGitHub, pre-commit, pytest, and more. The initial frontend, based on Vue.js, was introduced by **Kateryna Golovanova** (Kate), who later became the project co-leader due to her invaluable frontend and project management skills. The **code is licensed under the MIT License**, encouraging contributions while protecting the authors from legal claims. All OWASP Nest leaders are OWASP members and adhere to the OWASP Code of Conduct.<br></br> Over time, OWASP Nest has expanded to address broader OWASP community needs, such as Google Summer of Code (GSoC) student guidance and contribution opportunities discovery. The platform, along with NestBot, has become a popular entry point for various OWASP aspects, including projects, chapters, users, and aggregated contribution opportunities -- with even more features planned. OWASP Nest's success is also the result of many valuable [contributions](https://github.com/OWASP/Nest/graphs/contributors) from the broader [OWASP Nest community](https://owasp.slack.com/archives/project-nest), whose efforts have helped shape and improve the project in countless ways."
+import aboutTextContent from '../content/about.md';
+export const aboutText = aboutTextContent;

4-23: Create a Leader interface for type safety.

Define an interface for the leader objects to ensure type safety and proper documentation.

+interface Leader {
+  avatar_url: string;
+  name: string;
+  github_profile_url: string;
+  company: string;
+}

-export const leaders = [
+export const leaders: Leader[] = [
  {
    avatar_url: 'https://avatars.githubusercontent.com/u/2201626?v=4',
    name: 'Arkadii Yakovets',
    github_profile_url: 'https://github.com/arkid15r/',
    company: 'OWASP',
  },
  // ...other leaders
]
frontend/__tests__/e2e/pages/About.spec.ts (3)

27-31: Verify leader information more thoroughly.

The test checks for the visibility of buttons with leader names but doesn't verify other leader details like company or avatar images.

test('displays leader information correctly', async ({ page }) => {
  await expect(page.getByRole('button', { name: 'Arkadii Yakovets Arkadii' })).toBeVisible()
  await expect(page.getByRole('button', { name: 'Kateryna Golovanova Kateryna' })).toBeVisible()
  await expect(page.getByRole('button', { name: 'Starr Brown Starr Brown OWASP' })).toBeVisible()
+ // Verify leader avatars are loaded
+ await expect(page.locator('img[alt="Arkadii Yakovets avatar"]')).toBeVisible()
+ await expect(page.locator('img[alt="Kateryna Golovanova avatar"]')).toBeVisible()
+ await expect(page.locator('img[alt="Starr Brown avatar"]')).toBeVisible()
})

38-41: Enhance roadmap items test with specific content verification.

The test could be more specific by checking for the actual text content of roadmap items rather than just counting list items.

test('loads roadmap items correctly', async ({ page }) => {
  await expect(page.getByRole('heading', { name: 'Roadmap' })).toBeVisible()
- expect(await page.locator('li').count()).toBeGreaterThan(0)
+ // Verify specific roadmap items
+ await expect(page.getByText('Extend OWASP NestBot with AI agent/assistant capabilities')).toBeVisible()
+ await expect(page.getByText('Create OWASP Contribution Hub to centralize collaboration opportunities')).toBeVisible()
})

4-59: Add test for empty state handling.

The test suite doesn't verify how the page behaves when no data is available from the API.

+ test('displays "No data available" message when API returns empty hits', async ({ page }) => {
+   await page.route('**/idx/', async (route) => {
+     await route.fulfill({
+       status: 200,
+       contentType: 'application/json',
+       body: JSON.stringify({
+         hits: [],
+         nbPages: 0,
+       }),
+     })
+   })
+   
+   await page.goto('/about')
+   await expect(page.getByText('No data available.')).toBeVisible()
+ })
frontend/src/pages/About.tsx (5)

75-95: Enhance accessibility for leader cards.

The UserCard component could benefit from additional ARIA attributes for better accessibility.

{leaders.map((leader) => (
  <UserCard
    key={leader.github_profile_url}
    avatar={leader.avatar_url}
    company={leader.company}
    name={leader.name}
    button={{
      label: 'View GitHub profile',
      icon: <FontAwesomeIconWrapper icon="fa-solid fa-right-to-bracket" />,
      onclick: () =>
        window.open(leader.github_profile_url, '_blank', 'noopener,noreferrer'),
+     ariaLabel: `View ${leader.name}'s GitHub profile`,
    }}
    email=""
    location=""
    className="h-64 w-40 bg-inherit"
+   aria-label={`Leader card for ${leader.name}`}
  />
))}

97-103: Add a fallback UI for when there are no contributors.

The component doesn't handle the case where top_contributors is an empty array.

-{projectNestData.top_contributors && (
+{projectNestData.top_contributors && projectNestData.top_contributors.length > 0 ? (
  <TopContributors
    contributors={projectNestData.top_contributors}
    maxInitialDisplay={6}
    type="contributor"
  />
+) : (
+  <SecondaryCard title="Top Contributors">
+    <p className="text-center text-gray-500">No contributors data available.</p>
+  </SecondaryCard>
)}

105-114: Add conditional rendering for empty roadmap.

Similar to contributors, there should be a fallback UI if the roadmap array is empty.

<SecondaryCard title="Roadmap">
-  <ul>
-    {roadmap.map((item) => (
-      <li key={item} className="mb-4 flex flex-row items-center gap-2">
-        <div className="h-2 w-2 flex-shrink-0 rounded-full bg-white"></div>
-        {item}
-      </li>
-    ))}
-  </ul>
+  {roadmap.length > 0 ? (
+    <ul>
+      {roadmap.map((item) => (
+        <li key={item} className="mb-4 flex flex-row items-center gap-2">
+          <div className="h-2 w-2 flex-shrink-0 rounded-full bg-white"></div>
+          {item}
+        </li>
+      ))}
+    </ul>
+  ) : (
+    <p className="text-center text-gray-500">No roadmap items available.</p>
+  )}
</SecondaryCard>

116-130: Optimize stat rendering logic.

The current approach maps over an array created inline. Consider extracting this to a constant to improve readability and performance.

+const statItems = [
+  { label: 'Contributors', value: projectNestData.contributors_count },
+  { label: 'Issues', value: projectNestData.issues_count },
+  { label: 'Forks', value: projectNestData.forks_count },
+  { label: 'Stars', value: projectNestData.stars_count },
+];

<div className="grid gap-6 md:grid-cols-4">
-  {[
-    { label: 'Contributors', value: projectNestData.contributors_count },
-    { label: 'Issues', value: projectNestData.issues_count },
-    { label: 'Forks', value: projectNestData.forks_count },
-    { label: 'Stars', value: projectNestData.stars_count },
-  ].map((stat, index) => (
+  {statItems.map((stat, index) => (
    <SecondaryCard key={index} className="text-center">
      <div className="mb-2 text-3xl font-bold text-blue-400">
        <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
      </div>
      <div className="text-gray-600 dark:text-gray-300">{stat.label}</div>
    </SecondaryCard>
  ))}
</div>

124-126: Consider rounding logic for the counter values.

The current implementation always rounds down to the nearest 10, which might be confusing if actual values are close to the next multiple of 10.

Consider using a more intuitive rounding function:

<div className="mb-2 text-3xl font-bold text-blue-400">
-  <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
+  <AnimatedCounter 
+    end={stat.value > 100 ? Math.round(stat.value / 10) * 10 : stat.value} 
+    duration={2} 
+  />+
</div>

This would show the exact value for smaller numbers and round to the nearest 10 for larger numbers.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b549e70 and 804e6ee.

📒 Files selected for processing (12)
  • frontend/__tests__/e2e/pages/About.spec.ts (1 hunks)
  • frontend/__tests__/unit/data/mockAboutData.ts (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/src/App.tsx (2 hunks)
  • frontend/src/components/ToggleContributors.tsx (4 hunks)
  • frontend/src/components/UserCard.tsx (1 hunks)
  • frontend/src/pages/About.tsx (1 hunks)
  • frontend/src/pages/Users.tsx (1 hunks)
  • frontend/src/types/card.ts (1 hunks)
  • frontend/src/types/project.ts (1 hunks)
  • frontend/src/utils/aboutData.ts (1 hunks)
  • frontend/src/utils/constants.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (5)
frontend/src/components/UserCard.tsx (1)
frontend/src/types/card.ts (1)
  • UserCardProps (52-60)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeAlgolia (25-46)
frontend/src/utils/aboutData.ts (3)
  • aboutText (1-2)
  • leaders (4-23)
  • roadmap (25-31)
frontend/__tests__/e2e/pages/About.spec.ts (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-24)
frontend/__tests__/unit/pages/About.test.tsx (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-24)
frontend/src/components/ToggleContributors.tsx (1)
frontend/src/types/contributor.ts (2)
  • TopContributorsTypeGraphql (8-15)
  • TopContributorsTypeAlgolia (1-6)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (26)
frontend/src/types/card.ts (1)

56-56: Good enhancement to the UserCardProps interface

Adding an optional className property provides more flexibility for styling the UserCard component in different contexts, which will be useful for the About page implementation.

frontend/src/types/project.ts (1)

30-30: LGTM: Issues count is a valuable addition

Adding the issues_count property to the ProjectTypeAlgolia interface will allow the About page to display the number of issues associated with the project, providing visitors with valuable information about project activity.

frontend/src/pages/Users.tsx (1)

46-46: Good implementation of the className property

Using the new className property to apply styling to the UserCard component is a great approach. The Tailwind classes provide a comprehensive set of styles that make the card visually appealing with hover effects.

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

27-27: Great update for internal navigation

Changing the About link to point to the new internal /about/ route instead of the external GitHub readme improves the user experience by keeping users within the application and providing them with a dedicated, more accessible About page.

frontend/src/App.tsx (2)

23-23: Clean import added for the About page component.

The import is properly placed with other page imports following the project's import organization pattern.


37-37: New route for About page properly implemented.

The route is correctly defined within the existing Routes component and follows the application's routing pattern. This implementation aligns with the PR objective to create an About page.

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

6-6: Props signature correctly updated to include className.

The component signature has been properly extended to accept the optional className prop defined in the UserCardProps interface.


10-10: Properly implemented className composition.

The implementation correctly uses template literals to combine the base classes with the optional className prop, allowing for flexible styling from parent components without affecting core functionality.

frontend/src/components/ToggleContributors.tsx (4)

7-7: Import properly updated to include Algolia type.

The import has been correctly extended to include the TopContributorsTypeAlgolia type to support the About page integration.


16-16: Props type expanded to support multiple data sources.

The contributors prop type has been properly updated to accept data from both GraphQL and Algolia sources, enhancing the component's flexibility.


47-50: Avatar source fallback pattern implemented.

The image source now correctly handles both camelCase (avatarUrl) and snake_case (avatar_url) property formats to support data from different sources.


59-59: Contributions count accessor properly updated.

The code now correctly handles both contribution count formats (contributionsCount and contributions_count) to display the correct number regardless of data source.

frontend/__tests__/unit/pages/About.test.tsx (4)

1-9: Well-structured test setup with appropriate mocks.

The test correctly imports and mocks the fetchAlgoliaData function, which is essential for isolating the component behavior from external API dependencies.


10-19: Good test lifecycle management.

The beforeEach/afterEach pattern properly sets up the mock data and cleans up after each test, ensuring test isolation.


31-37: Excellent error state testing.

The test properly verifies that the component displays a fallback message when no data is available.


39-49: Good contributor rendering test.

The test effectively verifies that the top contributors are correctly displayed from the mock data.

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

25-31: Well-structured roadmap items.

The roadmap is clear and well-organized as a simple array of string items.

frontend/__tests__/e2e/pages/About.spec.ts (5)

5-18: Good test setup with API mocking.

The test correctly mocks the API response to provide consistent test data, ensuring tests are deterministic and independent of external services.


20-25: Effective verification of main page sections.

The test verifies all required headings are visible, which is a good check for the overall page structure.


33-36: Good contributor verification.

The test correctly verifies that contributor information is displayed when data is loaded.


43-48: Good verification of counter values.

The test effectively checks that animated counters display the correct values from the mock data.


50-59: Excellent user interaction testing.

The test properly verifies that clicking a leader's profile button opens their GitHub profile in a new window, using the correct Playwright patterns for handling multiple pages.

frontend/src/pages/About.tsx (4)

13-16: Good state initialization and typing.

The component correctly initializes state variables with appropriate types and default values.


46-52: Good loading state handling.

The component appropriately displays a loading spinner while data is being fetched.


54-60: Good fallback for missing data.

The component displays a clear message when no project data is available.


97-103:

Details

❓ Verification inconclusive

Verify that contributors prop matches TopContributors component requirements.

Make sure the top_contributors array structure from the API matches what the TopContributors component expects.


🏁 Script executed:

#!/bin/bash
# Check TopContributors component prop type requirements
ast-grep --pattern "export interface TopContributorsProps" -A 10

Length of output: 66


Action Required: Manual Verification of TopContributors Prop Types

The initial automated check did not return any explicit type definitions (e.g. an exported TopContributorsProps interface) for the TopContributors component. As a result, we cannot conclusively verify that the contributors prop passed from projectNestData.top_contributors matches the expected structure.

Please ensure that:

  • The structure of the top_contributors array from the API (for example, required fields like contributor ID, name, avatar URL, etc.) aligns with what the TopContributors component uses.
  • If the TopContributors component uses inline type definitions or type inference instead of an explicit interface, review its implementation (likely in frontend/src/components/TopContributors.tsx) to confirm that the prop expectations are met.

Once these aspects are manually verified or adjusted as necessary, the risk of mismatches can be minimized.

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 (11)
frontend/__tests__/unit/data/mockAboutData.ts (1)

1-24: Good structured mock data for About page testing

The mock data is well-organized with a comprehensive representation of project properties, including contributors, issues, and various metadata. This will be useful for testing the About page component.

Consider adding TypeScript interfaces to this mock data to improve type safety and documentation. This would make the structure more explicit and provide better IDE support:

+interface Contributor {
+  avatar_url: string;
+  contributions_count: number;
+  login: string;
+  name: string;
+}
+
+interface ProjectData {
+  contributors_count: number;
+  issues_count: number;
+  forks_count: number;
+  stars_count: number;
+  key: string;
+  top_contributors: Contributor[];
+  is_active: boolean;
+  languages: string[];
+  level: string;
+  name: string;
+  repositories_count: number;
+  summary: string;
+  topics: string[];
+  type: string;
+  url: string;
+}
+
+export const mockAboutData: { project: ProjectData } = {
frontend/src/utils/aboutData.ts (3)

1-2: Inconsistent formatting in aboutText

The aboutText mixes Markdown formatting (**bold**) with HTML tags (<br></br>), which might cause rendering inconsistencies depending on how it's displayed.

Consider using a consistent approach for formatting - either use React components for all formatting or convert all formatting to JSX-compatible syntax:

-export const aboutText =
-  "OWASP Nest OWASPs **originally created by Arkadii Yakovets** (Ark) to address challenges in navigating OWASP projects. The project was **built from scratch based on Ark's ideas and discussions with Starr Brown** (Starr), ensuring a well-structured system design aligned with OWASP's ecosystem. Ark, an experienced software development professional with over 10 years of expertise in Python, Django, Django REST Framework (DRF), and related backend technologies, led the development of the backend using widely adopted Python **open-source frameworks and libraries**, including DRF, django-filter, OpenAI, Algolia Search, slack-bolt, PyGitHub, pre-commit, pytest, and more. The initial frontend, based on Vue.js, was introduced by **Kateryna Golovanova** (Kate), who later became the project co-leader due to her invaluable frontend and project management skills. The **code is licensed under the MIT License**, encouraging contributions while protecting the authors from legal claims. All OWASP Nest leaders are OWASP members and adhere to the OWASP Code of Conduct.<br></br> Over time, OWASP Nest has expanded to address broader OWASP community needs, such as Google Summer of Code (GSoC) student guidance and contribution opportunities discovery. The platform, along with NestBot, has become a popular entry point for various OWASP aspects, including projects, chapters, users, and aggregated contribution opportunities -- with even more features planned. OWASP Nest's success is also the result of many valuable [contributions](https://github.com/OWASP/Nest/graphs/contributors) from the broader [OWASP Nest community](https://owasp.slack.com/archives/project-nest), whose efforts have helped shape and improve the project in countless ways."
+export const aboutText = {
+  part1: "OWASP Nest OWASPs <strong>originally created by Arkadii Yakovets</strong> (Ark) to address challenges in navigating OWASP projects. The project was <strong>built from scratch based on Ark's ideas and discussions with Starr Brown</strong> (Starr), ensuring a well-structured system design aligned with OWASP's ecosystem. Ark, an experienced software development professional with over 10 years of expertise in Python, Django, Django REST Framework (DRF), and related backend technologies, led the development of the backend using widely adopted Python <strong>open-source frameworks and libraries</strong>, including DRF, django-filter, OpenAI, Algolia Search, slack-bolt, PyGitHub, pre-commit, pytest, and more. The initial frontend, based on Vue.js, was introduced by <strong>Kateryna Golovanova</strong> (Kate), who later became the project co-leader due to her invaluable frontend and project management skills. The <strong>code is licensed under the MIT License</strong>, encouraging contributions while protecting the authors from legal claims. All OWASP Nest leaders are OWASP members and adhere to the OWASP Code of Conduct.",
+  part2: "Over time, OWASP Nest has expanded to address broader OWASP community needs, such as Google Summer of Code (GSoC) student guidance and contribution opportunities discovery. The platform, along with NestBot, has become a popular entry point for various OWASP aspects, including projects, chapters, users, and aggregated contribution opportunities -- with even more features planned. OWASP Nest's success is also the result of many valuable <a href='https://github.com/OWASP/Nest/graphs/contributors'>contributions</a> from the broader <a href='https://owasp.slack.com/archives/project-nest'>OWASP Nest community</a>, whose efforts have helped shape and improve the project in countless ways."
+}

This approach allows for more structured text and consistent formatting.


4-23: Missing TypeScript types for leaders data

The leaders array lacks type definitions, which would improve code readability and maintainability.

Add an interface for the leader objects for better type safety:

+interface Leader {
+  avatar_url: string;
+  name: string;
+  github_profile_url: string;
+  company: string;
+}

-export const leaders = [
+export const leaders: Leader[] = [
  {
    avatar_url: 'https://avatars.githubusercontent.com/u/2201626?v=4',
    name: 'Arkadii Yakovets',
    github_profile_url: 'https://github.com/arkid15r/',
    company: 'OWASP',
  },
  // ...remaining entries
]

15-15: Inconsistency in company naming conventions

There's an inconsistency in company naming: "OWASP" is all uppercase while "skillstruck" is all lowercase.

Consider standardizing the naming convention for company names:

-    company: 'skillstruck',
+    company: 'Skillstruck',

Or explicitly document if this difference is intentional and represents the official company styling.

frontend/__tests__/unit/pages/About.test.tsx (3)

21-29: Consider testing more specific content

This test verifies basic section headers but doesn't validate any specific content from the aboutData.ts file.

Enhance the test to verify some of the actual content from the aboutData file:

test('renders project data after loading', async () => {
  render(<About />)
  await waitFor(() => {
    expect(screen.getByText('About')).toBeInTheDocument()
    expect(screen.getByText('Project history')).toBeInTheDocument()
    expect(screen.getByText('Leaders')).toBeInTheDocument()
    expect(screen.getByText('Roadmap')).toBeInTheDocument()
+    
+    // Verify some specific content from aboutData
+    expect(screen.getByText(/originally created by Arkadii Yakovets/i)).toBeInTheDocument()
+    expect(screen.getByText('Arkadii Yakovets')).toBeInTheDocument()
+    expect(screen.getByText('Extend OWASP NestBot with AI agent/assistant capabilities')).toBeInTheDocument()
  })
})

44-44: Inconsistent variable naming convention

Variable casing is inconsistent - "SecondContributor" uses PascalCase while other variables use camelCase.

-      const SecondContributor = mockAboutData.project.top_contributors[1]
+      const secondContributor = mockAboutData.project.top_contributors[1]
-      expect(screen.getByText(SecondContributor.name)).toBeInTheDocument()
+      expect(screen.getByText(secondContributor.name)).toBeInTheDocument()

39-49: Consider adding a test for loading state

The current tests verify loaded content and empty data scenarios, but there's no test for the loading state.

Add a test to verify the component's behavior during the loading state:

test('shows loading state before data is loaded', async () => {
  // Make the mock not resolve immediately
  (fetchAlgoliaData as jest.Mock).mockImplementation(
    () => new Promise(resolve => setTimeout(() => resolve({ hits: [mockAboutData.project] }), 100))
  )
  
  render(<About />)
  
  // Check for loading indicator
  expect(screen.getByText(/loading/i)).toBeInTheDocument()
  
  // Wait for data to load
  await waitFor(() => {
    expect(screen.getByText('About')).toBeInTheDocument()
  })
})

This ensures the loading state is handled correctly and provides visual feedback to users.

frontend/src/pages/About.tsx (1)

125-125: Consider more precise counter values or document the rounding approach.

The current implementation divides by 10 and multiplies by 10, effectively rounding values to the nearest 10, which might not be obvious to other developers.

- <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
+ {/* Round to nearest 10 for cleaner display */}
+ <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+

Alternatively, for more precision:

- <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
+ <AnimatedCounter end={stat.value} duration={2} />+
frontend/__tests__/e2e/pages/About.spec.ts (3)

33-36: Consider using more robust selectors for contributor tests.

The current test uses text content selectors (getByText) which could be fragile to content changes. Consider using role-based selectors or data-testid attributes for more robust tests.

- await expect(page.getByText('Contributor 1')).toBeVisible()
- await expect(page.getByText('Contributor 2')).toBeVisible()
+ await expect(page.getByRole('button', { name: /Contributor 1/i })).toBeVisible()
+ await expect(page.getByRole('button', { name: /Contributor 2/i })).toBeVisible()

43-48: Make animated counter assertions more resilient to formatting changes.

The current test is sensitive to the exact formatting of the counter values. Consider testing components individually or using more flexible assertions.

- await expect(page.getByText('1.2K+Contributors')).toBeVisible()
- await expect(page.getByText('40+Issues')).toBeVisible()
- await expect(page.getByText('60+Forks')).toBeVisible()
- await expect(page.getByText('890+Stars')).toBeVisible()
+ // Test the counter containers separately from their content
+ const counters = page.locator('.text-blue-400');
+ await expect(counters).toHaveCount(4);
+ 
+ // Test labels separately
+ await expect(page.getByText('Contributors')).toBeVisible();
+ await expect(page.getByText('Issues')).toBeVisible();
+ await expect(page.getByText('Forks')).toBeVisible();
+ await expect(page.getByText('Stars')).toBeVisible();

50-59: Verify the exact GitHub profile URL.

The current test checks only if the URL contains 'github.com', but it would be more precise to verify the exact URL pattern or match it against the expected leader URLs.

  const pagePromise = context.waitForEvent('page')
  await page.getByRole('button', { name: 'View profile' }).first().click()
  const newPage = await pagePromise
  await newPage.waitForLoadState()
- expect(newPage.url()).toContain('github.com')
+ // Verify against a specific pattern or use a regular expression
+ expect(newPage.url()).toMatch(/https:\/\/github\.com\/[^\/]+\//)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b549e70 and 804e6ee.

📒 Files selected for processing (12)
  • frontend/__tests__/e2e/pages/About.spec.ts (1 hunks)
  • frontend/__tests__/unit/data/mockAboutData.ts (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/src/App.tsx (2 hunks)
  • frontend/src/components/ToggleContributors.tsx (4 hunks)
  • frontend/src/components/UserCard.tsx (1 hunks)
  • frontend/src/pages/About.tsx (1 hunks)
  • frontend/src/pages/Users.tsx (1 hunks)
  • frontend/src/types/card.ts (1 hunks)
  • frontend/src/types/project.ts (1 hunks)
  • frontend/src/utils/aboutData.ts (1 hunks)
  • frontend/src/utils/constants.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (5)
frontend/__tests__/unit/pages/About.test.tsx (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-24)
frontend/src/components/UserCard.tsx (1)
frontend/src/types/card.ts (1)
  • UserCardProps (52-60)
frontend/__tests__/e2e/pages/About.spec.ts (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-24)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeAlgolia (25-46)
frontend/src/utils/aboutData.ts (3)
  • aboutText (1-2)
  • leaders (4-23)
  • roadmap (25-31)
frontend/src/components/ToggleContributors.tsx (1)
frontend/src/types/contributor.ts (2)
  • TopContributorsTypeGraphql (8-15)
  • TopContributorsTypeAlgolia (1-6)
🔇 Additional comments (16)
frontend/src/types/project.ts (1)

30-30: LGTM! Added property matches existing schema pattern

The addition of issues_count property to the ProjectTypeAlgolia interface aligns well with the existing data structure. This mirrors the issuesCount property already present in the ProjectTypeGraphql interface (line 52), ensuring consistency across data sources.

frontend/src/types/card.ts (1)

56-56: LGTM! Enhances component flexibility

Adding an optional className property to UserCardProps follows React best practices for component customization. This change enables more flexible styling of user cards through prop passing, which will be useful for the About page implementation.

frontend/src/pages/Users.tsx (1)

46-46: LGTM! Improves visual presentation with responsive design

The added Tailwind CSS classes provide a complete styling solution for the user cards with appropriate dimensions, shadows, transitions, and hover effects. The inclusion of dark mode styles also ensures accessibility across different user preferences.

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

27-27: LGTM! Updates navigation to point to new internal page

Changing the About link from an external GitHub URL to the internal /about/ route improves user experience by keeping users within the application. This change properly connects the footer navigation to the newly implemented About page mentioned in the PR objectives.

frontend/src/App.tsx (2)

23-23: LGTM: About page import properly added

The import for the About component is cleanly added.


37-37: LGTM: About route properly configured

The route for the About page is correctly implemented and properly positioned in the routes list.

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

25-31: LGTM: Clear and concise roadmap items

The roadmap items are well-defined and provide a clear direction for the project's future.

frontend/__tests__/unit/pages/About.test.tsx (3)

1-9: LGTM: Test setup with proper mocking

The imports and mocking setup for the About page tests are correctly implemented.


10-20: LGTM: Well-organized test suite with proper setup and teardown

The test suite is organized with appropriate beforeEach and afterEach hooks to ensure clean tests.


31-37: LGTM: Testing empty data scenario

Good test for handling the case when no project data is available.

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

6-6: Well implemented className prop for enhanced styling flexibility.

The addition of the className prop allows for more customizable styling when using the UserCard component in different contexts, which is essential for the About page implementation.

Also applies to: 10-10

frontend/src/components/ToggleContributors.tsx (3)

7-7: Good type handling to support multiple data sources.

The update to import and support both TopContributorsTypeAlgolia and TopContributorsTypeGraphql types enhances the component's flexibility to work with different data sources.

Also applies to: 16-16


47-50: Well-implemented fallback mechanism for avatar URLs.

The fallback pattern (item?.avatarUrl || item?.avatar_url) ensures the component can display avatars correctly regardless of the property naming convention used in the data source.


59-59: Good fallback for contribution count display.

The implementation handles both naming conventions for contribution counts, making the component work seamlessly with different data structures.

frontend/src/pages/About.tsx (1)

62-133: Well-structured and responsive layout with comprehensive information.

The component is well-organized with clear sections for project history, leaders, contributors, roadmap, and statistics. The responsive design ensures good user experience across devices.

frontend/__tests__/e2e/pages/About.spec.ts (1)

4-59: Great comprehensive test coverage for the About page.

The tests thoroughly cover the main functionality of the About page, including rendering of sections, displaying data, and interaction with external links. The test structure follows good practices with setup in beforeEach and focused test cases.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

The UI looks good, I have an idea of adding contribute section to this page -- but we can take care of that later. Please address these first:

@arkid15r arkid15r requested a review from aramattamara March 29, 2025 23:35
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 (4)
frontend/src/utils/aboutData.ts (1)

1-4: Consider breaking down long text paragraphs for better maintainability

The aboutText paragraphs are quite lengthy. Consider breaking them into smaller, more focused paragraphs to improve readability and make future maintenance easier.

frontend/src/pages/About.tsx (3)

17-17: Consider making leaders list dynamic

The leaders array is currently hardcoded. Consider fetching this from the project data dynamically, as the project leaders might change over time.

-const leaders = ['arkid15r', 'kasya', 'mamicidal']
+// Use project.leaders from the API response if available
+const About = () => {
+  // ...existing state code
+  const [leaders, setLeaders] = useState(['arkid15r', 'kasya', 'mamicidal'])
+  
+  useEffect(() => {
+    if (data && data.project && data.project.leaders) {
+      setLeaders(data.project.leaders)
+    }
+  }, [data])

106-120: Consider more precise rounding in statistics display

The current implementation rounds down to the nearest 10 (Math.floor(stat.value / 10) * 10), which could significantly underrepresent the actual values.

-                <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
+                <AnimatedCounter end={stat.value} duration={2} />+

Or if you really want to round for aesthetic purposes, consider rounding to the nearest value rather than always down:

-                <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
+                <AnimatedCounter end={Math.round(stat.value / 10) * 10} duration={2} />+

139-139: Consider handling null company values more gracefully

Using user.company || 'OWASP' is good for providing a fallback, but consider checking if user exists first to avoid potential errors.

-      company={user.company || 'OWASP'}
+      company={user?.company || 'OWASP'}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 804e6ee and 1ea5e99.

📒 Files selected for processing (8)
  • frontend/__tests__/e2e/pages/About.spec.ts (1 hunks)
  • frontend/__tests__/unit/data/mockAboutData.ts (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/src/App.tsx (2 hunks)
  • frontend/src/pages/About.tsx (1 hunks)
  • frontend/src/types/card.ts (1 hunks)
  • frontend/src/utils/aboutData.ts (1 hunks)
  • frontend/src/utils/constants.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src/utils/constants.ts
  • frontend/src/types/card.ts
  • frontend/src/App.tsx
  • frontend/tests/e2e/pages/About.spec.ts
🧰 Additional context used
🧬 Code Definitions (2)
frontend/__tests__/unit/pages/About.test.tsx (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-44)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeGraphql (48-69)
frontend/src/utils/aboutData.ts (2)
  • aboutText (1-4)
  • roadmap (6-29)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (10)
frontend/__tests__/unit/data/mockAboutData.ts (1)

1-44: Comprehensive mock data structure for testing

The mock data structure is well-organized and provides all necessary data for testing the About page component. It includes project metrics, contributor information, and user details that accurately reflect the data structure expected by the component.

frontend/src/utils/aboutData.ts (2)

6-29: Well-structured roadmap with issue links

The roadmap implementation is clean and each item properly links to its corresponding GitHub issue, which is excellent for user navigation and transparency.


1-29: Consider implementing dynamic data fetching

Based on previous feedback, it appears there's a preference to fetch this data dynamically using GraphQL rather than having it hardcoded.

#!/bin/bash
# Check if there's a GraphQL endpoint that could provide this content
rg -A 5 -B 5 "roadmap|aboutText" --type ts --type tsx --type js
frontend/__tests__/unit/pages/About.test.tsx (3)

50-208: Comprehensive test coverage with proper error handling

The test suite is thorough and covers all key functionality of the About component, including normal rendering, user interactions, and error states. The approach to mocking Apollo's useQuery and handling async operations is well-implemented.


97-118: Well-structured error handling test

This test correctly verifies that the component gracefully handles leader data loading errors, which is crucial for robustness in production environments.


131-155: Comprehensive UI interaction testing

The tests for toggling the contributors list thoroughly verify both expanding and collapsing functionality, ensuring the UI behaves as expected during user interactions.

frontend/src/pages/About.tsx (4)

24-41: Well-implemented data fetching with proper error handling

The GraphQL query implementation with proper error handling using the toaster notification is a good approach. This ensures users are informed when data cannot be retrieved.


62-123: Well-structured page layout with clear section organization

The page layout is well-organized with logical sections that provide a good user experience. The use of SecondaryCard components for each section creates a consistent visual structure.


90-103: Roadmap items with proper left margin

The roadmap items include appropriate left margin with responsive design (pl-4 md:pl-6), addressing the previous review comment about adding margin on the left side.


126-151: Well-implemented LeaderData component with proper error handling

The LeaderData component correctly handles loading and error states for individual leader data, providing a good user experience even when some data fails to load.

@Dishant1804 Dishant1804 requested a review from arkid15r March 30, 2025 02:16
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/pages/About.tsx (3)

17-18: Move leaders array to a constants file.

For better maintainability, consider moving the leaders array to the aboutData.ts file where other about page data is defined. This would centralize all about page configuration data in one place.

// In utils/aboutData.ts
export const aboutText = [...]
export const roadmap = [...]
+ export const leaders = ['arkid15r', 'kasya', 'mamicidal']

// In this file
- const leaders = ['arkid15r', 'kasya', 'mamicidal']
+ import { aboutText, roadmap, leaders } from 'utils/aboutData'

94-101: Add security attributes to external link.

When opening links in a new tab, it's recommended to include rel="noopener noreferrer" to prevent potential security vulnerabilities.

<a
  href={item.issueLink}
  target="_blank"
+ rel="noopener noreferrer"
  className="text-gray-600 hover:underline dark:text-gray-300"
>
  {item.title}
</a>

106-120: Consider extracting statistics rendering to a separate component.

The statistics section could be extracted into a dedicated component to improve readability and maintainability of the main component.

// Proposed component
const StatisticsGrid = ({ project }: { project: ProjectTypeGraphql }) => {
  const stats = [
    { label: 'Contributors', value: project.contributorsCount },
    { label: 'Issues', value: project.issuesCount },
    { label: 'Forks', value: project.forksCount },
    { label: 'Stars', value: project.starsCount },
  ];
  
  return (
    <div className="grid gap-6 md:grid-cols-4">
      {stats.map((stat, index) => (
        <SecondaryCard key={index} className="text-center">
          <div className="mb-2 text-3xl font-bold text-blue-400">
            <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
          </div>
          <div className="text-gray-600 dark:text-gray-300">{stat.label}</div>
        </SecondaryCard>
      ))}
    </div>
  );
};

Then in the main component:

{/* Replace current statistics grid */}
<StatisticsGrid project={project} />
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a89b6b6 and 14ee00e.

📒 Files selected for processing (1)
  • frontend/src/pages/About.tsx (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeGraphql (48-69)
frontend/src/utils/aboutData.ts (2)
  • aboutText (1-4)
  • roadmap (6-29)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (4)
frontend/src/pages/About.tsx (4)

28-41: The error handling implementation looks good.

The useEffect properly updates state based on data and error responses with appropriate error notification. This addresses the previous review comments about improving error handling for data fetching.


92-92: Good job adding left margin as requested.

The implementation now includes pl-4 md:pl-6 classes for left margin on roadmap items, addressing the previous review comment.


24-26: Good job implementing GraphQL queries.

The implementation now uses GraphQL queries instead of hitting the Algolia index directly, addressing the previous comment from the reviewer.


144-144: ⚠️ Potential issue

Fix security attributes in window.open.

The window.open call passes 'noopener,noreferrer' as the third parameter, but these should be comma-separated values in the second parameter. The third parameter is for window features.

- onclick: () => window.open(user.url, '_blank', 'noopener,noreferrer'),
+ onclick: () => window.open(user.url, '_blank', 'noopener noreferrer'),

Likely an incorrect or invalid review comment.

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

♻️ Duplicate comments (2)
frontend/src/pages/About.tsx (2)

19-22: ⚠️ Potential issue

Fix the type definition for project state

The project state is typed as ProjectTypeGraphql but initialized as null, which could cause type errors.

-const [project, setProject] = useState<ProjectTypeGraphql>(null)
+const [project, setProject] = useState<ProjectTypeGraphql | null>(null)

153-177: ⚠️ Potential issue

Add null check before accessing user data

The component doesn't check if data?.user exists before accessing its properties. This could cause runtime errors if the user data is not available.

const user = data?.user

+if (!user) {
+  return <p>No data available for {username}</p>
+}

return (
  <UserCard
    avatar={user.avatarUrl}
    company={user.company || user.location}
    name={user.name || username}
    button={{
      label: 'View Profile',
      icon: <FontAwesomeIconWrapper icon="fa-solid fa-right-to-bracket" />,
      onclick: () => window.open(user.url, '_blank', 'noopener,noreferrer'),
    }}
    email={''}
    location=""
    className="h-64 w-40 bg-inherit"
  />
)
🧹 Nitpick comments (2)
frontend/__tests__/e2e/pages/About.spec.ts (2)

34-36: Leaders section test could be more specific

While the test verifies that the Leaders heading is visible, it would be better to also verify that the actual leader names are displayed.

test('displays leaders data when data is loaded', async ({ page }) => {
  await expect(page.getByRole('heading', { name: 'Leaders' })).toBeVisible()
+  await expect(page.getByText('Arkadii Yakovets')).toBeVisible()
+  await expect(page.getByText('Kate Golovanova')).toBeVisible()
+  await expect(page.getByText('Starr Brown')).toBeVisible()
})

49-52: Roadmap verification could be more specific

While the test verifies that the Roadmap heading is visible and list items exist, it would be better to also verify that specific roadmap items are displayed.

test('loads roadmap items correctly', async ({ page }) => {
  await expect(page.getByRole('heading', { name: 'Roadmap' })).toBeVisible()
  expect(await page.locator('li').count()).toBeGreaterThan(0)
+  await expect(page.getByText('Extend OWASP NestBot with AI agent/assistant capabilities')).toBeVisible()
+  await expect(page.getByText('Create OWASP Contribution Hub to centralize collaboration opportunities')).toBeVisible()
})
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14ee00e and 360377b.

📒 Files selected for processing (5)
  • frontend/__tests__/e2e/pages/About.spec.ts (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/index.html (1 hunks)
  • frontend/src/pages/About.tsx (1 hunks)
  • frontend/src/utils/aboutData.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/index.html
🧰 Additional context used
🧬 Code Definitions (3)
frontend/__tests__/unit/pages/About.test.tsx (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-44)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeGraphql (48-69)
frontend/src/utils/aboutData.ts (3)
  • aboutText (1-4)
  • technologies (31-96)
  • roadmap (6-29)
frontend/__tests__/e2e/pages/About.spec.ts (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-44)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (29)
frontend/src/utils/aboutData.ts (3)

1-4: Great job implementing the about text with markdown support!

The use of Markdown syntax for styling (bold text, links) in the about text allows for rich content formatting. The organization into paragraphs is clean and well-structured.


6-29: Well-structured roadmap with GitHub issue links 👍

Excellent implementation of the roadmap section with clear titles and direct links to corresponding GitHub issues. This satisfies the requirement to have links to GitHub issues from the previous review.


31-96: Consider making the technologies data fetch dynamic

The technologies data structure is well-organized by categories, with each tool having an icon and URL. However, based on a previous comment, consider making this data dynamic by fetching it from your database via GraphQL instead of hardcoding it.

This would allow for easier updates to the technology stack without requiring code changes.

frontend/__tests__/unit/pages/About.test.tsx (12)

7-10: Good use of Apollo Client mocking

The Apollo client mock setup is clean and follows best practices by preserving the actual implementation while overriding only the necessary functionality.


12-46: Well-structured test data mocks

Good job creating comprehensive mock data for about text, roadmap, and technologies. The mock data closely resembles the actual data structure while being simplified enough for testing purposes.


48-56: Effective mocking of external components

The approach to mocking MarkdownWrapper and react-router-dom is excellent - it preserves the essential functionality while simplifying the implementation for testing.


74-92: Thorough test setup with proper cleanup

The test suite is well-structured with appropriate setup in beforeEach and cleanup in afterEach. The conditional mock implementation based on query variables is particularly good for simulating different API responses.


94-106: Good test coverage for project history

The test properly verifies that the markdown content is rendered correctly, covering all aspects of the project history section.


108-119: Comprehensive leader data verification

The test effectively verifies that all three leaders are displayed correctly after data loading.


121-142: Robust error handling test

Good job testing the error handling scenario. This ensures that the application degrades gracefully when one leader's data fails to load while still displaying the others.


144-179: Thorough testing of contributors functionality

The tests for top contributors section are well-structured, covering both the initial display and the show more/show less functionality.


181-211: Detailed technology section testing

The tests for the technologies section are thorough, verifying both the structure (sections and categories) and the content (tools, links, and icons).


213-228: Good roadmap verification

The test properly verifies that all roadmap items are displayed correctly with their corresponding links.


230-239: Comprehensive stats testing

The test effectively verifies that all stats cards are rendered correctly.


241-260: Excellent external link behavior testing

The test for opening external links is well-implemented, using a spy on window.open and verifying the correct URL and window options.

frontend/src/pages/About.tsx (8)

24-41: Good implementation of GraphQL data fetching

The use of GraphQL for data fetching is a good improvement over directly hitting an index, as suggested in a previous review comment. The error handling is also well-implemented with the toaster notification.


43-59: Well-implemented loading and error states

Good job implementing both loading and error states. The use of LoadingSpinner during data fetching and ErrorDisplay when project data is not found provides a good user experience.


61-71: Clean implementation of project history section

The project history section is well-structured, mapping through the aboutText array and rendering each paragraph with the Markdown component.


73-79: Good organization of leaders section

The leaders section is well-organized with appropriate flexbox styling for responsive layout.


81-87: Good conditional rendering of top contributors

The conditional rendering of the TopContributors component only when project.topContributors exists is a good practice.


89-114: Well-structured technologies section

The technologies section is well-organized with appropriate grid layout and spacing. The proper use of semantic HTML elements (ul, li) for the tools list is a good practice.


116-131: Roadmap section with proper list styling

The roadmap section is well-implemented with proper list styling. The left margin on list items has been added as requested in a previous review comment.


133-147: Well-designed stats section with animation

The stats section is well-designed with a responsive grid layout and animated counters. The rounding of values to the nearest 10 is a nice touch.

frontend/__tests__/e2e/pages/About.spec.ts (6)

4-20: Excellent setup for E2E testing

The test setup with route mocking is very well done. It properly intercepts GraphQL requests and returns appropriate mock data based on the request content.


22-27: Good verification of main sections

The test effectively verifies that all main section headings are visible on the page.


29-32: Good contributor data verification

The test properly verifies that contributor information is displayed after data loading.


38-47: Comprehensive technology verification

The test thoroughly verifies that all technology categories and tools are displayed correctly.


54-59: Clear stats verification

The test effectively verifies that all stats are displayed with their expected values.


61-70: Excellent external link verification

The test for opening external links is very well implemented, properly waiting for a new page to open and verifying its URL.

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 (8)
frontend/src/pages/About.tsx (8)

17-17: Consider fetching leaders from the API instead of hardcoding.

Hardcoding the leaders list could lead to maintenance issues if leadership changes. Consider fetching this data from the API if available.

-const leaders = ['arkid15r', 'kasya', 'mamicidal']
+// If leaders are available in the project data
+const getLeaders = (project: ProjectTypeGraphql | null) => {
+  return project?.leaders || ['arkid15r', 'kasya', 'mamicidal'];
+}

Then in the render function:

<SecondaryCard title="Leaders">
  <div className="flex w-full flex-col items-center justify-around overflow-hidden md:flex-row">
-   {leaders.map((username) => (
+   {getLeaders(project).map((username) => (
      <LeaderData key={username} username={username} />
    ))}
  </div>
</SecondaryCard>

24-26: Consider adding fetchPolicy to optimize GraphQL queries.

The current GraphQL query doesn't specify a fetchPolicy, which could lead to unnecessary network requests.

  const { data, error: graphQLRequestError } = useQuery(GET_PROJECT_DATA, {
    variables: { key: projectKey },
+   fetchPolicy: 'cache-first',
  });

91-91: Improve grid layout for better responsiveness.

The current grid layout could be improved for better responsiveness across different screen sizes.

-<div className="grid w-full grid-cols-1 justify-center sm:grid-cols-2 lg:grid-cols-4 lg:pl-8">
+<div className="grid w-full grid-cols-1 gap-6 justify-center sm:grid-cols-2 lg:grid-cols-4 lg:pl-8">

98-98: Add proper accessibility attributes to icons.

Icons should have proper accessibility attributes to improve screen reader support.

-<i className={`${details.icon} text-xl`} style={{ color: '#9ca3af' }}></i>
+<i 
+  className={`${details.icon} text-xl`} 
+  style={{ color: '#9ca3af' }} 
+  aria-hidden="true"
+  role="img"
+  aria-label={`${name} icon`}
+></i>

142-142: Improve accuracy of animated counter.

The current implementation rounds down to the nearest 10, which doesn't accurately represent the actual count.

-<AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
+<AnimatedCounter end={stat.value} duration={2} />+

Or if you want to keep the rounding for aesthetic reasons, consider adding a tooltip with the exact value:

-<div className="mb-2 text-3xl font-bold text-blue-400">
+<div className="mb-2 text-3xl font-bold text-blue-400" title={`Exact count: ${stat.value}`}>
  <AnimatedCounter end={Math.floor(stat.value / 10) * 10} duration={2} />+
</div>

154-156: Add error handling for the LeaderData component.

Similar to the main component, consider adding better error handling and retry functionality for the LeaderData component.

const LeaderData = ({ username }: { username: string }) => {
  const { data, loading, error } = useQuery(GET_USER_DATA, {
    variables: { key: username },
+   fetchPolicy: 'cache-first',
+   onError: (error) => {
+     console.error(`Error fetching data for ${username}:`, error);
+   }
  })

158-159: Improve loading and error state UI for LeaderData.

The current loading and error states are basic text elements that could be improved for better user experience.

-if (loading) return <p>Loading {username}...</p>
-if (error) return <p>Error loading {username}'s data</p>
+if (loading) return (
+  <div className="flex h-64 w-40 flex-col items-center justify-center rounded-lg border border-gray-200 p-4 shadow-sm dark:border-gray-700">
+    <div className="h-8 w-8 animate-spin rounded-full border-b-2 border-t-2 border-blue-500"></div>
+    <p className="mt-2 text-sm text-gray-500">Loading {username}...</p>
+  </div>
+)
+if (error) return (
+  <div className="flex h-64 w-40 flex-col items-center justify-center rounded-lg border border-red-200 p-4 shadow-sm dark:border-red-700">
+    <FontAwesomeIconWrapper icon="fa-solid fa-exclamation-circle" className="text-2xl text-red-500" />
+    <p className="mt-2 text-sm text-red-500">Error loading {username}'s data</p>
+  </div>
+)

177-179: Avoid passing unused props to UserCard.

The component is passing empty strings for email and location properties which seems unnecessary if they're not being used.

    <UserCard
      avatar={user.avatarUrl}
      company={user.company || user.location}
      name={user.name || username}
      button={{
        label: 'View Profile',
        icon: <FontAwesomeIconWrapper icon="fa-solid fa-right-to-bracket" />,
        onclick: () => window.open(user.url, '_blank', 'noopener,noreferrer'),
      }}
-     email={''}
-     location=""
      className="h-64 w-40 bg-inherit"
    />
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 360377b and 9d5d14b.

📒 Files selected for processing (1)
  • frontend/src/pages/About.tsx (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeGraphql (48-69)
frontend/src/utils/aboutData.ts (3)
  • aboutText (1-4)
  • technologies (31-96)
  • roadmap (6-29)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (5)
frontend/src/pages/About.tsx (5)

19-41: Improve error handling in the data fetching logic.

The current implementation shows a toaster notification for GraphQL errors but doesn't provide users with a way to retry or understand what went wrong directly on the page.

  const [project, setProject] = useState<ProjectTypeGraphql | null>(null)
  const [isLoading, setIsLoading] = useState<boolean>(true)
+ const [error, setError] = useState<string | null>(null)
  const projectKey = 'nest'

  const { data, error: graphQLRequestError } = useQuery(GET_PROJECT_DATA, {
    variables: { key: projectKey },
  })

  useEffect(() => {
    if (data) {
      setProject(data?.project)
      setIsLoading(false)
    }
    if (graphQLRequestError) {
      toaster.create({
        description: 'Unable to complete the requested operation.',
        title: 'GraphQL Request Failed',
        type: 'error',
      })
+     setError('Failed to load project data. Please try again.')
      setIsLoading(false)
    }
  }, [data, graphQLRequestError, projectKey])

Then add error state rendering between the loading and project checks:

  if (isLoading) {
    // ...loading spinner code...
  }

+ if (error) {
+   return (
+     <div className="flex min-h-[60vh] items-center justify-center text-gray-500">
+       <p>{error}</p>
+       <button 
+         onClick={() => window.location.reload()} 
+         className="ml-4 rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
+       >
+         Retry
+       </button>
+     </div>
+   )
+ }

  if (!project) {
    // ...error display code...
  }

119-119: Add left margin to list items in Roadmap section.

The left margin on the roadmap list items could be improved for better readability, especially on smaller screens.

-<li key={item.title} className="mb-4 flex flex-row items-center gap-2 pl-4 md:pl-6">
+<li key={item.title} className="mb-4 flex flex-row items-center gap-2 pl-6 md:pl-8">

1-15: LGTM: Import statements are well-organized.

The import statements are properly organized and include all necessary components and utilities for the page.


81-87: LGTM: Good defensive programming with conditional rendering.

The code correctly checks if project.topContributors exists before rendering the section, which is a good defensive programming practice.


43-59: LGTM: Loading and error states are properly handled.

The component appropriately handles loading state with a spinner and shows an error display when project data is not found.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
7.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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 (3)
frontend/src/pages/About.tsx (1)

153-182: Clean implementation of LeaderData component.

The component properly handles loading, error states, and null checks for user data. However, consider changing the profile link behavior.

-        onclick: () => window.open(`/community/users/${username}`, '_blank', 'noopener,noreferrer'),
+        onclick: () => window.location.href = `/community/users/${username}`,

Opening user profiles in the same tab would provide a more seamless navigation experience, as users typically expect internal links to navigate within the same tab unless explicitly indicated otherwise.

frontend/__tests__/e2e/pages/About.spec.ts (2)

61-66: Consider making counter tests more robust.

The current tests check for exact text combinations like "1.2K+Contributors" which might be fragile if formatting changes (e.g., if spaces are added).

-    await expect(page.getByText('1.2K+Contributors')).toBeVisible()
-    await expect(page.getByText('40+Issues')).toBeVisible()
-    await expect(page.getByText('60+Forks')).toBeVisible()
-    await expect(page.getByText('890+Stars')).toBeVisible()
+    // Check counter values and labels separately
+    await expect(page.getByText('1.2K+')).toBeVisible()
+    await expect(page.getByText('Contributors')).toBeVisible()
+    await expect(page.getByText('40+')).toBeVisible()
+    await expect(page.getByText('Issues')).toBeVisible()
+    await expect(page.getByText('60+')).toBeVisible()
+    await expect(page.getByText('Forks')).toBeVisible()
+    await expect(page.getByText('890+')).toBeVisible()
+    await expect(page.getByText('Stars')).toBeVisible()

68-77: Improve user profile navigation test.

The test verifies that clicking a leader button opens a new page with a URL containing '/community/users/', but it doesn't check which specific user's profile is being opened.

  test('opens user profile in new window when leader button is clicked', async ({
    page,
    context,
  }) => {
+   // Select a specific leader to test
+   const leaderName = 'Arkadii Yakovets'
+   const leaderButton = page.getByRole('button', { name: 'View Profile' })
+                            .filter({ has: page.locator(`:text("${leaderName}")`) })
+                            .first()
    const pagePromise = context.waitForEvent('page')
-   await page.getByRole('button', { name: 'View Profile' }).first().click()
+   await leaderButton.click()
    const newPage = await pagePromise
    await newPage.waitForLoadState()
    expect(newPage.url()).toContain('/community/users/')
+   // Check for specific username in URL
+   expect(newPage.url()).toContain('/community/users/arkid15r')
  })
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d5d14b and c7a3297.

📒 Files selected for processing (6)
  • frontend/__tests__/e2e/pages/About.spec.ts (1 hunks)
  • frontend/__tests__/unit/data/mockAboutData.ts (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/src/App.tsx (2 hunks)
  • frontend/src/pages/About.tsx (1 hunks)
  • frontend/src/utils/aboutData.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/tests/unit/data/mockAboutData.ts
  • frontend/src/App.tsx
  • frontend/tests/unit/pages/About.test.tsx
🧰 Additional context used
🧬 Code Definitions (2)
frontend/src/pages/About.tsx (2)
frontend/src/types/project.ts (1)
  • ProjectTypeGraphql (48-69)
frontend/src/utils/aboutData.ts (3)
  • aboutText (1-5)
  • technologies (32-101)
  • roadmap (7-30)
frontend/__tests__/e2e/pages/About.spec.ts (2)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-44)
frontend/src/utils/aboutData.ts (1)
  • technologies (32-101)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
🔇 Additional comments (12)
frontend/src/utils/aboutData.ts (3)

1-5: Consider making leader information dynamic.

The text includes hardcoded information about project leaders and their roles. Based on previous comments in the PR, it would be better to fetch this information dynamically from the database via GraphQL rather than hardcoding it.


7-30: Good implementation of roadmap with issue links.

The roadmap items are well-structured with clear titles and links to their corresponding GitHub issues, which addresses previous feedback.


32-101: Well-organized technology structure.

The technologies are well-categorized with proper section names, tool icons, and relevant URLs. This structure makes it easy to maintain and extend in the future.

frontend/src/pages/About.tsx (6)

17-17: Leaders should be fetched dynamically.

Consider fetching the leader usernames from the database rather than hardcoding them in the component.


19-42: Good error handling implementation.

The component properly handles GraphQL errors and shows appropriate error messages using the toaster component, which addresses previous feedback about error handling.


43-59: Proper loading and error states.

The component correctly displays a loading spinner while data is being fetched and an error display when project data is not found.


81-87: Good use of conditional rendering for contributors.

The TopContributors component is only rendered when the project.topContributors data is available, which prevents potential errors.


116-131: Well-implemented roadmap section with accessible links.

The roadmap items are properly displayed with bullet points and linked to their corresponding GitHub issues, making them accessible and informative.


133-147: Clever use of AnimatedCounter for project statistics.

The statistics cards with animated counters provide an engaging way to display project metrics. The rounding to the nearest 10 ensures smooth animation.

frontend/__tests__/e2e/pages/About.spec.ts (3)

5-20: Well-structured test setup with proper mocking.

The test setup properly mocks GraphQL responses for both user and project data, ensuring consistent test behavior.


22-27: Good basic section visibility tests.

The test correctly verifies that all main section headings are visible on the page.


38-54: Comprehensive technology verification.

The test ensures that all technology names are visible on the page, which is a good verification of the technologies section.

@arkid15r arkid15r enabled auto-merge March 30, 2025 18:40
Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

LGTM 👍

Thank for the solid About page foundation

@arkid15r arkid15r added this pull request to the merge queue Mar 30, 2025
Merged via the queue into OWASP:main with commit 9e95982 Mar 30, 2025
19 of 20 checks passed
shdwcodr pushed a commit to shdwcodr/Nest that referenced this pull request Jun 5, 2025
* about page added

* suggestions implemented

* cspell new word

* Update code

* technologies section added

* code rabbit suggestions

* Update code

---------

Co-authored-by: Arkadii Yakovets <arkadii.yakovets@owasp.org>
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.

Implement OWASP Nest About Page

2 participants