feat(api): include project health in dashboard detail
This commit is contained in:
@@ -16,6 +16,7 @@ type ReportQueryResult = {
|
||||
totalCount: number;
|
||||
columns: unknown;
|
||||
groups: unknown;
|
||||
explainability?: unknown;
|
||||
};
|
||||
|
||||
type DashboardInsightsReportsDeps = {
|
||||
@@ -53,13 +54,13 @@ export const dashboardInsightsReportsToolDefinitions: ToolDef[] = withToolAccess
|
||||
type: "function",
|
||||
function: {
|
||||
name: "get_dashboard_detail",
|
||||
description: "Get detailed dashboard data: peak allocation times, top-value resources, demand pipeline, chargeability overview.",
|
||||
description: "Get detailed dashboard data: peak allocation times, top-value resources, demand pipeline, chargeability overview, and project health risks.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
section: {
|
||||
type: "string",
|
||||
description: "Which section: peak_times, top_resources, demand_pipeline, chargeability_overview, or all",
|
||||
description: "Which section: peak_times, top_resources, demand_pipeline, chargeability_overview, project_health, or all",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -174,6 +175,7 @@ export const dashboardInsightsReportsToolDefinitions: ToolDef[] = withToolAccess
|
||||
},
|
||||
get_budget_forecast: {
|
||||
allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
|
||||
requiredPermissions: [PermissionKey.VIEW_COSTS],
|
||||
},
|
||||
get_insights_summary: {
|
||||
allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
|
||||
@@ -255,6 +257,7 @@ export function createDashboardInsightsReportsExecutors(
|
||||
totalCount: result.totalCount,
|
||||
columns: result.columns,
|
||||
groups: result.groups,
|
||||
...(result.explainability ? { explainability: result.explainability } : {}),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -293,6 +293,12 @@ function mapChargeabilityByChapter(
|
||||
));
|
||||
}
|
||||
|
||||
function getProjectHealthRating(overall: number): "healthy" | "at_risk" | "critical" {
|
||||
if (overall >= 80) return "healthy";
|
||||
if (overall >= 50) return "at_risk";
|
||||
return "critical";
|
||||
}
|
||||
|
||||
export async function getDashboardOverviewRead(ctx: DashboardProcedureContext) {
|
||||
return getOverviewCached(ctx.db);
|
||||
}
|
||||
@@ -438,6 +444,39 @@ export async function getDashboardDetail(ctx: DashboardProcedureContext, input:
|
||||
);
|
||||
}
|
||||
|
||||
if (section === "all" || section === "project_health") {
|
||||
const projectHealth = await getDashboardProjectHealthRead(ctx);
|
||||
result.projectHealth = [...projectHealth]
|
||||
.sort((left, right) => left.compositeScore - right.compositeScore)
|
||||
.slice(0, 10)
|
||||
.map((project) => ({
|
||||
project: `${project.projectName} (${project.shortCode})`,
|
||||
status: project.status,
|
||||
overall: project.compositeScore,
|
||||
rating: getProjectHealthRating(project.compositeScore),
|
||||
budget: project.budgetHealth,
|
||||
staffing: project.staffingHealth,
|
||||
timeline: project.timelineHealth,
|
||||
timelineStatus: project.timelineStatus ?? "UNSCHEDULED",
|
||||
daysUntilEndDate: project.daysUntilEndDate ?? null,
|
||||
demandHeadcountOpen: project.demandHeadcountOpen ?? 0,
|
||||
explainability: {
|
||||
demandHeadcountTotal: project.demandHeadcountTotal ?? 0,
|
||||
demandHeadcountFilled: project.demandHeadcountFilled ?? 0,
|
||||
demandHeadcountOpen: project.demandHeadcountOpen ?? 0,
|
||||
demandRequirementCount: project.demandRequirementCount ?? 0,
|
||||
plannedEndDate: project.plannedEndDate?.toISOString() ?? null,
|
||||
budgetUtilizationPercent: project.budgetUtilizationPercent ?? null,
|
||||
remainingBudgetCents: project.remainingBudgetCents ?? null,
|
||||
calendarContextCount: project.derivation?.calendarContextCount ?? 0,
|
||||
holidayAwareAssignmentCount: project.derivation?.holidayAwareAssignmentCount ?? 0,
|
||||
publicHolidayCostDeductionCents:
|
||||
project.derivation?.publicHolidayCostDeductionCents ?? 0,
|
||||
absenceCostDeductionCents: project.derivation?.absenceCostDeductionCents ?? 0,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user