import { useQuery } from "@tanstack/react-query" import { Link } from "@tanstack/react-router" import type { FlowRollup, HistoryPoint } from "@/client" import { type Range, RangePicker } from "@/components/Common/RangePicker" import { Sparkline } from "@/components/Common/Sparkline" import { PANEL_SECTION } from "@/components/Flow/SidePanel" import { Badge } from "@/components/ui/badge" import { si } from "@/lib/utils" import { ago, CARD, failuresQueryOptions, flowRollupsQueryOptions, summaryQueryOptions, } from "./queries" function Tile({ label, value, note, }: { label: string value: string note?: string }) { return (
{label}
{value}
{note ? (
{note}
) : null}
) } /** * A flow's execution trend, drawn from the 60 slices the rollup carries. * * Sixty slices of whatever window is selected, so the curve stays the same * width and only its resolution moves. The same curve the node panel and the * edge popover draw, dot included, in the chart ramp this page's other graphs * use. The dot marks the newest slice rather than this instant — the rollups * are polled, so that slice is the last complete one. */ function Spark({ counts }: { counts: number[] }) { const points: HistoryPoint[] = counts.map((value, index) => ({ ts: index, value, })) if (points.every((point) => point.value === 0)) { return nothing yet } return ( ) } /** * How the engine is doing, and how each flow has been doing over the window. * * The tiles are the standing state; the table below is the same window the * charts cover, one row per flow. The range control sits on this heading * because it governs the whole health block, the activity below included — * one window, not one per card. */ export function HealthOverview({ range, onRangeChange, }: { range: Range onRangeChange: (range: Range) => void }) { const { data: summary } = useQuery(summaryQueryOptions()) const { data: flows } = useQuery(flowRollupsQueryOptions(range)) // Shares the list below's cache entry, for the one tile that dates them. const { data: failures } = useQuery(failuresQueryOptions(range)) const queue = (summary?.queue ?? {}) as Record const degraded = summary?.status === "degraded" const errors = (flows ?? []).reduce((total, row) => total + row.errors, 0) return ( <>

Health

{degraded ? "Degraded" : "Running normally"}
{summary?.problems.length ? (

{summary.problems.join(" · ")}

) : null}

Flow activity ({range.label})

{/* The name anchors the left, the numbers read down their own centre, and the trend closes the row on the right. */} {/* A bounded share rather than all the slack: the columns beside it grow with their own content, so the numbers spread across the middle instead of huddling on the left. */} {(flows ?? []).map((row: FlowRollup) => ( {/* The dot straddles the curve's right edge, so the cell keeps a little room for the half that hangs out. */} ))} {flows?.length === 0 ? ( ) : null}
Flow Executions Errors Avg Lag Trend
{row.flow || "—"} {si(row.executions)} {row.errors ? ( {si(row.errors)} failed ) : ( none )} {si(row.avg_ms)} ms {si(row.avg_lag_ms)} ms
No flow has run in the last {range.label}.
) }