Skip to content

Conversation

@kasya
Copy link
Collaborator

@kasya kasya commented Dec 1, 2025

Update to use markdown text for Program and Module summary/description.

Checklist

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Summary by CodeRabbit

  • New Features

    • Added Markdown rendering support for descriptions across multiple components, enabling richer content formatting with fallback text for missing content.
  • Style

    • Implemented comprehensive styling for Markdown content, including light/dark mode support, list formatting, nested link styling, and proper spacing.
  • Tests

    • Updated test selectors and module resolution to reflect new component structure.

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

Walkthrough

Replaces plain-text description rendering with a Markdown component across multiple card components, updates Markdown import paths, adds .md-wrapper CSS rules, and adjusts tests to assert against the Markdown wrapper element.

Changes

Cohort / File(s) Change Summary
Markdown import & tests
frontend/src/components/MarkdownWrapper.tsx, frontend/__tests__/unit/components/MarkdownWrapper.test.tsx
Switched import resolution from 'markdown-it/index.mjs' to 'markdown-it' in component and test mock.
Component Markdown integration
frontend/src/components/ProgramCard.tsx, frontend/src/components/SingleModuleCard.tsx
Replaced plain <p> description rendering with <Markdown content={...} />, added import for MarkdownWrapper, and added a fallback description when missing.
Details page rendering & layout
frontend/src/components/CardDetailsPage.tsx
Summary now rendered via Markdown component; replaced conditional secondaryCardStyles with a Map-based lookup and a default fallback.
Markdown styling
frontend/src/app/globals.css
Added .md-wrapper styles (light/dark color rules, link color inheritance, ul/ol margins and list-style settings, li spacing), duplicated across default and utility sections.
Test assertions
frontend/__tests__/unit/components/ProgramCard.test.tsx
Updated test to find description text then select the nearest .md-wrapper ancestor and assert it has line-clamp-8.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas to inspect closely:
    • Map-based secondaryCardStyles lookup in CardDetailsPage.tsx for completeness and fallback correctness.
    • CSS duplication in globals.css — confirm intent or consolidate.
    • Updated test DOM traversal in ProgramCard.test.tsx and the Markdown mock path change to ensure test reliability.

Possibly related PRs

Suggested reviewers

  • arkid15r

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing markdown-it for rendering summaries in the mentorship portal across multiple components.
Description check ✅ Passed The description is directly related to the changeset, explaining the update to use markdown text for Program and Module summary/description fields.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch description-formatting-update

📜 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 772629b and 8701aeb.

📒 Files selected for processing (1)
  • frontend/src/components/SingleModuleCard.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/SingleModuleCard.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CodeQL (javascript-typescript)

Tip

✨ Issue Enrichment is now available for GitHub issues!

CodeRabbit can now help you manage issues more effectively:

  • Duplicate Detection — Identify similar or duplicate issues
  • Related Issues & PRs — Find relevant issues and PR's from your repository
  • Suggested Assignees — Find the best person to work on the issue
  • Implementation Planning — Generate detailed coding plans for engineers and agents
Disable automatic issue enrichment

To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

issue_enrichment:
  auto_enrich:
    enabled: false

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

2-2: Import path update is good; consider hoisting the markdown-it instance and defaulting className.

Using the package entrypoint for markdown-it is appropriate and keeps the component aligned with how tests mock it. You can also avoid re-instantiating the parser on every render and eliminate the "undefined" class when no className is passed by hoisting md and giving className a default:

-export default function Markdown({ content, className }: { content: string; className?: string }) {
-  const md = markdownit({
-    html: true,
-    linkify: true,
-    typographer: true,
-    breaks: true,
-  }).use(taskLists)
+const md = markdownit({
+  html: true,
+  linkify: true,
+  typographer: true,
+  breaks: true,
+}).use(taskLists)
+
+export default function Markdown({
+  content,
+  className = '',
+}: {
+  content: string
+  className?: string
+}) {
   return (
     <div
       dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(md.render(content)) }}
       className={`md-wrapper ${className}`}
     />
   )
 }

This preserves the existing DOMPurify-based sanitization pattern while reducing per-render work. Based on learnings, this keeps the established XSS protection in place.

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

81-86: Map-based type→style lookup is fine; an object literal would be a bit leaner.

The typeStylesMap works, but for this small, static mapping a plain object is simpler and avoids constructing a Map instance each render:

-  const typeStylesMap = new Map([
-    ['program', 'gap-2 md:col-span-7'],
-    ['module', 'gap-2 md:col-span-7'],
-    ['chapter', 'gap-2 md:col-span-3'],
-  ])
-  const secondaryCardStyles = typeStylesMap.get(type) ?? 'gap-2 md:col-span-5'
+  const typeStyles: Record<string, string> = {
+    program: 'gap-2 md:col-span-7',
+    module: 'gap-2 md:col-span-7',
+    chapter: 'gap-2 md:col-span-3',
+  }
+  const secondaryCardStyles = typeStyles[type] ?? 'gap-2 md:col-span-5'

Purely a readability/ergonomics tweak; behavior stays identical.

frontend/src/app/globals.css (1)

272-288: List styling is good; consider deduping the .md-wrapper ol definition.

The new .md-wrapper ul/ol/li rules give Markdown lists sane spacing and bullets. There is now both:

.md-wrapper ol {
  list-style: decimal;
}

and later:

.md-wrapper ol {
  list-style-type: decimal;
}

These are functionally equivalent; you could drop the earlier list-style: decimal; block and keep the newer one for a single source of truth.

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

279-281: Tests correctly assert on the Markdown wrapper around descriptions.

