Skip to content

Add metric info cards for overview, repository and contributor insights#71

Open
Ri1tik wants to merge 1 commit into
AOSSIE-Org:mainfrom
Ri1tik:feature/info-cards
Open

Add metric info cards for overview, repository and contributor insights#71
Ri1tik wants to merge 1 commit into
AOSSIE-Org:mainfrom
Ri1tik:feature/info-cards

Conversation

@Ri1tik

@Ri1tik Ri1tik commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

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

  • My code follows the project's code style and conventions
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • I have read the Contributing Guidelines

⚠️ AI Notice - Important!

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

  • New Features
    • Added informational help cards to the Contributors page for Signals, Bus Factor, and Freshness Index metrics.
    • Added help tooltip to the High Impact Repositories card on the Overview page.
    • Added explanatory overlay to the Repositories page header describing health metrics and lifecycle classification.
    • All help elements can be toggled and automatically close when clicking outside.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Three pages add informational UI elements: ContributorsPage introduces three info popovers for Bus Factor, Freshness Index, and Signals; OverviewPage adds a tooltip to High Impact Repositories; RepositoriesPage adds an info overlay to the header. All follow the same pattern with local state, refs, and outside-click detection.

Changes

Info UI Popovers and Tooltips

Layer / File(s) Summary
ContributorsPage info popovers
src/pages/ContributorsPage.jsx
Imports useEffect and useRef; adds openInfo state and three refs (busFactorRef, freshnessRef, signalRef) with a document mousedown listener to dismiss popovers. Bus Factor, Freshness Index, and SIGNALS table headers now each include an info-toggle button and conditional absolute-positioned help card. Page subtitle text is updated, contributors-count display text is simplified, and EmptyStateCard props are reformatted.
OverviewPage info tooltip
src/pages/OverviewPage.jsx
Introduces open state and infoRef with a useEffect mousedown handler for outside-click dismissal. High Impact Repositories card gains an info-toggle button that reveals a tooltip explaining the composite health score. Stats card and navigation card JSX lines are updated for formatting without changing rendering logic.
RepositoriesPage info overlay
src/pages/RepositoriesPage.jsx
Adds openInfo state with ref and a useEffect mousedown listener to close the info overlay on outside clicks. Page header now includes an info-toggle button that opens an absolute-positioned popover describing Repository Health Metrics and lifecycle classifications. Main content rendering, list/grid views, and empty-state behavior remain unchanged structurally.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • AOSSIE-Org/OrgExplorer#69: Updates to ContributorsPage.jsx and RepositoriesPage.jsx include changes to EmptyStateCard usage, directly tied to empty-state card refactoring in PR #69.

Suggested labels

Typescript Lang

Suggested reviewers

  • bhavik-mangla
  • Zahnentferner

Poem

🐰 Popover magic flows through three pages bright,
Click a button, watch the info take flight,
Bus factors and metrics dance into view,
Click outside to dismiss—the pattern shines true!
State and refs align, a tooltip ballet—
OrgExplorer's users will love this display!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes across all three modified files: adding metric info cards to the overview, repository, and contributor insights pages.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added no-issue-linked PR has no linked issue configuration Config file changes frontend Frontend changes javascript JavaScript/TypeScript changes size/XL 500+ lines changed labels Jun 9, 2026
@Ri1tik Ri1tik added gsoc GSoC students and removed no-issue-linked PR has no linked issue javascript JavaScript/TypeScript changes configuration Config file changes frontend Frontend changes labels Jun 9, 2026
@github-actions github-actions Bot added the external-contributor External contributor label Jun 9, 2026
@github-actions github-actions Bot added no-issue-linked PR has no linked issue configuration Config file changes frontend Frontend changes javascript JavaScript/TypeScript changes size/XL 500+ lines changed and removed size/XL 500+ lines changed labels Jun 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 win

Externalize 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

📥 Commits

Reviewing files that changed from the base of the PR and between 775f7ad and edc9706.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • src/pages/ContributorsPage.jsx
  • src/pages/OverviewPage.jsx
  • src/pages/RepositoriesPage.jsx

Comment on lines 11 to +18
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

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.

Suggested change
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

Comment on lines +86 to +121
<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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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

Comment on lines +148 to +194
<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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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

Comment on lines 250 to 304
<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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

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.

Comment on lines +251 to +303
<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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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

Comment on lines 11 to +29
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)
}
}, [])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

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

Comment on lines 14 to +37
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)
}
}, [])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

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

Comment on lines +69 to +149
<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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

configuration Config file changes external-contributor External contributor frontend Frontend changes gsoc GSoC students javascript JavaScript/TypeScript changes no-issue-linked PR has no linked issue size/XL 500+ lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant