From f105ffb52c333d9d7a60528eaebc388ff28e1b30 Mon Sep 17 00:00:00 2001
From: tianM <46552064+a3384379@users.noreply.github.com>
Date: Wed, 23 Sep 2026 23:33:55 +0800
Subject: [PATCH 1/2] fix(workflows): keep reverted node edits and edge drafts
isolated
---
.../flow/WorkflowApiRequestEditor.test.tsx | 116 ++++++++++++--
.../src/flow/WorkflowNodeEditSession.test.tsx | 150 +++++++++++++-----
frontend/src/flow/WorkflowNodeEditSession.tsx | 38 +++--
frontend/src/flow/WorkflowNodeInspector.tsx | 7 +-
frontend/src/flow/editor/node-edit-session.ts | 1 +
5 files changed, 247 insertions(+), 65 deletions(-)
diff --git a/frontend/src/flow/WorkflowApiRequestEditor.test.tsx b/frontend/src/flow/WorkflowApiRequestEditor.test.tsx
index c73e935f..938c239c 100644
--- a/frontend/src/flow/WorkflowApiRequestEditor.test.tsx
+++ b/frontend/src/flow/WorkflowApiRequestEditor.test.tsx
@@ -504,6 +504,51 @@ describe('WorkflowApiRequestEditor', () => {
expect(session.unsafe.size).toBe(0)
})
+ it('keeps an unfinished request draft when only an edge changes', async () => {
+ const user = userEvent.setup()
+ const session = new DraftSession()
+ const changed = vi.fn()
+ vi.mocked(getApiDetail).mockResolvedValue({
+ ...detail,
+ version: { ...detail.version, body_kind: 'json', body: { initial: true } },
+ })
+ render()
+ await screen.findByText('继承接口模板 v3')
+ await user.click(screen.getByRole('tab', { name: 'Body' }))
+ await user.click(within(screen.getByRole('tabpanel')).getByText('节点自定义'))
+ fireEvent.change(screen.getByRole('textbox', { name: 'JSON Body' }), {
+ target: { value: '{"pending":' },
+ })
+
+ await user.click(screen.getByRole('button', { name: '切换节点名称测试' }))
+ await user.click(screen.getByRole('button', { name: '切换节点名称测试' }))
+ expect([...session.nodeEditors.values()][0].requestDirty).toBe(true)
+ expect(session.unsafe.size).toBe(1)
+
+ await user.click(screen.getByRole('button', { name: '修改连线测试' }))
+ expect(screen.getByRole('textbox', { name: 'JSON Body' })).toHaveValue('{"pending":')
+ expect([...session.nodeEditors.values()][0].requestDraft).toMatchObject({
+ activeTab: 'body',
+ fields: { body_text: '{"pending":' },
+ })
+ expect(changed).toHaveBeenCalledTimes(1)
+ expect(changed.mock.calls[0][0].nodes[0]).toEqual({
+ ...node,
+ config: { ...node.config, request_overrides: {} },
+ })
+
+ fireEvent.change(screen.getByRole('textbox', { name: 'JSON Body' }), {
+ target: { value: '{"ready":true}' },
+ })
+ await user.click(screen.getByRole('button', { name: '保存节点配置' }))
+ await waitFor(() => expect(changed).toHaveBeenCalledTimes(2))
+ expect(changed.mock.calls[1][0].edges).toEqual(changed.mock.calls[0][0].edges)
+ expect(changed.mock.calls[1][0].nodes[0].config.request_overrides.body).toEqual({
+ kind: 'json',
+ value: { ready: true },
+ })
+ })
+
it('applies request edits after restoring the fullscreen inspector to quick mode', async () => {
const user = userEvent.setup()
const session = new DraftSession()
@@ -666,20 +711,63 @@ function RequestSessionHarness({
+
+
diff --git a/frontend/src/flow/WorkflowNodeEditSession.test.tsx b/frontend/src/flow/WorkflowNodeEditSession.test.tsx
index 4be48640..ef7fb091 100644
--- a/frontend/src/flow/WorkflowNodeEditSession.test.tsx
+++ b/frontend/src/flow/WorkflowNodeEditSession.test.tsx
@@ -6,6 +6,7 @@ import { workflowDefinition } from '../test/fixtures'
import type { WorkflowDefinition } from '../lib/api'
import WorkflowNodeEditSession from './WorkflowNodeEditSession'
import WorkflowJsonInput from './WorkflowJsonInput'
+import { editorNode, restoreEditedNode } from './editor/graph-analysis'
function Harness({
session,
@@ -37,31 +38,34 @@ function Harness({