-
- {projects.data.map((project) => {
- // Find active deployment and associated domain for this project
- const activeDeployment = project.liveDeploymentId
- ? allDeployments.find((d) => d.id === project.liveDeploymentId)
- : null;
-
- // Find domain for this project
- const projectDomain = allDomains.find((d) => d.projectId === project.id);
-
- // Extract deployment regions for display
- const regions = activeDeployment?.runtimeConfig?.regions?.map((r) => r.region) ?? [];
-
- return (
-
0 ? regions : ["No deployments"]}
- repository={project.gitRepositoryUrl || undefined}
- actions={
-
-
-
-
-
- }
- />
- );
- })}
-
+
+
+ {projects.data.map((project) => (
+
+
+
+
+
+ }
+ />
+ ))}
- >
+
);
};
diff --git a/apps/dashboard/app/(app)/projects/_components/list/projects-card.tsx b/apps/dashboard/app/(app)/projects/_components/list/projects-card.tsx
index 9cb0edb8c0..15a80fd4fe 100644
--- a/apps/dashboard/app/(app)/projects/_components/list/projects-card.tsx
+++ b/apps/dashboard/app/(app)/projects/_components/list/projects-card.tsx
@@ -9,7 +9,7 @@ type ProjectCardProps = {
name: string;
domain: string;
commitTitle: string;
- commitTimestamp?: number;
+ commitTimestamp?: number | null;
branch: string;
author: string;
regions: string[];
diff --git a/apps/dashboard/lib/collections/deploy/projects.ts b/apps/dashboard/lib/collections/deploy/projects.ts
index ee5a22ec24..8ff351c45d 100644
--- a/apps/dashboard/lib/collections/deploy/projects.ts
+++ b/apps/dashboard/lib/collections/deploy/projects.ts
@@ -11,6 +11,14 @@ const schema = z.object({
gitRepositoryUrl: z.string().nullable(),
updatedAt: z.number().int().nullable(),
liveDeploymentId: z.string().nullable(),
+ // Flattened deployment fields for UI
+ commitTitle: z.string(),
+ branch: z.string(),
+ author: z.string(),
+ commitTimestamp: z.number().int().nullable(),
+ regions: z.array(z.string()),
+ // Domain field
+ domain: z.string(),
});
export const createProjectRequestSchema = z.object({
diff --git a/apps/dashboard/lib/trpc/routers/deploy/project/list.ts b/apps/dashboard/lib/trpc/routers/deploy/project/list.ts
index 5c279b5acd..b465ba1eed 100644
--- a/apps/dashboard/lib/trpc/routers/deploy/project/list.ts
+++ b/apps/dashboard/lib/trpc/routers/deploy/project/list.ts
@@ -1,30 +1,68 @@
-import { db } from "@/lib/db";
+import type { Deployment } from "@/lib/collections/deploy/deployments";
+import type { Project } from "@/lib/collections/deploy/projects";
+import { db, sql } from "@/lib/db";
import { ratelimit, requireUser, requireWorkspace, t, withRatelimit } from "@/lib/trpc/trpc";
-import { TRPCError } from "@trpc/server";
+import { deployments, domains, projects } from "@unkey/db/src/schema";
+
+type ProjectRow = {
+ id: string;
+ name: string;
+ slug: string;
+ updated_at: number | null;
+ git_repository_url: string | null;
+ live_deployment_id: string | null;
+ git_commit_message: string | null;
+ git_branch: string | null;
+ git_commit_author_name: string | null;
+ git_commit_timestamp: number | null;
+ runtime_config: Deployment["runtimeConfig"] | null;
+ domain: string | null;
+};
export const listProjects = t.procedure
.use(requireUser)
.use(requireWorkspace)
.use(withRatelimit(ratelimit.read))
.query(async ({ ctx }) => {
- return await db.query.projects
- .findMany({
- where: (table, { eq }) => eq(table.workspaceId, ctx.workspace.id),
- columns: {
- id: true,
- name: true,
- slug: true,
- updatedAt: true,
- gitRepositoryUrl: true,
- liveDeploymentId: true,
- },
- })
- .catch((error) => {
- console.error("Error querying projects:", error);
- throw new TRPCError({
- code: "INTERNAL_SERVER_ERROR",
- message:
- "Failed to retrieve projects due to an error. If this issue persists, please contact support.",
- });
- });
+ const result = await db.execute(sql`
+ SELECT
+ ${projects.id},
+ ${projects.name},
+ ${projects.slug},
+ ${projects.updatedAt},
+ ${projects.gitRepositoryUrl},
+ ${projects.liveDeploymentId},
+ ${deployments.gitCommitMessage},
+ ${deployments.gitBranch},
+ ${deployments.gitCommitAuthorName},
+ ${deployments.gitCommitTimestamp},
+ ${deployments.runtimeConfig},
+ ${domains.domain}
+ FROM ${projects}
+ LEFT JOIN ${deployments}
+ ON ${projects.liveDeploymentId} = ${deployments.id}
+ AND ${deployments.workspaceId} = ${ctx.workspace.id}
+ LEFT JOIN ${domains}
+ ON ${projects.id} = ${domains.projectId}
+ AND ${domains.workspaceId} = ${ctx.workspace.id}
+ WHERE ${projects.workspaceId} = ${ctx.workspace.id}
+ ORDER BY ${projects.updatedAt} DESC
+ `);
+
+ return (result.rows as ProjectRow[]).map(
+ (row): Project => ({
+ id: row.id,
+ name: row.name,
+ slug: row.slug,
+ updatedAt: row.updated_at,
+ gitRepositoryUrl: row.git_repository_url,
+ liveDeploymentId: row.live_deployment_id,
+ commitTitle: row.git_commit_message ?? "[DUMMY] Initial commit",
+ branch: row.git_branch ?? "main",
+ author: row.git_commit_author_name ?? "[DUMMY] Unknown Author",
+ commitTimestamp: row.git_commit_timestamp ?? Date.now() - 86400000,
+ regions: row.runtime_config?.regions?.map((r) => r.region) ?? ["us-east-1"],
+ domain: row.domain ?? "project-temp.unkey.app",
+ }),
+ );
});