Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/utils/integrations/projects/boardsStartRoute.server.ts
T

53 lines
1.8 KiB
TypeScript

// WF-P8 Subframe delta (S00 boards start page) — server helper for
// `/projects/boards`. Lists the viewer-visible pipelines (listPipelines applies
// the deny-based pipeline access scope) and adds stage/project counts. Project
// counts use the same read scope as the board/list (projectReadScopeWhere) so
// the numbers match what the viewer sees on the board; demo rows are excluded
// like the list default. Server-only (.server) — never imported by a component.
import { withTenantRLS } from "~/utils/db/.server/tenantRls.server";
import { listPipelines, projectReadScopeWhere } from "./projectService.server";
import type { ProjectRouteContext } from "./projectAccess.server";
export type BoardsStartPipeline = {
id: string;
name: string;
typHint: "sales" | "auftrag" | "custom";
isDefault: boolean;
stageCount: number;
projectCount: number;
};
export async function loadBoardsStartPipelines({
tenantId,
ctx,
}: {
tenantId: string;
ctx: ProjectRouteContext;
}): Promise<BoardsStartPipeline[]> {
const [pipelines, projectTotals] = await Promise.all([
listPipelines({ tenantId, ctx }),
withTenantRLS(tenantId, async (tx) =>
tx.projekt.groupBy({
by: ["pipelineId"],
where: {
tenantId,
archivedAt: null,
isDemoData: false,
...projectReadScopeWhere(tenantId, ctx),
},
_count: { _all: true },
}),
),
]);
const countsByPipeline = new Map(projectTotals.map((total) => [total.pipelineId, total._count._all]));
return pipelines.map((pipeline) => ({
id: pipeline.id,
name: pipeline.name,
typHint: pipeline.typHint,
isDefault: pipeline.isDefault,
stageCount: pipeline.stages.length,
projectCount: countsByPipeline.get(pipeline.id) ?? 0,
}));
}