diff --git a/src/components/dashboard/RepositoryList.tsx b/src/components/dashboard/RepositoryList.tsx
index 668f878..d2fc9ea 100644
--- a/src/components/dashboard/RepositoryList.tsx
+++ b/src/components/dashboard/RepositoryList.tsx
@@ -81,6 +81,11 @@ export function RepositoryList({ repositories }: RepositoryListProps) {
Private
)}
+ {repo.isForked && (
+
+ Fork
+
+ )}
- {org.repositoryCount}{" "}
- {org.repositoryCount === 1 ? "repository" : "repositories"}
-
+
diff --git a/src/components/repositories/RepositoryTable.tsx b/src/components/repositories/RepositoryTable.tsx
index 7fde87a..ca7aeec 100644
--- a/src/components/repositories/RepositoryTable.tsx
+++ b/src/components/repositories/RepositoryTable.tsx
@@ -249,6 +249,11 @@ export default function RepositoryTable({
Private
)}
+ {repo.isForked && (
+
+ Fork
+
+ )}
{/* Owner */}
diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts
index cfc60e8..87eb622 100644
--- a/src/lib/db/schema.ts
+++ b/src/lib/db/schema.ts
@@ -152,6 +152,9 @@ export const organizationSchema = z.object({
errorMessage: z.string().optional(),
repositoryCount: z.number().default(0),
+ publicRepositoryCount: z.number().optional(),
+ privateRepositoryCount: z.number().optional(),
+ forkRepositoryCount: z.number().optional(),
createdAt: z.date().default(() => new Date()),
updatedAt: z.date().default(() => new Date()),
diff --git a/src/pages/api/github/organizations.ts b/src/pages/api/github/organizations.ts
index 2bbe198..dbe42a4 100644
--- a/src/pages/api/github/organizations.ts
+++ b/src/pages/api/github/organizations.ts
@@ -1,7 +1,7 @@
import type { APIRoute } from "astro";
import { db } from "@/lib/db";
-import { organizations } from "@/lib/db";
-import { eq, sql } from "drizzle-orm";
+import { organizations, repositories, configs } from "@/lib/db";
+import { eq, sql, and, count } from "drizzle-orm";
import {
membershipRoleEnum,
type OrganizationsApiResponse,
@@ -25,24 +25,114 @@ export const GET: APIRoute = async ({ request }) => {
}
try {
+ // Fetch the user's active configuration to respect filtering settings
+ const [config] = await db
+ .select()
+ .from(configs)
+ .where(and(eq(configs.userId, userId), eq(configs.isActive, true)));
+
+ if (!config) {
+ return jsonResponse({
+ data: {
+ success: false,
+ error: "No active configuration found for this user",
+ },
+ status: 404,
+ });
+ }
+
+ const githubConfig = config.githubConfig as {
+ mirrorStarred: boolean;
+ skipForks: boolean;
+ privateRepositories: boolean;
+ };
+
const rawOrgs = await db
.select()
.from(organizations)
.where(eq(organizations.userId, userId))
.orderBy(sql`name COLLATE NOCASE`);
- const orgsWithIds: Organization[] = rawOrgs.map((org) => ({
- ...org,
- status: repoStatusEnum.parse(org.status),
- membershipRole: membershipRoleEnum.parse(org.membershipRole),
- lastMirrored: org.lastMirrored ?? undefined,
- errorMessage: org.errorMessage ?? undefined,
- }));
+ // Calculate repository breakdowns for each organization
+ const orgsWithBreakdown = await Promise.all(
+ rawOrgs.map(async (org) => {
+ // Build base conditions for this organization (without private/fork filters)
+ const baseConditions = [
+ eq(repositories.userId, userId),
+ eq(repositories.organization, org.name)
+ ];
+
+ if (!githubConfig.mirrorStarred) {
+ baseConditions.push(eq(repositories.isStarred, false));
+ }
+
+ // Get total count with all user config filters applied
+ const totalConditions = [...baseConditions];
+ if (githubConfig.skipForks) {
+ totalConditions.push(eq(repositories.isForked, false));
+ }
+ if (!githubConfig.privateRepositories) {
+ totalConditions.push(eq(repositories.isPrivate, false));
+ }
+
+ const [totalCount] = await db
+ .select({ count: count() })
+ .from(repositories)
+ .where(and(...totalConditions));
+
+ // Get public count
+ const publicConditions = [...baseConditions, eq(repositories.isPrivate, false)];
+ if (githubConfig.skipForks) {
+ publicConditions.push(eq(repositories.isForked, false));
+ }
+
+ const [publicCount] = await db
+ .select({ count: count() })
+ .from(repositories)
+ .where(and(...publicConditions));
+
+ // Get private count (only if private repos are enabled in config)
+ const [privateCount] = githubConfig.privateRepositories ? await db
+ .select({ count: count() })
+ .from(repositories)
+ .where(
+ and(
+ ...baseConditions,
+ eq(repositories.isPrivate, true),
+ ...(githubConfig.skipForks ? [eq(repositories.isForked, false)] : [])
+ )
+ ) : [{ count: 0 }];
+
+ // Get fork count (only if forks are enabled in config)
+ const [forkCount] = !githubConfig.skipForks ? await db
+ .select({ count: count() })
+ .from(repositories)
+ .where(
+ and(
+ ...baseConditions,
+ eq(repositories.isForked, true),
+ ...(!githubConfig.privateRepositories ? [eq(repositories.isPrivate, false)] : [])
+ )
+ ) : [{ count: 0 }];
+
+ return {
+ ...org,
+ status: repoStatusEnum.parse(org.status),
+ membershipRole: membershipRoleEnum.parse(org.membershipRole),
+ lastMirrored: org.lastMirrored ?? undefined,
+ errorMessage: org.errorMessage ?? undefined,
+ repositoryCount: totalCount.count,
+ publicRepositoryCount: publicCount.count,
+ privateRepositoryCount: privateCount.count,
+ forkRepositoryCount: forkCount.count,
+ };
+ })
+ );
const resPayload: OrganizationsApiResponse = {
success: true,
message: "Organizations fetched successfully",
- organizations: orgsWithIds,
+ organizations: orgsWithBreakdown,
};
return jsonResponse({ data: resPayload, status: 200 });
diff --git a/src/types/organizations.ts b/src/types/organizations.ts
index c829870..4b0927e 100644
--- a/src/types/organizations.ts
+++ b/src/types/organizations.ts
@@ -33,6 +33,9 @@ export interface GitOrg {
isIncluded: boolean;
status: RepoStatus;
repositoryCount: number;
+ publicRepositoryCount?: number;
+ privateRepositoryCount?: number;
+ forkRepositoryCount?: number;
createdAt: Date;
updatedAt: Date;
}