feat: Shoring column in ProjectHealth widget + populate country data

Widget: added "Shoring" column with ShoringBadge per project showing
offshore % with color indicator (green/yellow/red).

Backend: added id field to ProjectHealthRow for badge queries.

Database: assigned diverse countries to 11 resources for realistic
shoring data (25 DE, 5 ES, 4 IN, 2 US instead of all-DE).

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-03-26 11:49:28 +01:00
parent 92a982b151
commit be2d2c0d56
2 changed files with 9 additions and 0 deletions
@@ -4,6 +4,7 @@ import { useMemo } from "react";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import type { WidgetProps } from "~/components/dashboard/widget-registry.js"; import type { WidgetProps } from "~/components/dashboard/widget-registry.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { ShoringBadge } from "~/components/projects/ShoringIndicator.js";
import { WidgetFilterBar, type WidgetFilter } from "~/components/dashboard/WidgetFilterBar.js"; import { WidgetFilterBar, type WidgetFilter } from "~/components/dashboard/WidgetFilterBar.js";
import { useWidgetFilterOptions } from "~/hooks/useWidgetFilterOptions.js"; import { useWidgetFilterOptions } from "~/hooks/useWidgetFilterOptions.js";
@@ -90,6 +91,9 @@ export function ProjectHealthWidget({ config, onConfigChange }: WidgetProps) {
<th className="px-3 py-2 text-center font-medium text-gray-500 dark:text-gray-400"> <th className="px-3 py-2 text-center font-medium text-gray-500 dark:text-gray-400">
B / S / T <InfoTooltip content="Budget health (spent vs budget), Staffing health (filled vs total demands), Timeline health (within end date)" /> B / S / T <InfoTooltip content="Budget health (spent vs budget), Staffing health (filled vs total demands), Timeline health (within end date)" />
</th> </th>
<th className="px-3 py-2 text-center font-medium text-gray-500 dark:text-gray-400">
Shoring <InfoTooltip content="Offshore staffing ratio: percentage of hours from non-onshore resources. Color indicates threshold status." />
</th>
<th className="px-3 py-2 text-right font-medium text-gray-500 dark:text-gray-400"> <th className="px-3 py-2 text-right font-medium text-gray-500 dark:text-gray-400">
Score <InfoTooltip content="Composite score: average of Budget, Staffing, and Timeline health (0-100)" /> Score <InfoTooltip content="Composite score: average of Budget, Staffing, and Timeline health (0-100)" />
</th> </th>
@@ -118,6 +122,9 @@ export function ProjectHealthWidget({ config, onConfigChange }: WidgetProps) {
/> />
</div> </div>
</td> </td>
<td className="px-3 py-2 text-center">
<ShoringBadge projectId={(row as any).id} />
</td>
<td className="px-3 py-2 text-right"> <td className="px-3 py-2 text-right">
<span <span
className={`inline-block px-2 py-0.5 rounded-full font-semibold tabular-nums ${scoreBadge(row.compositeScore)}`} className={`inline-block px-2 py-0.5 rounded-full font-semibold tabular-nums ${scoreBadge(row.compositeScore)}`}
@@ -2,6 +2,7 @@ import type { PrismaClient } from "@planarchy/db";
import { calculateInclusiveDays } from "./shared.js"; import { calculateInclusiveDays } from "./shared.js";
export interface ProjectHealthRow { export interface ProjectHealthRow {
id: string;
projectName: string; projectName: string;
shortCode: string; shortCode: string;
clientId: string | null; clientId: string | null;
@@ -94,6 +95,7 @@ export async function getDashboardProjectHealth(
); );
return { return {
id: p.id,
projectName: p.name, projectName: p.name,
shortCode: p.shortCode, shortCode: p.shortCode,
clientId: p.clientId, clientId: p.clientId,