Skip to content

Conversation

@brendan-kellam
Copy link
Contributor

@brendan-kellam brendan-kellam commented Dec 17, 2025

This PR improves the /repos page performance by adding server-side pagination.

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR refactors the repositories listing page to implement URL-driven pagination and search, introduces a new InputGroup UI component system, updates repository data fetching with filter and pagination support, and restructures test data injection to create per-repo job records with randomized statuses.

Changes

Cohort / File(s) Summary
Test Data Injection
packages/db/tools/scripts/inject-repo-data.ts
Reduces NUM_REPOS from 100,000 to 1,000; adds constants for per-repo permission and indexing jobs (NUM_PERMISSION_JOBS_PER_REPO and NUM_INDEXING_JOBS_PER_REPO, both 10,000); restructures creation loop to generate repoPermissionSyncJob and repoIndexingJob records per repo with randomized statuses, completion states, and error messages.
Repositories Page & Data Fetching
packages/web/src/app/[domain]/repos/page.tsx
Refactors ReposPage to accept searchParams; implements skip/take pagination and URL query filtering; updates getReposWithLatestJob to accept filter object (skip, take, search, status) and return object with repos and totalCount; adds where clause for name/displayName search and updates sorting by indexedAt and name.
Repositories Table Component
packages/web/src/app/[domain]/repos/components/reposTable.tsx
Migrates from internal React-Table filtering to URL query parameter-driven state; introduces debounced search, URL-synced pagination, and status filtering; updates component signature to accept currentPage, pageSize, totalCount, initialSearch, and initialStatus props; replaces inline input with InputGroup component; adds loading indicator for pending searches.
UI Components
packages/web/src/components/ui/input-group.tsx
Introduces new InputGroup component system with subcomponents: InputGroup (wrapper), InputGroupAddon (addon container with alignment variants), InputGroupButton (button wrapper), InputGroupText (text adornment), InputGroupInput (input element), and InputGroupTextarea (textarea element); all use class-variance-authority for variant-based styling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • File cohort spread and heterogeneity: Changes span test data generation, page-level data fetching logic, table component refactoring, and new UI component library—each with distinct concerns and no repetitive patterns.
  • State management pattern shift: Table component migration from internal React-Table state to URL-driven state requires careful validation of query parameter handling, debouncing, and page reset logic on search/filter changes.
  • Data fetching changes: Updates to getReposWithLatestJob introduce new parameter structure and return shape; verify where clause logic, totalCount computation, and sorting behavior (especially nulls-first for indexedAt).
  • Component signature breaking change: ReposTable props expanded significantly; confirm all call sites properly supply new pagination and filter initialization props.
  • New UI component integration: InputGroup and related subcomponents introduce styling via cva; verify variant combinations work as intended and integrate cleanly with existing design system.

Possibly related PRs

Suggested labels

sourcebot-team

Suggested reviewers

  • msukkari

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main objective of the changeset: implementing pagination and URL-driven search/filtering to improve performance on the /repos page.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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.

@brendan-kellam
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/app/[domain]/repos/components/reposTable.tsx (1)

151-156: Typo: "Lastest" should be "Latest".

     {
         accessorKey: "latestJobStatus",
         size: 150,
-        header: "Lastest status",
+        header: "Latest status",
         cell: ({ row }) => getStatusBadge(row.getValue("latestJobStatus")),
     },
🧹 Nitpick comments (3)
packages/db/tools/scripts/inject-repo-data.ts (1)

37-91: Inconsistent indentation breaks code style.

Lines 37-91 use 4-space indentation while the surrounding code uses 8-space indentation (inside the run function body). This appears to be an accidental de-indent.

packages/web/src/app/[domain]/repos/page.tsx (1)

90-98: Use Prisma.QueryMode enum for type safety.

