Docs / docs (push) Successful in 23s
Playwright Tests / test-playwright (1, 2) (push) Successful in 3m18s
Playwright Tests / test-playwright (2, 2) (push) Successful in 1m49s
pre-commit / pre-commit (push) Failing after 2m5s
Test Backend / test-backend (push) Successful in 2m39s
Compose Smoke Test / test-compose (push) Successful in 33s
Playwright Tests / merge-reports (push) Successful in 1m11s
Runs: a run can now be deleted (DELETE /runs/{id}, cancelling a live one
first), exported as csv from the screen's own filters, and its flow label
opens the flow. Its "Parameters" panel became "Inputs" and lists every
input the flow declares, marking the ones that took the flow's own value
rather than the run's — the comparison table resolves the same defaults
instead of printing "unset".
Home reads brain, dashboards, health, flows: the mosaic is one full-width
scrolling strip, and the flows list and the flow-activity rollups merged
into a single left-joined table so a flow's state and its numbers sit on
one row.
Charts take a drag to narrow the x window and a double click or tap to
come back out. UplotChart holds the scale and passes resetScales:false
while a window is held, which is what the old comment said made this
impossible.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019LrWVRguqbk33YzfEeUx5W
91 lines
3.7 KiB
TypeScript
91 lines
3.7 KiB
TypeScript
import { useQuery } from "@tanstack/react-query"
|
|
import { createFileRoute } from "@tanstack/react-router"
|
|
import { useState } from "react"
|
|
|
|
import { byRecency, DashboardMosaic } from "@/components/Common/DashboardMosaic"
|
|
import { DEFAULT_RANGE } from "@/components/Common/RangePicker"
|
|
import { dashboardsQueryOptions } from "@/components/Dashboard/queries"
|
|
import { BrainView } from "@/components/Flow/BrainView"
|
|
import { flowsQueryOptions } from "@/components/Flow/queries"
|
|
import { FlowTable } from "@/components/Health/FlowTable"
|
|
import { HealthActivity } from "@/components/Health/HealthActivity"
|
|
import { HealthOverview } from "@/components/Health/HealthOverview"
|
|
import { LiveIndicator } from "@/components/Health/LiveIndicator"
|
|
import { Card } from "@/components/ui/card"
|
|
|
|
export const Route = createFileRoute("/_layout/")({
|
|
component: Home,
|
|
head: () => ({
|
|
meta: [
|
|
{
|
|
title: "Home - Fluksio",
|
|
},
|
|
],
|
|
}),
|
|
})
|
|
|
|
/** DESIGN-GUIDELINES.md → Typography, the canonical section header. */
|
|
const HEADER =
|
|
"text-xs font-medium uppercase tracking-[0.5px] text-muted-foreground"
|
|
|
|
/**
|
|
* The one overview: what the engine is wired up as, what is running, and how
|
|
* it has been doing. The brain and the health screens compose in here rather
|
|
* than living at routes of their own.
|
|
*
|
|
* Top to bottom it is a widening lens: the whole installation as a graph, what
|
|
* has been built on it, whether it is well, then flow by flow and finally
|
|
* moment by moment.
|
|
*/
|
|
function Home() {
|
|
// The health block's window: one choice, read by the tiles, the flow table,
|
|
// the charts and the lists under them.
|
|
const [range, setRange] = useState(DEFAULT_RANGE)
|
|
const boards = useQuery(dashboardsQueryOptions())
|
|
// Only to know whether the brain has anything to draw; the table below runs
|
|
// its own copy of the same query.
|
|
const { data } = useQuery(flowsQueryOptions())
|
|
|
|
const flows = data?.data ?? []
|
|
const dashboards = [...(boards.data?.data ?? [])].sort(byRecency)
|
|
|
|
return (
|
|
// `[&>*]:min-w-0`: a grid item's automatic minimum is its content, so one
|
|
// long name or wide table widens the whole column and the page with it.
|
|
// Every section here is free to shrink instead. See DESIGN-GUIDELINES.md
|
|
// → Responsive.
|
|
<div className="grid gap-6 [&>*]:min-w-0">
|
|
{/* Nothing at all while the socket is up. Everything below is polled, so
|
|
a dead socket would otherwise look like an engine that went quiet. */}
|
|
<LiveIndicator />
|
|
|
|
{/* Nothing wired up yet means nothing to draw, and the band would still
|
|
hold a screenful of empty space above the flows table. Node count
|
|
rather than flow count: a flow made a minute ago has none. */}
|
|
{flows.some((flow) => (flow.node_count ?? 0) > 0) ? <BrainView /> : null}
|
|
|
|
{/* One row across the full width rather than a column beside the flows:
|
|
a dashboard tile is a picture, and a picture wants to be wide. Past
|
|
what fits, the strip scrolls sideways on its own — the page must not,
|
|
which is what the `min-w-0` above is holding. */}
|
|
<section className="grid gap-2">
|
|
<h2 className={HEADER}>Dashboards</h2>
|
|
{/* `min-w-0`: the strip inside scrolls, but this card is a grid item
|
|
whose automatic minimum is its content — without this the tiles
|
|
widen it, and the page with it. */}
|
|
<Card className="min-w-0 gap-0 py-0">
|
|
<DashboardMosaic
|
|
dashboards={dashboards}
|
|
isPending={boards.isPending}
|
|
row
|
|
/>
|
|
</Card>
|
|
</section>
|
|
|
|
<HealthOverview range={range} onRangeChange={setRange} />
|
|
<FlowTable range={range} />
|
|
<HealthActivity range={range} />
|
|
</div>
|
|
)
|
|
}
|