Let a dashboard be read against runs instead of the live engine

This commit is contained in:
2026-08-25 11:48:15 +02:00
parent d2951a325e
commit 5ece544b14
13 changed files with 438 additions and 32 deletions
+54 -3
View File
@@ -1,9 +1,14 @@
import { useQuery } from "@tanstack/react-query"
import { createFileRoute, redirect } from "@tanstack/react-router"
import { createFileRoute, redirect, useNavigate } from "@tanstack/react-router"
import { ContextBar } from "@/components/Dashboard/ContextBar"
import type { Dashboard } from "@/components/Dashboard/DashboardView"
import { useDataContext } from "@/components/Dashboard/dataContext"
import { PanelSurface } from "@/components/Dashboard/PanelSurface"
import { dashboardQueryOptions } from "@/components/Dashboard/queries"
import {
RunsContextProvider,
runIdsOf,
} from "@/components/Dashboard/RunsContext"
import { useCanvasRoot } from "@/components/Dashboard/ui/core/look"
import { useFlowSocket } from "@/components/Flow/useFlowSocket"
import { isLoggedIn } from "@/hooks/useAuth"
@@ -28,14 +33,24 @@ export const Route = createFileRoute("/view/$name")({
throw redirect({ to: "/login" })
}
},
// Which runs this dashboard is being read against, if any. In the address
// rather than in the document: it is a way of looking at the page, not a
// change to it, and a comparison someone found is then a link they can send.
validateSearch: (search: Record<string, unknown>): { runs?: string } => ({
runs:
typeof search.runs === "string" && search.runs ? search.runs : undefined,
}),
head: ({ params }) => ({ meta: [{ title: `${params.name} - Fluksio` }] }),
})
function PanelView() {
const { name } = Route.useParams()
const { runs } = Route.useSearch()
const navigate = useNavigate()
useFlowSocket()
const { data: dashboard } = useQuery(dashboardQueryOptions(name))
const stacked = useIsMobile()
const runIds = runIdsOf(runs)
// A tab pointed at one dashboard is that dashboard, so its appearance
// covers the whole page rather than only the canvas inside it.
const root = useCanvasRoot(dashboard as Dashboard | undefined)
@@ -54,7 +69,43 @@ function PanelView() {
)}
style={root.style}
>
<PanelSurface dashboard={dashboard as Dashboard} stacked={stacked} />
{runIds.length > 0 ? (
<RunsContextProvider runIds={runIds} dashboard={dashboard as Dashboard}>
<ContextBarFor
members={runIds}
onChange={(next) =>
navigate({
to: "/view/$name",
params: { name },
search: next.length ? { runs: next.join(",") } : {},
})
}
/>
<PanelSurface dashboard={dashboard as Dashboard} stacked={stacked} />
</RunsContextProvider>
) : (
<PanelSurface dashboard={dashboard as Dashboard} stacked={stacked} />
)}
</main>
)
}
/** The bar, drawn from inside the provider so it can read what it resolved. */
function ContextBarFor({
members,
onChange,
}: {
members: string[]
onChange: (next: string[]) => void
}) {
const context = useDataContext()
if (!context) return null
return (
<ContextBar
context={context}
members={members}
onRemove={(id) => onChange(members.filter((one) => one !== id))}
onExit={() => onChange([])}
/>
)
}