import * as React from 'react' import { cn } from '../../lib/utils' import { GitBranch } from 'lucide-react' import { HealthCard } from './HealthCard' import { HEALTH_TONE, worstStatus, type HealthStatus } from './health-status' export interface PipelineStage { label: string count: number /** Optional per-stage tone accent (default derived: 0 records = neutral, else ok). */ tone?: HealthStatus } export interface PipelineHealthProps { title?: string stages: PipelineStage[] /** Records stuck / aging past their SLA — surfaces as the card's warning. */ attention?: number attentionLabel?: string onStageClick?: (label: string) => void emptyMessage?: string className?: string } /** * Content-pipeline health: the count of records in each stage of a status field, * plus a "stuck / aging" attention flag. Presentational — a tenant dashboard * widget derives `stages` from groupByStatus over one content type's records. */ export function PipelineHealth({ title = 'Pipeline', stages, attention = 0, attentionLabel, onStageClick, emptyMessage = 'No records yet.', className, }: PipelineHealthProps) { const total = stages.reduce((sum, s) => sum + s.count, 0) const max = Math.max(1, ...stages.map((s) => s.count)) const status: HealthStatus = total === 0 ? 'neutral' : attention > 0 ? worstStatus(['warn', ...stages.map((s) => s.tone ?? 'ok')]) : 'ok' const statusLabel = total === 0 ? undefined : attention > 0 ? (attentionLabel ?? `${attention} need attention`) : `${total} total` return (
{stages.map((stage) => { const tone = HEALTH_TONE[stage.tone ?? (stage.count === 0 ? 'neutral' : 'ok')] const pct = (stage.count / max) * 100 const clickable = Boolean(onStageClick) return ( ) })}
) }