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

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

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

This provides a convenient shortcut for editing actor 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:56:30 +02:00
parent a4db401ff7
commit 47957b4188
3 changed files with 79 additions and 7 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';
@ -23,15 +23,29 @@ import type { NodeTypeConfig, NodeShape } from '../../types';
interface Props { interface Props {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
initialEditingTypeId?: string | null;
} }
const NodeTypeConfigModal = ({ isOpen, onClose }: Props) => { const NodeTypeConfigModal = ({ isOpen, onClose, initialEditingTypeId }: Props) => {
const { nodeTypes, addNodeType, updateNodeType, deleteNodeType } = useGraphWithHistory(); const { nodeTypes, addNodeType, updateNodeType, deleteNodeType } = useGraphWithHistory();
const { confirm, ConfirmDialogComponent } = useConfirm(); const { confirm, ConfirmDialogComponent } = useConfirm();
const { showToast } = useToastStore(); const { showToast } = useToastStore();
const [editingType, setEditingType] = useState<NodeTypeConfig | null>(null); const [editingType, setEditingType] = useState<NodeTypeConfig | null>(null);
// Set editing type when initialEditingTypeId changes
useEffect(() => {
if (initialEditingTypeId && isOpen) {
const typeToEdit = nodeTypes.find(t => t.id === initialEditingTypeId);
if (typeToEdit) {
setEditingType(typeToEdit);
}
} else if (!isOpen) {
// Clear editing type when modal closes
setEditingType(null);
}
}, [initialEditingTypeId, isOpen, nodeTypes]);
const handleAddType = (type: { name: string; color: string; shape: NodeShape; icon: string; description: string }) => { const handleAddType = (type: { name: string; color: string; shape: NodeShape; icon: string; description: string }) => {
const id = type.name.toLowerCase().replace(/\s+/g, '-'); const id = type.name.toLowerCase().replace(/\s+/g, '-');

View file

@ -82,7 +82,6 @@ const QuickAddTypeForm = ({ onAdd }: Props) => {
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
nameInputRef={nameInputRef} nameInputRef={nameInputRef}
autoFocusName={false} autoFocusName={false}
showAdvancedByDefault={false}
/> />
<button <button

View file

@ -7,12 +7,14 @@ import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import SyncAltIcon from '@mui/icons-material/SyncAlt'; import SyncAltIcon from '@mui/icons-material/SyncAlt';
import RemoveIcon from '@mui/icons-material/Remove'; import RemoveIcon from '@mui/icons-material/Remove';
import EditIcon from '@mui/icons-material/Edit';
import { usePanelStore } from '../../stores/panelStore'; import { usePanelStore } from '../../stores/panelStore';
import { useGraphWithHistory } from '../../hooks/useGraphWithHistory'; import { useGraphWithHistory } from '../../hooks/useGraphWithHistory';
import { useDocumentHistory } from '../../hooks/useDocumentHistory'; import { useDocumentHistory } from '../../hooks/useDocumentHistory';
import { useConfirm } from '../../hooks/useConfirm'; 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 type { Actor, Relation, EdgeDirectionality } from '../../types'; import type { Actor, Relation, EdgeDirectionality } from '../../types';
/** /**
@ -80,6 +82,10 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
const [hasNodeChanges, setHasNodeChanges] = useState(false); const [hasNodeChanges, setHasNodeChanges] = useState(false);
const [hasEdgeChanges, setHasEdgeChanges] = useState(false); const [hasEdgeChanges, setHasEdgeChanges] = useState(false);
// Actor type modal state
const [showActorTypeModal, setShowActorTypeModal] = useState(false);
const [editingActorTypeId, setEditingActorTypeId] = useState<string | null>(null);
// Update state when selected node changes // Update state when selected node changes
useEffect(() => { useEffect(() => {
if (selectedNode) { if (selectedNode) {
@ -204,6 +210,19 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
setEdges(updatedEdges); setEdges(updatedEdges);
}; };
// Handle edit actor type
const handleEditActorType = () => {
if (!actorType) return;
setEditingActorTypeId(actorType);
setShowActorTypeModal(true);
};
// Handle close actor type modal
const handleCloseActorTypeModal = () => {
setShowActorTypeModal(false);
setEditingActorTypeId(null);
};
// Get connections for selected node // Get connections for selected node
const getNodeConnections = () => { const getNodeConnections = () => {
if (!selectedNode) return []; if (!selectedNode) return [];
@ -225,6 +244,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
</IconButton> </IconButton>
</Tooltip> </Tooltip>
{ConfirmDialogComponent} {ConfirmDialogComponent}
<NodeTypeConfigModal
isOpen={showActorTypeModal}
onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId}
/>
</div> </div>
); );
} }
@ -239,6 +263,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
<PanelHeader title="Graph Analysis" onCollapse={collapseRightPanel} /> <PanelHeader title="Graph Analysis" onCollapse={collapseRightPanel} />
<GraphMetrics nodes={nodes} edges={edges} /> <GraphMetrics nodes={nodes} edges={edges} />
{ConfirmDialogComponent} {ConfirmDialogComponent}
<NodeTypeConfigModal
isOpen={showActorTypeModal}
onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId}
/>
</div> </div>
); );
} }
@ -258,9 +287,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">
{/* Actor Type */} {/* Actor Type */}
<div> <div>
<label className="block text-xs font-medium text-gray-700 mb-1"> <div className="flex items-center justify-between mb-1">
<label className="block text-xs font-medium text-gray-700">
Actor Type Actor Type
</label> </label>
<Tooltip title="Edit Actor Type">
<IconButton
size="small"
onClick={handleEditActorType}
sx={{ padding: '2px' }}
>
<EditIcon sx={{ fontSize: 14 }} />
</IconButton>
</Tooltip>
</div>
<select <select
value={actorType} value={actorType}
onChange={(e) => { onChange={(e) => {
@ -406,6 +446,11 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
)} )}
</div> </div>
{ConfirmDialogComponent} {ConfirmDialogComponent}
<NodeTypeConfigModal
isOpen={showActorTypeModal}
onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId}
/>
</div> </div>
); );
} }
@ -587,11 +632,25 @@ const RightPanel = ({ selectedNode, selectedEdge, onClose }: Props) => {
)} )}
</div> </div>
{ConfirmDialogComponent} {ConfirmDialogComponent}
<NodeTypeConfigModal
isOpen={showActorTypeModal}
onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId}
/>
</div> </div>
); );
} }
return null; return (
<>
{ConfirmDialogComponent}
<NodeTypeConfigModal
isOpen={showActorTypeModal}
onClose={handleCloseActorTypeModal}
initialEditingTypeId={editingActorTypeId}
/>
</>
);
}; };
export default RightPanel; export default RightPanel;