diff --git a/src/components/FlowEditor/editor/Automation2FlowEditor.module.css b/src/components/FlowEditor/editor/Automation2FlowEditor.module.css index fecec92..42fb1aa 100644 --- a/src/components/FlowEditor/editor/Automation2FlowEditor.module.css +++ b/src/components/FlowEditor/editor/Automation2FlowEditor.module.css @@ -593,7 +593,7 @@ .canvasArea { flex: 1; - padding: 2rem; + padding: 0; min-height: 400px; overflow-x: visible; overflow-y: hidden; diff --git a/src/components/FlowEditor/editor/Automation2FlowEditor.tsx b/src/components/FlowEditor/editor/Automation2FlowEditor.tsx index 4d3e24e..b55e4ed 100644 --- a/src/components/FlowEditor/editor/Automation2FlowEditor.tsx +++ b/src/components/FlowEditor/editor/Automation2FlowEditor.tsx @@ -136,6 +136,7 @@ export const Automation2FlowEditor: React.FC = ({ in zoom: 1, selectedNodeCount: 0, connectionSelected: false, + stickyNoteSelected: false, }); const [canvasConnectionToolActive, setCanvasConnectionToolActive] = useState(false); const [canvasStickyNotes, setCanvasStickyNotes] = useState([]); @@ -822,6 +823,7 @@ export const Automation2FlowEditor: React.FC = ({ in zoomPercent: Math.round(canvasViewportEdit.zoom * 100), selectedNodeCount: canvasViewportEdit.selectedNodeCount, connectionSelected: canvasViewportEdit.connectionSelected, + stickyNoteSelected: canvasViewportEdit.stickyNoteSelected, connectionToolActive: canvasConnectionToolActive, canUndo: canCanvasUndo, canRedo: canCanvasRedo, diff --git a/src/components/FlowEditor/editor/CanvasHeader.tsx b/src/components/FlowEditor/editor/CanvasHeader.tsx index 4daeb09..5c013bf 100644 --- a/src/components/FlowEditor/editor/CanvasHeader.tsx +++ b/src/components/FlowEditor/editor/CanvasHeader.tsx @@ -39,6 +39,7 @@ export interface CanvasHeaderCanvasEditProps { zoomPercent: number; selectedNodeCount: number; connectionSelected: boolean; + stickyNoteSelected: boolean; connectionToolActive: boolean; canUndo: boolean; canRedo: boolean; @@ -206,7 +207,10 @@ export const CanvasHeader: React.FC = ({ }; const _canDeleteSelection = - !!canvasEdit && (canvasEdit.selectedNodeCount > 0 || canvasEdit.connectionSelected); + !!canvasEdit && + (canvasEdit.selectedNodeCount > 0 || + canvasEdit.connectionSelected || + canvasEdit.stickyNoteSelected); const _singleNodeOnly = !!canvasEdit && canvasEdit.selectedNodeCount === 1 && !canvasEdit.connectionSelected; diff --git a/src/components/FlowEditor/editor/FlowCanvas.tsx b/src/components/FlowEditor/editor/FlowCanvas.tsx index 0961c9d..511f574 100644 --- a/src/components/FlowEditor/editor/FlowCanvas.tsx +++ b/src/components/FlowEditor/editor/FlowCanvas.tsx @@ -123,6 +123,8 @@ export interface FlowCanvasViewportEditState { zoom: number; selectedNodeCount: number; connectionSelected: boolean; + /** Canvas-Sticky-/Kommentarnote ausgewählt (nicht Workflow-Knoten). */ + stickyNoteSelected: boolean; } export type FlowCanvasHandle = { @@ -518,8 +520,9 @@ export const FlowCanvas = forwardRef(function zoom, selectedNodeCount: selectedNodeIds.size, connectionSelected: !!selectedConnectionId, + stickyNoteSelected: !!selectedStickyId, }); - }, [zoom, selectedNodeIds, selectedConnectionId, onViewportEditState]); + }, [zoom, selectedNodeIds, selectedConnectionId, selectedStickyId, onViewportEditState]); useEffect(() => { onConnectionToolActiveChange?.(connectionToolActive); @@ -590,17 +593,27 @@ export const FlowCanvas = forwardRef(function emitHistoryCheckpoint(); return; } - if (selectedNodeIds.size === 0) return; - const ids = selectedNodeIds; - onNodesChange(nodes.filter((n) => !ids.has(n.id))); - onConnectionsChange( - connections.filter((c) => !ids.has(c.sourceId) && !ids.has(c.targetId)) - ); - setSelectedNodeIds(new Set()); - setEditingNodeId(null); - setEditingField(null); - setSelectedStickyId(null); - emitHistoryCheckpoint(); + if (selectedNodeIds.size > 0) { + const ids = selectedNodeIds; + onNodesChange(nodes.filter((n) => !ids.has(n.id))); + onConnectionsChange( + connections.filter((c) => !ids.has(c.sourceId) && !ids.has(c.targetId)) + ); + setSelectedNodeIds(new Set()); + setEditingNodeId(null); + setEditingField(null); + setSelectedStickyId(null); + emitHistoryCheckpoint(); + return; + } + const changeSticky = onStickyNotesChangeRef.current; + const sid = selectedStickyId; + if (sid && changeSticky) { + changeSticky(stickyNotesRef.current.filter((s) => s.id !== sid)); + setSelectedStickyId(null); + setEditingStickyId(null); + emitHistoryCheckpoint(); + } }, duplicateSingleSelection: () => { if (selectedNodeIds.size !== 1) return; @@ -663,6 +676,7 @@ export const FlowCanvas = forwardRef(function onNodesChange, selectedConnectionId, selectedNodeIds, + selectedStickyId, ] ); @@ -1199,6 +1213,15 @@ export const FlowCanvas = forwardRef(function emitHistoryCheckpoint(); }, [selectedNodeIds, nodes, connections, onNodesChange, onConnectionsChange, emitHistoryCheckpoint]); + const handleDeleteSelectedStickyNote = useCallback(() => { + const change = onStickyNotesChangeRef.current; + if (!selectedStickyId || !change) return; + change(stickyNotesRef.current.filter((s) => s.id !== selectedStickyId)); + setSelectedStickyId(null); + setEditingStickyId(null); + emitHistoryCheckpoint(); + }, [selectedStickyId, emitHistoryCheckpoint]); + React.useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { const target = e.target as HTMLElement; @@ -1220,12 +1243,22 @@ export const FlowCanvas = forwardRef(function } else if (selectedNodeIds.size > 0) { e.preventDefault(); handleDeleteNode(); + } else if (selectedStickyId && onStickyNotesChangeRef.current) { + e.preventDefault(); + handleDeleteSelectedStickyNote(); } } }; window.addEventListener('keydown', onKeyDown); return () => window.removeEventListener('keydown', onKeyDown); - }, [handleDeleteNode, handleDeleteConnection, selectedNodeIds.size, selectedConnectionId]); + }, [ + handleDeleteNode, + handleDeleteConnection, + handleDeleteSelectedStickyNote, + selectedNodeIds.size, + selectedConnectionId, + selectedStickyId, + ]); const handleNodeUpdate = useCallback( (nodeId: string, updates: Partial>) => { @@ -1778,6 +1811,11 @@ export const FlowCanvas = forwardRef(function backgroundColor: pal.bg, borderColor: pal.border, }} + onFocus={() => { + setSelectedStickyId(sn.id); + setSelectedNodeIds(new Set()); + setSelectedConnectionId(null); + }} onDoubleClick={(e) => { e.stopPropagation(); setSelectedStickyId(sn.id);