Skip to content

Add tag display to issue cards on contribute page - #3158

Merged
kasya merged 27 commits into
OWASP:mainfrom
Mr-Rahul-Paul:add_tags_to_issues
Jan 16, 2026
Merged

kasya merged 27 commits into
OWASP:mainfrom
Mr-Rahul-Paul:add_tags_to_issues

Conversation

@Mr-Rahul-Paul

Copy link
Copy Markdown
Collaborator

Fixes #2962

Summary

This PR implements the display of GitHub issue labels #2962 on issue cards within the /contribute page. Tags are fetched from the Algolia index and rendered as badge-like elements, improving issue discoverability for contributors.

Feature:

  • Tags are displayed on each issue card as styled badges
  • Priority-based filtering ensures only relevant tags are shown (configurable)
  • Graceful fallback when no priority tags match

screenshots

pc:
image

mobile:
image

Implementation Details

Frontend: Extended Card component to support priority-based tag rendering with a fallback to raw tags. Includes test coverage for tag filtering, sorting, and display limits.

Backend:

  • backend/apps/github/models/mixins/issue.py: Added idx_tags property method to return tags from the associated project
  • backend/apps/github/index/registry/issue.py: Added idx_tags to the fields tuple for Algolia indexing
  • backend/apps/core/utils/index.py: Added idx_tags to attributesToRetrieve list for the issues index
  • backend/apps/owasp/index/search/issue.py: Added idx_tags to the default attributesToRetrieve list in get_issues function

Discussion Points

Tag Display Implementation

Tags are fully implemented and functional. The current implementation includes:

  • Priority-based filtering logic
  • Sorting capability
  • Configurable tag selection

I have worked on sorting and filtering functionality that can be enabled if maintainers want. The priority tags can be manually selected based on project requirements.

Current placeholder priority tags:

  • good first issue
  • help wanted
  • backend
  • tag-4 (placeholder for testing)

Decision needed: Which tags should be prioritized for display? [TBD!]

Responsiveness

Current behavior shows 2 tags on mobile and 3 (or 4) on larger screens. Please confirm if this meets the design requirements or if adjustments are needed.

Migration Required

For production deployment, the following migration steps will be required:

  1. Algolia Schema Update: Add idx_tags attribute to the local_issues index schema
  2. Reindexing: Run a reindex operation to populate idx_tags for all existing issues
  3. GitHub Label Sync (Future): Currently using project-level tags; real GitHub issue labels can be fetched via REST API if needed

This PR prepares the frontend and backend code but does not execute the migration. Migration can be coordinated with maintainers to avoid index disruption.

I can also work on the reindexing process and GitHub REST API integration for fetching real labels, if required, under guidance from maintainers.

@coderabbitai

coderabbitai Bot commented Jan 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Cards now display issue labels: shows up to five labels, with a “+N more” indicator when additional labels exist.
    • Contribute page surfaces issue labels on cards so label context is visible alongside contributors and actions.
  • Tests

    • Added tests covering label rendering: no labels, few labels, and overflow behavior with the “+N more” indicator.

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

Walkthrough

Card components now accept and render an optional labels?: string[] prop: type updated, Contribute page passes issue labels to Card, Card renders a LabelList (maxVisible=5) when labels exist, and unit tests were extended with a mocked LabelList and label-related cases.

Changes

Cohort / File(s) Summary
Type Definitions
frontend/src/types/card.ts
Added optional labels?: string[] to CardProps.
Component Implementation
frontend/src/components/Card.tsx
Imported LabelList, added labels prop to Card signature; render labels section using <LabelList maxVisible={5} /> when labels.length > 0.
Data Integration
frontend/src/app/contribute/page.tsx
Pass labels={issue.labels} into Card.
Test Suite
frontend/__tests__/unit/components/Card.test.tsx
Added MockLabelListProps and mocked LabelList; extended tests to cover: renders labels, omits labels when none, shows first 5 with “+N more”, and shows all when ≤5.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • arkid15r
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main feature: adding tag display to issue cards on the contribute page.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering implementation details, screenshots, discussion points, and migration requirements.
Linked Issues check ✅ Passed The PR successfully implements the core objectives from issue #2962: displaying tags/labels on issue cards using existing Algolia idx_labels data, updating Card/Issue types, passing labels to Card, adding tests, and providing responsive display.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing tag display on issue cards as specified in issue #2962; no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🧹 Recent nitpick comments
frontend/__tests__/unit/components/Card.test.tsx (1)

52-56: MockLabelListProps is defined but never used; LabelList mock is missing.

The interface MockLabelListProps is defined but there's no corresponding jest.mock('components/LabelList', ...) in the file. Other components like ActionButton, ContributorAvatar, and DisplayIcon are all mocked, but LabelList is not.

