Skip to content

feat: Add repo pinning — pin up to 3 repos in TopRepos #221#302

Open
pawanakapkv wants to merge 5 commits into
Priyanshu-byte-coder:mainfrom
pawanakapkv:feat/repo-pinning-221
Open

feat: Add repo pinning — pin up to 3 repos in TopRepos #221#302
pawanakapkv wants to merge 5 commits into
Priyanshu-byte-coder:mainfrom
pawanakapkv:feat/repo-pinning-221

Conversation

@pawanakapkv
Copy link
Copy Markdown

Summary

Resolves #221
This PR implements the "Repo Pinning" feature in the TopRepos widget, allowing users to pin up to 3 of their repositories so they always appear at the top of the list for permanent visibility.

Closes #221

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactor / code cleanup

Changes Made

  • Frontend (TopRepos.tsx):
    • Added a pinnedRepos state hooked up to /api/user/settings via GET to load existing pins.
    • Injected an interactive pin icon on each repository row with optimistic UI updates for pinning/unpinning.
    • Enforced a max 3-pin limit via a frontend alert.
    • Dynamically sorted the rendered list so pinned repositories naturally stay at the top in the exact order they were pinned, while unpinned repos retain their current sort order.
  • Backend (route.ts):
    • Updated the /api/user/settings GET endpoint to include the pinned_repos column.
    • Refactored the PATCH endpoint to use a dynamic update payload, successfully processing updates for pinned_repos and is_public independently. Added validation for the 3-pin limit on the backend.
  • Database:
    • Created a Supabase migration script (20260518000000_add_pinned_repos_to_users.sql) to add the pinned_repos text[] column to the users table, including a DB-level constraint to ensure a maximum of 3 pins.

How to Test

Steps for the reviewer to verify this works:

  1. Apply the new Supabase migration locally to add the pinned_repos column to your database.
  2. Run the application and log in. Navigate to the dashboard where the TopRepos widget is displayed.
  3. Click the pin icon on any repository. It should instantly jump to the top of the list and turn blue.
  4. Pin 3 repositories. Try to pin a 4th — you should get an alert preventing you from doing so.
  5. Refresh the page to verify that the pins persist correctly and remain at the top.

Screenshots (if UI change)

Dark Mode:
localhost_3000_dashboard (1)
Screenshot 2026-05-18 010410
Screenshot 2026-05-18 010422

Max Alert:
image

Light Mode:
localhost_3000_dashboard
Screenshot 2026-05-18 010443
Screenshot 2026-05-18 010433

Checklist

  • Linked issue in summary
  • npm run lint passes locally
  • No TypeScript errors (npm run type-check)
  • Self-reviewed the diff
  • Added/updated tests if applicable

@vercel
Copy link
Copy Markdown

vercel Bot commented May 17, 2026

@pawanakapkv is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Thanks for your first PR on DevTrack! 🎉

A maintainer will review it within 48 hours. While you wait:

  • Make sure CI is passing (type-check + lint)
  • Double-check the PR description is filled out and the issue is linked
  • Feel free to ask questions in Discussions if you need help

@Priyanshu-byte-coder
Copy link
Copy Markdown
Owner

Good feature — DB migration with constraint, optimistic update, 3-pin limit at both API and DB layer. A few things to fix before merge:

Conflict: PR #303 (sortable columns) just merged and touched TopRepos.tsx. Please rebase:

git fetch upstream && git rebase upstream/main

Hardcoded colors to replace with CSS vars:

// pin icon className — replace:
className={isPinned ? "text-blue-500" : "text-gray-400"}
// with:
className={isPinned ? "text-[var(--accent)]" : "text-[var(--muted-foreground)]"}

// Pinned badge — replace bg-blue-500/10, text-blue-400, ring-blue-500/20:
className="ml-2 inline-flex items-center rounded-md bg-[color-mix(in_srgb,var(--accent)_10%,transparent)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--accent)] ring-1 ring-inset ring-[color-mix(in_srgb,var(--accent)_20%,transparent)] align-middle"

