diff --git a/src/components/Editor/EdgePropertiesPanel.tsx b/src/components/Editor/EdgePropertiesPanel.tsx deleted file mode 100644 index 618d033..0000000 --- a/src/components/Editor/EdgePropertiesPanel.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import { useState, useEffect } from 'react'; -import { useGraphWithHistory } from '../../hooks/useGraphWithHistory'; -import PropertyPanel from '../Common/PropertyPanel'; -import LabelSelector from '../Common/LabelSelector'; -import type { Relation } from '../../types'; - -/** - * EdgePropertiesPanel - Side panel for editing edge/relation properties - * - * Features: - * - Change relation type - * - Edit relation label - * - Delete relation - * - Visual preview of line style - */ - -interface Props { - selectedEdge: Relation | null; - onClose: () => void; -} - -const EdgePropertiesPanel = ({ selectedEdge, onClose }: Props) => { - const { edgeTypes, updateEdge, deleteEdge } = useGraphWithHistory(); - const [relationType, setRelationType] = useState(''); - const [relationLabel, setRelationLabel] = useState(''); - const [relationLabels, setRelationLabels] = useState([]); - - useEffect(() => { - if (selectedEdge && selectedEdge.data) { - setRelationType(selectedEdge.data.type || ''); - // Only show custom label if it exists and differs from type label - const typeLabel = edgeTypes.find((et) => et.id === selectedEdge.data?.type)?.label; - const hasCustomLabel = selectedEdge.data.label && selectedEdge.data.label !== typeLabel; - setRelationLabel((hasCustomLabel && selectedEdge.data.label) || ''); - setRelationLabels(selectedEdge.data.labels || []); - } - }, [selectedEdge, edgeTypes]); - - const handleSave = () => { - if (!selectedEdge) return; - updateEdge(selectedEdge.id, { - type: relationType, - // Only set label if user provided a custom one (not empty) - label: relationLabel.trim() || undefined, - labels: relationLabels.length > 0 ? relationLabels : undefined, - }); - onClose(); - }; - - const handleDelete = () => { - if (!selectedEdge) return; - deleteEdge(selectedEdge.id); - onClose(); - }; - - const selectedEdgeTypeConfig = edgeTypes.find((et) => et.id === relationType); - - const renderStylePreview = () => { - if (!selectedEdgeTypeConfig) return null; - - const strokeDasharray = { - solid: '0', - dashed: '8,4', - dotted: '2,4', - }[selectedEdgeTypeConfig.style || 'solid']; - - return ( - - - - ); - }; - - return ( - - {/* Relation Type */} -
- - - {renderStylePreview()} -
- - {/* Custom Label */} -
- - setRelationLabel(e.target.value)} - placeholder={selectedEdgeTypeConfig?.label || 'Enter label'} - className="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" - /> -

- Leave empty to use default type label -

-
- - {/* Labels */} -
- - -
- - {/* Connection Info */} - {selectedEdge && ( -
-

- From: {selectedEdge.source} -

-

- To: {selectedEdge.target} -

-
- )} -
- ); -}; - -export default EdgePropertiesPanel; diff --git a/src/components/Editor/NodePropertiesPanel.tsx b/src/components/Editor/NodePropertiesPanel.tsx deleted file mode 100644 index 319e549..0000000 --- a/src/components/Editor/NodePropertiesPanel.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { useState, useEffect, useRef } from 'react'; -import { useGraphWithHistory } from '../../hooks/useGraphWithHistory'; -import PropertyPanel from '../Common/PropertyPanel'; -import LabelSelector from '../Common/LabelSelector'; -import type { Actor } from '../../types'; - -/** - * NodePropertiesPanel - Side panel for editing node/actor properties - * - * Features: - * - Change actor type - * - Edit actor label - * - Edit description - * - Delete actor - * - Visual color preview - */ - -interface Props { - selectedNode: Actor | null; - onClose: () => void; -} - -const NodePropertiesPanel = ({ selectedNode, onClose }: Props) => { - const { nodeTypes, updateNode, deleteNode } = useGraphWithHistory(); - const [actorType, setActorType] = useState(''); - const [actorLabel, setActorLabel] = useState(''); - const [actorDescription, setActorDescription] = useState(''); - const [actorLabels, setActorLabels] = useState([]); - const labelInputRef = useRef(null); - - useEffect(() => { - if (selectedNode) { - setActorType(selectedNode.data?.type || ''); - setActorLabel(selectedNode.data?.label || ''); - setActorDescription(selectedNode.data?.description || ''); - setActorLabels(selectedNode.data?.labels || []); - - // Focus and select the label input when panel opens - setTimeout(() => { - if (labelInputRef.current) { - labelInputRef.current.focus(); - labelInputRef.current.select(); - } - }, 100); // Small delay to ensure panel animation completes - } - }, [selectedNode]); - - const handleSave = () => { - if (!selectedNode) return; - updateNode(selectedNode.id, { - data: { - type: actorType, - label: actorLabel, - description: actorDescription || undefined, - labels: actorLabels.length > 0 ? actorLabels : undefined, - }, - }); - onClose(); - }; - - const handleDelete = () => { - if (!selectedNode) return; - deleteNode(selectedNode.id); - onClose(); - }; - - const selectedNodeTypeConfig = nodeTypes.find((nt) => nt.id === actorType); - - return ( - - {/* Actor Type */} -
- - - {selectedNodeTypeConfig && ( -
- Color Preview -
- )} -
- - {/* Actor Label */} -
- - setActorLabel(e.target.value)} - placeholder="Enter actor name" - className="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" - /> -
- - {/* Description */} -
- -