import { useQuery } from "@tanstack/react-query" 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" import { useIsMobile } from "@/hooks/useMobile" import { cn } from "@/lib/utils" /** * What a wall panel is pointed at when it shows one dashboard and nothing else. * * Deliberately outside both shells: no sidebar, no footer, no editing, and no * column cap — the widgets are the whole page. Route splitting means a panel * never downloads the editor or the grid library either. * * A device that was paired to a panel uses `/panel/{id}` instead, which is the * same surface with a rail for switching between the dashboards it was * assigned. This route stays for a browser tab pointed straight at one. */ export const Route = createFileRoute("/view/$name")({ component: PanelView, beforeLoad: async () => { if (!isLoggedIn()) { 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): { 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) if (!dashboard) return
return (
{runIds.length > 0 ? ( navigate({ to: "/view/$name", params: { name }, search: next.length ? { runs: next.join(",") } : {}, }) } /> ) : ( )}
) } /** 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 ( onChange(members.filter((one) => one !== id))} onExit={() => onChange([])} /> ) }