Skip to content

feat: add shareable deep-link for individual repo modals#822

Merged
Sachinchaurasiya360 merged 1 commit into
Sachinchaurasiya360:mainfrom
Rajal-ui:feat/repo-deep-link-shareable-url
May 30, 2026
Merged

feat: add shareable deep-link for individual repo modals#822
Sachinchaurasiya360 merged 1 commit into
Sachinchaurasiya360:mainfrom
Rajal-ui:feat/repo-deep-link-shareable-url

Conversation

@Rajal-ui

@Rajal-ui Rajal-ui commented May 30, 2026

Copy link
Copy Markdown
Contributor

Description

Repo detail modals had no URL — closing the tab or sharing a link lost the specific repo entirely. Students could not bookmark or share individual repos with peers.

Changes:

  • URL updates to ?repo= when any repo modal opens
  • URL param removed cleanly when modal closes
  • Pasting the URL in a new tab fetches and opens the correct modal
  • Invalid or deleted repo IDs silently ignored — no broken state
  • Share button in modal header copies full URL with ?repo= param
  • "Copied!" feedback for 1.5s then resets
  • replace: true keeps browser back button behavior natural

Related Issue

Fixes #703

Type of Change

  • Feature

Testing

  1. Open any repo modal → URL shows ?repo=123
  2. Close modal → URL param removed
  3. Copy URL, open in new tab → correct modal opens automatically
  4. Manually edit URL to ?repo=99999 → silently ignored, no crash
  5. Click Share button → "Copied!" appears for 1.5s
  6. Paste copied URL → opens correct repo modal
  7. Back button works naturally after closing modal

Screenshots

image
image

Checklist

  • Code follows project guidelines
  • No new compile/type errors
  • Tested manually
  • No .env, credentials, or node_modules committed
  • Screenshots added for UI changes

Summary by CodeRabbit

  • New Features
    • Repository deep-linking—users can now share direct links to specific repositories and access them via URL
    • Share button in repo detail modal allows copying repository links to clipboard with "Copied!" confirmation feedback
    • Improved modal interactions with enhanced close button handling

Review Change Stack

- Update URL with ?repo=<id> when modal opens (replace: true)
- Remove repo param when modal closes
- On mount read ?repo= param and open correct modal
- Fetch repo by ID on mount if param present
- Silently ignore invalid or 404 repo IDs
- Add Share button in modal header copies URL to clipboard
- Share button shows Copied! for 1.5s then resets
- replace: true keeps back button behavior natural
- Resolves Sachinchaurasiya360#703
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

RepoDiscoveryPage now supports deep-linking to individual repos via URL query parameters (?repo=<id>), fetches repo data from the URL on page load, and provides a Share button in the modal header. Opening a repo card or loading a shareable URL updates the URL params and opens the detail modal; closing the modal clears the params. The Share button copies the current page URL to clipboard with temporary UI feedback.

Changes

Repo Deep-Linking and Share Functionality

Layer / File(s) Summary
Imports and UI icons
client/src/module/student/opensource/RepoDiscoveryPage.tsx (lines 2, 23–24)
Add useSearchParams import from React Router and extend lucide icons with Share2 and Check for share button state rendering.
URL-driven deep-linking and share logic
client/src/module/student/opensource/RepoDiscoveryPage.tsx (lines 65–105)
Introduce copiedShareUrl state for clipboard feedback, initialize useSearchParams hook, define handleOpenRepo and handleCloseRepo to set/clear the repo query param, add useQuery to fetch repo data from the URL param on mount, sync component state on successful fetch, clear URL on fetch error, and implement handleShare to copy the shareable URL and toggle button feedback.
Modal integration and header UI
client/src/module/student/opensource/RepoDiscoveryPage.tsx (lines 438, 467, 495–525)
Wire RepoCard selection to handleOpenRepo, connect modal backdrop click to handleCloseRepo, replace modal header with two-button layout: Share button that conditionally renders "Share" or "Copied!" based on clipboard state and calls handleShare, plus explicit close button wired to handleCloseRepo.

Sequence Diagram