The mode: 'insensitive' string literal works but using the Prisma enum provides better type safety and IDE support:

 const whereClause: Prisma.RepoWhereInput = {
     orgId: org.id,
     ...(search && {
         OR: [
-            { name: { contains: search, mode: 'insensitive' } },
-            { displayName: { contains: search, mode: 'insensitive' } }
+            { name: { contains: search, mode: Prisma.QueryMode.insensitive } },
+            { displayName: { contains: search, mode: Prisma.QueryMode.insensitive } }
         ]
     }),
 };
packages/web/src/app/[domain]/repos/components/reposTable.tsx (1)

306-326: Cleanup function may prematurely hide the loading indicator.

The cleanup function sets setIsPendingSearch(false) which runs on every re-render before the new effect runs. This could cause a brief flicker where the loader disappears and reappears. Consider only clearing the pending state when the navigation completes:

     useEffect(() => {
         setIsPendingSearch(true);
         const timer = setTimeout(() => {
             const params = new URLSearchParams(searchParams.toString());
             if (searchValue) {
                 params.set('search', searchValue);
             } else {
                 params.delete('search');
             }
             params.set('page', '1');
             router.replace(`${pathname}?${params.toString()}`);
             setIsPendingSearch(false);
         }, 300);
         
-        return () => {
-            clearTimeout(timer);
-            setIsPendingSearch(false);
-        };
+        return () => clearTimeout(timer);
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [searchValue]);

The pending state will be reset when the navigation completes and the component re-renders with new data.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b36e550 and 09d05a5.

📒 Files selected for processing (4)
  • packages/db/tools/scripts/inject-repo-data.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/components/reposTable.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/page.tsx (2 hunks)
  • packages/web/src/components/ui/input-group.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/web/src/components/ui/input-group.tsx (4)
packages/web/src/lib/utils.ts (1)
  • cn (24-26)
packages/web/src/components/ui/button.tsx (1)
  • Button (56-56)
packages/web/src/components/ui/input.tsx (1)
  • Input (22-22)
packages/web/src/components/ui/textarea.tsx (1)
  • Textarea (22-22)
packages/web/src/app/[domain]/repos/page.tsx (5)
packages/web/src/lib/utils.ts (1)
  • isServiceError (438-444)
packages/web/src/lib/serviceError.ts (1)
  • ServiceErrorException (16-20)
packages/web/src/app/[domain]/repos/components/reposTable.tsx (1)
  • ReposTable (281-481)
packages/web/src/actions.ts (1)
  • sew (44-57)
packages/web/src/withAuthV2.ts (1)
  • withOptionalAuthV2 (43-67)
🔇 Additional comments (5)
packages/web/src/app/[domain]/repos/page.tsx (2)

81-86: The status parameter is accepted but not used in filtering.

The status parameter is passed to getReposWithLatestJob but the whereClause doesn't filter by it. This aligns with the PR TODO "Fix status filtering" but worth noting for tracking.


43-47: The isFirstTimeIndex logic looks correct for single-job fetch.

The filter on repo.jobs works correctly since take: 1 fetches only the latest job. The logic correctly identifies repos that haven't been indexed yet but have a pending/in-progress job.

packages/web/src/components/ui/input-group.tsx (1)

11-37: Well-designed InputGroup wrapper with comprehensive styling.

The use of CSS has-[] selectors for focus/error state propagation and alignment variants is a clean approach that keeps the components loosely coupled while maintaining visual cohesion.

packages/web/src/app/[domain]/repos/components/reposTable.tsx (2)

300-304: Nice UX: keyboard shortcut for search focus.

The / hotkey for focusing the search input is a good developer-friendly UX pattern commonly seen in documentation sites and GitHub.


272-288: Clean URL-driven state management.

The prop-based approach with currentPage, pageSize, totalCount, initialSearch, and initialStatus properly separates server-provided state from client-side URL manipulation. This aligns well with Next.js App Router patterns.

@brendan-kellam brendan-kellam force-pushed the bkellam/paginated-repos-SOU-158 branch from 10d1647 to 2ccdebc Compare December 18, 2025 18:15
@brendan-kellam brendan-kellam marked this pull request as ready for review December 18, 2025 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant