feat: add quick edit button for relation types in properties panel

Adds a small edit icon button next to the "Relation Type" label in the
RightPanel Relation Properties section that opens the EdgeTypeConfigModal
directly in edit mode for the selected relation's type.

Changes:
- Added edit icon button aligned to the right of "Relation Type" label
- Opens existing EdgeTypeConfigModal in edit mode for current type
- Enhanced EdgeTypeConfigModal to support initialEditingTypeId prop
- Modal automatically enters edit mode when opened with a type ID

This mirrors the actor type edit button functionality and provides a
convenient shortcut for editing relation types without navigating to
the settings menu or left panel configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jan-Henrik Bruhn 2025-10-16 19:59:45 +02:00
parent 47957b4188
commit cfd7a0b76f
2 changed files with 72 additions and 9 deletions

View file

@ -1,4 +1,4 @@
import { useState } from 'react'; import { useState, useEffect } from 'react';
import { useGraphWithHistory } from '../../hooks/useGraphWithHistory'; import { useGraphWithHistory } from '../../hooks/useGraphWithHistory';
import { useConfirm } from '../../hooks/useConfirm'; import { useConfirm } from '../../hooks/useConfirm';
import { useToastStore } from '../../stores/toastStore'; import { useToastStore } from '../../stores/toastStore';
@ -21,15 +21,29 @@ import type { EdgeTypeConfig, EdgeDirectionality } from '../../types';
interface Props { interface Props {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
initialEditingTypeId?: string | null;
} }
const EdgeTypeConfigModal = ({ isOpen, onClose }: Props) => { const EdgeTypeConfigModal = ({ isOpen, onClose, initialEditingTypeId }: Props) => {
const { edgeTypes, addEdgeType, updateEdgeType, deleteEdgeType } = useGraphWithHistory(); const { edgeTypes, addEdgeType, updateEdgeType, deleteEdgeType } = useGraphWithHistory();
const { confirm, ConfirmDialogComponent } = useConfirm(); const { confirm, ConfirmDialogComponent } = useConfirm();
const { showToast } = useToastStore(); const { showToast } = useToastStore();
const [editingType, setEditingType] = useState<EdgeTypeConfig | null>(null); const [editingType, setEditingType] = useState<EdgeTypeConfig | null>(null);
// Set editing type when initialEditingTypeId changes
useEffect(() => {
if (initialEditingTypeId && isOpen) {
const typeToEdit = edgeTypes.find(t => t.id === initialEditingTypeId);
if (typeToEdit) {
setEditingType(typeToEdit);
}
} else if (!isOpen) {
// Clear editing type when modal closes
setEditingType(null);
}
}, [initialEditingTypeId, isOpen, edgeTypes]);
const handleAddType = (type: { const handleAddType = (type: {
label: string; label: string;
color: string; color: string;

View file

@ -15,6 +15,7 @@ import { useConfirm } from '../../hooks/useConfirm';
import GraphMetrics from '../Common/GraphMetrics'; import GraphMetrics from '../Common/GraphMetrics';
import ConnectionDisplay from '../Common/ConnectionDisplay'; import ConnectionDisplay from '../Common/ConnectionDisplay';
import NodeTypeConfigModal from '../Config/NodeTypeConfig'; import NodeTypeConfigModal from '../Config/NodeTypeConfig';
import EdgeTypeConfigModal from '../Config/EdgeTypeConfig';
import type { Actor, Relation, EdgeDirectionality } from '../../types'; import type { Actor, Relation, EdgeDirectionality } from '../../types';
/** /**
@ -86,6 +87,10 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
const [showActorTypeModal, setShowActorTypeModal] = useState(false); const [showActorTypeModal, setShowActorTypeModal] = useState(false);
const [editingActorTypeId, setEditingActorTypeId] = useState<string | null>(null); const [editingActorTypeId, setEditingActorTypeId] = useState<string | null>(null);
// Relation type modal state
const [showRelationTypeModal, setShowRelationTypeModal] = useState(false);
const [editingRelationTypeId, setEditingRelationTypeId] = useState<string | null>(null);
// Update state when selected node changes // Update state when selected node changes
useEffect(() => { useEffect(() => {
if (selectedNode) { if (selectedNode) {
@ -223,6 +228,19 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
setEditingActorTypeId(null); setEditingActorTypeId(null);
}; };
// Handle edit relation type
const handleEditRelationType = () => {
if (!relationType) return;
setEditingRelationTypeId(relationType);
setShowRelationTypeModal(true);
};
// Handle close relation type modal
const handleCloseRelationTypeModal = () => {
setShowRelationTypeModal(false);
setEditingRelationTypeId(null);
};
// Get connections for selected node // Get connections for selected node
const getNodeConnections = () => { const getNodeConnections = () => {
if (!selectedNode) return []; if (!selectedNode) return [];
@ -249,6 +267,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
onClose={handleCloseActorTypeModal} onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId} initialEditingTypeId={editingActorTypeId}
/> />
<EdgeTypeConfigModal
isOpen={showRelationTypeModal}
onClose={handleCloseRelationTypeModal}
initialEditingTypeId={editingRelationTypeId}
/>
</div> </div>
); );
} }
@ -268,6 +291,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
onClose={handleCloseActorTypeModal} onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId} initialEditingTypeId={editingActorTypeId}
/> />
<EdgeTypeConfigModal
isOpen={showRelationTypeModal}
onClose={handleCloseRelationTypeModal}
initialEditingTypeId={editingRelationTypeId}
/>
</div> </div>
); );
} }
@ -451,6 +479,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
onClose={handleCloseActorTypeModal} onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId} initialEditingTypeId={editingActorTypeId}
/> />
<EdgeTypeConfigModal
isOpen={showRelationTypeModal}
onClose={handleCloseRelationTypeModal}
initialEditingTypeId={editingRelationTypeId}
/>
</div> </div>
); );
} }
@ -495,9 +528,20 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
<div className="flex-1 overflow-y-auto overflow-x-hidden px-3 py-3 space-y-4"> <div className="flex-1 overflow-y-auto overflow-x-hidden px-3 py-3 space-y-4">
{/* Relation Type */} {/* Relation Type */}
<div> <div>
<label className="block text-xs font-medium text-gray-700 mb-1"> <div className="flex items-center justify-between mb-1">
Relation Type <label className="block text-xs font-medium text-gray-700">
</label> Relation Type
</label>
<Tooltip title="Edit Relation Type">
<IconButton
size="small"
onClick={handleEditRelationType}
sx={{ padding: '2px' }}
>
<EditIcon sx={{ fontSize: 14 }} />
</IconButton>
</Tooltip>
</div>
<select <select
value={relationType} value={relationType}
onChange={(e) => { onChange={(e) => {
@ -632,10 +676,10 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
)} )}
</div> </div>
{ConfirmDialogComponent} {ConfirmDialogComponent}
<NodeTypeConfigModal <EdgeTypeConfigModal
isOpen={showActorTypeModal} isOpen={showRelationTypeModal}
onClose={handleCloseActorTypeModal} onClose={handleCloseRelationTypeModal}
initialEditingTypeId={editingActorTypeId} initialEditingTypeId={editingRelationTypeId}
/> />
</div> </div>
); );
@ -649,6 +693,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
onClose={handleCloseActorTypeModal} onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId} initialEditingTypeId={editingActorTypeId}
/> />
<EdgeTypeConfigModal
isOpen={showRelationTypeModal}
onClose={handleCloseRelationTypeModal}
initialEditingTypeId={editingRelationTypeId}
/>
</> </>
); );
}; };