diff --git a/frontend/src/components/panels/DetailPanel.tsx b/frontend/src/components/panels/DetailPanel.tsx index c238dad..71cbe7d 100644 --- a/frontend/src/components/panels/DetailPanel.tsx +++ b/frontend/src/components/panels/DetailPanel.tsx @@ -1,8 +1,7 @@ -import { X, Edit, Trash2 } from 'lucide-react' -import { Badge } from '@/components/ui/badge' +import { X, Edit, Trash2, ExternalLink } from 'lucide-react' import { Button } from '@/components/ui/button' import { useCanvasStore } from '@/stores/canvasStore' -import { NODE_TYPE_LABELS, STATUS_COLORS } from '@/types' +import { NODE_TYPE_LABELS, STATUS_COLORS, type ServiceInfo } from '@/types' interface DetailPanelProps { onEdit: (id: string) => void @@ -64,16 +63,10 @@ export function DetailPanel({ onEdit }: DetailPanelProps) { {/* Services */} {data.services.length > 0 && (
-
Services
-
+
Services ({data.services.length})
+
{data.services.map((svc) => ( - - {svc.port}/{svc.protocol} {svc.service_name} - + ))}
@@ -123,3 +116,59 @@ function DetailRow({ label, value, mono }: { label: string; value: string; mono?
) } + +const CATEGORY_COLORS: Record = { + web: '#00d4ff', + database: '#a855f7', + monitoring: '#39d353', + storage: '#e3b341', + security: '#f85149', + remote: '#8b949e', +} + +function getServiceUrl(svc: ServiceInfo, ip?: string): string | null { + if (!ip) return null + const name = svc.service_name.toLowerCase() + const isHttps = name.includes('https') || name.includes('ssl') || svc.port === 443 || svc.port === 8443 + const isHttp = name.includes('http') || [80, 8080, 8000, 3000, 8888, 9000, 8090, 7080].includes(svc.port) + if (isHttps) return `https://${ip}:${svc.port}` + if (isHttp) return `http://${ip}:${svc.port}` + return null +} + +function ServiceBadge({ svc, ip }: { svc: ServiceInfo; ip?: string }) { + const url = getServiceUrl(svc, ip) + const color = CATEGORY_COLORS[svc.category ?? ''] ?? '#8b949e' + + const inner = ( +
+
+ + {svc.service_name} +
+
+ {svc.port}/{svc.protocol} + {url && } +
+
+ ) + + if (url) { + return ( + + {inner} + + ) + } + return inner +}