- {table.getFilteredRowModel().rows.length} {data.length > 1 ? 'repositories' : 'repository'} total
+ {totalCount} {totalCount !== 1 ? 'repositories' : 'repository'} total
+ {totalPages > 1 && ` • Page ${currentPage} of ${totalPages}`}
-
diff --git a/packages/web/src/app/[domain]/repos/page.tsx b/packages/web/src/app/[domain]/repos/page.tsx
index 79c4497b..476228dd 100644
--- a/packages/web/src/app/[domain]/repos/page.tsx
+++ b/packages/web/src/app/[domain]/repos/page.tsx
@@ -3,30 +3,49 @@ import { ServiceErrorException } from "@/lib/serviceError";
import { isServiceError } from "@/lib/utils";
import { withOptionalAuthV2 } from "@/withAuthV2";
import { ReposTable } from "./components/reposTable";
-import { RepoIndexingJobStatus } from "@sourcebot/db";
+import { RepoIndexingJobStatus, Prisma } from "@sourcebot/db";
+import z from "zod";
-export default async function ReposPage() {
+interface ReposPageProps {
+ searchParams: Promise<{
+ page?: string;
+ pageSize?: string;
+ search?: string;
+ status?: string;
+ sortBy?: string;
+ sortOrder?: string;
+ }>;
+}
+
+export default async function ReposPage({ searchParams }: ReposPageProps) {
+ const params = await searchParams;
+
+ // Parse pagination parameters with defaults
+ const page = z.number().int().positive().safeParse(params.page).data ?? 1;
+ const pageSize = z.number().int().positive().safeParse(params.pageSize).data ?? 5;
- const _repos = await getReposWithLatestJob();
- if (isServiceError(_repos)) {
- throw new ServiceErrorException(_repos);
+ // Parse filter parameters
+ const search = z.string().optional().safeParse(params.search).data ?? '';
+ const status = z.enum(['all', 'none', 'COMPLETED', 'IN_PROGRESS', 'PENDING', 'FAILED']).safeParse(params.status).data ?? 'all';
+ const sortBy = z.enum(['displayName', 'indexedAt']).safeParse(params.sortBy).data ?? undefined;
+ const sortOrder = z.enum(['asc', 'desc']).safeParse(params.sortOrder).data ?? 'asc';
+
+ // Calculate skip for pagination
+ const skip = (page - 1) * pageSize;
+
+ const _result = await getRepos({
+ skip,
+ take: pageSize,
+ search,
+ status,
+ sortBy,
+ sortOrder,
+ });
+ if (isServiceError(_result)) {
+ throw new ServiceErrorException(_result);
}
- const repos = _repos
- .map((repo) => ({
- ...repo,
- latestJobStatus: repo.jobs.length > 0 ? repo.jobs[0].status : null,
- isFirstTimeIndex: repo.indexedAt === null && repo.jobs.filter((job) => job.status === RepoIndexingJobStatus.PENDING || job.status === RepoIndexingJobStatus.IN_PROGRESS).length > 0,
- }))
- .sort((a, b) => {
- if (a.isFirstTimeIndex && !b.isFirstTimeIndex) {
- return -1;
- }
- if (!a.isFirstTimeIndex && b.isFirstTimeIndex) {
- return 1;
- }
- return a.name.localeCompare(b.name);
- });
+ const { repos, totalCount, stats } = _result;
return (
<>
@@ -34,42 +53,129 @@ export default async function ReposPage() {
Repositories
View and manage your code repositories and their indexing status.