diff --git a/frontend/src/components/Dashboard/DashboardView.tsx b/frontend/src/components/Dashboard/DashboardView.tsx index 0157d19..d92c007 100644 --- a/frontend/src/components/Dashboard/DashboardView.tsx +++ b/frontend/src/components/Dashboard/DashboardView.tsx @@ -9,13 +9,7 @@ import { cn } from "@/lib/utils" import "./dashboard.css" import { WidgetBody, WidgetFrame, widgetIssue } from "./widgets" -/** - * A dashboard, plus the settings the generated client does not carry yet. - * - * `columns` is stored by the backend but the SDK is regenerated on its own - * schedule, so it is widened here rather than waited for. - */ -export type Dashboard = DashboardDef_Output & { columns?: number } +export type Dashboard = DashboardDef_Output /** How many columns a wall panel is cut into, if the document does not say. */ export const DEFAULT_COLUMNS = 12 diff --git a/frontend/src/components/Flow/FlowDock.tsx b/frontend/src/components/Flow/FlowDock.tsx index 59d567a..3f72d90 100644 --- a/frontend/src/components/Flow/FlowDock.tsx +++ b/frontend/src/components/Flow/FlowDock.tsx @@ -9,6 +9,7 @@ import { Play, PlayCircle, Plus, + StepForward, WifiOff, ZoomIn, ZoomOut, @@ -62,6 +63,8 @@ export function FlowDock({ onAddNode, onRun, onTogglePause, + onStep, + stepping, onFocusNode, onEditFlow, onPublish, @@ -79,6 +82,8 @@ export function FlowDock({ onAddNode: () => void onRun: () => void onTogglePause: () => void + onStep: () => void + stepping: boolean onFocusNode: (nodeId: string) => void onEditFlow: () => void onPublish: () => void @@ -214,6 +219,25 @@ export function FlowDock({ + {paused && enabled ? ( + + + + + Let one held-back item through + + ) : null} + diff --git a/frontend/src/components/Flow/FlowEditor.tsx b/frontend/src/components/Flow/FlowEditor.tsx index ff723fd..9edea38 100644 --- a/frontend/src/components/Flow/FlowEditor.tsx +++ b/frontend/src/components/Flow/FlowEditor.tsx @@ -211,7 +211,7 @@ function FlowEditorInner({ }) { const navigate = useNavigate() const queryClient = useQueryClient() - const { showErrorToast } = useCustomToast() + const { showErrorToast, showSuccessToast } = useCustomToast() const { screenToFlowPosition, fitView } = useReactFlow() const updateNodeInternals = useUpdateNodeInternals() @@ -507,6 +507,13 @@ function FlowEditorInner({ onError: () => showErrorToast("The flow could not be paused."), }) + const stepMutation = useMutation({ + mutationFn: () => FlowsService.stepFlow({ name: flowName }), + // Says which node ran, or that nothing was held back — both are answers. + onSuccess: (result) => showSuccessToast(result.message), + onError: () => showErrorToast("The flow could not be stepped."), + }) + const deleteMutation = useMutation({ mutationFn: () => FlowsService.deleteFlow({ name: flowName }), onSuccess: () => { @@ -970,6 +977,8 @@ function FlowEditorInner({ runMutation.mutate() }} onTogglePause={() => pauseMutation.mutate(!paused)} + onStep={() => stepMutation.mutate()} + stepping={stepMutation.isPending} onFocusNode={focusNode} />