The tests at lines 566–616 rely on specific test IDs (label-list, label, label-more) that likely come from the actual LabelList implementation. If LabelList isn't mocked:

  1. Tests become integration tests rather than unit tests for Card
  2. Tests are brittle and may break if LabelList implementation changes
  3. The MockLabelListProps interface serves no purpose

Either remove the unused interface, or add the mock:

🔧 Add LabelList mock to use the interface
+jest.mock('components/LabelList', () => {
+  return function LabelList({ labels, maxVisible = 5, className }: MockLabelListProps) {
+    const visibleLabels = labels.slice(0, maxVisible)
+    const remaining = labels.length - maxVisible
+    return (
+      <div data-testid="label-list" className={className}>
+        {visibleLabels.map((label, index) => (
+          <span key={index} data-testid="label">
+            {label}
+          </span>
+        ))}
+        {remaining > 0 && <span data-testid="label-more">+{remaining} more</span>}
+      </div>
+    )
+  }
+})

📜 Recent 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 5ed04ce and 2ea5724.

📒 Files selected for processing (1)
  • frontend/__tests__/unit/components/Card.test.tsx
🔇 Additional comments (1)
frontend/__tests__/unit/components/Card.test.tsx (1)

566-616: Well-structured test coverage for the labels feature.

The new tests provide good coverage:

  • Positive case with labels rendering
  • Negative case when labels are absent
  • Boundary case at exactly 5 labels
  • Overflow case with 7 labels showing "+2 more"

The assertions correctly use queryByText and queryByTestId for negative checks, and the test naming follows the existing convention.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (3)
backend/apps/github/models/mixins/issue.py (1)

72-75: Suggest refactoring to reduce code duplication.

The new idx_tags property is identical to idx_project_tags (lines 68-70). While this alias may improve clarity for frontend consumers, consider refactoring to avoid duplication:

🔎 Proposed refactor
 @property
 def idx_project_tags(self) -> list[str]:
     """Return project tags for indexing."""
     return self.project.idx_tags if self.project else []

 @property
 def idx_tags(self) -> list[str]:
-    """Return tags for indexing (from project)."""
-    return self.project.idx_tags if self.project else []
+    """Return tags for indexing (alias for idx_project_tags)."""
+    return self.idx_project_tags
frontend/src/components/Card.tsx (2)

142-154: Use tag value as key instead of index and fix formatting.

The current implementation has a few refinements needed:

  1. Index as key: Using index as a key can cause React rendering issues if tags are reordered or filtered. Use the tag value itself as the key.
  2. Inaccurate comment: The comment states "key =tag-1 ,2, 3 ..." but indices start at 0, so it would be "tag-0", "tag-1", "tag-2".
  3. Formatting inconsistency: The className string has irregular spacing and line breaks.
