import type { ProjectSummary, RunStatus } from "@/contracts";
import { useQuery } from "@tanstack/react-query";
import { FolderGit2, FolderPlus, GitBranch, RefreshCw } from "lucide-react";
import { Link } from "react-router-dom";
import { useAuth } from "@/client/auth";
import { StatusPill } from "@/client/components";
import { Badge, Button, ButtonLink, EmptyState, ErrorBanner, PageHeader, Skeleton } from "@/client/components/ui";
import {
formatApiError,
formatProjectUpdatedLabel,
getApiClient,
inferRepositoryProvider,
queryKeys,
} from "@/client/lib";
const countByStatus = (projects: ProjectSummary[], target: RunStatus): number =>
projects.filter((project) => project.lastRunStatus === target).length;
const ProjectCard = ({ project }: { project: ProjectSummary }) => (
{project.name}
{project.ownerSlug}/{project.projectSlug}
{inferRepositoryProvider(project.repoUrl)}
{project.defaultBranch}
updated {formatProjectUpdatedLabel(project)}
);
const ProjectCardSkeleton = () => (
);
export const ProjectsPage = () => {
const { user } = useAuth();
const userId = user?.id ?? "";
const projectsQuery = useQuery({
queryKey: queryKeys.projects(userId),
queryFn: () => getApiClient().getProjects(),
enabled: userId.length > 0,
});
const projects = projectsQuery.data?.projects ?? [];
const loading = projectsQuery.isPending;
const error = projectsQuery.isError ? formatApiError(projectsQuery.error) : null;
const activeCount =
countByStatus(projects, "queued") +
countByStatus(projects, "starting") +
countByStatus(projects, "running") +
countByStatus(projects, "cancel_requested") +
countByStatus(projects, "canceling");
const healthyCount = countByStatus(projects, "passed");
return (
0
? `${projects.length} project${projects.length !== 1 ? "s" : ""} \u00b7 ${activeCount} active, ${healthyCount} passing`
: undefined
}
actions={
<>
New Project
}
aria-label="Refresh"
onClick={() => {
void projectsQuery.refetch();
}}
/>
>
}
/>
{error ? : null}
{loading ? (
{Array.from({ length: 4 }, (_, i) => (
))}
) : projects.length === 0 ? (
}
title="No projects yet"
description="Create the first repository connection for this workspace."
action={
Create Project
}
/>
) : (
{projects.map((project) => (
))}
)}
);
};