mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 07:43:41 +00:00
fix: remove unused variables
This commit is contained in:
parent
e7ff53dcd7
commit
79edc902c5
1 changed files with 150 additions and 97 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { useCallback, useMemo, useEffect, useState, useRef } from 'react';
|
import { useCallback, useMemo, useEffect, useState, useRef } from "react";
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
Controls,
|
Controls,
|
||||||
|
|
@ -18,24 +18,24 @@ import ReactFlow, {
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
Viewport,
|
Viewport,
|
||||||
useOnSelectionChange,
|
useOnSelectionChange,
|
||||||
} from 'reactflow';
|
} from "reactflow";
|
||||||
import 'reactflow/dist/style.css';
|
import "reactflow/dist/style.css";
|
||||||
|
|
||||||
import { useGraphWithHistory } from '../../hooks/useGraphWithHistory';
|
import { useGraphWithHistory } from "../../hooks/useGraphWithHistory";
|
||||||
import { useDocumentHistory } from '../../hooks/useDocumentHistory';
|
import { useDocumentHistory } from "../../hooks/useDocumentHistory";
|
||||||
import { useEditorStore } from '../../stores/editorStore';
|
import { useEditorStore } from "../../stores/editorStore";
|
||||||
import { useActiveDocument } from '../../stores/workspace/useActiveDocument';
|
import { useActiveDocument } from "../../stores/workspace/useActiveDocument";
|
||||||
import { useWorkspaceStore } from '../../stores/workspaceStore';
|
import { useWorkspaceStore } from "../../stores/workspaceStore";
|
||||||
import CustomNode from '../Nodes/CustomNode';
|
import CustomNode from "../Nodes/CustomNode";
|
||||||
import CustomEdge from '../Edges/CustomEdge';
|
import CustomEdge from "../Edges/CustomEdge";
|
||||||
import ContextMenu from './ContextMenu';
|
import ContextMenu from "./ContextMenu";
|
||||||
import EmptyState from '../Common/EmptyState';
|
import EmptyState from "../Common/EmptyState";
|
||||||
import { createNode } from '../../utils/nodeUtils';
|
import { createNode } from "../../utils/nodeUtils";
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import { useConfirm } from '../../hooks/useConfirm';
|
import { useConfirm } from "../../hooks/useConfirm";
|
||||||
|
|
||||||
import type { Actor, Relation } from '../../types';
|
import type { Actor, Relation } from "../../types";
|
||||||
|
|
||||||
interface GraphEditorProps {
|
interface GraphEditorProps {
|
||||||
selectedNode: Actor | null;
|
selectedNode: Actor | null;
|
||||||
|
|
@ -77,11 +77,21 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
|
|
||||||
const { pushToHistory } = useDocumentHistory();
|
const { pushToHistory } = useDocumentHistory();
|
||||||
|
|
||||||
const { showGrid, snapToGrid, gridSize, panOnDrag, zoomOnScroll, selectedRelationType } =
|
const {
|
||||||
useEditorStore();
|
showGrid,
|
||||||
|
snapToGrid,
|
||||||
|
gridSize,
|
||||||
|
panOnDrag,
|
||||||
|
zoomOnScroll,
|
||||||
|
selectedRelationType,
|
||||||
|
} = useEditorStore();
|
||||||
|
|
||||||
// React Flow instance for screen-to-flow coordinates and viewport control
|
// React Flow instance for screen-to-flow coordinates and viewport control
|
||||||
const { screenToFlowPosition, setViewport, getViewport: getCurrentViewport } = useReactFlow();
|
const {
|
||||||
|
screenToFlowPosition,
|
||||||
|
setViewport,
|
||||||
|
getViewport: getCurrentViewport,
|
||||||
|
} = useReactFlow();
|
||||||
|
|
||||||
// Track previous document ID to save viewport before switching
|
// Track previous document ID to save viewport before switching
|
||||||
const prevDocumentIdRef = useRef<string | null>(null);
|
const prevDocumentIdRef = useRef<string | null>(null);
|
||||||
|
|
@ -90,8 +100,12 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
const { confirm, ConfirmDialogComponent } = useConfirm();
|
const { confirm, ConfirmDialogComponent } = useConfirm();
|
||||||
|
|
||||||
// React Flow state (synchronized with store)
|
// React Flow state (synchronized with store)
|
||||||
const [nodes, setNodesState, onNodesChange] = useNodesState(storeNodes as Node[]);
|
const [nodes, setNodesState, onNodesChange] = useNodesState(
|
||||||
const [edges, setEdgesState, onEdgesChange] = useEdgesState(storeEdges as Edge[]);
|
storeNodes as Node[],
|
||||||
|
);
|
||||||
|
const [edges, setEdgesState, onEdgesChange] = useEdgesState(
|
||||||
|
storeEdges as Edge[],
|
||||||
|
);
|
||||||
|
|
||||||
// Track if a drag is in progress to capture state before drag
|
// Track if a drag is in progress to capture state before drag
|
||||||
const dragInProgressRef = useRef(false);
|
const dragInProgressRef = useRef(false);
|
||||||
|
|
@ -100,7 +114,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
const [contextMenu, setContextMenu] = useState<{
|
const [contextMenu, setContextMenu] = useState<{
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
type: 'pane' | 'node' | 'edge';
|
type: "pane" | "node" | "edge";
|
||||||
target?: Node | Edge;
|
target?: Node | Edge;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
|
|
@ -118,22 +132,37 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
if (!activeDocumentId) return;
|
if (!activeDocumentId) return;
|
||||||
|
|
||||||
// Save viewport for the previous document
|
// Save viewport for the previous document
|
||||||
if (prevDocumentIdRef.current && prevDocumentIdRef.current !== activeDocumentId) {
|
if (
|
||||||
|
prevDocumentIdRef.current &&
|
||||||
|
prevDocumentIdRef.current !== activeDocumentId
|
||||||
|
) {
|
||||||
const currentViewport = getCurrentViewport();
|
const currentViewport = getCurrentViewport();
|
||||||
saveViewport(prevDocumentIdRef.current, currentViewport);
|
saveViewport(prevDocumentIdRef.current, currentViewport);
|
||||||
console.log(`Saved viewport for document: ${prevDocumentIdRef.current}`, currentViewport);
|
console.log(
|
||||||
|
`Saved viewport for document: ${prevDocumentIdRef.current}`,
|
||||||
|
currentViewport,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore viewport for the new document
|
// Restore viewport for the new document
|
||||||
const savedViewport = getViewport(activeDocumentId);
|
const savedViewport = getViewport(activeDocumentId);
|
||||||
if (savedViewport) {
|
if (savedViewport) {
|
||||||
console.log(`Restoring viewport for document: ${activeDocumentId}`, savedViewport);
|
console.log(
|
||||||
|
`Restoring viewport for document: ${activeDocumentId}`,
|
||||||
|
savedViewport,
|
||||||
|
);
|
||||||
setViewport(savedViewport, { duration: 0 });
|
setViewport(savedViewport, { duration: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the ref to current document
|
// Update the ref to current document
|
||||||
prevDocumentIdRef.current = activeDocumentId;
|
prevDocumentIdRef.current = activeDocumentId;
|
||||||
}, [activeDocumentId, saveViewport, getViewport, setViewport, getCurrentViewport]);
|
}, [
|
||||||
|
activeDocumentId,
|
||||||
|
saveViewport,
|
||||||
|
getViewport,
|
||||||
|
setViewport,
|
||||||
|
getCurrentViewport,
|
||||||
|
]);
|
||||||
|
|
||||||
// Save viewport periodically (debounced)
|
// Save viewport periodically (debounced)
|
||||||
const handleViewportChange = useCallback(
|
const handleViewportChange = useCallback(
|
||||||
|
|
@ -147,12 +176,18 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
|
|
||||||
return () => clearTimeout(timeoutId);
|
return () => clearTimeout(timeoutId);
|
||||||
},
|
},
|
||||||
[activeDocumentId, saveViewport]
|
[activeDocumentId, saveViewport],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle selection changes using ReactFlow's dedicated hook
|
// Handle selection changes using ReactFlow's dedicated hook
|
||||||
const handleSelectionChange = useCallback(
|
const handleSelectionChange = useCallback(
|
||||||
({ nodes: selectedNodes, edges: selectedEdges }: { nodes: Node[]; edges: Edge[] }) => {
|
({
|
||||||
|
nodes: selectedNodes,
|
||||||
|
edges: selectedEdges,
|
||||||
|
}: {
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
}) => {
|
||||||
// If a node is selected, notify parent
|
// If a node is selected, notify parent
|
||||||
if (selectedNodes.length > 0) {
|
if (selectedNodes.length > 0) {
|
||||||
const selectedNode = selectedNodes[0] as Actor;
|
const selectedNode = selectedNodes[0] as Actor;
|
||||||
|
|
@ -171,7 +206,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
onEdgeSelect(null);
|
onEdgeSelect(null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onNodeSelect, onEdgeSelect]
|
[onNodeSelect, onEdgeSelect],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register the selection change handler with ReactFlow
|
// Register the selection change handler with ReactFlow
|
||||||
|
|
@ -186,9 +221,9 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
// Check if a drag operation just started (dragging: true)
|
// Check if a drag operation just started (dragging: true)
|
||||||
const dragStartChanges = changes.filter(
|
const dragStartChanges = changes.filter(
|
||||||
(change) =>
|
(change) =>
|
||||||
change.type === 'position' &&
|
change.type === "position" &&
|
||||||
'dragging' in change &&
|
"dragging" in change &&
|
||||||
change.dragging === true
|
change.dragging === true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Capture state BEFORE the drag operation begins (for undo/redo)
|
// Capture state BEFORE the drag operation begins (for undo/redo)
|
||||||
|
|
@ -196,7 +231,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
if (dragStartChanges.length > 0 && !dragInProgressRef.current) {
|
if (dragStartChanges.length > 0 && !dragInProgressRef.current) {
|
||||||
dragInProgressRef.current = true;
|
dragInProgressRef.current = true;
|
||||||
// Capture the state before any changes are applied
|
// Capture the state before any changes are applied
|
||||||
pushToHistory('Move Actor');
|
pushToHistory("Move Actor");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the changes
|
// Apply the changes
|
||||||
|
|
@ -205,9 +240,9 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
// Check if any drag operation just completed (dragging: false)
|
// Check if any drag operation just completed (dragging: false)
|
||||||
const dragEndChanges = changes.filter(
|
const dragEndChanges = changes.filter(
|
||||||
(change) =>
|
(change) =>
|
||||||
change.type === 'position' &&
|
change.type === "position" &&
|
||||||
'dragging' in change &&
|
"dragging" in change &&
|
||||||
change.dragging === false
|
change.dragging === false,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If a drag just ended, sync to store
|
// If a drag just ended, sync to store
|
||||||
|
|
@ -224,7 +259,10 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
} else {
|
} else {
|
||||||
// For non-drag changes (dimension, etc), just sync to store
|
// For non-drag changes (dimension, etc), just sync to store
|
||||||
const hasNonSelectionChanges = changes.some(
|
const hasNonSelectionChanges = changes.some(
|
||||||
(change) => change.type !== 'select' && change.type !== 'remove' && change.type !== 'position'
|
(change) =>
|
||||||
|
change.type !== "select" &&
|
||||||
|
change.type !== "remove" &&
|
||||||
|
change.type !== "position",
|
||||||
);
|
);
|
||||||
if (hasNonSelectionChanges) {
|
if (hasNonSelectionChanges) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -236,7 +274,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onNodesChange, setNodesState, setNodes, pushToHistory]
|
[onNodesChange, setNodesState, setNodes, pushToHistory],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleEdgesChange = useCallback(
|
const handleEdgesChange = useCallback(
|
||||||
|
|
@ -245,7 +283,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
|
|
||||||
// Only sync to store for non-selection changes
|
// Only sync to store for non-selection changes
|
||||||
const hasNonSelectionChanges = changes.some(
|
const hasNonSelectionChanges = changes.some(
|
||||||
(change) => change.type !== 'select' && change.type !== 'remove'
|
(change) => change.type !== "select" && change.type !== "remove",
|
||||||
);
|
);
|
||||||
if (hasNonSelectionChanges) {
|
if (hasNonSelectionChanges) {
|
||||||
// Debounce store updates to avoid loops
|
// Debounce store updates to avoid loops
|
||||||
|
|
@ -257,7 +295,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onEdgesChange, setEdgesState, setEdges]
|
[onEdgesChange, setEdgesState, setEdges],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle new edge connections
|
// Handle new edge connections
|
||||||
|
|
@ -266,12 +304,13 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
if (!connection.source || !connection.target) return;
|
if (!connection.source || !connection.target) return;
|
||||||
|
|
||||||
// Use selected relation type or fall back to first available
|
// Use selected relation type or fall back to first available
|
||||||
const edgeType = selectedRelationType || edgeTypeConfigs[0]?.id || 'default';
|
const edgeType =
|
||||||
|
selectedRelationType || edgeTypeConfigs[0]?.id || "default";
|
||||||
|
|
||||||
// Create edge with custom data (no label - will use type default)
|
// Create edge with custom data (no label - will use type default)
|
||||||
const edgeWithData = {
|
const edgeWithData = {
|
||||||
...connection,
|
...connection,
|
||||||
type: 'custom',
|
type: "custom",
|
||||||
data: {
|
data: {
|
||||||
type: edgeType,
|
type: edgeType,
|
||||||
// Don't set label - will use type's label as default
|
// Don't set label - will use type's label as default
|
||||||
|
|
@ -292,7 +331,14 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
// Use the history-tracked addEdge function
|
// Use the history-tracked addEdge function
|
||||||
addEdgeWithHistory(newEdge);
|
addEdgeWithHistory(newEdge);
|
||||||
},
|
},
|
||||||
[storeEdges, edgeTypeConfigs, addEdgeWithHistory, selectedRelationType, nodes, setNodesState]
|
[
|
||||||
|
storeEdges,
|
||||||
|
edgeTypeConfigs,
|
||||||
|
addEdgeWithHistory,
|
||||||
|
selectedRelationType,
|
||||||
|
nodes,
|
||||||
|
setNodesState,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle node deletion
|
// Handle node deletion
|
||||||
|
|
@ -302,7 +348,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
deleteNode(node.id);
|
deleteNode(node.id);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[deleteNode]
|
[deleteNode],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle edge deletion
|
// Handle edge deletion
|
||||||
|
|
@ -312,7 +358,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
deleteEdge(edge.id);
|
deleteEdge(edge.id);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[deleteEdge]
|
[deleteEdge],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register custom node types
|
// Register custom node types
|
||||||
|
|
@ -320,7 +366,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
() => ({
|
() => ({
|
||||||
custom: CustomNode,
|
custom: CustomNode,
|
||||||
}),
|
}),
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register custom edge types
|
// Register custom edge types
|
||||||
|
|
@ -328,37 +374,28 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
() => ({
|
() => ({
|
||||||
custom: CustomEdge,
|
custom: CustomEdge,
|
||||||
}),
|
}),
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle node click - ReactFlow handles selection automatically
|
// Handle node click - ReactFlow handles selection automatically
|
||||||
const handleNodeClick = useCallback(
|
const handleNodeClick = useCallback(() => {
|
||||||
(_event: React.MouseEvent, _node: Node) => {
|
|
||||||
setContextMenu(null); // Close context menu if open
|
setContextMenu(null); // Close context menu if open
|
||||||
},
|
}, []);
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle edge click - ReactFlow handles selection automatically
|
// Handle edge click - ReactFlow handles selection automatically
|
||||||
const handleEdgeClick = useCallback(
|
const handleEdgeClick = useCallback(() => {
|
||||||
(_event: React.MouseEvent, _edge: Edge) => {
|
|
||||||
setContextMenu(null); // Close context menu if open
|
setContextMenu(null); // Close context menu if open
|
||||||
},
|
}, []);
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle right-click on pane (empty space)
|
// Handle right-click on pane (empty space)
|
||||||
const handlePaneContextMenu = useCallback(
|
const handlePaneContextMenu = useCallback((event: React.MouseEvent) => {
|
||||||
(event: React.MouseEvent) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setContextMenu({
|
setContextMenu({
|
||||||
x: event.clientX,
|
x: event.clientX,
|
||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
type: 'pane',
|
type: "pane",
|
||||||
});
|
});
|
||||||
},
|
}, []);
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle right-click on node
|
// Handle right-click on node
|
||||||
const handleNodeContextMenu = useCallback(
|
const handleNodeContextMenu = useCallback(
|
||||||
|
|
@ -367,11 +404,11 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
setContextMenu({
|
setContextMenu({
|
||||||
x: event.clientX,
|
x: event.clientX,
|
||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
type: 'node',
|
type: "node",
|
||||||
target: node,
|
target: node,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle right-click on edge
|
// Handle right-click on edge
|
||||||
|
|
@ -381,11 +418,11 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
setContextMenu({
|
setContextMenu({
|
||||||
x: event.clientX,
|
x: event.clientX,
|
||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
type: 'edge',
|
type: "edge",
|
||||||
target: edge,
|
target: edge,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle left-click on pane to close context menu
|
// Handle left-click on pane to close context menu
|
||||||
|
|
@ -419,7 +456,16 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
addNodeWithHistory(newNode);
|
addNodeWithHistory(newNode);
|
||||||
setContextMenu(null);
|
setContextMenu(null);
|
||||||
},
|
},
|
||||||
[contextMenu, screenToFlowPosition, nodeTypeConfigs, addNodeWithHistory, nodes, edges, setNodesState, setEdgesState]
|
[
|
||||||
|
contextMenu,
|
||||||
|
screenToFlowPosition,
|
||||||
|
nodeTypeConfigs,
|
||||||
|
addNodeWithHistory,
|
||||||
|
nodes,
|
||||||
|
edges,
|
||||||
|
setNodesState,
|
||||||
|
setEdgesState,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Show empty state when no document is active
|
// Show empty state when no document is active
|
||||||
|
|
@ -430,7 +476,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
onOpenDocumentManager={() => {
|
onOpenDocumentManager={() => {
|
||||||
// This will be handled by the parent component
|
// This will be handled by the parent component
|
||||||
// We'll trigger it via a custom event
|
// We'll trigger it via a custom event
|
||||||
window.dispatchEvent(new CustomEvent('openDocumentManager'));
|
window.dispatchEvent(new CustomEvent("openDocumentManager"));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -483,9 +529,9 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
nodeColor={(node) => {
|
nodeColor={(node) => {
|
||||||
const actor = node as Actor;
|
const actor = node as Actor;
|
||||||
const nodeType = nodeTypeConfigs.find(
|
const nodeType = nodeTypeConfigs.find(
|
||||||
(nt) => nt.id === actor.data?.type
|
(nt) => nt.id === actor.data?.type,
|
||||||
);
|
);
|
||||||
return nodeType?.color || '#6b7280';
|
return nodeType?.color || "#6b7280";
|
||||||
}}
|
}}
|
||||||
pannable
|
pannable
|
||||||
zoomable
|
zoomable
|
||||||
|
|
@ -493,13 +539,13 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
|
||||||
{/* Context Menu - Pane */}
|
{/* Context Menu - Pane */}
|
||||||
{contextMenu && contextMenu.type === 'pane' && (
|
{contextMenu && contextMenu.type === "pane" && (
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
x={contextMenu.x}
|
x={contextMenu.x}
|
||||||
y={contextMenu.y}
|
y={contextMenu.y}
|
||||||
sections={[
|
sections={[
|
||||||
{
|
{
|
||||||
title: 'Add Actor',
|
title: "Add Actor",
|
||||||
actions: nodeTypeConfigs.map((nodeType) => ({
|
actions: nodeTypeConfigs.map((nodeType) => ({
|
||||||
label: nodeType.label,
|
label: nodeType.label,
|
||||||
color: nodeType.color,
|
color: nodeType.color,
|
||||||
|
|
@ -512,7 +558,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Context Menu - Node */}
|
{/* Context Menu - Node */}
|
||||||
{contextMenu && contextMenu.type === 'node' && contextMenu.target && (
|
{contextMenu && contextMenu.type === "node" && contextMenu.target && (
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
x={contextMenu.x}
|
x={contextMenu.x}
|
||||||
y={contextMenu.y}
|
y={contextMenu.y}
|
||||||
|
|
@ -520,7 +566,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
{
|
{
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
label: 'Edit Properties',
|
label: "Edit Properties",
|
||||||
icon: <EditIcon fontSize="small" />,
|
icon: <EditIcon fontSize="small" />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
// Select the node in ReactFlow (which will trigger the right panel)
|
// Select the node in ReactFlow (which will trigger the right panel)
|
||||||
|
|
@ -529,21 +575,25 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
...n,
|
...n,
|
||||||
selected: n.id === nodeId,
|
selected: n.id === nodeId,
|
||||||
}));
|
}));
|
||||||
const updatedEdges = edges.map((e) => ({ ...e, selected: false }));
|
const updatedEdges = edges.map((e) => ({
|
||||||
|
...e,
|
||||||
|
selected: false,
|
||||||
|
}));
|
||||||
setNodesState(updatedNodes as Node[]);
|
setNodesState(updatedNodes as Node[]);
|
||||||
setEdgesState(updatedEdges as Edge[]);
|
setEdgesState(updatedEdges as Edge[]);
|
||||||
setContextMenu(null);
|
setContextMenu(null);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Delete',
|
label: "Delete",
|
||||||
icon: <DeleteIcon fontSize="small" />,
|
icon: <DeleteIcon fontSize="small" />,
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
const confirmed = await confirm({
|
const confirmed = await confirm({
|
||||||
title: 'Delete Actor',
|
title: "Delete Actor",
|
||||||
message: 'Are you sure you want to delete this actor? All connected relations will also be deleted.',
|
message:
|
||||||
confirmLabel: 'Delete',
|
"Are you sure you want to delete this actor? All connected relations will also be deleted.",
|
||||||
severity: 'danger',
|
confirmLabel: "Delete",
|
||||||
|
severity: "danger",
|
||||||
});
|
});
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
deleteNode(contextMenu.target!.id);
|
deleteNode(contextMenu.target!.id);
|
||||||
|
|
@ -559,7 +609,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Context Menu - Edge */}
|
{/* Context Menu - Edge */}
|
||||||
{contextMenu && contextMenu.type === 'edge' && contextMenu.target && (
|
{contextMenu && contextMenu.type === "edge" && contextMenu.target && (
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
x={contextMenu.x}
|
x={contextMenu.x}
|
||||||
y={contextMenu.y}
|
y={contextMenu.y}
|
||||||
|
|
@ -567,7 +617,7 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
{
|
{
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
label: 'Edit Properties',
|
label: "Edit Properties",
|
||||||
icon: <EditIcon fontSize="small" />,
|
icon: <EditIcon fontSize="small" />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
// Select the edge in ReactFlow (which will trigger the right panel)
|
// Select the edge in ReactFlow (which will trigger the right panel)
|
||||||
|
|
@ -576,21 +626,24 @@ const GraphEditor = ({ onNodeSelect, onEdgeSelect }: GraphEditorProps) => {
|
||||||
...e,
|
...e,
|
||||||
selected: e.id === edgeId,
|
selected: e.id === edgeId,
|
||||||
}));
|
}));
|
||||||
const updatedNodes = nodes.map((n) => ({ ...n, selected: false }));
|
const updatedNodes = nodes.map((n) => ({
|
||||||
|
...n,
|
||||||
|
selected: false,
|
||||||
|
}));
|
||||||
setEdgesState(updatedEdges as Edge[]);
|
setEdgesState(updatedEdges as Edge[]);
|
||||||
setNodesState(updatedNodes as Node[]);
|
setNodesState(updatedNodes as Node[]);
|
||||||
setContextMenu(null);
|
setContextMenu(null);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Delete',
|
label: "Delete",
|
||||||
icon: <DeleteIcon fontSize="small" />,
|
icon: <DeleteIcon fontSize="small" />,
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
const confirmed = await confirm({
|
const confirmed = await confirm({
|
||||||
title: 'Delete Relation',
|
title: "Delete Relation",
|
||||||
message: 'Are you sure you want to delete this relation?',
|
message: "Are you sure you want to delete this relation?",
|
||||||
confirmLabel: 'Delete',
|
confirmLabel: "Delete",
|
||||||
severity: 'danger',
|
severity: "danger",
|
||||||
});
|
});
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
deleteEdge(contextMenu.target!.id);
|
deleteEdge(contextMenu.target!.id);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue