module Web.View.Hubs.BottleneckDashboard where import Web.Types import Generated.Types import IHP.Prelude import IHP.ViewPrelude import Web.Routes () import Data.Time.Clock (diffUTCTime, getCurrentTime) data BottleneckDashboardView = BottleneckDashboardView { hub :: !Hub , widgets :: ![Widget] , bottlenecks :: ![BottleneckRecord] } instance View BottleneckDashboardView where html BottleneckDashboardView { .. } = [hsx|

Bottleneck Dashboard

{hub.name}

Detect ← Hub
{forEach stages renderStageSection} {if null bottlenecks then noBottlenecksMsg else mempty} |] where stages = ["candidate", "requirement", "decision", "observation"] :: [Text] stageLabel s = case s of "candidate" -> "Stale Candidates (>30 days open)" "requirement" -> "Requirements Without Decision (>60 days)" "decision" -> "Decisions Without Deployment (>30 days)" "observation" -> "Deployments Without Outcome Signal (>14 days)" _ -> s active = filter (\b -> isNothing b.resolvedAt) bottlenecks renderStageSection :: Text -> Html renderStageSection stage = let stageBNs = filter (\b -> b.stage == stage) active in if null stageBNs then mempty else [hsx|

{stageLabel stage}

{forEach stageBNs renderRow}
Subject Stalled Since Severity
|] renderRow :: BottleneckRecord -> Html renderRow b = [hsx| {show b.subjectId} {show b.stalledSince} " text-xs px-2 py-0.5 rounded font-medium"}> {b.severity} Resolve |] noBottlenecksMsg :: Html noBottlenecksMsg = [hsx|

No active bottlenecks detected.

|] severityBadge :: Text -> Text severityBadge s = case s of "critical" -> "bg-red-100 text-red-800" "high" -> "bg-orange-100 text-orange-800" "medium" -> "bg-yellow-100 text-yellow-800" _ -> "bg-gray-100 text-gray-600"