import { useMutation, useQueryClient } from "@tanstack/react-query" import { type DashboardDef_Input, DashboardsService, MessagesService, } from "@/client" export const dashboardKeys = { all: ["dashboards"] as const, /** The working copy and the published document are two different reads. */ detail: (name: string, draft = false) => ["dashboards", name, draft ? "draft" : "published"] as const, messages: ["messages"] as const, history: (message: string) => ["messages", message, "history"] as const, } export const dashboardsQueryOptions = () => ({ queryKey: dashboardKeys.all, queryFn: () => DashboardsService.readDashboards(), }) /** * A dashboard as a panel shows it, or with `draft` the copy being edited. * * A wall panel asks for the published one, which is the whole point of the * split: nothing half-arranged reaches the wall until someone publishes. */ export const dashboardQueryOptions = (name: string, draft = false) => ({ queryKey: dashboardKeys.detail(name, draft), queryFn: () => DashboardsService.readDashboard({ name, draft }), }) /** Every message any flow declares — what a widget can be pointed at. */ export const messageCatalogQueryOptions = () => ({ queryKey: dashboardKeys.messages, queryFn: () => MessagesService.readMessages(), }) export const messageHistoryQueryOptions = (message: string) => ({ queryKey: dashboardKeys.history(message), queryFn: () => MessagesService.readMessageHistory({ name: message }), }) /** Saving a dashboard, carrying the version it was based on. * * This writes the draft; panels keep showing the published document. */ export function useSaveDashboard(name: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (body: DashboardDef_Input) => DashboardsService.saveDashboard({ name, requestBody: body }), onSuccess: (saved) => { queryClient.setQueryData(dashboardKeys.detail(name, true), saved) queryClient.invalidateQueries({ queryKey: dashboardKeys.all }) }, }) } /** Publish the unpublished changes, which is what puts them on the panels. */ export function usePublishDashboard(name: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (version: number) => DashboardsService.publishDashboard({ name, requestBody: { version }, }), onSuccess: (published) => { queryClient.setQueryData(dashboardKeys.detail(name, true), published) queryClient.setQueryData(dashboardKeys.detail(name), published) queryClient.invalidateQueries({ queryKey: dashboardKeys.all }) }, }) } /** What an input widget does: put a value into the graph. * * The widget names itself so the flow canvas can show the value arriving from * here, rather than crediting whichever node is drawn as a producer. */ export function usePublishMessage() { return useMutation({ mutationFn: ({ name, value, dashboard, widget, label, kind, }: { name: string value: unknown dashboard?: string widget?: string label?: string kind?: string }) => MessagesService.publishMessage({ name, requestBody: { value, source_kind: "dashboard", // Matches the endpoint id the canvas builds for this widget. source_id: dashboard && widget ? `dashboard:${dashboard}:${widget}` : "", source_label: label ?? widget ?? "Dashboard", source_detail: kind ?? "", }, }), }) }