From ee4ae04ced77b5318cd557f682c6cf1fded053a0 Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Tue, 23 Jun 2026 16:08:23 +0530 Subject: [PATCH 1/8] fix: replace info icon and update interaction for contributor info buttons --- src/pages/ContributorsPage.jsx | 42 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/pages/ContributorsPage.jsx b/src/pages/ContributorsPage.jsx index 757571b..8ccc2eb 100644 --- a/src/pages/ContributorsPage.jsx +++ b/src/pages/ContributorsPage.jsx @@ -6,7 +6,7 @@ import { useSortedData } from '../hooks/useSortedData' import { computeBusFactor, exportContributorsCSV } from '../services/analytics' import { useNavigate } from 'react-router-dom' import EmptyStateCard from '../components/EmptyStateCard' -import { BsFillInfoSquareFill } from "react-icons/bs"; +import { AiOutlineInfoCircle } from "react-icons/ai"; export default function ContributorsPage() { const { model } = useApp() @@ -90,12 +90,11 @@ export default function ContributorsPage() {

Bus Factor Risk

{openInfo === 'busfactor' && ( @@ -152,12 +151,11 @@ export default function ContributorsPage() {

Freshness Index

{openInfo === 'freshness' && ( @@ -258,12 +256,11 @@ export default function ContributorsPage() {

SIGNALS

{openInfo === 'signals' && ( @@ -306,10 +303,23 @@ export default function ContributorsPage() { {visible.map((c, i) => ( +
{c.login} {c.login}
+
From ebaed0f6a967711e41da864ef6636bec0048e585 Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Tue, 23 Jun 2026 22:26:30 +0530 Subject: [PATCH 2/8] fix: repositories page work. --- src/pages/RepositoriesPage.jsx | 108 +++++++++------------------------ 1 file changed, 29 insertions(+), 79 deletions(-) diff --git a/src/pages/RepositoriesPage.jsx b/src/pages/RepositoriesPage.jsx index d551094..30646da 100644 --- a/src/pages/RepositoriesPage.jsx +++ b/src/pages/RepositoriesPage.jsx @@ -1,6 +1,6 @@ import React, { useState, useMemo, useEffect, useRef } from 'react' import { FiDatabase, FiDownload, FiGrid, FiList } from 'react-icons/fi' -import { BsFillInfoSquareFill } from "react-icons/bs"; +import { AiOutlineInfoCircle } from "react-icons/ai"; import { useApp } from '../context/AppContext' import { C, Badge, HealthBar, SortTh, PageTitle, LoadMore } from '../components/UI' import { useSortedData } from '../hooks/useSortedData' @@ -15,8 +15,7 @@ export default function RepositoriesPage() { const { model } = useApp() const [search, setSearch] = useState('') const [activityClassification, setActivityClassification] = useState('All') - const [lang, setLang] = useState('All') - const [view, setView] = useState('grid') + const [lang, setLang] = useState('All Languages') const [shown, setShown] = useState(20) const [openInfo, setOpenInfo] = useState(false) const infoRef = useRef(null) @@ -41,12 +40,12 @@ export default function RepositoriesPage() { const { allRepos } = model const langs = useMemo(() => - ['All', ...new Set(allRepos.map(r => r.language).filter(Boolean))].slice(0, 10), + ['All Languages', ...new Set(allRepos.map(r => r.language).filter(Boolean))].slice(0, 10), [allRepos]) const filtered = useMemo(() => allRepos.filter(r => (activityClassification === 'All' || r.activityClassification === activityClassification) && - (lang === 'All' || r.language === lang) && + (lang === 'All Languages' || r.language === lang) && (!search || r.name.toLowerCase().includes(search.toLowerCase()) || (r.description || '').toLowerCase().includes(search.toLowerCase())) ), [allRepos, activityClassification, lang, search]) @@ -60,8 +59,7 @@ export default function RepositoriesPage() { ['forks_count', 'Forks'], ['open_issues_count', 'Open Issues'], ['healthScore', 'Health'], - ['activityClassification', 'Activity Classification'], - ['pushed_at', 'Last Push'], + ['pushed_at', 'Repository Activity'], ] return ( @@ -73,10 +71,11 @@ export default function RepositoriesPage() { Repository Explorer
} @@ -159,14 +158,6 @@ export default function RepositoriesPage() { -
- - -
@@ -190,7 +181,6 @@ export default function RepositoriesPage() { {allRepos?.length ? ( <> {/* Table view */} - {view === 'list' && (
@@ -203,77 +193,37 @@ export default function RepositoriesPage() { {visible.map((r, i) => ( - + + - - - + + ))}
+ +
{r.name}
{r.orgLogin &&
{r.orgLogin}
} -
{r.stargazers_count.toLocaleString()} {r.forks_count.toLocaleString()} 30 ? 'var(--red)' : 'var(--text2)' }}>{r.open_issues_count} {r.pushed_at?.slice(0, 10)}
+
+ + Last push: {r.pushed_at?.slice(0, 10)} + +
+
setShown(s => s + 20)} />
- )} - - {/* Grid view */} - {view === 'grid' && ( - <> -
- {visible.map(r => ( -
e.currentTarget.style.borderColor = 'var(--accent)'} - onMouseLeave={e => e.currentTarget.style.borderColor = ACTIVITY_COLORS[r.activityClassification]} - style={{ - ...C.card, - borderColor: ACTIVITY_COLORS[r.activityClassification], - transition: 'border-color .2s', display: 'flex', flexDirection: 'column', gap: 10, - }} - > -
-
-
{r.name}
- {r.orgLogin &&
{r.orgLogin}
} -
- -
-

- {r.description || 'No description provided'} -

-
- {[['Stars', r.stargazers_count.toLocaleString()], ['Forks', r.forks_count.toLocaleString()], ['Issues', r.open_issues_count]].map(([l, v]) => ( -
-
{v}
-
{l}
-
- ))} -
- {r.language && ( -
- - {r.language} -
- )} -
-
- HEALTH SCORE - {r.pushed_at?.slice(0, 10)} -
- -
-
ACTIVITY 40% · ISSUES 30% · DIVERSITY 30%
-
- ))} -
- setShown(s => s + 20)} /> - - )} ) : (
Date: Tue, 23 Jun 2026 22:37:54 +0530 Subject: [PATCH 3/8] Fix: Overview page Info icon and Theme inconsistency in navbar. --- src/components/Navbar.jsx | 2 +- src/pages/OverviewPage.jsx | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index fb430db..4b9248d 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -22,7 +22,7 @@ export default function Navbar() { return (
{open && (
Health Score estimates the overall health of a repository on a scale of 0 – 100. @@ -163,7 +165,7 @@ export default function OverviewPage() { -

+

Higher scores indicate healthier and more actively maintained repositories.

From e56def8af4f9d61eacbc78206ce30b94f477c4ef Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Wed, 24 Jun 2026 00:18:29 +0530 Subject: [PATCH 4/8] fix: Image for organization in overview page --- src/pages/OverviewPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/OverviewPage.jsx b/src/pages/OverviewPage.jsx index 4c058fe..36e957b 100644 --- a/src/pages/OverviewPage.jsx +++ b/src/pages/OverviewPage.jsx @@ -72,7 +72,7 @@ export default function OverviewPage() { ) : ( orgs[0]?.avatar_url && ( - + ) )}
From eb21124958d904d17043ea50032aacb89837cd2d Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Wed, 24 Jun 2026 01:32:02 +0530 Subject: [PATCH 5/8] feat: enhanced the top repo calculation matric based on new formula for without PAT --- src/context/AppContext.jsx | 6 ++---- src/services/analytics.js | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/context/AppContext.jsx b/src/context/AppContext.jsx index 19f4adb..aed1c9a 100644 --- a/src/context/AppContext.jsx +++ b/src/context/AppContext.jsx @@ -1,6 +1,6 @@ import { createContext, useContext, useState, useCallback, useEffect } from 'react' import { fetchOrg, fetchRepos, fetchContributors, fetchIssues, } from '../services/github' -import { buildAnalyticalModel } from '../services/analytics' +import { buildAnalyticalModel, getTopRepositories } from '../services/analytics' const Ctx = createContext(null) @@ -83,9 +83,7 @@ export function AppProvider({ children }) { setLoadMsg('Fetching contributor data for top repositories...') const contribsPerRepo = {} for (const org of validOrgs) { - const top = (reposPerOrg[org.login] || []) - .sort((a, b) => b.stargazers_count - a.stargazers_count) - .slice(0, 10) + const top = getTopRepositories(reposPerOrg[org.login] || [], 10); await Promise.allSettled(top.map(async repo => { contribsPerRepo[`${org.login}/${repo.name}`] = await fetchContributors(org.login, repo.name, pat) })) diff --git a/src/services/analytics.js b/src/services/analytics.js index 09d1df6..b583249 100644 --- a/src/services/analytics.js +++ b/src/services/analytics.js @@ -168,3 +168,28 @@ export function exportTrendsCSV(series) { const rows = series.map(s => [s.date, s.prs_created, s.prs_merged, s.prs_closed, s.issues_created, s.issues_closed]) download([header, ...rows].map(r => r.join(',')).join('\n'), 'orgexplorer-trends.csv') } + +export function getTopRepositories(repos, limit = 10) { + const MS_PER_DAY = 1000 * 60 * 60 * 24; + + return [...repos] + .map(repo => { + const daysSinceLastPush = + (Date.now() - new Date(repo.pushed_at).getTime()) / MS_PER_DAY; + + const activityBonus = 0.5 * Math.max(0, 365 - daysSinceLastPush); + + const score = + repo.stargazers_count + + repo.forks_count * 2 + + repo.watchers_count * 1.5 + + activityBonus; + + return { + ...repo, + score, + }; + }) + .sort((a, b) => b.score - a.score) + .slice(0, limit); +} From bea2f0c53480b2289107a27f293d477b2c8e325d Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Wed, 24 Jun 2026 17:28:56 +0530 Subject: [PATCH 6/8] fix: only include top repon to analyze and all the top contributor for each top repo --- src/context/AppContext.jsx | 1 + src/pages/NetworkPage.jsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/context/AppContext.jsx b/src/context/AppContext.jsx index aed1c9a..310548f 100644 --- a/src/context/AppContext.jsx +++ b/src/context/AppContext.jsx @@ -84,6 +84,7 @@ export function AppProvider({ children }) { const contribsPerRepo = {} for (const org of validOrgs) { const top = getTopRepositories(reposPerOrg[org.login] || [], 10); + reposPerOrg[org.login] = top; // Update to only include top repos await Promise.allSettled(top.map(async repo => { contribsPerRepo[`${org.login}/${repo.name}`] = await fetchContributors(org.login, repo.name, pat) })) diff --git a/src/pages/NetworkPage.jsx b/src/pages/NetworkPage.jsx index 5364d29..9359655 100644 --- a/src/pages/NetworkPage.jsx +++ b/src/pages/NetworkPage.jsx @@ -28,7 +28,7 @@ export default function NetworkPage() { // Top repos and contributors for performance const topRepos = model.allRepos.slice(0, 30) - const topContribs = model.contributors.slice(0, 40) + const topContribs = model.contributors const nodes = [] if (showRepos) topRepos.forEach(r => nodes.push({ id: `repo:${r.name}`, type: 'repo', data: r, ts: new Date(r.pushed_at).getTime() })) From e019717e91ea38d7c05af660042a96cb1f8fdeea Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Thu, 25 Jun 2026 01:16:05 +0530 Subject: [PATCH 7/8] fix: Repo number count on Overview page --- src/context/AppContext.jsx | 11 +++++++++-- src/pages/OverviewPage.jsx | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/context/AppContext.jsx b/src/context/AppContext.jsx index 310548f..a56f89c 100644 --- a/src/context/AppContext.jsx +++ b/src/context/AppContext.jsx @@ -58,7 +58,7 @@ export function AppProvider({ children }) { return () => clearTimeout(timeout) }, [rateLimit]) - + const [totalRepo, setTotalRepo] = useState(0); const savePat = useCallback(token => { setPat(token) token ? localStorage.setItem('oe_pat', token) : localStorage.removeItem('oe_pat') @@ -80,6 +80,13 @@ export function AppProvider({ children }) { reposPerOrg[org.login] = await fetchRepos(org.login, pat) })) + const total = Object.values(reposPerOrg).reduce( + (sum, repos) => sum + repos.length, + 0 + ); + + setTotalRepo(total); + setLoadMsg('Fetching contributor data for top repositories...') const contribsPerRepo = {} for (const org of validOrgs) { @@ -130,7 +137,7 @@ export function AppProvider({ children }) { return ( {children} diff --git a/src/pages/OverviewPage.jsx b/src/pages/OverviewPage.jsx index 36e957b..89fc753 100644 --- a/src/pages/OverviewPage.jsx +++ b/src/pages/OverviewPage.jsx @@ -11,7 +11,7 @@ const LANG_COLORS = ['#22c55e', '#f5c518', '#3b82f6', '#ef4444', '#a855f7', '#f9 const fmt = n => n > 999 ? (n / 1000).toFixed(1) + 'k' : String(n) export default function OverviewPage() { - const { orgs, model } = useApp() + const { orgs, model, totalRepo } = useApp() const navigate = useNavigate() if (!model) return null @@ -103,10 +103,10 @@ export default function OverviewPage() { {/* Stats */}
- + - +
{/* Language + top repos */} From af334bc09cf78467ef7289a710d8b30db3e3b7d9 Mon Sep 17 00:00:00 2001 From: Rahul Vyas Date: Thu, 25 Jun 2026 14:55:00 +0530 Subject: [PATCH 8/8] Guard score inputs to avoid NaN rankings. --- src/services/analytics.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/services/analytics.js b/src/services/analytics.js index b583249..7ca784b 100644 --- a/src/services/analytics.js +++ b/src/services/analytics.js @@ -174,16 +174,16 @@ export function getTopRepositories(repos, limit = 10) { return [...repos] .map(repo => { - const daysSinceLastPush = - (Date.now() - new Date(repo.pushed_at).getTime()) / MS_PER_DAY; + const pushedAtMs = Date.parse(repo.pushed_at); + const daysSinceLastPush = Number.isFinite(pushedAtMs) ? (Date.now() - pushedAtMs) / MS_PER_DAY : Infinity; const activityBonus = 0.5 * Math.max(0, 365 - daysSinceLastPush); - const score = - repo.stargazers_count + - repo.forks_count * 2 + - repo.watchers_count * 1.5 + - activityBonus; + const score = + (repo.stargazers_count ?? 0) + + (repo.forks_count ?? 0) * 2 + + (repo.watchers_count ?? 0) * 1.5 + + activityBonus; return { ...repo,