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({ + +