🔎 Proposed fixes
         {/* Tags Section */}
         {displayTags && displayTags.length > 0 && (
-          <div className=" flex flex-wrap gap-2">
+          <div className="flex flex-wrap gap-2">
             {displayTags.slice(0, 3).map((tag, index) => (
               <span
-                key={`tag-${index}`} //key =tag-1 ,2, 3 ... 
-                className={`flex items-center gap-2 px-2 py-1 rounded-md border border-1 transition-all whitespace-nowrap justify-center bg-transparent text-zinc-300 hover:text-white
-               ${index >= 2 ? 'hidden sm:flex' : ''
-                  }`}
+                key={tag}
+                className={`flex items-center gap-2 px-2 py-1 rounded-md border border-1 transition-all whitespace-nowrap justify-center bg-transparent text-zinc-300 hover:text-white ${
+                  index >= 2 ? 'hidden sm:flex' : ''
+                }`}
               >
                 {tag}
               </span>

177-177: Fix spacing in closing tag.

Minor formatting issue: there's an extra space before the closing angle bracket.

-    </div >
+    </div>
📜 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 53e8020 and 8d02c78.

📒 Files selected for processing (9)
  • backend/apps/core/utils/index.py
  • backend/apps/github/index/registry/issue.py
  • backend/apps/github/models/mixins/issue.py
  • backend/apps/owasp/index/search/issue.py
  • frontend/__tests__/unit/components/Card.test.tsx
  • frontend/src/app/contribute/page.tsx
  • frontend/src/components/Card.tsx
  • frontend/src/types/card.ts
  • frontend/src/types/issue.ts
🧰 Additional context used
🧠 Learnings (4)
📚 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/Card.test.tsx
📚 Learning: 2025-12-31T05:17:39.659Z
Learnt from: kart-u
Repo: OWASP/Nest PR: 3101
File: backend/apps/common/extensions.py:92-98
Timestamp: 2025-12-31T05:17:39.659Z
Learning: In this codebase, import OperationType for GraphQL operations from the graphql-core package rather than from strawberry. Use 'from graphql import OperationType'. Strawberry re-exports via graphql-core internally, so relying on strawberry's API may be brittle. Apply this rule to all Python files that deal with GraphQL operation types; ensure imports come from graphql (graphql-core) and not from strawberry packages. This improves compatibility and avoids coupling to strawberry's internals.

Applied to files:

  • backend/apps/github/index/registry/issue.py
  • backend/apps/core/utils/index.py
  • backend/apps/github/models/mixins/issue.py
  • backend/apps/owasp/index/search/issue.py
📚 Learning: 2026-01-01T17:48:23.963Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:41-47
Timestamp: 2026-01-01T17:48:23.963Z
Learning: In Django code, be aware that a QuerySet's boolean evaluation (e.g., if not queryset) runs a database query to determine emptiness. While it is technically valid to use the queryset in a boolean context, use queryset.exists() for existence checks to avoid unnecessary queries and improve performance. Applicable broadly to Python/Django files rather than just this specific path.

Applied to files:

  • backend/apps/github/index/registry/issue.py
  • backend/apps/core/utils/index.py
  • backend/apps/github/models/mixins/issue.py
  • backend/apps/owasp/index/search/issue.py
📚 Learning: 2026-01-01T18:57:05.007Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/video.py:189-215
Timestamp: 2026-01-01T18:57:05.007Z
Learning: In the OWASP backend area, maintain the established pattern: when dealing with sponsors, include all entries from Sponsor.objects.all() (including NOT_SPONSOR) and perform in-memory sorting using the same criteria/pattern used by the GraphQL sponsor query implemented in backend/apps/owasp/api/internal/queries/sponsor.py. Apply this behavior consistently to files in backend/apps/owasp (not just video.py), and ensure code paths that render sponsor lists follow this in-code sorting approach rather than pre-filtering NOT_SPONSOR entries before sorting.

Applied to files:

  • backend/apps/owasp/index/search/issue.py
🧬 Code graph analysis (3)
frontend/src/app/contribute/page.tsx (1)
backend/tests/apps/github/models/issue_test.py (1)
  • issue (26-28)
frontend/src/components/Card.tsx (1)
frontend/src/types/card.ts (1)
  • CardProps (18-36)
backend/apps/github/models/mixins/issue.py (2)
backend/apps/owasp/models/mixins/common.py (1)
  • idx_tags (33-35)
backend/apps/github/models/repository.py (1)
  • project (162-164)
🔇 Additional comments (7)
backend/apps/core/utils/index.py (1)

123-123: LGTM! Clean addition of idx_tags to issues index.

The addition of "idx_tags" to the attributesToRetrieve list is consistent with the existing pattern (chapters index already has this field at line 142) and maintains alphabetical ordering.

backend/apps/owasp/index/search/issue.py (1)

45-45: LGTM! Consistent addition of idx_tags to search defaults.

The addition of "idx_tags" to the default attributesToRetrieve list maintains alphabetical ordering and aligns with the corresponding change in backend/apps/core/utils/index.py.

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

24-24: LGTM! Clean type extension for tags support.

The addition of the optional tags?: string[] property to the Issue type is correct and maintains type safety. The property name aligns with the backend idx_tags field (camelized as per the deep_camelize utility).

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

35-35: LGTM! Consistent type extension for tags support.

The addition of the optional tags?: string[] property to CardProps is correct and aligns with the Issue type extension. Note that DetailsCardProps already has tags?: string[] at line 79, so this change brings consistency across card-related types.

backend/apps/github/index/registry/issue.py (1)

33-33: LGTM! The idx_tags property is properly implemented.

The addition of "idx_tags" to the IssueIndex.fields tuple is correct and maintains alphabetical ordering. The idx_tags property is properly implemented on IssueIndexMixin with the correct type annotation (list[str]) and returns self.project.idx_tags with a sensible fallback to an empty list if no project is associated.

frontend/src/app/contribute/page.tsx (1)

54-54: LGTM!

The tags prop is correctly passed from the issue data to the Card component.

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

491-527: LGTM!

The test coverage for tag functionality is comprehensive and properly validates:

  1. Basic tag rendering
  2. Priority tag filtering behavior
  3. Display limit truncation to 3 tags

All assertions correctly verify the expected behavior.

Comment thread frontend/src/components/Card.tsx Outdated
Comment on lines +29 to +35
const filteredTags = tags?.filter(tag => {
const lowerTag = tag.toLowerCase()
//tag priority to be set by the devs
return lowerTag.includes('good first issue') || lowerTag.includes('help wanted') || lowerTag.includes('tag-4') || lowerTag.includes('backend')
}) || []
// If no filtered tags, use tags prop directly
const displayTags = filteredTags.length > 0 ? filteredTags : (tags || [])

@coderabbitai coderabbitai Bot Jan 3, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Refactor hardcoded priority tags to a configurable constant and use exact matching.

The current implementation has several concerns:

  1. Hardcoded priority list: The priority tags are embedded in the component logic, making them difficult to maintain and configure.
  2. Overly broad matching: Using includes() could match unintended tags (e.g., "good first issue" would match "not a good first issue").
  3. Placeholder values: "tag-4" and "backend" appear to be temporary placeholders based on the PR description.
  4. Redundant fallback: Line 35 has || [] but line 33 already provides the same fallback.
🔎 Proposed refactor

Define a constant at the top of the file:

+// Priority tags configuration - update this list to control which tags are displayed
+const PRIORITY_TAGS = ['good first issue', 'help wanted', 'backend'] as const
+
 const Card = ({

Then use exact matching with the constant:

-  const filteredTags = tags?.filter(tag => {
-    const lowerTag = tag.toLowerCase()
-    //tag priority to be set by the devs
-    return lowerTag.includes('good first issue') || lowerTag.includes('help wanted') || lowerTag.includes('tag-4') || lowerTag.includes('backend')
-  }) || []
-  // If no filtered tags, use tags prop directly
-  const displayTags = filteredTags.length > 0 ? filteredTags : (tags || [])
+  const filteredTags = tags?.filter(tag => 
+    PRIORITY_TAGS.some(priority => tag.toLowerCase() === priority.toLowerCase())
+  ) || []
+  
+  // If no priority tags matched, show all tags
+  const displayTags = filteredTags.length > 0 ? filteredTags : tags

Note: Coordinate with maintainers on the final priority tag list before merging, as mentioned in the PR objectives.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/src/components/Card.tsx around lines 29 to 35, the component uses
hardcoded priority tags and broad includes() matching; extract a configurable
constant (e.g., PRIORITY_TAGS) at the top of the file and replace the inline
literals with that constant, perform exact case-insensitive matching by
normalizing tag to lower-case and checking equality against the set (avoid
includes()), remove the redundant || [] fallback (keep a single fallback when
computing filteredTags) and ensure placeholder tags like "tag-4"/"backend" are
easily editable or removed per maintainer guidance.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Mr-Rahul-Paul This seems like a valid point. I'm not sure if I like the idea of hardcoding label values that we check with. These could be anything set by the project owners.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jan 3, 2026

@kasya kasya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Mr-Rahul-Paul hi! Requested changes.
And please run make check-test locally and address found issues - this is required for all PRs.

Image

Comment thread frontend/src/components/Card.tsx Outdated
Comment on lines +29 to +35
const filteredTags = tags?.filter(tag => {
const lowerTag = tag.toLowerCase()
//tag priority to be set by the devs
return lowerTag.includes('good first issue') || lowerTag.includes('help wanted') || lowerTag.includes('tag-4') || lowerTag.includes('backend')
}) || []
// If no filtered tags, use tags prop directly
const displayTags = filteredTags.length > 0 ? filteredTags : (tags || [])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Mr-Rahul-Paul This seems like a valid point. I'm not sure if I like the idea of hardcoding label values that we check with. These could be anything set by the project owners.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There are also 2 new issues introduced in this PR

Image

Please resolve those before requesting a review in the future

Comment thread frontend/src/components/Card.tsx Resolved
Comment thread frontend/src/components/Card.tsx Resolved
Comment thread frontend/src/components/Card.tsx Resolved
Comment thread frontend/src/types/issue.ts Outdated
title: string
updatedAt?: string | number
url: string
tags?: string[]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That's not the best place to have this property listed. Notice the order of items ⏫

Comment thread frontend/src/types/card.ts Outdated
tooltipLabel?: string
topContributors?: Contributor[]
url: string
tags?: string[]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same here - update the order.

Co-authored-by: Kate Golovanova <kate@kgthreads.com>
Mr-Rahul-Paul and others added 2 commits January 4, 2026 18:18
Co-authored-by: Kate Golovanova <kate@kgthreads.com>
Co-authored-by: Kate Golovanova <kate@kgthreads.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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

29-35: The hardcoded priority tags concern was previously raised.

The maintainer kasya has already acknowledged concerns about hardcoded label values in the previous review thread. This should be addressed per that discussion before merging.

Additionally, the comment on line 31 could be more professional and specific.

Optional: improve comment clarity
-    //tag priority to be set by the devs
+    // Priority tags - configure PRIORITY_TAGS constant to control display
🧹 Nitpick comments (1)
frontend/src/components/Card.tsx (1)

139-153: Clean up minor code quality issues.

Several small improvements would enhance maintainability:

  1. Line 140: The displayTags && check is redundant since displayTags is always an array (guaranteed by the || [] fallback on line 35).
  2. Line 141: Remove the extra leading space in className=" flex".
  3. Line 144: The comment doesn't add meaningful context—React key usage is self-explanatory.
  4. Lines 145-147: The multi-line className is difficult to read and maintain.
🔎 Suggested improvements
-          {displayTags && displayTags.length > 0 && (
-            <div className=" flex flex-wrap gap-2">
+          {displayTags.length > 0 && (
+            <div className="flex flex-wrap gap-2">
               {displayTags.slice(0, 3).map((tag, index) => (
                 <span
-                  key={`tag-${index}`} //key =tag-1 ,2, 3 ... 
-                  className={`flex items-center gap-2 px-2 py-1 rounded-md border border-1 transition-all whitespace-nowrap justify-center bg-transparent text-zinc-300 hover:text-white
-                 ${index >= 2 ? 'hidden sm:flex' : ''
-                    }`}
+                  key={`tag-${index}`}
+                  className={`flex items-center gap-2 px-2 py-1 rounded-md border border-1 transition-all whitespace-nowrap justify-center bg-transparent text-zinc-300 hover:text-white ${
+                    index >= 2 ? 'hidden sm:flex' : ''
+                  }`}
                 >
                   {tag}
                 </span>

Note: These changes may help resolve the SonarCloud issues mentioned by the maintainer.

📜 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 8d02c78 and 9d28d79.

📒 Files selected for processing (1)
  • frontend/src/components/Card.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-28T14:51:14.736Z
Learnt from: adithya-naik
Repo: OWASP/Nest PR: 1894
File: frontend/src/components/TopContributorsList.tsx:74-74
Timestamp: 2025-07-28T14:51:14.736Z
Learning: In the OWASP/Nest project, the maintainer adithya-naik prefers not to create separate components for code that's only used in two specific cases, following the YAGNI principle to avoid over-engineering when the duplication is limited and manageable.

Applied to files:

  • frontend/src/components/Card.tsx
📚 Learning: 2025-08-16T13:23:34.874Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 2021
File: backend/apps/slack/models/google_auth.py:25-36
Timestamp: 2025-08-16T13:23:34.874Z
Learning: In the OWASP Nest project, encryption and decryption for Google OAuth tokens stored in BinaryField are being handled in a separate PR, not in the initial Google Auth setup implementation.

Applied to files:

  • frontend/src/components/Card.tsx
🧬 Code graph analysis (1)
frontend/src/components/Card.tsx (1)
frontend/src/types/card.ts (1)
  • CardProps (18-36)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
frontend/src/components/Card.tsx (1)

29-41: Address the hardcoded priority tags and matching logic.

This filtering logic has been discussed in previous reviews. The concerns remain:

  1. Priority tags are hardcoded and include placeholders ("tag-4", "backend")
  2. Using includes() for matching is overly broad and could match unintended substrings
  3. Redundant fallback operators (|| [] on both lines 39 and 41)
  4. Line 32: Comment should have a space after //

Per the past discussion, this needs coordination with maintainers on the final priority tag list and should use exact case-insensitive matching with a configurable constant.

🧹 Nitpick comments (1)
frontend/src/components/Card.tsx (1)

149-149: Improve comment clarity.

The comment //key =tag-1 ,2, 3 ... is unclear and has formatting issues. Either make it more descriptive or remove it since the code is self-explanatory.

🔎 Suggested fix
-                  key={`tag-${index}`} //key =tag-1 ,2, 3 ...
+                  key={`tag-${index}`}

Or if keeping the comment:

-                  key={`tag-${index}`} //key =tag-1 ,2, 3 ...
+                  key={`tag-${index}`} // Unique key for each tag element
📜 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 9d28d79 and 1ae606a.

📒 Files selected for processing (5)
  • backend/tests/apps/core/utils/match_test.py
  • frontend/__tests__/unit/components/Card.test.tsx
  • frontend/src/components/Card.tsx
  • frontend/src/types/card.ts
  • frontend/src/types/issue.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/types/issue.ts
  • frontend/tests/unit/components/Card.test.tsx
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-28T14:51:14.736Z
Learnt from: adithya-naik
Repo: OWASP/Nest PR: 1894
File: frontend/src/components/TopContributorsList.tsx:74-74
Timestamp: 2025-07-28T14:51:14.736Z
Learning: In the OWASP/Nest project, the maintainer adithya-naik prefers not to create separate components for code that's only used in two specific cases, following the YAGNI principle to avoid over-engineering when the duplication is limited and manageable.

Applied to files:

  • frontend/src/components/Card.tsx
📚 Learning: 2025-08-16T13:23:34.874Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 2021
File: backend/apps/slack/models/google_auth.py:25-36
Timestamp: 2025-08-16T13:23:34.874Z
Learning: In the OWASP Nest project, encryption and decryption for Google OAuth tokens stored in BinaryField are being handled in a separate PR, not in the initial Google Auth setup implementation.

Applied to files:

  • frontend/src/components/Card.tsx
📚 Learning: 2025-12-31T05:17:39.659Z
Learnt from: kart-u
Repo: OWASP/Nest PR: 3101
File: backend/apps/common/extensions.py:92-98
Timestamp: 2025-12-31T05:17:39.659Z
Learning: In this codebase, import OperationType for GraphQL operations from the graphql-core package rather than from strawberry. Use 'from graphql import OperationType'. Strawberry re-exports via graphql-core internally, so relying on strawberry's API may be brittle. Apply this rule to all Python files that deal with GraphQL operation types; ensure imports come from graphql (graphql-core) and not from strawberry packages. This improves compatibility and avoids coupling to strawberry's internals.

Applied to files:

  • backend/tests/apps/core/utils/match_test.py
📚 Learning: 2026-01-01T17:48:23.963Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:41-47
Timestamp: 2026-01-01T17:48:23.963Z
Learning: In Django code, be aware that a QuerySet's boolean evaluation (e.g., if not queryset) runs a database query to determine emptiness. While it is technically valid to use the queryset in a boolean context, use queryset.exists() for existence checks to avoid unnecessary queries and improve performance. Applicable broadly to Python/Django files rather than just this specific path.

Applied to files:

  • backend/tests/apps/core/utils/match_test.py
🧬 Code graph analysis (1)
frontend/src/components/Card.tsx (1)
frontend/src/types/card.ts (1)
  • CardProps (18-36)
🔇 Additional comments (3)
backend/tests/apps/core/utils/match_test.py (1)

21-21: LGTM! Test expectation correctly updated.

The addition of idx_tags to the expected attributesToRetrieve list for the issues index is correct and maintains alphabetical ordering. This aligns with the broader PR changes that add idx_tags to issue indexing and retrieval throughout the backend.

Note: The chapters index (line 48) already includes idx_tags, so this change brings consistency across index types.

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

27-27: Clarify and apply the property ordering convention.

A previous review comment indicates the property order should be updated. Please clarify the project's convention for ordering properties in type definitions (e.g., alphabetical, logical grouping, required-then-optional) and reorder accordingly.

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

27-27: LGTM!

The tags prop is correctly added to the component signature, matching the updated CardProps type.

Comment thread frontend/src/components/Card.tsx Resolved
Comment thread frontend/src/components/Card.tsx Outdated
{/* Tags Section */}
{displayTags && displayTags.length > 0 && (
<div className="flex flex-wrap gap-2">
{displayTags.slice(0, 3).map((tag, index) => (

@coderabbitai coderabbitai Bot Jan 4, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract the hardcoded tag display limit to a named constant.

The magic number 3 should be defined as a named constant at the top of the file for maintainability and to make the responsive behavior (2 on mobile, 3 on desktop) more explicit.

🔎 Proposed refactor
+// Maximum number of tags to display (2 visible on mobile, 3 on desktop)
+const MAX_DISPLAY_TAGS = 3
+
 const Card = ({

Then use the constant:

-            {displayTags.slice(0, 3).map((tag, index) => (
+            {displayTags.slice(0, MAX_DISPLAY_TAGS).map((tag, index) => (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{displayTags.slice(0, 3).map((tag, index) => (
// Maximum number of tags to display (2 visible on mobile, 3 on desktop)
const MAX_DISPLAY_TAGS = 3
const Card = ({
// ... component props ...
// Later in the render section:
{displayTags.slice(0, MAX_DISPLAY_TAGS).map((tag, index) => (
🤖 Prompt for AI Agents
In frontend/src/components/Card.tsx around line 147, the tag display slice uses
a magic number (3); define a named constant (e.g., TAG_DISPLAY_LIMIT_DESKTOP = 3
and/or a responsive TAG_DISPLAY_LIMIT) at the top of the file and replace the
hardcoded 3 with that constant in the slice call; if responsive behavior is
required, add a small helper or derive the constant based on viewport/isMobile
prop and use that value here so the 2-on-mobile / 3-on-desktop intent is
explicit and maintainable.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Mr-Rahul-Paul also these comments by Rabbit seems reasonable.
It's required for you to address all comments before we review. I can see this one (and the one above) shows as outdated, but the code is the same 🤔

Do you think you could address these?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

coderabbitai[bot]
coderabbitai Bot previously requested changes Jan 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
frontend/src/components/Card.tsx (3)

133-133: Magic number should be extracted to a named constant.

As noted in previous reviews, the hardcoded 3 should be extracted to a named constant for maintainability.

Please refer to the previous review suggestion to define a constant like MAX_DISPLAY_TAGS = 3 at the top of the file.


131-144: Add semantic HTML and ARIA attributes for accessibility.

As flagged in previous reviews, the tags section lacks semantic structure and ARIA attributes for screen reader users.

Please refer to the previous review suggestion to wrap tags in a semantic container (e.g., <ul> with role="list" and aria-label="Issue tags").


135-135: Fix: Use index-based key to prevent React warnings with duplicate tags.

Using the tag value as the key will cause React to throw warnings and potentially break rendering if the tags array contains duplicates. Keys should be unique and stable.

🔎 Proposed fix
              {tags.slice(0, 3).map((tag, index) => (
                <span
-                  key={tag}
+                  key={`tag-${index}`}
                  className={`flex items-center justify-center gap-2 rounded-md border border-1 bg-transparent px-2 py-1 whitespace-nowrap text-zinc-300 transition-all hover:text-white ${
🧹 Nitpick comments (1)
frontend/__tests__/unit/components/Card.test.tsx (1)

491-513: Consider adding edge case tests for tag handling.

The current tests cover basic rendering and truncation, but miss important edge cases that would improve coverage:

Suggested additional test cases
it('does not render tags section when tags is undefined', () => {
  const propsWithoutTags = {
    ...baseProps,
    tags: undefined,
  }
  render(<Card {...propsWithoutTags} />)
  // Verify tags section doesn't appear
  expect(screen.queryByText('good first issue')).not.toBeInTheDocument()
})

it('does not render tags section when tags array is empty', () => {
  const propsWithEmptyTags = {
    ...baseProps,
    tags: [],
  }
  render(<Card {...propsWithEmptyTags} />)
  // Verify no tags are rendered
  expect(screen.queryByText('tag1')).not.toBeInTheDocument()
})

it('renders single tag correctly', () => {
  const propsWithOneTag = {
    ...baseProps,
    tags: ['bug'],
  }
  render(<Card {...propsWithOneTag} />)
  expect(screen.getByText('bug')).toBeInTheDocument()
})

Note: Testing the responsive behavior (2 tags on mobile, 3 on desktop) would require additional viewport mocking and is acceptable to defer to integration/E2E tests.

📜 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 1ae606a and a6a2906.

📒 Files selected for processing (2)
  • frontend/__tests__/unit/components/Card.test.tsx
  • frontend/src/components/Card.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-28T14:51:14.736Z
Learnt from: adithya-naik
Repo: OWASP/Nest PR: 1894
File: frontend/src/components/TopContributorsList.tsx:74-74
Timestamp: 2025-07-28T14:51:14.736Z
Learning: In the OWASP/Nest project, the maintainer adithya-naik prefers not to create separate components for code that's only used in two specific cases, following the YAGNI principle to avoid over-engineering when the duplication is limited and manageable.

Applied to files:

  • frontend/src/components/Card.tsx
📚 Learning: 2025-08-16T13:23:34.874Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 2021
File: backend/apps/slack/models/google_auth.py:25-36
Timestamp: 2025-08-16T13:23:34.874Z
Learning: In the OWASP Nest project, encryption and decryption for Google OAuth tokens stored in BinaryField are being handled in a separate PR, not in the initial Google Auth setup implementation.

Applied to files:

  • frontend/src/components/Card.tsx
📚 Learning: 2025-06-21T12:21:32.372Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.

Applied to files:

  • frontend/src/components/Card.tsx
🔇 Additional comments (1)
frontend/src/components/Card.tsx (1)

27-27: LGTM!

The tags prop is correctly added to the component signature and properly typed in CardProps.

@Mr-Rahul-Paul
Mr-Rahul-Paul requested a review from kasya January 4, 2026 21:08

@kasya kasya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi @Mr-Rahul-Paul !

Left requests ⬇️

Comment on lines +72 to +76
@property
def idx_tags(self) -> list[str]:
"""Return tags for indexing (from project)."""
return self.project.idx_tags if self.project else []

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Mr-Rahul-Paul do we really need this? Isn't it identical to idx_project_tags() above?

Comment thread frontend/src/components/Card.tsx Outdated
Comment on lines +130 to +144
{/* Tags Section */}
{tags && tags.length > 0 && (
<div className="flex flex-wrap gap-2">
{tags.slice(0, 3).map((tag, index) => (
<span
key={tag}
className={`flex items-center justify-center gap-2 rounded-md border border-1 bg-transparent px-2 py-1 whitespace-nowrap text-zinc-300 transition-all hover:text-white ${
index >= 2 ? 'hidden sm:flex' : ''
}`}
>
{tag}
</span>
))}
</div>
)}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Mr-Rahul-Paul have you checked if this works? I see no labels at all - not even those coming from a project tags that you added on the backend.

Image

The issue.tags is undefined

body?: string
createdAt: string | number
hint?: string
labels?: string[]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe this is the property you need.
Unless you really wanted to show project tags instead 🤔

@Mr-Rahul-Paul

Mr-Rahul-Paul commented Jan 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Hey @kasya

Yes, the tags will come up as undefined because idx_tags wasn't populated in the Algolia index. I manually added them using a script to demonstrate the idea.


image

In the mock data we have by default:

  • idx_labels is just an empty array , If the actual index has tags in the labels array, we can replace "tags" with "labels"
    • if not , populating idx_tags in Algolia will require - your guidance on the migration/reindexing process and Access/permissions to update the Algolia index
  • idx_project_tags is NOT the same as GitHub issue labels

idx_project_tags are project-level tags (self.project.idx_tags ,eg "impact" , "scrm" ), which are conceptually different from GitHub issue labels ("frontend-tests" , "good first issue")


I made a test.js script that runs and populates all the db objects with hard coded tags , This is mentioned in the Issue

Currently, mock tags ("good first issue" and "help wanted") are added to all issues inside 'local_issues' in Algolia using a test.js script. In the future, real tags can be added using the GitHub RESTful API


⚠️⚠️ Also , Even though labels array is passed from Algolia to the frontend Issue type, the Card component cannot receive or display it because its never passed into card props.
(although DetailsCardProps has labels, it's not used on the contribute page)

@Mr-Rahul-Paul
Mr-Rahul-Paul requested a review from kasya January 8, 2026 11:18
@kasya

kasya commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

Hey @kasya

  • idx_project_tags is NOT the same as GitHub issue labels

idx_project_tags are project-level tags (self.project.idx_tags ,eg "impact" , "scrm" ), which are conceptually different from GitHub issue labels ("frontend-tests" , "good first issue")

I understand that and that was exactly my point.

Where would the idx_tags you suggest to use come from then? Clearly we won't be manually adding them to every issue - they should come from somewhere. I'm just trying to understand how are they different from labels that we have and how you envision us using it in general.

As I mentioned above I did think this would come from the issue labels on GitHub 🤔

For example, here's a screenshot from the issue obj in Algolia for one of the Next issues:
Screenshot 2026-01-08 at 5 27 49 PM

idx_labels are exactly issue labels we have attached.

⚠️⚠️ Also , Even though labels array is passed from Algolia to the frontend Issue type, the Card component cannot receive or display it because its never passed into card props.
(although DetailsCardProps has labels, it's not used on the contribute page)

I don't see any problem with updating the props if needed 🤔 As long as you have data you can use it wherever you want.

@Mr-Rahul-Paul

Mr-Rahul-Paul commented Jan 9, 2026 •

Copy link
Copy Markdown
Collaborator Author

It makes perfect sense now

idx_labels already contains the GitHub issue labels , we don’t need a separate idx_tags parameter for every object.

I’ll update the code to pass labels into the Card props and use those on the cards in contribute page

@Mr-Rahul-Paul

Mr-Rahul-Paul commented Jan 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

@kasya

  • Passed idx_labels to card props
  • Reverted backend changes ( removed idx_tags from attributesToRetrieve and tests as well )
  • Updated frontend tests to use labels
  • All tests passed

For objects with non-empty labels array, labels are now displayed on cards.

image

The Sonar suggestion is unrelated to this issue and breaks tests, so I’m leaving it as-is.

@sonarqubecloud

Copy link
Copy Markdown

@kasya kasya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

hi @Mr-Rahul-Paul !
I updated your code to use LabelList component instead that we already had.

Thank you!

@kasya
kasya added this pull request to the merge queue Jan 16, 2026
Merged via the queue into OWASP:main with commit f27a5a9 Jan 16, 2026
27 checks passed
@Mr-Rahul-Paul

Copy link
Copy Markdown
Collaborator Author

Thank you for the help with the LabelList update and for merging this! Happy to contribute.

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.

Add Tags Display to Issue Cards on Contribute Page

2 participants