Skip to content

Conversation

@ahmedxgouda
Copy link
Collaborator

@ahmedxgouda ahmedxgouda commented Jun 18, 2025

Resolves #1622

Screencast.from.2025-06-20.19-36-54.mp4

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 18, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a comprehensive health metrics section on project detail pages, displaying trends for issues, pull requests, stars, forks, and days since last commit/release.
    • Added interactive charts and visual indicators for project health, including color-coded scores and trend visualizations.
  • Bug Fixes
    • None.
  • Tests
    • Added unit and end-to-end tests to verify the display and functionality of the health metrics section.
  • Chores
    • Added new dependencies for advanced charting capabilities.
    • Updated custom dictionary for improved spell checking.

Summary by CodeRabbit

  • New Features

    • Added a comprehensive Health Metrics section to the Project Details page, featuring visualizations for issues, pull requests, stars, forks, and activity trends.
    • Introduced interactive charts for health metrics, including trend lines and radial charts for days since last commit and last release.
    • Health Metrics data now includes detailed project health indicators and requirement thresholds.
  • Bug Fixes

    • None.
  • Tests

    • Added unit and end-to-end tests to verify the display and correctness of the Health Metrics section and its visual components.
  • Chores

    • Updated dependencies to include ApexCharts and its React wrapper for chart rendering.
    • Extended dictionaries and type definitions to support new health metrics data.

Walkthrough

This change introduces a comprehensive project health visualization section to the Project page. It adds new backend fields and properties for health requirements, extends the frontend data model, integrates ApexCharts for chart rendering, implements reusable chart components, updates the UI to display health metrics and trends, and includes new unit and end-to-end tests.

Changes

Files / Grouped Files Change Summary
backend/apps/owasp/models/project_health_metrics.py, backend/apps/owasp/graphql/nodes/project_health_metrics.py Add properties and GraphQL fields for last commit/release day requirements in project health metrics.
backend/tests/apps/owasp/graphql/nodes/project_health_metrics_test.py Update tests to cover new GraphQL fields for health requirements.
frontend/package.json, cspell/custom-dict.txt Add ApexCharts and its React wrapper as dependencies; update custom dictionary for "apexcharts".
frontend/src/server/queries/projectQueries.ts Extend GraphQL query to fetch healthMetrics with detailed fields (last 30 days).
frontend/src/types/healthMetrics.ts Add new type definitions for health metrics and chart series.
frontend/src/types/card.ts, frontend/src/types/project.ts Extend type definitions to support health metrics data in project and card props.
frontend/src/components/GradientRadialChart.tsx, frontend/src/components/LineChart.tsx Introduce reusable chart components for radial and line charts using ApexCharts.
frontend/src/components/HealthMetrics.tsx Add HealthMetrics component to aggregate and display all project health charts and metrics.
frontend/src/components/CardDetailsPage.tsx, frontend/src/app/projects/[projectKey]/page.tsx Integrate HealthMetrics into the Project Details UI, passing healthMetrics data as a prop.
frontend/tests/e2e/pages/ProjectDetails.spec.ts, frontend/tests/unit/pages/ProjectDetails.test.tsx Add end-to-end and unit tests to verify health metrics section rendering and content.
frontend/tests/unit/data/mockProjectDetailsData.ts Update mock data to include healthMetrics for testing.

Assessment against linked issues

