feat: inline label editing for topology links

This commit is contained in:
Brückner
2026-06-04 13:51:30 +02:00
parent 5769b38f74
commit e9fb79041e

View File

@ -8,7 +8,7 @@ import { LabTemplate, Device, TopologyLink } from '../types';
import TopologyPanel from './TopologyPanel'; import TopologyPanel from './TopologyPanel';
import { import {
Server, Plus, Edit3, Trash, User, MapPin, Server, Plus, Edit3, Trash, User, MapPin,
Layers, ChevronRight, Save, X, Check Layers, ChevronRight, Save, X, Check, Pencil
} from 'lucide-react'; } from 'lucide-react';
interface LabTemplatesProps { interface LabTemplatesProps {
@ -37,6 +37,8 @@ export default function LabTemplates({
const [linkFrom, setLinkFrom] = useState(''); const [linkFrom, setLinkFrom] = useState('');
const [linkTo, setLinkTo] = useState(''); const [linkTo, setLinkTo] = useState('');
const [linkType, setLinkType] = useState('Trunk Uplink'); const [linkType, setLinkType] = useState('Trunk Uplink');
const [editingLinkIdx, setEditingLinkIdx] = useState<number | null>(null);
const [editingLinkLabel, setEditingLinkLabel] = useState('');
const [formData, setFormData] = useState<{ const [formData, setFormData] = useState<{
id?: string; id?: string;
@ -467,18 +469,53 @@ export default function LabTemplates({
{tempLinks.map((link, idx) => { {tempLinks.map((link, idx) => {
const fromDev = devices.find(d => d.id === link.fromDevice)?.hostname || link.fromDevice; const fromDev = devices.find(d => d.id === link.fromDevice)?.hostname || link.fromDevice;
const toDev = devices.find(d => d.id === link.toDevice)?.hostname || link.toDevice; const toDev = devices.find(d => d.id === link.toDevice)?.hostname || link.toDevice;
const isEditingThis = editingLinkIdx === idx;
return ( return (
<div key={idx} className="flex justify-between items-center bg-slate-950 px-3 py-1.5 rounded border border-slate-855 font-mono text-[10px] hover:border-slate-700"> <div key={idx} className="flex items-center gap-2 bg-slate-950 px-3 py-1.5 rounded border border-slate-855 font-mono text-[10px] hover:border-slate-700">
<span className="text-slate-300"> <span className="text-slate-300 shrink-0"><strong>{fromDev}</strong> </span>
<strong>{fromDev}</strong> {link.type} <strong>{toDev}</strong> {isEditingThis ? (
</span> <input
<button autoFocus
type="button" value={editingLinkLabel}
onClick={() => handleRemoveLink(idx)} onChange={(e) => setEditingLinkLabel(e.target.value)}
className="text-rose-500 hover:text-rose-450 font-sans font-bold" onBlur={() => {
> if (editingLinkLabel.trim()) {
Remove setTempLinks(tempLinks.map((l, i) => i === idx ? { ...l, type: editingLinkLabel.trim() } : l));
</button> }
setEditingLinkIdx(null);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
if (editingLinkLabel.trim()) {
setTempLinks(tempLinks.map((l, i) => i === idx ? { ...l, type: editingLinkLabel.trim() } : l));
}
setEditingLinkIdx(null);
}
if (e.key === 'Escape') setEditingLinkIdx(null);
}}
className="flex-1 min-w-0 bg-slate-800 text-slate-100 border border-indigo-500 rounded px-1.5 py-0.5 focus:outline-none"
/>
) : (
<span className="flex-1 min-w-0 text-indigo-300 truncate">{link.type}</span>
)}
<span className="text-slate-300 shrink-0"> <strong>{toDev}</strong></span>
<div className="flex gap-1.5 shrink-0 ml-auto font-sans">
<button
type="button"
onClick={() => { setEditingLinkIdx(idx); setEditingLinkLabel(link.type); }}
className="text-slate-400 hover:text-indigo-400 transition-colors"
title="Edit label"
>
<Pencil className="w-3 h-3" />
</button>
<button
type="button"
onClick={() => handleRemoveLink(idx)}
className="text-rose-500 hover:text-rose-400 font-bold"
>
<X className="w-3 h-3" />
</button>
</div>
</div> </div>
); );
})} })}