path max width set to 80px
This commit is contained in:
@@ -63,66 +63,69 @@ export function DetailPanel({ onEdit }: DetailPanelProps) {
|
|||||||
node={node}
|
node={node}
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
onUngroup={() => { ungroup(node.id) }}
|
onUngroup={() => { ungroup(node.id) }}
|
||||||
onToggleBorder={() => {
|
// Layout: service name always takes precedence, path truncates first or hides if needed, port/protocol always shown
|
||||||
snapshotHistory()
|
return (
|
||||||
updateNode(node.id, {
|
<div
|
||||||
custom_colors: {
|
className="group flex items-center border rounded-md text-xs transition-colors px-2 py-1.5 min-w-0"
|
||||||
...node.data.custom_colors,
|
style={{ background: '#21262d', borderColor: '#30363d', position: 'relative' }}
|
||||||
show_border: !(node.data.custom_colors?.show_border !== false),
|
>
|
||||||
},
|
<span className="shrink-0 w-1.5 h-1.5 rounded-full mr-1" style={{ backgroundColor: color }} />
|
||||||
})
|
<div className="flex items-center min-w-0 flex-grow" style={{ minWidth: 0 }}>
|
||||||
}}
|
<span
|
||||||
onClose={() => setSelectedNode(null)}
|
className="font-medium truncate min-w-0"
|
||||||
onSelectChild={(id) => setSelectedNode(id)}
|
style={{ color, maxWidth: '100%', marginRight: 8 }}
|
||||||
/>
|
title={svc.service_name}
|
||||||
)
|
tabIndex={0}
|
||||||
}
|
aria-label={svc.service_name}
|
||||||
|
>
|
||||||
// Normal single-node panel
|
{svc.service_name}
|
||||||
const addingService = addingForNode === node.id
|
</span>
|
||||||
const editingIndex = editingFor?.nodeId === node.id ? editingFor.index : null
|
{/* Path: only show if name is not too long, truncate path first */}
|
||||||
const { data } = node
|
{pathLabel && (
|
||||||
const services = data.services ?? []
|
<span
|
||||||
const statusColor = STATUS_COLORS[data.status]
|
className="truncate text-[#8b949e] text-right"
|
||||||
const host = data.ip ?? data.hostname
|
style={{ minWidth: 0, maxWidth: 80, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block', marginLeft: 8 }}
|
||||||
|
title={pathLabel}
|
||||||
const handleDelete = () => {
|
tabIndex={0}
|
||||||
if (confirm(`Delete "${data.label}"?`)) {
|
aria-label={pathLabel}
|
||||||
snapshotHistory()
|
>
|
||||||
deleteNode(node.id)
|
{pathLabel}
|
||||||
}
|
</span>
|
||||||
}
|
)}
|
||||||
|
</div>
|
||||||
const handleAddService = () => {
|
{/* Port/protocol always shown, never truncated, always right-aligned */}
|
||||||
const trimmedPort = newSvc.port.trim()
|
{hasPort && (
|
||||||
const port = trimmedPort === '' ? undefined : parseInt(trimmedPort, 10)
|
<span className="font-mono text-[#8b949e] ml-2" style={{ whiteSpace: 'nowrap', flexShrink: 0 }}>{portLabel}/{svc.protocol}</span>
|
||||||
if (!newSvc.service_name.trim()) return
|
)}
|
||||||
if (trimmedPort !== '' && (port == null || Number.isNaN(port) || port < 1 || port > 65535)) return
|
<span className="inline-flex w-2.5 h-2.5 items-center justify-center shrink-0 ml-2" aria-hidden="true">
|
||||||
snapshotHistory()
|
{url ? <ExternalLink size={10} className="text-muted-foreground" /> : <span style={{ width: 10, display: 'inline-block' }} />}
|
||||||
const path = newSvc.path.trim()
|
</span>
|
||||||
const svc: ServiceInfo = {
|
<button
|
||||||
...(port != null ? { port } : {}),
|
onClick={(e) => { e.preventDefault(); e.stopPropagation(); onEdit(); }}
|
||||||
protocol: newSvc.protocol,
|
className="opacity-100 transition-opacity text-[#8b949e] hover:text-[#00d4ff] ml-0.5"
|
||||||
service_name: newSvc.service_name.trim(),
|
title="Edit service"
|
||||||
...(path ? { path } : {}),
|
>
|
||||||
}
|
<Pencil size={10} />
|
||||||
updateNode(node.id, { services: [...services, svc] })
|
</button>
|
||||||
setNewSvc(EMPTY_FORM)
|
<button
|
||||||
setAddingForNode(null)
|
onClick={(e) => { e.preventDefault(); e.stopPropagation(); onRemove(); }}
|
||||||
}
|
className="opacity-100 transition-opacity text-[#8b949e] hover:text-[#f85149] ml-0.5"
|
||||||
|
title="Remove service"
|
||||||
const handleRemoveService = (index: number) => {
|
>
|
||||||
snapshotHistory()
|
<X size={10} />
|
||||||
const updated = services.filter((_, i) => i !== index)
|
</button>
|
||||||
updateNode(node.id, { services: updated })
|
{url && (
|
||||||
if (editingIndex === index) setEditingFor(null)
|
<a
|
||||||
}
|
href={url}
|
||||||
|
target="_blank"
|
||||||
const handleStartEdit = (index: number) => {
|
rel="noopener noreferrer"
|
||||||
const svc = services[index]
|
style={{ position: 'absolute', left: 0, top: 0, bottom: 0, right: 80, zIndex: 1, opacity: 0 }}
|
||||||
if (!svc) return
|
tabIndex={-1}
|
||||||
setEditSvc({ port: svc.port != null ? String(svc.port) : '', protocol: svc.protocol, service_name: svc.service_name, path: svc.path ?? '' })
|
aria-hidden="true"
|
||||||
setEditingFor({ nodeId: node.id, index })
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
setAddingForNode(null)
|
setAddingForNode(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,7 +687,7 @@ function ServiceBadge({ svc, host, onEdit, onRemove }: { svc: ServiceInfo; host?
|
|||||||
{pathLabel && (
|
{pathLabel && (
|
||||||
<span
|
<span
|
||||||
className="truncate text-[#8b949e] text-right"
|
className="truncate text-[#8b949e] text-right"
|
||||||
style={{ minWidth: 0, maxWidth: 70, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}
|
style={{ minWidth: 0, maxWidth: 80, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}
|
||||||
title={pathLabel}
|
title={pathLabel}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
aria-label={pathLabel}
|
aria-label={pathLabel}
|
||||||
|
|||||||
Reference in New Issue
Block a user