sequenceDiagram
  participant User
  participant RepoCard
  participant RepoDiscoveryPage
  participant URLSearchParams
  participant useQuery
  participant Clipboard
  
  Note over User,Clipboard: User opens repo from card
  User->>RepoCard: clicks repo card
  RepoCard->>RepoDiscoveryPage: onSelect(repo)
  RepoDiscoveryPage->>RepoDiscoveryPage: handleOpenRepo(repo.id)
  RepoDiscoveryPage->>URLSearchParams: setSearchParams({repo: id})
  RepoDiscoveryPage->>RepoDiscoveryPage: setSelectedRepo(repo)
  
  Note over User,Clipboard: Deep-link: user visits URL with ?repo=id
  User->>RepoDiscoveryPage: page load with ?repo=id
  RepoDiscoveryPage->>useQuery: fetch /api/opensource/:id
  useQuery-->>RepoDiscoveryPage: repo data
  RepoDiscoveryPage->>RepoDiscoveryPage: setSelectedRepo(repo)
  
  Note over User,Clipboard: User shares repo
  User->>RepoDiscoveryPage: clicks Share button
  RepoDiscoveryPage->>RepoDiscoveryPage: handleShare()
  RepoDiscoveryPage->>Clipboard: copy window.location.href
  RepoDiscoveryPage->>RepoDiscoveryPage: setCopiedShareUrl(true)
  Note right of RepoDiscoveryPage: Button shows "Copied!" for ~2s
  
  Note over User,Clipboard: User closes modal
  User->>RepoDiscoveryPage: backdrop click or close button
  RepoDiscoveryPage->>RepoDiscoveryPage: handleCloseRepo()
  RepoDiscoveryPage->>URLSearchParams: clearSearchParams()
  RepoDiscoveryPage->>RepoDiscoveryPage: setSelectedRepo(null)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #674: Both changes add URL query param handling via useSearchParams to RepoDiscoveryPage.tsx; this PR implements repo deep-linking while #674 implements filter persistence, which could interact if both are used together.
  • #707: Both changes implement repo deep-link handling (?repo=id URL param reading/loading) in RepoDiscoveryPage.tsx and should be reviewed together for consistency.

Poem

🐰 A link, a share, a modal bright,
?repo=id shines in the night,
Share button gleams with a copied cheer—
Now peers can bookmark repos dear! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: adding shareable deep-links (URL query params) for individual repo modals.
Description check ✅ Passed The PR description includes all required template sections: description of changes, related issue, type of change, detailed testing steps, and screenshots demonstrating the new functionality.
Linked Issues check ✅ Passed All acceptance criteria from issue #703 are addressed: URL updates with ?repo= on open, loading URL opens correct modal, Share button copies URL, and closing removes param.
Out of Scope Changes check ✅ Passed All changes are scoped to the linked issue #703: URL deep-linking, repo modal state management, and share functionality. No unrelated modifications detected.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
client/src/module/student/opensource/RepoDiscoveryPage.tsx (1)

496-524: 💤 Low value

Consider using the reusable Button component for new buttons.

The close button at lines 517-524 could use Button with variant="ghost" and mode="icon". The share button has state-dependent styling that may require custom classes, but the close button is a good candidate.

As per coding guidelines: "Use the reusable Button component from client/src/components/ui/button.tsx for all new buttons".

🤖 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 `@client/src/module/student/opensource/RepoDiscoveryPage.tsx` around lines 496
- 524, Replace the plain close <button> with the shared Button component to
follow UI guidelines: locate the close handler usage (onClick={handleCloseRepo})
and the X icon markup in RepoDiscoveryPage and swap the raw <button> for the
reusable Button from client/src/components/ui/button.tsx, passing
variant="ghost", mode="icon", aria-label="Close", and keep the
onClick={handleCloseRepo} and the <X /> child so behavior and accessibility
remain identical; leave the share button as-is since it has custom state
styling.
🤖 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 `@client/src/module/student/opensource/RepoDiscoveryPage.tsx`:
- Around line 101-105: The handleShare function currently calls
navigator.clipboard.writeText without handling Promise rejections; update
handleShare to be async and follow the existing ShareButton pattern: if
navigator.share is available, call it first inside try/catch, otherwise await
navigator.clipboard.writeText(window.location.href) inside try/catch, and on
success call setCopiedShareUrl(true) with the existing timeout; on failure catch
and log/report the error and optionally show a fallback UI message. Reference
the handleShare function and the setCopiedShareUrl state to implement these
changes.

---

Nitpick comments:
In `@client/src/module/student/opensource/RepoDiscoveryPage.tsx`:
- Around line 496-524: Replace the plain close <button> with the shared Button
component to follow UI guidelines: locate the close handler usage
(onClick={handleCloseRepo}) and the X icon markup in RepoDiscoveryPage and swap
the raw <button> for the reusable Button from
client/src/components/ui/button.tsx, passing variant="ghost", mode="icon",
aria-label="Close", and keep the onClick={handleCloseRepo} and the <X /> child
so behavior and accessibility remain identical; leave the share button as-is
since it has custom state styling.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 510ce5c0-d6ec-4031-9f0e-712c0b942127

📥 Commits

Reviewing files that changed from the base of the PR and between 6446d69 and 350ca2a.

📒 Files selected for processing (1)
  • client/src/module/student/opensource/RepoDiscoveryPage.tsx