Updating the expectations to locate the closest .md-wrapper and check for line-clamp-8 matches the new Markdown structure and keeps the layout contract tested. If you want to go a bit further, you could mirror this check in the fallback description tests ('No description available.') to ensure all description paths still use the same wrapper.

Also applies to: 298-300

📜 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 28ef47f and 772629b.

📒 Files selected for processing (7)
  • frontend/__tests__/unit/components/MarkdownWrapper.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/ProgramCard.test.tsx (2 hunks)
  • frontend/src/app/globals.css (2 hunks)
  • frontend/src/components/CardDetailsPage.tsx (3 hunks)
  • frontend/src/components/MarkdownWrapper.tsx (1 hunks)
  • frontend/src/components/ProgramCard.tsx (2 hunks)
  • frontend/src/components/SingleModuleCard.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (9)
📚 Learning: 2025-04-04T05:23:43.562Z
Learnt from: M-ayank2005
Repo: OWASP/Nest PR: 1282
File: frontend/src/pages/About.tsx:94-98
Timestamp: 2025-04-04T05:23:43.562Z
Learning: In the OWASP/Nest frontend project, DOMPurify is used to sanitize HTML content before rendering it with dangerouslySetInnerHTML, following security best practices to prevent XSS vulnerabilities.

Applied to files:

  • frontend/src/components/MarkdownWrapper.tsx
📚 Learning: 2025-07-12T17:14:28.536Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/[programKey]/edit/page.tsx:90-128
Timestamp: 2025-07-12T17:14:28.536Z
Learning: Both ProgramForm (programCard.tsx) and ModuleForm (mainmoduleCard.tsx) components already implement HTML validation using the `required` attribute on form fields. The browser's native validation prevents form submission and displays error messages when required fields are empty, eliminating the need for additional JavaScript validation before GraphQL mutations.

Applied to files:

  • frontend/src/components/SingleModuleCard.tsx
  • frontend/src/components/ProgramCard.tsx
📚 Learning: 2025-06-20T16:12:59.256Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/HealthMetrics.tsx:30-30
Timestamp: 2025-06-20T16:12:59.256Z
Learning: In the DetailsCard component (frontend/src/components/CardDetailsPage.tsx), there's a length check before rendering HealthMetrics: `healthMetricsData.length > 0`. This ensures that when HealthMetrics is rendered, the data array has at least one element, making accessing data[0] safe within the HealthMetrics component.

Applied to files:

  • frontend/src/components/CardDetailsPage.tsx
📚 Learning: 2025-06-20T16:12:59.256Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/HealthMetrics.tsx:30-30
Timestamp: 2025-06-20T16:12:59.256Z
Learning: In the DetailsCard component (frontend/src/components/CardDetailsPage.tsx), there's a safety check that ensures HealthMetrics component is only rendered when healthMetricsData exists and has at least one element: `healthMetricsData && healthMetricsData.length > 0`. This makes accessing data[0] safe within the HealthMetrics component.

Applied to files:

  • frontend/src/components/CardDetailsPage.tsx
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.

Applied to files:

  • frontend/src/components/CardDetailsPage.tsx
📚 Learning: 2025-07-13T11:34:31.823Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:14-14
Timestamp: 2025-07-13T11:34:31.823Z
Learning: In the Next.js frontend mentorship application, there are two distinct types for authentication-related data: ExtendedSession for useSession hook (containing accessToken and user.login properties) and UserRolesData for useUserRoles hook (containing currentUserRoles.roles array). The correct access pattern for GitHub username is `(session as ExtendedSession)?.user?.login`.

Applied to files:

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

Applied to files:

  • frontend/src/components/ProgramCard.tsx
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details.

Applied to files:

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

Applied to files:

  • frontend/src/components/ProgramCard.tsx
🧬 Code graph analysis (3)
frontend/src/components/SingleModuleCard.tsx (1)
frontend/src/components/MarkdownWrapper.tsx (1)
  • Markdown (5-19)
frontend/src/components/CardDetailsPage.tsx (2)
frontend/src/components/MarkdownWrapper.tsx (1)
  • Markdown (5-19)
backend/apps/github/models/release.py (1)
  • summary (59-61)
frontend/src/components/ProgramCard.tsx (1)
frontend/src/components/MarkdownWrapper.tsx (1)
  • Markdown (5-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
🔇 Additional comments (4)
frontend/src/components/CardDetailsPage.tsx (1)

25-25: Markdown summary rendering aligns with the new pattern and looks safe.

Wiring the summary through the shared Markdown wrapper keeps formatting consistent with other mentorship views and continues to rely on DOMPurify sanitization from MarkdownWrapper.tsx, so enabling rich text here is a solid move.

Also applies to: 123-124

frontend/src/app/globals.css (1)

134-148: Link color overrides for Markdown inside links are well targeted.

The a .md-wrapper / .dark a .md-wrapper rules solve the “entire card turns link-blue” issue while still letting actual links inside Markdown use the primary link color via .md-wrapper a. This is a good balance for the Program/Module cards.

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

8-8: Program description Markdown integration is consistent and safe.

Using the shared Markdown component for description with a "line-clamp-8" class on the wrapper keeps the existing truncation behavior while enabling rich text. The description fallback ensures Markdown always receives a string, which avoids runtime surprises.

Also applies to: 100-100

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

9-19: markdown-it mock path now matches the production import.

Switching the mock to 'markdown-it' keeps the tests in sync with the component’s import while preserving the existing mock behavior (custom render + use chaining), so coverage should remain representative.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 3, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

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.

2 participants