From 4d3f35a4228385cf105c4622068be0d53e9e6daa Mon Sep 17 00:00:00 2001 From: Lucio Lelii Date: Mon, 9 Mar 2026 16:55:58 +0100 Subject: [PATCH] Remove undo redo support from flow editor --- .../shared/nodes/generic-node/generic-node.ts | 9 +++- src/app/shared/rete-editor/rete-editor.ts | 1 + .../shared/title-toolbar/title-toolbar.html | 19 -------- src/app/shared/title-toolbar/title-toolbar.ts | 8 ---- src/app/stores/flow-editor.ts | 48 +++---------------- src/app/utilities/rete-editor.ts | 11 ++++- 6 files changed, 25 insertions(+), 71 deletions(-) diff --git a/src/app/shared/nodes/generic-node/generic-node.ts b/src/app/shared/nodes/generic-node/generic-node.ts index c5307d2..fe222f2 100644 --- a/src/app/shared/nodes/generic-node/generic-node.ts +++ b/src/app/shared/nodes/generic-node/generic-node.ts @@ -344,7 +344,7 @@ export class GenericNodeComponent { private markFlowDirty() { const flow = this.editorState.currentFlow(); if (!flow) return; - this.editorState.updateData(flow.data); + this.editorState.updateData(this.cloneFlowData(flow.data)); } private async loadSchemaContext() { @@ -809,6 +809,13 @@ export class GenericNodeComponent { }); } + private cloneFlowData(value: T): T { + if (typeof globalThis.structuredClone === 'function') { + return globalThis.structuredClone(value); + } + return JSON.parse(JSON.stringify(value)) as T; + } + private maybeCreateBlockOnServer() { const nodeData = this.data?.data as Record | undefined; if (!nodeData?.['__needsServerCreate']) return; diff --git a/src/app/shared/rete-editor/rete-editor.ts b/src/app/shared/rete-editor/rete-editor.ts index 27909f9..d90186f 100644 --- a/src/app/shared/rete-editor/rete-editor.ts +++ b/src/app/shared/rete-editor/rete-editor.ts @@ -159,6 +159,7 @@ export class ReteEditor implements OnChanges, OnDestroy { if (this.readonly()) return; this.syncNodePositionFromContext(rete, context); if (this.flowState.currentFlow()?.id !== this.flowId()) return; + const updatedData = exportGraph(rete.editor); this.flowState.updateData(updatedData); this.flowChanged.emit(updatedData); diff --git a/src/app/shared/title-toolbar/title-toolbar.html b/src/app/shared/title-toolbar/title-toolbar.html index 193b247..97e60aa 100644 --- a/src/app/shared/title-toolbar/title-toolbar.html +++ b/src/app/shared/title-toolbar/title-toolbar.html @@ -52,25 +52,6 @@ -
- - - - - diff --git a/src/app/shared/title-toolbar/title-toolbar.ts b/src/app/shared/title-toolbar/title-toolbar.ts index 028bdb7..ddbc0d7 100644 --- a/src/app/shared/title-toolbar/title-toolbar.ts +++ b/src/app/shared/title-toolbar/title-toolbar.ts @@ -66,14 +66,6 @@ export class TitleToolbar { }); } - undo() { - this.editorState.undo(); - } - - redo() { - this.editorState.redo(); - } - execute() { const flow = this.flow(); if (!flow || !this.canExecute() || this.executeLoading()) return; diff --git a/src/app/stores/flow-editor.ts b/src/app/stores/flow-editor.ts index 8811383..6753212 100644 --- a/src/app/stores/flow-editor.ts +++ b/src/app/stores/flow-editor.ts @@ -18,13 +18,6 @@ export class EditorStateHolder { constructor(private confirm: ConfirmDialogService) { } - - previousDataStack : FlowData[] = []; - nextDataStack : FlowData[] = []; - - redoEnabled = computed(() => this.nextDataStack.length > 0); - undoEnabled = computed(() => this.previousDataStack.length > 1); - /** Intent: open document */ async openDocument(doc: Flow, options?: { skipDirtyCheck?: boolean }): Promise { if (this.isDirty() && !options?.skipDirtyCheck) { @@ -60,22 +53,17 @@ export class EditorStateHolder { const current = this.currentFlow(); if (!current) return; - this.currentFlow.update(flow => { - if (!flow) return flow; - return { ...flow, data }; - }); - this.previousDataStack.push(data); + const nextFlow = { ...current, data }; + this.currentFlow.set(nextFlow); this.markDirty(); } updateFlowTitle(newTitle: string) { - const flow = this.currentFlow(); - if (!flow) return; - this.currentFlow.update(flow => { - if (!flow) return flow; - return { ...flow, name: newTitle }; - }); - this.previousDataStack.push(flow.data); + const current = this.currentFlow(); + if (!current) return; + + const nextFlow = { ...current, name: newTitle }; + this.currentFlow.set(nextFlow); this.markDirty(); } @@ -87,26 +75,4 @@ export class EditorStateHolder { }) ) } - - undo() { - const stack = this.previousDataStack; - if (stack.length < 2) return; // Nothing to undo - - // Remove the current state - this.nextDataStack.push(stack.pop()!); - // Get the previous state - const previousData = stack[stack.length - 1]; - this.updateData(previousData); - } - - redo() { - const stack = this.nextDataStack; - if (stack.length === 0) return; // Nothing to redo - - const nextData = stack.pop()!; - this.previousDataStack.push(nextData); - this.updateData(nextData); - } - - } diff --git a/src/app/utilities/rete-editor.ts b/src/app/utilities/rete-editor.ts index c84a0c6..058f010 100644 --- a/src/app/utilities/rete-editor.ts +++ b/src/app/utilities/rete-editor.ts @@ -103,7 +103,7 @@ export function exportGraph(editor: NodeEditor) { position: blockData?.position, inputs, outputs, - specificConfiguration: blockData?.specificConfiguration ?? {}, + specificConfiguration: cloneValue(blockData?.specificConfiguration ?? {}), typeName: blockData?.typeName ?? "LLMBlock" }; }); @@ -140,7 +140,7 @@ export async function addBlockToEditor( await addBlockToEditor(editor, area, { ...createdBlock, position: currentPosition }, currentPosition); }; node.data = { - ...block, + ...cloneValue(block), position: position ?? block.position, deleteNode: removeNode, replaceWithCreatedBlock @@ -206,3 +206,10 @@ function toNodeLabel(typeName: string) { if (typeName === "OutputBlock") return "Output"; return typeName; } + +function cloneValue(value: T): T { + if (typeof globalThis.structuredClone === "function") { + return globalThis.structuredClone(value); + } + return JSON.parse(JSON.stringify(value)) as T; +}