Add metric info cards for overview, repository and contributor insights#71
Add metric info cards for overview, repository and contributor insights#71Ri1tik wants to merge 1 commit into
Conversation
WalkthroughThree pages add informational UI elements: ChangesInfo UI Popovers and Tooltips
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/OverviewPage.jsx (1)
132-181:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winExternalize user-visible strings for internationalization.
The Health Score tooltip contains hardcoded user-visible strings like "Health Score estimates...", "Activity (40%)", "Issue Health (30%)", etc. As per coding guidelines, user-visible strings should be externalized to resource files (i18n).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/OverviewPage.jsx` around lines 132 - 181, The tooltip and visible labels in OverviewPage.jsx contain hardcoded strings and must be moved to the i18n resource files: replace strings inside the info panel and the surrounding labels (e.g., "High Impact Repositories", "Health Score estimates the overall health of a repository on a scale of 0 – 100.", "Activity (40%)", "Issue Health (30%)", "Contributor Diversity (30%)", "Higher scores indicate healthier...", and "By Composite Health Score") with localized keys and load them via your translation helper (e.g., useTranslation()/t()) where they are rendered (the button/label area that toggles open via setOpen, the div referenced by infoRef, and the tooltip content rendered when open); keep the HealthBar usage and topRepos mapping intact, only swap literal strings for t('...') keys and add corresponding entries to your locale resource files.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/pages/ContributorsPage.jsx`:
- Around line 148-194: Extract all hardcoded user-facing strings inside the
Freshness Index popover (e.g., the labels and paragraphs rendered when openInfo
=== 'freshness', including "Freshness Index", the descriptive paragraph, "High
Score"/"Medium Score"/"Low Score", and the final sentence) into your i18n
resource files and replace them with lookups from your localization utility (the
same pattern used elsewhere in ContributorsPage.jsx). Update the JSX to call the
i18n keys (use the existing state/symbols like freshnessRef, openInfo,
setOpenInfo and keep the popover rendering logic and styles intact) and add new
keys to the locale resources for each string so translations can be provided.
- Around line 250-304: The markup nests two <th> elements causing invalid HTML;
remove the outer <th> and keep the inner <th> that has ref={signalRef},
transferring any needed styles/attributes from the removed outer element into
that inner <th>; ensure the inner <th> retains the style object,
ref={signalRef}, the SIGNALS label, the info button (BsFillInfoSquareFill) with
onClick using setOpenInfo/openInfo, and the tooltip rendering (using C.card) so
functionality and styling remain identical.
- Around line 86-121: Replace hardcoded UI strings in the ContributorsPage
popover with i18n resource keys: move texts like "Bus Factor Risk", "Bus
Factor", "Measures contributor concentration risk.", list items "1 = Critical
Risk", "2 = High Risk", "3+ = Healthy Distribution", and the paragraph about
higher values into your localization files and reference them via the app's
translation helper (e.g., t('contributors.busFactor.title'),
t('contributors.busFactor.description'), etc.) inside the component that uses
busFactorRef, openInfo, setOpenInfo and the popover JSX (the element using
C.card and BsFillInfoSquareFill); update the JSX to call the translation
function for each user-visible string and ensure any punctuation or markup
remains in the component while text lives in the resource file.
- Around line 251-303: Externalize all hardcoded user-visible strings inside the
SIGNALS popover in ContributorsPage.jsx (the th using ref signalRef and the
conditional block that checks openInfo === 'signals') by replacing literals like
"SIGNALS", "Contributor Signals", "Measures how contributors connect
repositories and organizations.", "Connector Contributors", "Cross-Org
Contributors", and the paragraph text with i18n keys and lookups (e.g. via the
project's translation helper such as t('contributors.signals.title')). Add
corresponding entries to the locale resource files and use the existing
translation hook/utility in this component (or import it if missing) so the
popover renders translated strings instead of hardcoded text. Ensure keys are
descriptive (e.g., contributors.signals.*) and keep markup/structure unchanged.
- Around line 11-18: This component (ContributorsPage) uses client-side hooks
(useState, useEffect, useRef) so add the Next.js client directive by placing
"use client" as the very first line of the file so the component is treated as a
client component; ensure the string is before the import/exports and leave all
existing hooks (useState, useEffect, useRef) and functions intact so
ContributorsPage continues to use client-side behavior correctly.
In `@src/pages/OverviewPage.jsx`:
- Around line 11-29: This component uses client-side hooks (useState, useEffect,
useRef) but lacks the Next.js App Router client directive; add the string
literal "use client" as the very first line of the file (above the OverviewPage
component and any imports) so OverviewPage and its hooks run on the client,
ensuring hooks like useState/useEffect/useRef work correctly.
In `@src/pages/RepositoriesPage.jsx`:
- Around line 69-149: The overlay inside the Repository Explorer (the JSX block
gated by openInfo in RepositoriesPage.jsx) contains hardcoded user strings—e.g.
"Repository Health Metrics", the paragraph starting "OrgExplorer evaluates
repositories...", the lifecycle labels ("🟢 Thriving → Updated within 30 days",
etc.), and list items like "Stars → Community interest"—which must be
externalized; replace these literals in the component (around the PageTitle
usage and the openInfo conditional block referencing infoRef, setOpenInfo,
filtered and allRepos) with i18n keys and load them from your translation
resource (e.g. use t('repositories.health.title'),
t('repositories.health.description'), t('repositories.lifecycle.thriving'),
etc.), update the resource files with the new keys/values, and ensure any icon +
label combos are composed from translated strings so the UI uses the i18n
function consistently.
- Around line 14-37: This file uses client-side hooks (useState, useEffect,
useRef) inside the RepositoriesPage component but is missing the required "use
client" directive; add the exact string "use client" as the very first line of
the module so Next.js treats RepositoriesPage as a client component and the
hooks (useState, useEffect, useRef) work correctly.
---
Outside diff comments:
In `@src/pages/OverviewPage.jsx`:
- Around line 132-181: The tooltip and visible labels in OverviewPage.jsx
contain hardcoded strings and must be moved to the i18n resource files: replace
strings inside the info panel and the surrounding labels (e.g., "High Impact
Repositories", "Health Score estimates the overall health of a repository on a
scale of 0 – 100.", "Activity (40%)", "Issue Health (30%)", "Contributor
Diversity (30%)", "Higher scores indicate healthier...", and "By Composite
Health Score") with localized keys and load them via your translation helper
(e.g., useTranslation()/t()) where they are rendered (the button/label area that
toggles open via setOpen, the div referenced by infoRef, and the tooltip content
rendered when open); keep the HealthBar usage and topRepos mapping intact, only
swap literal strings for t('...') keys and add corresponding entries to your
locale resource files.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ca67f873-75f5-4810-9b57-48d69a90c1d4
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
src/pages/ContributorsPage.jsxsrc/pages/OverviewPage.jsxsrc/pages/RepositoriesPage.jsx
| export default function ContributorsPage() { | ||
| const { model } = useApp() | ||
| const [search, setSearch] = useState('') | ||
| const [shown, setShown] = useState(20) | ||
| const [shown, setShown] = useState(20) | ||
| const [openInfo, setOpenInfo] = useState(null) | ||
| const busFactorRef = useRef(null) | ||
| const freshnessRef = useRef(null) | ||
| const signalRef = useRef(null) |
There was a problem hiding this comment.
Add "use client" directive for client-side hooks.
This component uses client-side React hooks (useState, useEffect, useRef) but is missing the "use client" directive required in NextJS 13+ App Router. Without it, the component will fail when rendered as a server component.
As per coding guidelines, ensure that "use client" is being used for components with client-side features.
🔧 Add the directive at the top of the file
+"use client"
+
import React, { useState, useMemo, useEffect, useRef } from 'react'📝 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.
| export default function ContributorsPage() { | |
| const { model } = useApp() | |
| const [search, setSearch] = useState('') | |
| const [shown, setShown] = useState(20) | |
| const [shown, setShown] = useState(20) | |
| const [openInfo, setOpenInfo] = useState(null) | |
| const busFactorRef = useRef(null) | |
| const freshnessRef = useRef(null) | |
| const signalRef = useRef(null) | |
| "use client" | |
| import React, { useState, useMemo, useEffect, useRef } from 'react' |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/ContributorsPage.jsx` around lines 11 - 18, This component
(ContributorsPage) uses client-side hooks (useState, useEffect, useRef) so add
the Next.js client directive by placing "use client" as the very first line of
the file so the component is treated as a client component; ensure the string is
before the import/exports and leave all existing hooks (useState, useEffect,
useRef) and functions intact so ContributorsPage continues to use client-side
behavior correctly.
Source: Coding guidelines
| <div ref={busFactorRef} | ||
| style={{ ...C.label, marginBottom: 8, position: 'relative' }} | ||
| className="flex justify-between items-center" | ||
| > | ||
| <p>Bus Factor Risk</p> | ||
|
|
||
| <button | ||
| onClick={() => | ||
| setOpenInfo(openInfo === 'busfactor' ? null : 'busfactor') | ||
| } | ||
| className="p-2 rounded-full hover:bg-zinc-800 transition" | ||
| > | ||
| <BsFillInfoSquareFill className="text-white cursor-pointer" /> | ||
| </button> | ||
|
|
||
| {openInfo === 'busfactor' && ( | ||
| <div style={{ ...C.card, position: 'absolute', top: '120%', right: 0, width: '320px', zIndex: 100 }}> | ||
| <div className='text-xs text-(--text)'> | ||
| <h4 style={{ marginBottom: 8 }} className='text-(--accent)'>Bus Factor</h4> | ||
|
|
||
| <p> Measures contributor concentration risk. </p> | ||
|
|
||
| <ul style={{ marginLeft: 16 }}> | ||
| <li>1 = Critical Risk</li> | ||
| <li>2 = High Risk</li> | ||
| <li>3+ = Healthy Distribution</li> | ||
| </ul> | ||
| </div> | ||
|
|
||
| <p style={{ marginTop: 8 }}> | ||
| Higher values indicate knowledge is distributed across more contributors, | ||
| reducing dependency on a small number of individuals. | ||
| </p> | ||
| </div> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
Externalize user-visible strings for internationalization.
The popover contains hardcoded user-visible strings like "Bus Factor Risk", "Measures contributor concentration risk", "1 = Critical Risk", etc. As per coding guidelines, user-visible strings should be externalized to resource files (i18n).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/ContributorsPage.jsx` around lines 86 - 121, Replace hardcoded UI
strings in the ContributorsPage popover with i18n resource keys: move texts like
"Bus Factor Risk", "Bus Factor", "Measures contributor concentration risk.",
list items "1 = Critical Risk", "2 = High Risk", "3+ = Healthy Distribution",
and the paragraph about higher values into your localization files and reference
them via the app's translation helper (e.g., t('contributors.busFactor.title'),
t('contributors.busFactor.description'), etc.) inside the component that uses
busFactorRef, openInfo, setOpenInfo and the popover JSX (the element using
C.card and BsFillInfoSquareFill); update the JSX to call the translation
function for each user-visible string and ensure any punctuation or markup
remains in the component while text lives in the resource file.
Source: Coding guidelines
| <div ref={freshnessRef} | ||
| style={{ ...C.label, marginBottom: 12, position: 'relative' }} | ||
| className="flex justify-between items-center" | ||
| > | ||
| <p>Freshness Index</p> | ||
|
|
||
| <button | ||
| onClick={() => | ||
| setOpenInfo(openInfo === 'freshness' ? null : 'freshness') | ||
| } | ||
| className="p-2 rounded-full hover:bg-zinc-800 transition" | ||
| > | ||
| <BsFillInfoSquareFill className="text-white cursor-pointer" /> | ||
| </button> | ||
|
|
||
| {openInfo === 'freshness' && ( | ||
| <div | ||
| style={{ | ||
| ...C.card, | ||
| position: 'absolute', | ||
| top: '120%', | ||
| right: 0, | ||
| width: '320px', | ||
| zIndex: 100, | ||
| }} | ||
| className='text-xs' | ||
| > | ||
| <div className="text-(--text) text-xs"> | ||
| <h4 className='text-(--accent)'>Freshness Index</h4> | ||
|
|
||
| <p> | ||
| Measures how active and recently engaged the contributor community is. | ||
| </p> | ||
|
|
||
| <ul className="ml-2"> | ||
| <li><strong>High Score</strong> = Contributors active recently</li> | ||
| <li><strong>Medium Score</strong> = Some recent activity</li> | ||
| <li><strong>Low Score</strong> = Limited recent participation</li> | ||
| </ul> | ||
| </div> | ||
|
|
||
| <p style={{ marginTop: 8 }}> | ||
| Higher values indicate stronger project momentum and ongoing maintenance. | ||
| </p> | ||
| </div> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
Externalize user-visible strings for internationalization.
The Freshness Index popover contains hardcoded user-visible strings like "Freshness Index", "Measures how active and recently engaged...", "High Score", etc. As per coding guidelines, user-visible strings should be externalized to resource files (i18n).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/ContributorsPage.jsx` around lines 148 - 194, Extract all hardcoded
user-facing strings inside the Freshness Index popover (e.g., the labels and
paragraphs rendered when openInfo === 'freshness', including "Freshness Index",
the descriptive paragraph, "High Score"/"Medium Score"/"Low Score", and the
final sentence) into your i18n resource files and replace them with lookups from
your localization utility (the same pattern used elsewhere in
ContributorsPage.jsx). Update the JSX to call the i18n keys (use the existing
state/symbols like freshnessRef, openInfo, setOpenInfo and keep the popover
rendering logic and styles intact) and add new keys to the locale resources for
each string so translations can be provided.
Source: Coding guidelines
| <th style={{ padding: '10px 14px', fontSize: 11, color: 'var(--text2)', fontWeight: 600, background: 'var(--surface2)', borderBottom: '1px solid var(--border)', textAlign: 'left' }}> | ||
| SIGNALS | ||
| <th | ||
| style={{ padding: '10px 14px', fontSize: 11, color: 'var(--text2)', fontWeight: 600, background: 'var(--surface2)', textAlign: 'left', position: 'relative' }} | ||
| ref={signalRef} | ||
| > | ||
| <div | ||
| className="flex items-center gap-2" | ||
| style={{ position: 'relative' }} | ||
| > | ||
| <p>SIGNALS</p> | ||
|
|
||
| <button | ||
| onClick={() => | ||
| setOpenInfo(openInfo === 'signals' ? null : 'signals') | ||
| } | ||
| className="p-2 rounded-full hover:bg-zinc-800 transition" | ||
| > | ||
| <BsFillInfoSquareFill className="text-white cursor-pointer" /> | ||
| </button> | ||
|
|
||
| {openInfo === 'signals' && ( | ||
| <div | ||
| style={{ | ||
| ...C.card, | ||
| position: 'absolute', | ||
| top: '130%', | ||
| right: 2, | ||
| width: '320px', | ||
| zIndex: 100, | ||
| }} | ||
| > | ||
| <h4 className='mb-2 text-(--accent)'>Contributor Signals</h4> | ||
|
|
||
| <div className="text-(--text) text-xs"> | ||
| <p> | ||
| Measures how contributors connect repositories and organizations. | ||
| </p> | ||
|
|
||
| <ul className="ml-2 mt-2"> | ||
| <li> | ||
| <strong>Connector Contributors</strong> — active in 3+ repositories. | ||
| </li> | ||
| <li> | ||
| <strong>Cross-Org Contributors</strong> — contribute across multiple organizations. | ||
| </li> | ||
| </ul></div> | ||
|
|
||
| <p style={{ marginTop: 8 }}> | ||
| Higher values indicate stronger collaboration and knowledge sharing. | ||
| </p> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </th> | ||
| </th> |
There was a problem hiding this comment.
Remove nested <th> elements (invalid HTML).
Lines 250-303 contain nested <th> elements, which is invalid HTML:
<th style={...}>
<th style={...} ref={signalRef}>Only one <th> element should wrap the SIGNALS header. Remove the outer <th> at line 250 and keep the inner one with the ref.
🐛 Remove the outer th element
- <th style={{ padding: '10px 14px', fontSize: 11, color: 'var(--text2)', fontWeight: 600, background: 'var(--surface2)', borderBottom: '1px solid var(--border)', textAlign: 'left' }}>
<th
style={{ padding: '10px 14px', fontSize: 11, color: 'var(--text2)', fontWeight: 600, background: 'var(--surface2)', textAlign: 'left', position: 'relative' }}
ref={signalRef}
>
...
</th>
- </th>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/ContributorsPage.jsx` around lines 250 - 304, The markup nests two
<th> elements causing invalid HTML; remove the outer <th> and keep the inner
<th> that has ref={signalRef}, transferring any needed styles/attributes from
the removed outer element into that inner <th>; ensure the inner <th> retains
the style object, ref={signalRef}, the SIGNALS label, the info button
(BsFillInfoSquareFill) with onClick using setOpenInfo/openInfo, and the tooltip
rendering (using C.card) so functionality and styling remain identical.
| <th | ||
| style={{ padding: '10px 14px', fontSize: 11, color: 'var(--text2)', fontWeight: 600, background: 'var(--surface2)', textAlign: 'left', position: 'relative' }} | ||
| ref={signalRef} | ||
| > | ||
| <div | ||
| className="flex items-center gap-2" | ||
| style={{ position: 'relative' }} | ||
| > | ||
| <p>SIGNALS</p> | ||
|
|
||
| <button | ||
| onClick={() => | ||
| setOpenInfo(openInfo === 'signals' ? null : 'signals') | ||
| } | ||
| className="p-2 rounded-full hover:bg-zinc-800 transition" | ||
| > | ||
| <BsFillInfoSquareFill className="text-white cursor-pointer" /> | ||
| </button> | ||
|
|
||
| {openInfo === 'signals' && ( | ||
| <div | ||
| style={{ | ||
| ...C.card, | ||
| position: 'absolute', | ||
| top: '130%', | ||
| right: 2, | ||
| width: '320px', | ||
| zIndex: 100, | ||
| }} | ||
| > | ||
| <h4 className='mb-2 text-(--accent)'>Contributor Signals</h4> | ||
|
|
||
| <div className="text-(--text) text-xs"> | ||
| <p> | ||
| Measures how contributors connect repositories and organizations. | ||
| </p> | ||
|
|
||
| <ul className="ml-2 mt-2"> | ||
| <li> | ||
| <strong>Connector Contributors</strong> — active in 3+ repositories. | ||
| </li> | ||
| <li> | ||
| <strong>Cross-Org Contributors</strong> — contribute across multiple organizations. | ||
| </li> | ||
| </ul></div> | ||
|
|
||
| <p style={{ marginTop: 8 }}> | ||
| Higher values indicate stronger collaboration and knowledge sharing. | ||
| </p> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </th> |
There was a problem hiding this comment.
Externalize user-visible strings for internationalization.
The SIGNALS popover contains hardcoded user-visible strings like "Contributor Signals", "Measures how contributors connect...", "Connector Contributors", etc. As per coding guidelines, user-visible strings should be externalized to resource files (i18n).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/ContributorsPage.jsx` around lines 251 - 303, Externalize all
hardcoded user-visible strings inside the SIGNALS popover in
ContributorsPage.jsx (the th using ref signalRef and the conditional block that
checks openInfo === 'signals') by replacing literals like "SIGNALS",
"Contributor Signals", "Measures how contributors connect repositories and
organizations.", "Connector Contributors", "Cross-Org Contributors", and the
paragraph text with i18n keys and lookups (e.g. via the project's translation
helper such as t('contributors.signals.title')). Add corresponding entries to
the locale resource files and use the existing translation hook/utility in this
component (or import it if missing) so the popover renders translated strings
instead of hardcoded text. Ensure keys are descriptive (e.g.,
contributors.signals.*) and keep markup/structure unchanged.
Source: Coding guidelines
| export default function OverviewPage() { | ||
| const { orgs, model } = useApp() | ||
| const navigate = useNavigate() | ||
| if (!model) return null | ||
|
|
||
| const [open, setOpen] = useState(false) | ||
| const infoRef = useRef(null) | ||
|
|
||
| useEffect(() => { | ||
| function handleClickOutside(event) { | ||
| if (infoRef.current && !infoRef.current.contains(event.target)) { | ||
| setOpen(false) | ||
| } | ||
| } | ||
| document.addEventListener('mousedown', handleClickOutside) | ||
| return () => { | ||
| document.removeEventListener('mousedown', handleClickOutside) | ||
| } | ||
| }, []) |
There was a problem hiding this comment.
Add "use client" directive for client-side hooks.
This component uses client-side React hooks (useState, useEffect, useRef) but is missing the "use client" directive required in NextJS 13+ App Router.
As per coding guidelines, ensure that "use client" is being used for components with client-side features.
🔧 Add the directive at the top of the file
+"use client"
+
import React, { useEffect, useState, useRef } from 'react'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/OverviewPage.jsx` around lines 11 - 29, This component uses
client-side hooks (useState, useEffect, useRef) but lacks the Next.js App Router
client directive; add the string literal "use client" as the very first line of
the file (above the OverviewPage component and any imports) so OverviewPage and
its hooks run on the client, ensuring hooks like useState/useEffect/useRef work
correctly.
Source: Coding guidelines
| export default function RepositoriesPage() { | ||
| const { model } = useApp() | ||
| const [search, setSearch] = useState('') | ||
| const [search, setSearch] = useState('') | ||
| const [lifecycle, setLifecycle] = useState('All') | ||
| const [lang, setLang] = useState('All') | ||
| const [view, setView] = useState('grid') | ||
| const [shown, setShown] = useState(20) | ||
| const [lang, setLang] = useState('All') | ||
| const [view, setView] = useState('grid') | ||
| const [shown, setShown] = useState(20) | ||
| const [openInfo, setOpenInfo] = useState(false) | ||
| const infoRef = useRef(null) | ||
|
|
||
| useEffect(() => { | ||
| function handleClickOutside(event) { | ||
| if ( | ||
| infoRef.current && | ||
| !infoRef.current.contains(event.target) | ||
| ) { | ||
| setOpenInfo(false) | ||
| } | ||
| } | ||
| document.addEventListener('mousedown', handleClickOutside) | ||
| return () => { | ||
| document.removeEventListener('mousedown', handleClickOutside) | ||
| } | ||
| }, []) |
There was a problem hiding this comment.
Add "use client" directive for client-side hooks.
This component uses client-side React hooks (useState, useEffect, useRef) but is missing the "use client" directive required in NextJS 13+ App Router.
As per coding guidelines, ensure that "use client" is being used for components with client-side features.
🔧 Add the directive at the top of the file
+"use client"
+
import React, { useState, useMemo, useEffect, useRef } from 'react'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/RepositoriesPage.jsx` around lines 14 - 37, This file uses
client-side hooks (useState, useEffect, useRef) inside the RepositoriesPage
component but is missing the required "use client" directive; add the exact
string "use client" as the very first line of the module so Next.js treats
RepositoriesPage as a client component and the hooks (useState, useEffect,
useRef) work correctly.
Source: Coding guidelines
| <div style={{ position: 'relative' }} ref={infoRef}> | ||
| <PageTitle | ||
| title={ | ||
| <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}> | ||
| Repository Explorer | ||
|
|
||
| <button | ||
| onClick={() => setOpenInfo(prev => !prev)} | ||
| className="p-3 rounded-full hover:bg-zinc-800 transition" | ||
| > | ||
| <BsFillInfoSquareFill className='size-4' /> | ||
| </button> | ||
| </div> | ||
| } | ||
| subtitle="Technical health and lifecycle across all repositories in the portfolio" | ||
| right={ | ||
| <span style={{ fontSize: 28, fontWeight: 700, color: 'var(--accent)' }}> | ||
| {filtered.length} | ||
| <span style={{ fontSize: 14, color: 'var(--text2)', fontWeight: 400 }}> | ||
| {' '} / {allRepos.length} repos | ||
| </span> | ||
| </span> | ||
| } | ||
| /> | ||
|
|
||
| {openInfo && ( | ||
| <div | ||
| style={{ | ||
| position: 'absolute', | ||
| top: 50, | ||
| left: 20, | ||
| width: 420, | ||
| zIndex: 100, | ||
| background: 'var(--surface)', | ||
| border: '1px solid var(--border)', | ||
| borderRadius: 12, | ||
| padding: 16, | ||
| boxShadow: '0 8px 30px rgba(0,0,0,.4)' | ||
| }} | ||
| > | ||
| <div | ||
| style={{ | ||
| fontWeight: 600, | ||
| marginBottom: 10, | ||
| color: 'var(--accent)' | ||
| }} | ||
| > | ||
| Repository Health Metrics | ||
| </div> | ||
|
|
||
| <p style={{ fontSize: 13, color: 'var(--text2)', marginBottom: 12 }}> | ||
| OrgExplorer evaluates repositories using activity, issue health, | ||
| contributor diversity, and lifecycle status. | ||
| </p> | ||
|
|
||
| <div style={{ fontSize: 12, lineHeight: 1.7 }}> | ||
| <strong>Health Score (0–100)</strong> | ||
| <ul style={{ marginLeft: 18 }}> | ||
| <li>Activity → 40%</li> | ||
| <li>Issue Health → 30%</li> | ||
| <li>Contributor Diversity → 30%</li> | ||
| </ul> | ||
|
|
||
| <strong>Lifecycle Classification</strong> | ||
| <ul style={{ marginLeft: 18 }}> | ||
| <li>🟢 Thriving → Updated within 30 days</li> | ||
| <li>🔵 Stable → Updated within 90 days</li> | ||
| <li>🟡 Dormant → Updated within 180 days</li> | ||
| <li>🔴 Abandoned → No updates for 180+ days</li> | ||
| </ul> | ||
|
|
||
| <strong>Repository Signals</strong> | ||
| <ul style={{ marginLeft: 18 }}> | ||
| <li>Stars → Community interest</li> | ||
| <li>Forks → Adoption & contributions</li> | ||
| <li>Issues → Current maintenance workload</li> | ||
| </ul> | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
Externalize user-visible strings for internationalization.
The Repository Health Metrics overlay contains extensive hardcoded user-visible strings including "Repository Health Metrics", "OrgExplorer evaluates repositories...", lifecycle classifications, etc. As per coding guidelines, user-visible strings should be externalized to resource files (i18n).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/RepositoriesPage.jsx` around lines 69 - 149, The overlay inside the
Repository Explorer (the JSX block gated by openInfo in RepositoriesPage.jsx)
contains hardcoded user strings—e.g. "Repository Health Metrics", the paragraph
starting "OrgExplorer evaluates repositories...", the lifecycle labels ("🟢
Thriving → Updated within 30 days", etc.), and list items like "Stars →
Community interest"—which must be externalized; replace these literals in the
component (around the PageTitle usage and the openInfo conditional block
referencing infoRef, setOpenInfo, filtered and allRepos) with i18n keys and load
them from your translation resource (e.g. use t('repositories.health.title'),
t('repositories.health.description'), t('repositories.lifecycle.thriving'),
etc.), update the resource files with the new keys/values, and ensure any icon +
label combos are composed from translated strings so the UI uses the i18n
function consistently.
Source: Coding guidelines
Addressed Issues:
Fixes #
Screenshots/Recordings:
https://drive.google.com/file/d/1tVKDnBVXC2hLmn1ktStpGnHkRs08HLLf/view?usp=sharing
Additional Notes:
This PR improves the discoverability and interpretability of OrgExplorer's analytical metrics by providing contextual explanations directly within the UI.
The following metrics now include dedicated information cards:
Repo's Lifestyle
Health Score
Bus Factor
Freshness Index
Contributor Signals
The implementation follows a consistent interaction pattern across pages and does not modify the underlying analytics engine or metric calculations.
Checklist
We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact.
Summary by CodeRabbit