Files
kandev/apps/web/hooks/use-workflows.ts
T

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 };
}