diff --git a/packages/editor-ui/src/__tests__/data/canvas.ts b/packages/editor-ui/src/__tests__/data/canvas.ts index 95c2ff3a5e..fd4516b4ac 100644 --- a/packages/editor-ui/src/__tests__/data/canvas.ts +++ b/packages/editor-ui/src/__tests__/data/canvas.ts @@ -64,12 +64,20 @@ export function createCanvasNodeProps({ id = 'node', label = 'Test Node', selected = false, + readOnly = false, data = {}, -}: { id?: string; label?: string; selected?: boolean; data?: Partial } = {}) { +}: { + id?: string; + label?: string; + selected?: boolean; + readOnly?: boolean; + data?: Partial; +} = {}) { return { id, label, selected, + readOnly, data: createCanvasNodeData(data), }; } diff --git a/packages/editor-ui/src/components/canvas/Canvas.vue b/packages/editor-ui/src/components/canvas/Canvas.vue index 4fdbc71503..b9f1ab4cb0 100644 --- a/packages/editor-ui/src/components/canvas/Canvas.vue +++ b/packages/editor-ui/src/components/canvas/Canvas.vue @@ -7,7 +7,7 @@ import { Controls } from '@vue-flow/controls'; import { MiniMap } from '@vue-flow/minimap'; import Node from './elements/nodes/CanvasNode.vue'; import Edge from './elements/edges/CanvasEdge.vue'; -import { computed, onMounted, onUnmounted, ref, useCssModule } from 'vue'; +import { computed, onMounted, onUnmounted, ref, useCssModule, watch } from 'vue'; import type { EventBus } from 'n8n-design-system'; import { createEventBus } from 'n8n-design-system'; import { useContextMenu, type ContextMenuAction } from '@/composables/useContextMenu'; @@ -59,6 +59,7 @@ const props = withDefaults( connections: CanvasConnection[]; controlsPosition?: PanelPosition; eventBus?: EventBus; + readOnly?: boolean; }>(), { id: 'canvas', @@ -66,6 +67,7 @@ const props = withDefaults( connections: () => [], controlsPosition: PanelPosition.BottomLeft, eventBus: () => createEventBus(), + readOnly: false, }, ); @@ -75,6 +77,8 @@ const { removeSelectedNodes, viewportRef, fitView, + setInteractive, + elementsSelectable, project, nodes: graphNodes, onPaneReady, @@ -267,6 +271,11 @@ async function onFitView() { await fitView({ maxZoom: 1.2, padding: 0.1 }); } +function setReadonly(value: boolean) { + setInteractive(!value); + elementsSelectable.value = true; +} + /** * Context menu */ @@ -337,6 +346,10 @@ onPaneReady(async () => { await onFitView(); paneReady.value = true; }); + +watch(() => props.readOnly, setReadonly, { + immediate: true, +});