Comment on lines +101 to +105
const handleShare = () => {
navigator.clipboard.writeText(window.location.href);
setCopiedShareUrl(true);
setTimeout(() => setCopiedShareUrl(false), 1500);
};

Copy link
Copy Markdown
Contributor

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

Add error handling for clipboard API.

navigator.clipboard.writeText() returns a Promise that can reject (e.g., permission denied, non-secure context). The existing ShareButton.tsx in the codebase uses async/await with try/catch and also leverages navigator.share as the primary method when available.

🛡️ Proposed fix following codebase pattern
- const handleShare = () => {
-   navigator.clipboard.writeText(window.location.href);
-   setCopiedShareUrl(true);
-   setTimeout(() => setCopiedShareUrl(false), 1500);
- };
+ const handleShare = async () => {
+   try {
+     await navigator.clipboard.writeText(window.location.href);
+     setCopiedShareUrl(true);
+     setTimeout(() => setCopiedShareUrl(false), 1500);
+   } catch (error) {
+     console.error("Failed to copy URL:", error);
+   }
+ };
🤖 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 `@client/src/module/student/opensource/RepoDiscoveryPage.tsx` around lines 101
- 105, The handleShare function currently calls navigator.clipboard.writeText
without handling Promise rejections; update handleShare to be async and follow
the existing ShareButton pattern: if navigator.share is available, call it first
inside try/catch, otherwise await
navigator.clipboard.writeText(window.location.href) inside try/catch, and on
success call setCopiedShareUrl(true) with the existing timeout; on failure catch
and log/report the error and optionally show a fallback UI message. Reference
the handleShare function and the setCopiedShareUrl state to implement these
changes.

@Sachinchaurasiya360 Sachinchaurasiya360 added level:beginner Good for first-time contributors type:feature New feature implementation labels May 30, 2026

@Sachinchaurasiya360 Sachinchaurasiya360 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Review: Changes Requested

Deep-linking for repo modals is a great UX improvement — bookmarking and sharing individual repos are real needs. Two issues must be fixed before merging.

1. Clipboard API rejection not handled

handleShare calls navigator.clipboard.writeText() without awaiting the Promise or handling rejection. If the clipboard write fails (e.g., page loses focus, non-secure context, permissions denied), the user still sees the "Copied!" confirmation even though nothing was copied. Fix:

const copyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

const handleShare = async () => {
  try {
    await navigator.clipboard.writeText(window.location.href);
    if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
    setCopiedShareUrl(true);
    copyTimerRef.current = setTimeout(() => setCopiedShareUrl(false), 1500);
  } catch {
    // silently fail — user's clipboard is unavailable
  }
};

2. Close button should use the shared Button component

The close button (around lines 517-524) is a raw <button> element. Per CLAUDE.md, all new buttons must use the shared Button from client/src/components/ui/button.tsx:

import { Button } from "../../components/ui/button";

<Button
  mode="icon"
  variant="ghost"
  onClick={handleCloseRepo}
  aria-label="Close"
>
  <X className="h-4 w-4" />
</Button>

Please fix both items. The deep-link logic itself (URL param on open, clean removal on close, auto-open on page load) is correct and well-implemented.

@Sachinchaurasiya360 Sachinchaurasiya360 added the gssoc:approved Approved for GSSoC scoring label May 30, 2026
@Sachinchaurasiya360 Sachinchaurasiya360 merged commit 85e9bde into Sachinchaurasiya360:main May 30, 2026
4 of 5 checks passed
@Rajal-ui

Rajal-ui commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Hey @Sachinchaurasiya360! 👋
Thanks for the contribution! Just noticed we could strengthen the label set for better scoring. Currently, we have gssoc:approved, level:beginner, and type:feature—all great!
Could you review and add one of these quality labels if applicable? quality:clean or quality:exceptional would help showcase the code quality and boost the points multiplier.
If any other labels from the official set fit (like type:accessibility, type:design, type:devops, etc.), those would be awesome too!

Thanks! 🙌

@Sachinchaurasiya360 Sachinchaurasiya360 added good first issue Good for newcomers level:intermediate Requires moderate project understanding level:critical High-impact or critical changes quality:clean Clean and well-structured contribution quality:exceptional Exceptional implementation quality type:accessibility Accessibility improvements labels Jun 1, 2026
@Rajal-ui Rajal-ui deleted the feat/repo-deep-link-shareable-url branch June 5, 2026 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good first issue Good for newcomers gssoc:approved Approved for GSSoC scoring level:beginner Good for first-time contributors level:critical High-impact or critical changes level:intermediate Requires moderate project understanding quality:clean Clean and well-structured contribution quality:exceptional Exceptional implementation quality type:accessibility Accessibility improvements type:feature New feature implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add shareable deep-link for individual repos (URL opens with modal pre-opened)

2 participants