feat: inline label editing for topology links
This commit is contained in:
@ -6,9 +6,9 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { LabTemplate, Device, TopologyLink } from '../types';
|
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>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user