Minor: Add aria-label to the pin button (title alone not enough for screen readers):

aria-label={isPinned ? `Unpin ` : `Pin `}

Fix these and push — will merge.

@pawanakapkv pawanakapkv force-pushed the feat/repo-pinning-221 branch from 825a105 to a9afc89 Compare May 19, 2026 09:56
@pawanakapkv
Copy link
Copy Markdown
Author

Hi @Priyanshu-byte-coder,

Thanks for the excellent feedback! I have resolved the conflicts and updated the implementation according to your recommendations.

Here is what has been updated:

  1. Rebase & Conflict Resolution Completed 🔄

    • Successfully rebased against the latest upstream/main (resolving the merge conflict with PR feat(toprepos): add sortable columns with asc/desc toggle #303).
    • Integrated the sorting and pinning logic dynamically: Pinned repositories will now always remain at the top in their exact pin order, while the remaining unpinned repositories below them will respect the newly introduced column sorting (commits or name) and sort directions (asc/desc).
    • Calculated maxCommits dynamically across all repositories to prevent bar width overflows when a pinned repository with fewer commits floats to the top.
  2. Replaced Hardcoded Colors with CSS Variables 🎨

    • Pin Button: Uses text-[var(--accent)] when pinned and text-[var(--muted-foreground)] when unpinned.
    • Pinned Badge: Switched to semantic CSS variable mixtures:
      • Background: bg-[color-mix(in_srgb,var(--accent)_10%,transparent)]
      • Border Ring: ring-[color-mix(in_srgb,var(--accent)_20%,transparent)]
      • Text: text-[var(--accent)]
  3. Accessibility Improvements

    • Added descriptive aria-label={isPinned ? Unpin ${repo.name}:Pin ${repo.name}} to the pin button for screen readers.

All local lints and type checks pass cleanly (npm run lint successfully returns 0). I have force-pushed the clean, updated commits to my branch. Ready for your final review and merge!

Copy link
Copy Markdown
Owner

@Priyanshu-byte-coder Priyanshu-byte-coder left a comment

Choose a reason for hiding this comment

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

Changes Required

1. Replace alert() with inline error state
alert("Maximum 3 pins allowed") uses the native browser dialog which is jarring in a modern UI and blocks the main thread. Use an inline error message instead:

const [pinError, setPinError] = useState<string | null>(null);

// In togglePin:
if (pinnedRepos.length >= 3) {
  setPinError("Maximum 3 pins allowed");
  return;
}
setPinError(null);

// In JSX (near the widget header):
{pinError && (
  <p className="text-xs text-[var(--destructive)]">{pinError}</p>
)}

2. Record<string, any> in settings/route.ts

const updates: Record<string, any> = {};

Use a typed interface:

const updates: { is_public?: boolean; pinned_repos?: string[] } = {};

The overall implementation is solid — optimistic UI with rollback, backend + DB-level 3-pin validation, and correct pin-first sort ordering. Address the two items above and this is ready to merge.

@Priyanshu-byte-coder Priyanshu-byte-coder added level:intermediate GSSoC: Intermediate difficulty (35 pts) gssoc26 GSSoC 2026 contribution labels May 20, 2026
@github-actions github-actions Bot added the type:feature GSSoC type bonus: new feature label May 20, 2026
@pawanakapkv
Copy link
Copy Markdown
Author

Hey @Priyanshu-byte-coder! 👋

Just a quick heads-up that I've pushed the requested changes for the pinning feature and merged the latest main branch to keep everything perfectly synced.

Could you please take another look when you have a moment? Let me know if there are any other adjustments you need me to make, or if we are good to merge! 🚀

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

Labels

gssoc26 GSSoC 2026 contribution level:intermediate GSSoC: Intermediate difficulty (35 pts) type:feature GSSoC type bonus: new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Add repo pinning — pin up to 3 repos in TopRepos for permanent visibility

2 participants