- Introduce a new workflow editor component for visualizing and managing workflows, allowing users to add nodes and define connections. - Implement backend support for node types, including validation and constraints for workflow graphs. - Add new API endpoints for retrieving node types and their specifications. - Enhance the AssistantPage to integrate the workflow editor, enabling users to create and edit workflows directly. - Update frontend components to support new workflow functionalities, including condition edges and generic nodes. - Refactor existing code to accommodate the new workflow features and improve overall structure.
62 lines
1.5 KiB
TypeScript
62 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* 拉取并缓存 /api/node-types 节点目录(每会话一次,模块级缓存)。
|
|
* 对齐 dograh 的 useNodeSpecs:规格随后端 + 刷新生效。
|
|
*/
|
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
import { nodeTypesApi, type NodeTypesResponse } from "@/lib/api";
|
|
import {
|
|
toRuntimeSpec,
|
|
type NodeSpecMap,
|
|
type RuntimeNodeSpec,
|
|
} from "./specs";
|
|
|
|
let _cache: NodeTypesResponse | null = null;
|
|
|
|
type State = {
|
|
specs: RuntimeNodeSpec[];
|
|
byType: NodeSpecMap;
|
|
loading: boolean;
|
|
error: string | null;
|
|
};
|
|
|
|
function build(data: NodeTypesResponse | null): {
|
|
specs: RuntimeNodeSpec[];
|
|
byType: NodeSpecMap;
|
|
} {
|
|
const specs = (data?.nodeTypes ?? []).map(toRuntimeSpec);
|
|
const byType: NodeSpecMap = {};
|
|
for (const spec of specs) byType[spec.type] = spec;
|
|
return { specs, byType };
|
|
}
|
|
|
|
export function useNodeSpecs(): State {
|
|
const fetched = useRef(false);
|
|
const [state, setState] = useState<State>(() => {
|
|
const { specs, byType } = build(_cache);
|
|
return { specs, byType, loading: !_cache, error: null };
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (_cache || fetched.current) return;
|
|
fetched.current = true;
|
|
|
|
nodeTypesApi
|
|
.list()
|
|
.then((data) => {
|
|
_cache = data;
|
|
const { specs, byType } = build(data);
|
|
setState({ specs, byType, loading: false, error: null });
|
|
})
|
|
.catch((err: unknown) => {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
setState((s) => ({ ...s, loading: false, error: message }));
|
|
});
|
|
}, []);
|
|
|
|
return state;
|
|
}
|