Objective (Issue #1622) Addressed Explanation
Add project health section with prominent score display
Display Issues Health Trend (open_issues_count, unassigned_issues_count, line chart)
Display Unanswered Issues Trend (open_issues_count, unanswered_issues_count, line chart)
Display Activity Trend (open_pull_requests_count, line chart)
Display Community Size (stars_count, forks_count, line charts)
Display Days Since Last Commit / Last Release (radial progress bar, color thresholds)
Use ApexCharts for rendering, ensure responsive design, reuse chart components
Data represents daily snapshots for the last 30 days

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

Suggested reviewers

  • kasya
  • arkid15r

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7e0aafb and f9b7386.

📒 Files selected for processing (1)
  • frontend/src/components/CardDetailsPage.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/CardDetailsPage.tsx
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

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

♻️ Duplicate comments (1)
frontend/src/types/card.ts (1)

41-42: Synchronise prop name with caller

If you adopt the earlier renaming suggestion, remember to rename the prop here:

-  healthMetricsData?: HealthMetricsProps[]
+  healthMetrics?: HealthMetricsProps[]
🧹 Nitpick comments (13)
frontend/src/app/projects/[projectKey]/page.tsx (2)

91-91: Keep TODOs actionable or create an issue

The inline TODO is easy to forget once the PR is merged. Prefer converting this into a GitHub issue (referencing the line) or tracking it in a ticket so it does not slip through the cracks.


93-99: Prop-name drift between caller and callee

You pass healthMetricsData={project.healthMetrics}, whereas the parent object uses healthMetrics and the type in Project mirrors that. Maintaining two names for the same payload (healthMetrics vs. healthMetricsData) increases cognitive load and can lead to accidental typos.

Consider normalising on a single prop/property name (healthMetrics) throughout:

-      healthMetricsData={project.healthMetrics}
+      healthMetrics={project.healthMetrics}

and update DetailsCardProps accordingly.

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

22-23: Make the collection read-only

Health metrics should be an immutable snapshot for the UI layer. Declare the property as a read-only tuple to prevent accidental in-place mutation by consumer components:

-  healthMetrics?: HealthMetricsProps[]
+  readonly healthMetrics?: readonly HealthMetricsProps[]

Helps TypeScript narrow immutability errors early.

backend/tests/apps/owasp/graphql/nodes/project_test.py (1)

47-51: Assertion could miss List wrapper

field.type.of_type works when type is List[ProjectHealthMetricsNode]; if the schema later changes to a non-list field, this test will silently pass. A stricter assertion:

assert getattr(field.type, "of_type", None) is ProjectHealthMetricsNode
assert getattr(field.type, "_of_type", None) is None  # guards against nested lists

or use Strawberry’s is_list_of_type.

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

17-17: Consider lazy-loading heavy chart bundle

HealthMetricsCharts likely pulls in ApexCharts (~100 kB). Importing it eagerly increases the initial JS payload for every details page, even those that are not projects. A simple React.lazy / dynamic import() keeps non-project pages lighter.

-import HealthMetricsCharts from 'components/HealthMetricsCharts'
+const HealthMetricsCharts = React.lazy(
+  () => import('components/HealthMetricsCharts'),
+)

Remember to wrap the usage in <Suspense> (or your app’s equivalent).


35-36: Prop should be optional in the component signature

healthMetricsData is only relevant for projects. Make it optional (healthMetricsData?: …) in DetailsCardProps to avoid forcing callers (e.g. chapter pages) to pass undefined.

backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py (2)

11-11: Magic number updated – assert the calculation instead

Hard-coding EXPECTED_SCORE = 34.0 means every future tweak to the scoring formula will require manual test edits. Prefer deriving the expected score from fields_weights to keep the test self-maintaining.


76-81: Assertion covers only score field – include side-effects

You assert bulk_save call and the final score. Consider also asserting that mock_metric.updated_at (or similar timestamp) was modified if the command is expected to bump it, ensuring the full behaviour is protected.

backend/apps/owasp/migrations/0041_merge_20250613_0336.py (1)

1-13: Silence Pylint false-positive for “too few public methods”

Merge migrations are intentionally empty, but Pylint still complains.
A terse pragma keeps CI green without affecting Django:

 from django.db import migrations
 
 
 class Migration(migrations.Migration):
+    # pylint: disable=too-few-public-methods
frontend/src/components/HealthMetricsCharts.tsx (2)

14-17: Reverse the dataset to chart chronological order

ProjectNode.health_metrics returns records ordered descending (-nest_created_at).
When you map directly, Day 1 represents the most recent day and the chart runs right-to-left, which is counter-intuitive.

-const openIssuesCountArray = data.map((item) => item.openIssuesCount)
-const labels = data.map((item, index) => `Day ${index + 1}`)
+const chronological = [...data].reverse()               // oldest → newest
+const openIssuesCountArray = chronological.map((i) => i.openIssuesCount)
+const labels = chronological.map((_, idx) => `Day ${idx + 1}`)

Optionally wrap those computations in useMemo to avoid recalculation on each render.


86-99: Radial charts: one series per chart, not N series

ApexCharts’ radialBar expects series: number[], one numeric value per radial bar.
Passing an array of many values causes a multi-series radial (concentric rings) which may not be what you want for “days since last commit / release”.

If the intent is to display only the latest value, do:

-series={data.map((item) => item.lastCommitDays)}
-labels={labels}
+series={[chronological.at(-1)?.lastCommitDays ?? 0]}
+labels={['Today']}

Adjust similarly for lastReleaseDays.

backend/tests/apps/owasp/graphql/nodes/project_health_metrics_test.py (1)

36-44: Dependence on Strawberry internals is brittle

The tests reach into __strawberry_definition__, an internal implementation detail that may change across Strawberry releases.
A safer approach is to validate the schema via Strawberry’s public API or GraphQL introspection:

schema = strawberry.Schema(query=Query)
introspection = schema._schema  # or use graphql-core introspection

This keeps the test future-proof.

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

20-28: Explicitly set the chart type to avoid silent behavioural changes

ApexCharts currently defaults to line, but being explicit guards against future default changes and improves readability.

-      <Chart
+      <Chart
+        type="line"
         options={{
           xaxis: {
             categories: labels,
           },
         }}
         series={series}
         height={450}
       />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e9c5f5f and 9fcac7b.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • backend/apps/owasp/graphql/nodes/project.py (2 hunks)
  • backend/apps/owasp/graphql/nodes/project_health_metrics.py (1 hunks)
  • backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py (1 hunks)
  • backend/apps/owasp/migrations/0038_projecthealthmetrics_has_long_open_issues_and_more.py (1 hunks)
  • backend/apps/owasp/migrations/0041_merge_20250613_0336.py (1 hunks)
  • backend/apps/owasp/migrations/0042_remove_projecthealthmetrics_has_no_recent_commits_and_more.py (1 hunks)
  • backend/apps/owasp/migrations/0043_remove_projecthealthmetrics_has_recent_commits_and_more.py (1 hunks)
  • backend/apps/owasp/migrations/0044_merge_20250615_0346.py (1 hunks)
  • backend/apps/owasp/migrations/0045_remove_projecthealthmetrics_has_long_open_issues_and_more.py (1 hunks)
  • backend/apps/owasp/models/project_health_metrics.py (1 hunks)
  • backend/tests/apps/owasp/graphql/nodes/project_health_metrics_test.py (1 hunks)
  • backend/tests/apps/owasp/graphql/nodes/project_test.py (2 hunks)
  • backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py (3 hunks)
  • cspell/custom-dict.txt (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/app/projects/[projectKey]/page.tsx (1 hunks)
  • frontend/src/components/CardDetailsPage.tsx (3 hunks)
  • frontend/src/components/GeneralCharts.tsx (1 hunks)
  • frontend/src/components/HealthMetricsCharts.tsx (1 hunks)
  • frontend/src/server/queries/projectQueries.ts (1 hunks)
  • frontend/src/types/card.ts (2 hunks)
  • frontend/src/types/healthMetrics.ts (1 hunks)
  • frontend/src/types/project.ts (2 hunks)
🧰 Additional context used
🪛 Pylint (3.3.7)
backend/apps/owasp/migrations/0043_remove_projecthealthmetrics_has_recent_commits_and_more.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0041_merge_20250613_0336.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0042_remove_projecthealthmetrics_has_no_recent_commits_and_more.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0045_remove_projecthealthmetrics_has_long_open_issues_and_more.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0044_merge_20250615_0346.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/tests/apps/owasp/graphql/nodes/project_health_metrics_test.py

[error] 14-14: Class 'ProjectHealthMetricsNode' has no 'strawberry_definition' member

(E1101)


[error] 40-40: Class 'ProjectHealthMetricsNode' has no 'strawberry_definition' member

(E1101)

backend/apps/owasp/migrations/0038_projecthealthmetrics_has_long_open_issues_and_more.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (14)
cspell/custom-dict.txt (1)

34-34: Add apexcharts to custom dictionary
This inclusion ensures the spell checker recognizes the new charting library name without false positives.

frontend/package.json (1)

39-39: Include ApexCharts dependencies
Adding apexcharts and its React wrapper in dependencies correctly equips the frontend for rendering health metric charts.

Also applies to: 58-58

backend/apps/owasp/migrations/0038_projecthealthmetrics_has_long_open_issues_and_more.py (1)

12-31: Skip review on auto-generated migration
This migration file is Django-generated schema change code; no manual edits needed.

backend/apps/owasp/models/project_health_metrics.py (1)

26-26: Skip trivial formatting change
The added blank line after forks_count is a harmless style adjustment.

backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py (1)

63-68: Approve refactored bulk_save call formatting
The multi-line argument format enhances readability without altering behavior.

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

2-3: Import location looks off

HealthMetricsProps lives in types/healthMetrics, but other domain-level types (Issue, Release, …) live in sibling directories. If healthMetrics.ts ended up in a different folder by mistake, move it next to the other types to keep project structure flat and predictable.

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

6-7: Circular dependency risk

Card types now pull HealthMetricsProps, which itself likely references project-level concepts. Watch out for circular type imports (types/healthMetricstypes/projecttypes/card). If you notice slow TS compile or weird “circular structure” warnings, extract shared primitives to a new module (e.g. types/metrics).

backend/apps/owasp/migrations/0045_remove_projecthealthmetrics_has_long_open_issues_and_more.py (1)

11-28: Data loss audit

Dropping four boolean columns permanently deletes historical data. Confirm that:

  1. No downstream analytics or dashboards still rely on them.
  2. A backup/ETL has archived the values if they are useful for future reporting.

If both checks pass, migration looks correct.

backend/apps/owasp/migrations/0042_remove_projecthealthmetrics_has_no_recent_commits_and_more.py (1)

11-21: ```shell
#!/bin/bash

Locate and display the contents of migration 0043 in the owasp app

migration_files=$(fd -e py '0043_.*.py' backend/apps/owasp/migrations)

if [ -z "$migration_files" ]; then
echo "No 0043 migration file found."
exit 1
fi

for file in $migration_files; do
echo "== $file =="
sed -n '1,200p' "$file"
done


</details>
<details>
<summary>backend/apps/owasp/migrations/0043_remove_projecthealthmetrics_has_recent_commits_and_more.py (1)</summary>

`11-21`: ```shell
#!/bin/bash
# List any migration files with “0042” in their name
echo "Migration files containing '0042':"
ls backend/apps/owasp/migrations | grep '0042' || echo "No 0042 files found"

# For each matching file, print its leading content to inspect the field operations
for file in backend/apps/owasp/migrations/*0042*.py; do
  echo
  echo "===== $file ====="
  sed -n '1,200p' "$file"
done
backend/apps/owasp/migrations/0044_merge_20250615_0346.py (1)

6-12: Merge migration is fine but indicates branching pains

The merge itself is harmless, but it’s another hint that the migration chain is oscillating. After consolidating 0042/0043, this merge will likely become unnecessary and can be deleted.

backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py (1)

39-54: Weights diverge: double-check with algorithm

The metric weights for open_issues_count, unanswered_issues_count, and unassigned_issues_count are now higher (7). Confirm that the production scoring code uses the same values; otherwise the test will give false confidence.

backend/apps/owasp/graphql/nodes/project.py (1)

39-44: ```shell
#!/bin/bash
set -e

rg "class BulkSaveModel" -A20 -n backend/apps/owasp/models


</details>
<details>
<summary>frontend/src/server/queries/projectQueries.ts (1)</summary>

`15-25`: **Verify camel-casing conventions between backend & frontend**

The query asks for `healthMetrics`, `forksCount`, etc., while the backend resolver defines `health_metrics` / `forks_count`.  
This only works when Strawberry’s `auto_camel_case` flag is enabled project-wide (it is by default, but can be disabled).

Please double-check that:

1. `settings.STRAWBERRY_SETTINGS["auto_camel_case"]` (or equivalent) is not overridden;  
2. No per-module override disables camel-casing.

If camel-case is turned off, this query will fail at runtime.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@ahmedxgouda ahmedxgouda force-pushed the dashboard/frontend-implementation branch from 9fcac7b to c033d35 Compare June 18, 2025 17:02
@ahmedxgouda ahmedxgouda force-pushed the dashboard/frontend-implementation branch from c033d35 to 9623f53 Compare June 18, 2025 17:55
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c033d35 and 9623f53.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • cspell/custom-dict.txt (1 hunks)
  • frontend/__tests__/unit/data/mockProjectDetailsData.ts (1 hunks)
  • frontend/__tests__/unit/pages/ProjectDetails.test.tsx (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/app/projects/[projectKey]/page.tsx (1 hunks)
  • frontend/src/components/CardDetailsPage.tsx (3 hunks)
  • frontend/src/components/GeneralCharts.tsx (1 hunks)
  • frontend/src/components/HealthMetricsCharts.tsx (1 hunks)
  • frontend/src/server/queries/projectQueries.ts (1 hunks)
  • frontend/src/types/card.ts (2 hunks)
  • frontend/src/types/healthMetrics.ts (1 hunks)
  • frontend/src/types/project.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/tests/unit/data/mockProjectDetailsData.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • cspell/custom-dict.txt
  • frontend/src/types/project.ts
  • frontend/src/types/card.ts
  • frontend/src/app/projects/[projectKey]/page.tsx
  • frontend/package.json
  • frontend/src/components/CardDetailsPage.tsx
  • frontend/src/types/healthMetrics.ts
  • frontend/src/server/queries/projectQueries.ts
  • frontend/src/components/HealthMetricsCharts.tsx
  • frontend/src/components/GeneralCharts.tsx
🧰 Additional context used
🪛 GitHub Actions: Run CI/CD
frontend/__tests__/unit/pages/ProjectDetails.test.tsx

[error] 25-25: CSpell: Unknown word 'apexchart' found during spelling check.

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)

@ahmedxgouda ahmedxgouda force-pushed the dashboard/frontend-implementation branch from a8afbfe to 88768dc Compare June 18, 2025 19:48
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.

Great PoC 👍
We need to play w/ the style a bit and have enough data to visualize.

You can start with addressing any of these:

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

Nice work!!! I know it's still in draft, but I also have a few comments 👍🏼

@ahmedxgouda ahmedxgouda requested a review from kasya June 23, 2025 21:48
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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a2233b4 and 7ecc6eb.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • backend/apps/owasp/graphql/nodes/project.py (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/components/CardDetailsPage.tsx (4 hunks)
  • frontend/src/components/GradientRadialChart.tsx (1 hunks)
  • frontend/src/components/HealthMetrics.tsx (1 hunks)
  • frontend/src/components/LineChart.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/package.json
  • frontend/src/components/HealthMetrics.tsx
  • frontend/src/components/LineChart.tsx
  • frontend/src/components/CardDetailsPage.tsx
🧰 Additional context used
🧠 Learnings (1)
frontend/src/components/GradientRadialChart.tsx (1)
Learnt from: ahmedxgouda
PR: OWASP/Nest#1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.328Z
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.
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
🔇 Additional comments (2)
backend/apps/owasp/graphql/nodes/project.py (1)

45-45: LGTM! Ordering change aligns with chronological chart display.

Changing from descending to ascending order makes sense for health metrics visualization where chronological progression (oldest to newest) is preferred for trend charts.

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

137-147: Excellent implementation of legend and pluralization features.

The component properly addresses the feedback from kasya:

  • ✅ Legend labels "Active" and "Stale" are clearly displayed
  • ✅ Proper pluralization using the existing utility function
  • ✅ Clean positioning with appropriate styling

Comment on lines +89 to +136
<div className="relative h-[200px] w-full">
<Chart
key={theme}
options={{
chart: {
animations: {
enabled: true,
speed: 1000,
},
},
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
dataLabels: {
show: true,
name: {
show: false,
},
value: {
formatter: () => `${days} ${pluralize(days, 'day', 'days')}`,
color: theme === 'dark' ? '#ececec' : '#1E1E2C',
fontSize: '20px',
show: true,
offsetY: 0,
},
},
track: {
background: theme === 'dark' ? '#1E1E2C' : '#ececec',
margin: 0,
},
},
},
fill: {
type: 'gradient',
gradient: {
shade: theme,
type: 'horizontal',
shadeIntensity: 0.5,
stops: stops,
colorStops: colorStops,
},
},
}}
series={[requirement ? normalizedDays : 0]}
height={300}
type="radialBar"
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix height inconsistency and add accessibility wrapper.

Two issues to address:

  1. Height mismatch: Container div has h-[200px] but Chart height is set to 300px, which may cause overflow.

  2. Missing accessibility: Based on retrieved learnings, Chart component needs a wrapper div with ARIA attributes.

Apply this fix:

-      <div className="relative h-[200px] w-full">
+      <div className="relative h-[300px] w-full">
+        <div 
+          role="img" 
+          aria-label={`Health metric chart showing ${days} ${pluralize(days, 'day', 'days')} out of ${requirement} required`}
+        >
          <Chart
            key={theme}
            options={{
              // ... existing options
            }}
            series={[requirement ? normalizedDays : 0]}
            height={300}
            type="radialBar"
          />
+        </div>
📝 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
<div className="relative h-[200px] w-full">
<Chart
key={theme}
options={{
chart: {
animations: {
enabled: true,
speed: 1000,
},
},
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
dataLabels: {
show: true,
name: {
show: false,
},
value: {
formatter: () => `${days} ${pluralize(days, 'day', 'days')}`,
color: theme === 'dark' ? '#ececec' : '#1E1E2C',
fontSize: '20px',
show: true,
offsetY: 0,
},
},
track: {
background: theme === 'dark' ? '#1E1E2C' : '#ececec',
margin: 0,
},
},
},
fill: {
type: 'gradient',
gradient: {
shade: theme,
type: 'horizontal',
shadeIntensity: 0.5,
stops: stops,
colorStops: colorStops,
},
},
}}
series={[requirement ? normalizedDays : 0]}
height={300}
type="radialBar"
/>
<div className="relative h-[300px] w-full">
+ <div
+ role="img"
+ aria-label={`Health metric chart showing ${days} ${pluralize(
+ days,
+ 'day',
+ 'days'
+ )} out of ${requirement} required`}
+ >
<Chart
key={theme}
options={{
chart: {
animations: {
enabled: true,
speed: 1000,
},
},
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
dataLabels: {
show: true,
name: { show: false },
value: {
formatter: () =>
`${days} ${pluralize(days, 'day', 'days')}`,
color: theme === 'dark' ? '#ececec' : '#1E1E2C',
fontSize: '20px',
show: true,
offsetY: 0,
},
},
track: {
background: theme === 'dark' ? '#1E1E2C' : '#ececec',
margin: 0,
},
},
},
fill: {
type: 'gradient',
gradient: {
shade: theme,
type: 'horizontal',
shadeIntensity: 0.5,
stops: stops,
colorStops: colorStops,
},
},
}}
series={[requirement ? normalizedDays : 0]}
height={300}
type="radialBar"
/>
+ </div>
</div>
🤖 Prompt for AI Agents
In frontend/src/components/GradientRadialChart.tsx between lines 89 and 136, fix
the height inconsistency by aligning the container div height with the Chart
height, either by changing the div's h-[200px] to h-[300px] or adjusting the
Chart height to 200px to prevent overflow. Additionally, wrap the Chart
component in a div with appropriate ARIA attributes (like role="img" and
aria-label) to improve accessibility.

Comment on lines +67 to +85
if (showRedAtEnd) {
stops.splice(stops.length - 2, 0, normalizedRequirement)
colorStops.push({
offset: normalizedRequirement,
color: redColor,
opacity: 1,
})
endColor = redColor
}

// Always add the end color at 100% if we have orange or red
if (showOrange || showRedAtEnd) {
stops.push(100)
colorStops.push({
offset: 100,
color: endColor,
opacity: 1,
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix gradient stops ordering and eliminate duplicate stops.

The gradient stops manipulation has two issues:

  1. Incorrect insertion position: When both showOrange and showRedAtEnd are true, normalizedRequirement is inserted before normalizedOrangeStop, but it should come after for proper green→orange→red progression.

  2. Duplicate 100 stop: The final push(100) creates a duplicate since 100 is already in the array.

Apply this fix:

  if (showRedAtEnd) {
-    stops.splice(stops.length - 2, 0, normalizedRequirement)
+    stops.splice(stops.length - 1, 0, normalizedRequirement)
    colorStops.push({
      offset: normalizedRequirement,
      color: redColor,
      opacity: 1,
    })
    endColor = redColor
  }

  // Always add the end color at 100% if we have orange or red
  if (showOrange || showRedAtEnd) {
-    stops.push(100)
    colorStops.push({
      offset: 100,
      color: endColor,
      opacity: 1,
    })
  }
🤖 Prompt for AI Agents
In frontend/src/components/GradientRadialChart.tsx around lines 67 to 85, fix
the gradient stops by inserting normalizedRequirement after the orange stop when
both showOrange and showRedAtEnd are true to maintain correct color progression,
and avoid pushing 100 twice to stops to eliminate duplicate end stops. Adjust
the splice position accordingly and ensure 100 is only added once at the end.

@sonarqubecloud
Copy link

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

Great work! @ahmedxgouda
p.s. I pushed small update for Health Score circle styling.

@arkid15r arkid15r enabled auto-merge June 25, 2025 02:51
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.

Thank you @ahmedxgouda for another great contribution 👍

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 Project Health Visualization to Project Page

3 participants