diff --git a/docs b/docs index fe29cfb..b6d08c0 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit fe29cfb3cc46382c6a2803f3cc9d7c3051ab5368 +Subproject commit b6d08c0964853a795979c2a2be941254ac4ab39d diff --git a/web/app/dashboard/ai-workflows/_components/flowgram-editor-provider.tsx b/web/app/dashboard/ai-workflows/_components/flowgram-editor-provider.tsx index a1d0a50..70f6493 100644 --- a/web/app/dashboard/ai-workflows/_components/flowgram-editor-provider.tsx +++ b/web/app/dashboard/ai-workflows/_components/flowgram-editor-provider.tsx @@ -64,7 +64,7 @@ export function useFlowgramEditorProps({ }, canDeleteNode: (_ctx, node) => { const type = String(node.flowNodeType ?? "") - return type !== "start" && type !== "end" + return type !== "start" }, canDeleteLine: () => !readonly, onContentChange: (ctx) => { diff --git a/web/app/dashboard/ai-workflows/_components/flowgram-node-registries.tsx b/web/app/dashboard/ai-workflows/_components/flowgram-node-registries.tsx index e4bfc2f..1a136e7 100644 --- a/web/app/dashboard/ai-workflows/_components/flowgram-node-registries.tsx +++ b/web/app/dashboard/ai-workflows/_components/flowgram-node-registries.tsx @@ -42,8 +42,8 @@ export function buildFlowgramNodeRegistries(nodeSpecs: AIWorkflowNodeSpec[]): Wo meta: { defaultExpanded: true, isStart: spec.type === "start", - deleteDisable: spec.type === "start" || spec.type === "end", - copyDisable: spec.type === "start" || spec.type === "end", + deleteDisable: spec.type === "start", + copyDisable: spec.type === "start", defaultPorts: defaultPortsForNodeType(spec.type), }, formMeta: { diff --git a/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx b/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx index 605dd74..6f7c5f9 100644 --- a/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx +++ b/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx @@ -208,7 +208,9 @@ function WorkflowEditorInner({ useEffect(() => { const disposable = selectService.onSelectionChanged(() => { - const selectedNode = selectService.selectedNodes[0] + const selectedNode = selectService.selectedNodes.length === 1 + ? selectService.selectedNodes[0] + : null onSelectNode(selectedNode?.id ?? "") }) return () => disposable.dispose() diff --git a/web/app/dashboard/ai-workflows/_components/workflow-utils.test.mjs b/web/app/dashboard/ai-workflows/_components/workflow-utils.test.mjs index 10f4847..c46b4f4 100644 --- a/web/app/dashboard/ai-workflows/_components/workflow-utils.test.mjs +++ b/web/app/dashboard/ai-workflows/_components/workflow-utils.test.mjs @@ -252,7 +252,7 @@ describe("workflow definition mutations", () => { }) }) - it("deletes normal nodes and related edges while keeping start and end protected", async () => { + it("deletes non-start nodes and related edges while keeping start protected", async () => { const { deleteWorkflowNode } = await loadModule() const definition = { schemaVersion: 2, @@ -270,6 +270,10 @@ describe("workflow definition mutations", () => { const protectedDefinition = deleteWorkflowNode(definition, "start_1") assert.deepEqual(protectedDefinition, definition) + + const withoutEnd = deleteWorkflowNode(definition, "end_1") + assert.deepEqual(withoutEnd.nodes.map((node) => node.id), ["start_1", "reply_1"]) + assert.deepEqual(withoutEnd.edges, [workflowEdge("start_1", "reply_1")]) }) it("upserts and deletes condition branches in node config", async () => { diff --git a/web/app/dashboard/ai-workflows/_components/workflow-utils.ts b/web/app/dashboard/ai-workflows/_components/workflow-utils.ts index 3894e3a..7d0ffb3 100644 --- a/web/app/dashboard/ai-workflows/_components/workflow-utils.ts +++ b/web/app/dashboard/ai-workflows/_components/workflow-utils.ts @@ -199,7 +199,7 @@ export function deleteWorkflowNode( nodeId: string ): AIWorkflowDefinition { const node = definition.nodes.find((item) => item.id === nodeId) - if (!node || node.type === "start" || node.type === "end") { + if (!node || node.type === "start") { return definition } return {