feat: add project admin scoring and dashboard#7
Conversation
|
@Ixotic27 is attempting to deploy a commit to the prodhoshvs2025-8980's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
Adds a new “Project Admin” role and dashboard to track admin activity across registered GSSoC repositories, backed by a new GitHub-driven scoring engine and surfaced via cross-navigation notices from the contributor dashboard and home role selector.
Changes:
- Introduces a server-side admin scoring builder (
buildAdminScore) that pulls PR/issue data from the GitHub Search API and computes a per-repo breakdown + totals. - Adds a new
/project-admin/[username]aggregate dashboard and updates/project-admin/[username]/[repo]to display admin points + a scoring guide. - Updates UI entry points (Home role selector, points guide modal, contributor dashboard) to include the Project Admin role and dual-role navigation.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/admin-scoring.ts | New scoring engine that fetches repo PRs/issues from GitHub and computes admin points. |
| src/components/HomePointsGuide.tsx | Adds a “Project Admin” tab explaining the new scoring rules. |
| src/app/project-admin/[username]/page.tsx | New aggregate admin dashboard for a user across registered repos. |
| src/app/project-admin/[username]/[repo]/page.tsx | Enhances repo-level admin page to show admin scoring stats + guide. |
| src/app/pr-tracker/[username]/page.tsx | Adds “dual-role” notice + link to admin dashboard when applicable. |
| src/app/page.tsx | Adds “Project Admin” as a selectable role and routes search accordingly. |
| package-lock.json | Lockfile updates from dependency resolution changes. |
Comments suppressed due to low confidence (1)
src/app/project-admin/[username]/[repo]/page.tsx:169
- This
subtext is a literal string ("by @owner ...") so the UI will render@ownerinstead of the actual username.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // 1. Merged PRs with gssoc:approved | ||
| // Note: search issues item has `pull_request` and `pull_request.merged_at` check | ||
| const mergedPRsCount = prs.filter((pr) => !!pr.pull_request?.merged_at || pr.state === "closed").length; | ||
| const mergedPRsPoints = mergedPRsCount * 15; |
| const q = `label:"gssoc:approved" repo:${owner}/${repo} type:pr`; | ||
| const url = `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&per_page=100&sort=created&order=desc`; |
| // Check difficulty: starts with level: | ||
| const hasDifficulty = labelNames.some((name: string) => name.startsWith("level:")); | ||
| // Check type: starts with type: | ||
| const hasType = labelNames.some((name: string) => name.startsWith("type:")); | ||
|
|
||
| if (hasDifficulty && hasType) { | ||
| labeledIssuesFullCount++; | ||
| } else if (hasDifficulty) { | ||
| labeledIssuesDiffCount++; | ||
| } |
|
Hello! I have updated the branch to resolve the feedback:
|
| async function _buildAdminScore(owner: string, repo: string, adminUsername: string): Promise<AdminScoreBreakdown> { | ||
| const [prs, issues] = await Promise.all([ | ||
| fetchRepoPRs(owner, repo), | ||
| fetchRepoIssues(owner, repo), | ||
| ]); | ||
|
|
||
| // 1. Merged PRs with gssoc:approved (the search query already filters to is:merged) | ||
| const mergedPRsCount = prs.length; | ||
| const mergedPRsPoints = mergedPRsCount * 15; |
| if (!r.ok) return []; | ||
| const d = await r.json() as { items: any[] }; | ||
| return d.items; |
| if (!r.ok) return []; | ||
| const d = await r.json() as { items: any[] }; | ||
| return d.items; |
| // Find user's repositories registered in GSSoC 2026 | ||
| const userRepos = Array.from(GSSOC_REPO_SET).filter((repoKey) => { | ||
| return repoKey.split("/")[0] === decoded.toLowerCase(); | ||
| }); |
| <Link | ||
| href={`/project-admin/${repoKey}`} | ||
| style={{ | ||
| fontSize: 12, |
…nonicalize login matching, and encode URL components
|
Hello! I have updated the branch to address the remaining feedback:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (2)
src/app/project-admin/[username]/[repo]/page.tsx:11
- There are now unused imports (
ProjectStatsGrid,ScoringGuide) and a duplicatelucide-reactimport. This adds noise and can trip unused-import lint rules. Consider removing the unused imports and consolidating the icon imports into a singlelucide-reactimport.
src/app/project-admin/[username]/[repo]/page.tsx:197 - The Project Admin scoring guide markup is duplicated here and in
src/app/project-admin/[username]/page.tsx(AdminScoringGuide). Duplicated copy/layout makes future point-rule changes easy to miss. Consider extracting a shared component (e.g.components/project-admin/AdminScoringGuide) and reusing it in both pages.
| if (data.total_count > 100) { | ||
| const pages = Math.min(Math.ceil((data.total_count - 100) / 100), 4); // fetch up to 500 PRs |
| if (data.total_count > 100) { | ||
| const pages = Math.min(Math.ceil((data.total_count - 100) / 100), 4); // fetch up to 500 issues |
| if (hasDifficulty && hasType) { | ||
| labeledIssuesFullCount++; | ||
| } else if (hasDifficulty) { | ||
| labeledIssuesDiffCount++; | ||
| } |
| @@ -0,0 +1,493 @@ | |||
| import { notFound } from "next/navigation"; | |||
| import Link from "next/link"; | |||
| import { ArrowLeft, Clock, AlertTriangle, Star, RefreshCw, FolderGit2, GitMerge, Tag, HelpCircle, Trophy, BookOpen, ExternalLink } from "lucide-react"; | |||
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…arify labeling points rules in UI
|
Hey @Ixotic27 Thanks for the pr |
|
|
Hey @PRODHOSH, thanks a lot for testing this and providing the detailed feedback with the actual score breakdown screenshot! 🙏 You're absolutely right — the scoring formula I used was reverse-engineered from assumptions, and as you pointed out, GSSoC's actual scoring includes a lot of undisclosed factors like:
Since these constraints aren't publicly available and can't be tracked via GitHub API, I've rebranded the feature in the latest commit: Changes made:
This way the feature still provides useful activity insights (merged PRs count, labeled issues, opened issues, resolution time) without falsely claiming to replicate the official scoring. Regarding your point about looking up by project repo instead of username — that route already exists at Let me know if this approach works for you or if you'd like any further changes! 🚀 |
… and remove display tilde prefixes
|
Hey @PRODHOSH, Quick update: after aligning on the scope of the tracking formula, I decided to revert back to the original points formula (which counts all approved and merged contributor PRs in the repository, rather than filtering exclusively by What's new:
The build is green and the branch has been updated. Let me know what you think! 🚀 |
|
Hey @PRODHOSH, Quick follow-up: I identified and resolved a caching issue and corrected the PR counting logic. What was happening:
Changes made:
The local page now correctly computes 9,444 points (matching the original score) for |
|
Hi @PRODHOSH please assign me this pr as an assignee and close this pr |
|
Sry, i saw u made some changes. |
|
|
@Ixotic27 thank you so much for the pr |
Take your time |
|
@Ixotic27 hey bro can u work on this.... with the supabase setup sry for making u do it again currently im fetching and filtering by date, so i can fetch more than 1000 so ye, pls check the new code and create a new pr |
@PRODHOSH ok will work on it |
|
Hey @PRODHOSH! Created a new PR as requested: #10 Key improvements over the old approach:
SQL for the two new tables (pa_repos, pa_pull_requests) is in the PR description. Let me know if you need any changes! |








Adds a Project Admin tracking dashboard under /project-admin/[username], dynamic scoring engine for merge, label, open issue events, and resolution time boost. Also resolves Next.js dynamic path collision and adds dual-role cross-navigation notices.