67 lines
2.6 KiB
TypeScript
67 lines
2.6 KiB
TypeScript
import { useEffect } from "react";
|
|
import { useAppStore } from "@/components/state-provider";
|
|
import { listWorkflows } from "@/lib/api";
|
|
import type { WorkflowsState } from "@/lib/state/slices";
|
|
|
|
type StoreWorkflow = WorkflowsState["items"][number];
|
|
type SetWorkflows = (workflows: StoreWorkflow[]) => void;
|
|
|
|
/**
|
|
* Fire-and-forget fetch effect. Kept internal so callers that only need to
|
|
* populate `state.workflows.items` (e.g. `useEnsureWorkspaceWorkflows`) don't
|
|
* also subscribe to the store slice they wrote to — that would re-render the
|
|
* caller on every fetch and defeats the "top-level layout" placement.
|
|
*/
|
|
function useWorkflowsFetchEffect(
|
|
workspaceId: string | null,
|
|
enabled: boolean,
|
|
setWorkflows: SetWorkflows,
|
|
) {
|
|
useEffect(() => {
|
|
if (!enabled || !workspaceId) return;
|
|
let cancelled = false;
|
|
listWorkflows(workspaceId, { cache: "no-store", includeHidden: true })
|
|
.then((response) => {
|
|
if (cancelled) return;
|
|
const mapped = response.workflows.map((workflow) => ({
|
|
id: workflow.id,
|
|
workspaceId: workflow.workspace_id,
|
|
name: workflow.name,
|
|
description: workflow.description,
|
|
sortOrder: workflow.sort_order ?? 0,
|
|
agent_profile_id: workflow.agent_profile_id,
|
|
hidden: workflow.hidden,
|
|
style: workflow.style,
|
|
}));
|
|
setWorkflows(mapped);
|
|
})
|
|
// Do not clear on error — the sidebar mounts on every route, and boot
|
|
// hydrates workflows before the refresh fires. Blowing the slice away on
|
|
// a network flake would leave the sidebar and board with no workflow IDs
|
|
// until another success. The next successful fetch replaces the slice.
|
|
.catch(() => {});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [enabled, setWorkflows, workspaceId]);
|
|
}
|
|
|
|
/**
|
|
* Load workflows for the active workspace. Call from a component that stays
|
|
* mounted independently of any collapsible section, so `state.workflows.items`
|
|
* follows the active workspace even when the sidebar's Tasks section is
|
|
* collapsed and its children (which consume workflows) are unmounted.
|
|
*/
|
|
export function useEnsureWorkspaceWorkflows() {
|
|
const workspaceId = useAppStore((state) => state.workspaces.activeId);
|
|
const setWorkflows = useAppStore((state) => state.setWorkflows);
|
|
useWorkflowsFetchEffect(workspaceId, true, setWorkflows);
|
|
}
|
|
|
|
export function useWorkflows(workspaceId: string | null, enabled = true) {
|
|
const workflows = useAppStore((state) => state.workflows.items);
|
|
const setWorkflows = useAppStore((state) => state.setWorkflows);
|
|
useWorkflowsFetchEffect(workspaceId, enabled, setWorkflows);
|
|
return { workflows };
|
|
}
|