Add workflow editor and node types support in frontend and backend
- 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.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* 条件边。边携带 condition(自然语言条件,LLM 据此决定是否走这条路径)与
|
||||
* label(日志里识别该路径的短标签)。悬停/选中时在标签旁显示「编辑 / 删除」按钮。
|
||||
*/
|
||||
|
||||
import {
|
||||
BaseEdge,
|
||||
EdgeLabelRenderer,
|
||||
getSmoothStepPath,
|
||||
type EdgeProps,
|
||||
useReactFlow,
|
||||
} from "@xyflow/react";
|
||||
import { Pencil, Trash2 } from "lucide-react";
|
||||
import { useContext, useState } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { EdgeActionContext } from "./context";
|
||||
|
||||
export function ConditionEdge({
|
||||
id,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
data,
|
||||
selected,
|
||||
}: EdgeProps) {
|
||||
const actions = useContext(EdgeActionContext);
|
||||
const { setEdges } = useReactFlow();
|
||||
const [hovered, setHovered] = useState(false);
|
||||
|
||||
// 点击标签:只选中这条边(露出编辑/删除按钮),不直接进入编辑。
|
||||
const selectThisEdge = () =>
|
||||
setEdges((eds) => eds.map((e) => ({ ...e, selected: e.id === id })));
|
||||
const [path, labelX, labelY] = getSmoothStepPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition,
|
||||
borderRadius: 8,
|
||||
offset: 20,
|
||||
});
|
||||
|
||||
const label = ((data?.label as string) || (data?.condition as string) || "")
|
||||
.toString()
|
||||
.trim();
|
||||
const expanded = hovered || selected;
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseEdge
|
||||
id={id}
|
||||
path={path}
|
||||
style={{
|
||||
stroke: selected ? "var(--primary)" : "var(--muted-soft)",
|
||||
strokeWidth: selected ? 2.5 : 1.5,
|
||||
transition: "stroke 0.15s ease, stroke-width 0.15s ease",
|
||||
}}
|
||||
/>
|
||||
<EdgeLabelRenderer>
|
||||
<div
|
||||
className="nodrag nopan pointer-events-auto absolute flex items-center gap-1"
|
||||
style={{
|
||||
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
|
||||
}}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
title="条件"
|
||||
className={cn(
|
||||
"max-w-[160px] truncate rounded-full border px-2.5 py-1 text-xs shadow-sm transition-colors",
|
||||
label
|
||||
? "border-hairline bg-card text-foreground hover:border-primary"
|
||||
: "border-dashed border-hairline-strong bg-card/80 text-muted-soft hover:text-foreground",
|
||||
selected && "border-primary ring-2 ring-primary/30",
|
||||
)}
|
||||
onClick={selectThisEdge}
|
||||
>
|
||||
{label || "+ 条件"}
|
||||
</button>
|
||||
|
||||
{expanded && (
|
||||
<button
|
||||
type="button"
|
||||
title="编辑条件"
|
||||
className="flex h-6 w-6 items-center justify-center rounded-full border border-hairline bg-card text-muted-foreground shadow-sm transition-colors hover:text-foreground"
|
||||
onClick={() => actions.edit(id)}
|
||||
>
|
||||
<Pencil size={12} />
|
||||
</button>
|
||||
)}
|
||||
{expanded && (
|
||||
<button
|
||||
type="button"
|
||||
title="删除连线"
|
||||
className="flex h-6 w-6 items-center justify-center rounded-full border border-hairline bg-card text-muted-foreground shadow-sm transition-colors hover:text-destructive"
|
||||
onClick={() => actions.remove(id)}
|
||||
>
|
||||
<Trash2 size={12} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</EdgeLabelRenderer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const edgeTypes = { condition: ConditionEdge };
|
||||
Reference in New Issue
Block a user