feat: hierarchical tree topology diagram
Replace grid layout with tree diagram: Modem → Firewall → Switch → 3 Proxmox servers → VMs/CTs - Services.yaml restructured with parent/type fields from real Proxmox API data (TYAN CAS, Cisco1, DellT430-2) - NetworkGraph renders vertical hierarchy with branch lines - ProxmoxColumn shows server card + VM pills grid - Compact VmPill for VMs/CTs (status dot + name + last octet) - InfraCard for physical infrastructure nodes - Other devices section at bottom (AP, printer, iDRACs, PCs) - Added type/parent fields to NetworkNode TypeScript interface Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,26 +1,28 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
# Topología de Red - Consultoria AS
|
# Topología de Red - Consultoria AS
|
||||||
# Edita este archivo para agregar credenciales y URLs públicas
|
# Jerarquía: Modem → Firewall → Switch → Proxmox → VMs
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
nodes:
|
nodes:
|
||||||
# ── Infraestructura de Red ──────────────────────────────────
|
# ── Nivel 1: ISP ───────────────────────────────────────────
|
||||||
- name: "Firewall OPNsense"
|
|
||||||
ip: "192.168.10.1"
|
|
||||||
username: "root"
|
|
||||||
password: "opnsense"
|
|
||||||
public_url: "https://192.168.10.1:8443"
|
|
||||||
icon: "firewall"
|
|
||||||
connections: []
|
|
||||||
|
|
||||||
- name: "Router Telmex"
|
- name: "Router Telmex"
|
||||||
ip: "192.168.1.254"
|
ip: "192.168.1.254"
|
||||||
username: "TELMEX"
|
username: "TELMEX"
|
||||||
password: ""
|
password: ""
|
||||||
public_url: "http://192.168.1.254"
|
public_url: "http://192.168.1.254"
|
||||||
icon: "router"
|
icon: "router"
|
||||||
connections: ["Firewall OPNsense"]
|
connections: []
|
||||||
|
|
||||||
|
# ── Nivel 2: Firewall ──────────────────────────────────────
|
||||||
|
- name: "Firewall OPNsense"
|
||||||
|
ip: "192.168.10.1"
|
||||||
|
username: "root"
|
||||||
|
password: "opnsense"
|
||||||
|
public_url: "https://192.168.10.1:8443"
|
||||||
|
icon: "firewall"
|
||||||
|
connections: ["Router Telmex"]
|
||||||
|
|
||||||
|
# ── Nivel 3: Switch ────────────────────────────────────────
|
||||||
- name: "Switch Cisco"
|
- name: "Switch Cisco"
|
||||||
ip: "192.168.10.250"
|
ip: "192.168.10.250"
|
||||||
username: ""
|
username: ""
|
||||||
@@ -28,355 +30,335 @@ nodes:
|
|||||||
icon: "switch"
|
icon: "switch"
|
||||||
connections: ["Firewall OPNsense"]
|
connections: ["Firewall OPNsense"]
|
||||||
|
|
||||||
- name: "Switch Mellanox"
|
# ── Nivel 4: Proxmox Servers ───────────────────────────────
|
||||||
|
- name: "TYAN CAS"
|
||||||
ip: "192.168.10.3"
|
ip: "192.168.10.3"
|
||||||
username: ""
|
username: "root"
|
||||||
password: ""
|
password: "Aasi940812"
|
||||||
icon: "switch"
|
public_url: "https://192.168.10.3:8006"
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Access Point EAP610"
|
|
||||||
ip: "192.168.10.166"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "ap"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Servidores Dell (iDRAC) ─────────────────────────────────
|
|
||||||
- name: "iDRAC Servidor 1"
|
|
||||||
ip: "192.168.10.159"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
icon: "server"
|
||||||
|
type: "proxmox"
|
||||||
connections: ["Switch Cisco"]
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
- name: "iDRAC Servidor 2"
|
- name: "Cisco1"
|
||||||
ip: "192.168.10.160"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Switch Cisco"]
|
|
||||||
|
|
||||||
- name: "Dell Server .185"
|
|
||||||
ip: "192.168.10.185"
|
ip: "192.168.10.185"
|
||||||
username: ""
|
username: "root"
|
||||||
password: ""
|
password: "Aasi940812"
|
||||||
|
public_url: "https://192.168.10.185:8006"
|
||||||
icon: "server"
|
icon: "server"
|
||||||
|
type: "proxmox"
|
||||||
connections: ["Switch Cisco"]
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
- name: "Dell Server .187"
|
- name: "DellT430-2"
|
||||||
ip: "192.168.10.187"
|
ip: "192.168.10.187"
|
||||||
username: ""
|
username: "root"
|
||||||
password: ""
|
password: "Aasi940812"
|
||||||
|
public_url: "https://192.168.10.187:8006"
|
||||||
icon: "server"
|
icon: "server"
|
||||||
|
type: "proxmox"
|
||||||
connections: ["Switch Cisco"]
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
# ── Servicios Principales ───────────────────────────────────
|
# ── VMs de TYAN CAS ────────────────────────────────────────
|
||||||
- name: "Servidor Odoo"
|
- name: "OMV"
|
||||||
|
ip: "192.168.10.5"
|
||||||
|
icon: "nas"
|
||||||
|
type: "vm"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "NocoDB"
|
||||||
|
ip: "192.168.10.134"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Dashy"
|
||||||
|
ip: "192.168.10.8"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Paperless-NGX"
|
||||||
|
ip: "192.168.10.9"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Immich"
|
||||||
|
ip: "192.168.10.10"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Debian"
|
||||||
|
ip: "192.168.10.148"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Dockge"
|
||||||
|
ip: "192.168.10.8"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "BookLore"
|
||||||
|
ip: "192.168.10.205"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "n8n"
|
||||||
|
ip: "192.168.10.14"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Navidrome"
|
||||||
|
ip: "192.168.10.202"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Uptime Kuma"
|
||||||
|
ip: "192.168.10.16"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Metabase"
|
||||||
|
ip: "192.168.10.142"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "Gitea"
|
||||||
|
ip: "192.168.10.150"
|
||||||
|
public_url: "https://git.consultoria-as.com"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "AMP"
|
||||||
|
ip: "192.168.10.151"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
- name: "NodeBB"
|
||||||
|
ip: "192.168.10.191"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
|
# ── VMs de Cisco1 ──────────────────────────────────────────
|
||||||
|
- name: "Ubuntu"
|
||||||
|
ip: "192.168.10.182"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "Cisco1"
|
||||||
|
connections: ["Cisco1"]
|
||||||
|
|
||||||
|
- name: "Tilmatli"
|
||||||
|
ip: "192.168.10.119"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "Cisco1"
|
||||||
|
connections: ["Cisco1"]
|
||||||
|
|
||||||
|
- name: "WhatsappBot Clawbot"
|
||||||
|
ip: "192.168.10.68"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "Cisco1"
|
||||||
|
connections: ["Cisco1"]
|
||||||
|
|
||||||
|
- name: "Ubuntu CT"
|
||||||
|
ip: "192.168.10.182"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "Cisco1"
|
||||||
|
connections: ["Cisco1"]
|
||||||
|
|
||||||
|
- name: "PostgreSQL"
|
||||||
|
ip: "192.168.10.71"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "Cisco1"
|
||||||
|
connections: ["Cisco1"]
|
||||||
|
|
||||||
|
# ── VMs de DellT430-2 ─────────────────────────────────────
|
||||||
|
- name: "JobHero"
|
||||||
|
ip: "192.168.10.197"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Autopartes"
|
||||||
|
ip: "192.168.10.200"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "ProksBot"
|
||||||
|
ip: "192.168.10.204"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "CAS PaginasWeb"
|
||||||
|
ip: "192.168.10.211"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "SIO Mexus"
|
||||||
|
ip: "192.168.10.207"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Horux"
|
||||||
|
ip: "192.168.10.212"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "ATLAS GPS"
|
||||||
|
ip: "192.168.10.216"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Trivy"
|
||||||
|
ip: "192.168.10.217"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Social Automation"
|
||||||
|
ip: "192.168.10.218"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Padel"
|
||||||
|
ip: "192.168.10.219"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "MSP"
|
||||||
|
ip: "192.168.10.223"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "VoIP"
|
||||||
|
ip: "192.168.10.228"
|
||||||
|
icon: "phone"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Sistema Hotel"
|
||||||
|
ip: "192.168.10.229"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Dashboard TV"
|
||||||
|
ip: "192.168.10.230"
|
||||||
|
icon: "device"
|
||||||
|
type: "vm"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "HoruxDB"
|
||||||
|
ip: "192.168.10.208"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
- name: "Odoo"
|
||||||
ip: "192.168.10.188"
|
ip: "192.168.10.188"
|
||||||
username: "root"
|
username: "root"
|
||||||
password: "Aasi940812"
|
password: "Aasi940812"
|
||||||
public_url: "https://crm.consultoria-as.com"
|
public_url: "https://crm.consultoria-as.com"
|
||||||
icon: "server"
|
icon: "device"
|
||||||
connections: ["Firewall OPNsense"]
|
type: "ct"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
- name: "Servidor Multimedia (Jellyfin)"
|
- name: "NodeBB 2"
|
||||||
|
ip: "192.168.10.192"
|
||||||
|
icon: "device"
|
||||||
|
type: "ct"
|
||||||
|
parent: "DellT430-2"
|
||||||
|
connections: ["DellT430-2"]
|
||||||
|
|
||||||
|
# ── Otros dispositivos (no Proxmox) ────────────────────────
|
||||||
|
- name: "Access Point EAP610"
|
||||||
|
ip: "192.168.10.166"
|
||||||
|
icon: "ap"
|
||||||
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
|
- name: "Impresora Epson"
|
||||||
|
ip: "192.168.10.177"
|
||||||
|
icon: "printer"
|
||||||
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
|
- name: "iDRAC TYAN"
|
||||||
|
ip: "192.168.10.159"
|
||||||
|
icon: "server"
|
||||||
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
|
- name: "iDRAC Dell"
|
||||||
|
ip: "192.168.10.160"
|
||||||
|
icon: "server"
|
||||||
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
|
- name: "Jellyfin"
|
||||||
ip: "192.168.10.103"
|
ip: "192.168.10.103"
|
||||||
username: "consultoria-as"
|
username: "consultoria-as"
|
||||||
password: "Aasi940812"
|
password: "Aasi940812"
|
||||||
public_url: "https://jellyfin.consultoria-as.com"
|
public_url: "https://jellyfin.consultoria-as.com"
|
||||||
icon: "server"
|
icon: "device"
|
||||||
connections: ["Firewall OPNsense"]
|
type: "ct"
|
||||||
|
parent: "TYAN CAS"
|
||||||
|
connections: ["TYAN CAS"]
|
||||||
|
|
||||||
- name: "Gitea"
|
|
||||||
ip: "192.168.10.150"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
public_url: "https://git.consultoria-as.com"
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "PostgreSQL"
|
|
||||||
ip: "192.168.10.71"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "OpenMediaVault (NAS)"
|
|
||||||
ip: "192.168.10.5"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "nas"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Monitoreo y Automatización ──────────────────────────────
|
|
||||||
- name: "Uptime Kuma"
|
|
||||||
ip: "192.168.10.16"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "n8n"
|
|
||||||
ip: "192.168.10.14"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Dashy"
|
|
||||||
ip: "192.168.10.8"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Gestión Documental y Datos ──────────────────────────────
|
|
||||||
- name: "Paperless-NGX"
|
|
||||||
ip: "192.168.10.9"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "NocoDB"
|
|
||||||
ip: "192.168.10.134"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Metabase"
|
|
||||||
ip: "192.168.10.142"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Multimedia y Contenido ──────────────────────────────────
|
|
||||||
- name: "Immich (Fotos)"
|
|
||||||
ip: "192.168.10.10"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Navidrome (Música)"
|
|
||||||
ip: "192.168.10.202"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "BookLore"
|
|
||||||
ip: "192.168.10.205"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Proyectos y Aplicaciones ────────────────────────────────
|
|
||||||
- name: "Hotel Production"
|
|
||||||
ip: "192.168.10.200"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Sistema Hotel"
|
|
||||||
ip: "192.168.10.229"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "HoruxDB"
|
|
||||||
ip: "192.168.10.208"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Adan Mesh Horux"
|
|
||||||
ip: "192.168.10.212"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "SIO Complete"
|
|
||||||
ip: "192.168.10.197"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "ATLAS GPS"
|
|
||||||
ip: "192.168.10.216"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "CAS Páginas Web"
|
|
||||||
ip: "192.168.10.211"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "AMP"
|
|
||||||
ip: "192.168.10.151"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Comunicaciones ──────────────────────────────────────────
|
|
||||||
- name: "NodeBB (Foro)"
|
|
||||||
ip: "192.168.10.191"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "NodeBB 2"
|
|
||||||
ip: "192.168.10.192"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "VoIP"
|
|
||||||
ip: "192.168.10.228"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "phone"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "MSP"
|
|
||||||
ip: "192.168.10.223"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Servidores Auxiliares ────────────────────────────────────
|
|
||||||
- name: "Debian Server"
|
|
||||||
ip: "192.168.10.148"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu Server .182"
|
|
||||||
ip: "192.168.10.182"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Test CAS"
|
|
||||||
ip: "192.168.10.119"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "pc"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Server .198"
|
|
||||||
ip: "192.168.10.198"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .204"
|
|
||||||
ip: "192.168.10.204"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .207"
|
|
||||||
ip: "192.168.10.207"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .217"
|
|
||||||
ip: "192.168.10.217"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .218"
|
|
||||||
ip: "192.168.10.218"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .219"
|
|
||||||
ip: "192.168.10.219"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .221"
|
|
||||||
ip: "192.168.10.221"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Ubuntu .222"
|
|
||||||
ip: "192.168.10.222"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "server"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Equipos de Escritorio ───────────────────────────────────
|
|
||||||
- name: "HP Consultoria-AS"
|
- name: "HP Consultoria-AS"
|
||||||
ip: "192.168.10.147"
|
ip: "192.168.10.147"
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "pc"
|
icon: "pc"
|
||||||
connections: ["Firewall OPNsense"]
|
connections: ["Switch Cisco"]
|
||||||
|
|
||||||
- name: "Desktop PC .57"
|
|
||||||
ip: "192.168.10.57"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "pc"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
- name: "Desktop PC .143"
|
|
||||||
ip: "192.168.10.143"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "pc"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Periféricos ─────────────────────────────────────────────
|
|
||||||
- name: "Impresora Epson"
|
|
||||||
ip: "192.168.10.177"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "printer"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
# ── Dashboard ───────────────────────────────────────────────
|
|
||||||
- name: "Dashboard TV"
|
|
||||||
ip: "192.168.10.230"
|
|
||||||
username: ""
|
|
||||||
password: ""
|
|
||||||
icon: "device"
|
|
||||||
connections: ["Firewall OPNsense"]
|
|
||||||
|
|
||||||
network_scan:
|
network_scan:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -1,50 +1,137 @@
|
|||||||
import { NodeCard } from "./NodeCard";
|
import { useState } from "react";
|
||||||
import type { NetworkNode } from "../../types";
|
import type { NetworkNode } from "../../types";
|
||||||
|
|
||||||
interface NetworkGraphProps {
|
interface NetworkGraphProps {
|
||||||
nodes: NetworkNode[];
|
nodes: NetworkNode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CATEGORY_ORDER: [string, string[]][] = [
|
const ICON_MAP: Record<string, string> = {
|
||||||
["Infraestructura", ["firewall", "router", "switch", "ap"]],
|
router: "🌐", firewall: "🛡️", server: "🖥️", switch: "🔀",
|
||||||
["Servidores", ["server"]],
|
ap: "📡", pc: "💻", nas: "💾", printer: "🖨️",
|
||||||
["Almacenamiento", ["nas"]],
|
phone: "📞", camera: "📷", device: "📱",
|
||||||
["Equipos", ["pc"]],
|
};
|
||||||
["Periféricos", ["printer", "phone", "camera"]],
|
|
||||||
["Otros", ["device"]],
|
|
||||||
];
|
|
||||||
|
|
||||||
function categorizeNodes(nodes: NetworkNode[]) {
|
/* ── Compact VM pill ─────────────────────────────────────── */
|
||||||
const categorized: { label: string; nodes: NetworkNode[] }[] = [];
|
function VmPill({ node }: { node: NetworkNode }) {
|
||||||
const assigned = new Set<string>();
|
const isUp = node.status === "up";
|
||||||
|
const dotColor = isUp ? "bg-success" : "bg-danger";
|
||||||
|
|
||||||
for (const [label, icons] of CATEGORY_ORDER) {
|
return (
|
||||||
const matching = nodes.filter(
|
<div className="flex items-center gap-2 bg-bg-card border border-border rounded-lg px-3 py-2">
|
||||||
(n) => icons.includes(n.icon) && !assigned.has(n.ip)
|
<span className={`w-2.5 h-2.5 rounded-full ${dotColor} shrink-0`} />
|
||||||
|
<span className="text-base font-medium text-text-primary truncate">{node.name}</span>
|
||||||
|
<span className="text-sm font-mono text-text-muted">{node.ip.split(".").pop()}</span>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
if (matching.length > 0) {
|
|
||||||
categorized.push({ label, nodes: matching });
|
|
||||||
for (const n of matching) assigned.add(n.ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const remaining = nodes.filter((n) => !assigned.has(n.ip));
|
|
||||||
if (remaining.length > 0) {
|
|
||||||
categorized.push({ label: "Otros", nodes: remaining });
|
|
||||||
}
|
|
||||||
|
|
||||||
return categorized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Full node card (infrastructure + proxmox) ───────────── */
|
||||||
|
function InfraCard({ node, isCenter }: { node: NetworkNode; isCenter?: boolean }) {
|
||||||
|
const [showPass, setShowPass] = useState(false);
|
||||||
|
const isUp = node.status === "up";
|
||||||
|
const borderColor = isUp ? "border-success/40" : "border-danger/40";
|
||||||
|
const bgColor = isUp ? "bg-success-dim" : "bg-danger-dim";
|
||||||
|
const dotColor = isUp ? "bg-success" : "bg-danger";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`${bgColor} border-2 ${borderColor} rounded-2xl px-6 py-5 cursor-pointer transition-all hover:brightness-110 ${isCenter ? "min-w-[280px]" : ""}`}
|
||||||
|
onClick={() => setShowPass((p) => !p)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3 mb-1">
|
||||||
|
<span className="text-3xl">{ICON_MAP[node.icon] || "📦"}</span>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-xl font-bold text-text-primary leading-tight">{node.name}</p>
|
||||||
|
<p className="text-base font-mono text-text-secondary">{node.ip}</p>
|
||||||
|
</div>
|
||||||
|
<span className={`w-4 h-4 rounded-full ${dotColor} shrink-0`} />
|
||||||
|
</div>
|
||||||
|
{node.username && (
|
||||||
|
<p className="text-sm text-text-secondary mt-1">
|
||||||
|
{node.username}
|
||||||
|
{node.password && (
|
||||||
|
<span className="ml-1 font-mono text-warning">
|
||||||
|
{showPass ? ` / ${node.password}` : " / ••••••"}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{node.public_url && (
|
||||||
|
<p className="text-sm text-accent mt-0.5">{node.public_url}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Proxmox server with its VMs ─────────────────────────── */
|
||||||
|
function ProxmoxColumn({ server, vms }: { server: NetworkNode; vms: NetworkNode[] }) {
|
||||||
|
const vmCount = vms.length;
|
||||||
|
const upCount = vms.filter((v) => v.status === "up").length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center gap-0">
|
||||||
|
{/* Server card */}
|
||||||
|
<InfraCard node={server} />
|
||||||
|
|
||||||
|
{/* Vertical connector */}
|
||||||
|
<div className="w-0.5 h-6 bg-border-light" />
|
||||||
|
|
||||||
|
{/* VM count badge */}
|
||||||
|
<div className="flex items-center gap-2 bg-bg-secondary border border-border rounded-full px-4 py-1.5 mb-2">
|
||||||
|
<span className="text-sm text-text-muted">
|
||||||
|
{upCount}/{vmCount} VMs
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* VM grid */}
|
||||||
|
<div className="grid grid-cols-2 gap-2 max-w-[520px]">
|
||||||
|
{vms.map((vm) => (
|
||||||
|
<VmPill key={vm.ip + vm.name} node={vm} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Vertical connector line ─────────────────────────────── */
|
||||||
|
function VLine() {
|
||||||
|
return <div className="w-0.5 h-8 bg-border-light mx-auto" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Main topology graph ─────────────────────────────────── */
|
||||||
export function NetworkGraph({ nodes }: NetworkGraphProps) {
|
export function NetworkGraph({ nodes }: NetworkGraphProps) {
|
||||||
const categories = categorizeNodes(nodes);
|
// Find nodes by role
|
||||||
|
const findByName = (name: string) => nodes.find((n) => n.name === name);
|
||||||
|
const modem = findByName("Router Telmex");
|
||||||
|
const firewall = findByName("Firewall OPNsense");
|
||||||
|
const switchNode = findByName("Switch Cisco");
|
||||||
|
|
||||||
|
const proxmoxServers = nodes.filter((n) => n.type === "proxmox");
|
||||||
|
const otherDevices = nodes.filter(
|
||||||
|
(n) =>
|
||||||
|
!n.type &&
|
||||||
|
n.name !== "Router Telmex" &&
|
||||||
|
n.name !== "Firewall OPNsense" &&
|
||||||
|
n.name !== "Switch Cisco"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Group VMs by parent
|
||||||
|
const vmsByParent = new Map<string, NetworkNode[]>();
|
||||||
|
for (const node of nodes) {
|
||||||
|
if ((node.type === "vm" || node.type === "ct") && node.parent) {
|
||||||
|
const list = vmsByParent.get(node.parent) || [];
|
||||||
|
list.push(node);
|
||||||
|
vmsByParent.set(node.parent, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onlineCount = nodes.filter((n) => n.status === "up").length;
|
const onlineCount = nodes.filter((n) => n.status === "up").length;
|
||||||
const total = nodes.length;
|
const total = nodes.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
{/* Summary bar */}
|
{/* Summary bar */}
|
||||||
<div className="flex items-center gap-10 px-16 py-5 bg-bg-secondary border-b border-border">
|
<div className="flex items-center gap-10 px-16 py-4 bg-bg-secondary border-b border-border">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<span className="w-4 h-4 rounded-full bg-success" />
|
<span className="w-4 h-4 rounded-full bg-success" />
|
||||||
<span className="text-xl text-text-secondary">
|
<span className="text-xl text-text-secondary">
|
||||||
@@ -59,30 +146,74 @@ export function NetworkGraph({ nodes }: NetworkGraphProps) {
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-border-light text-2xl">|</span>
|
<span className="text-border-light text-2xl">|</span>
|
||||||
<span className="text-xl text-text-secondary">
|
<span className="text-xl text-text-secondary">
|
||||||
<span className="font-bold text-text-primary">{total}</span> dispositivos
|
<span className="font-bold text-text-primary">{proxmoxServers.length}</span> Proxmox
|
||||||
|
<span className="mx-2">·</span>
|
||||||
|
<span className="font-bold text-text-primary">
|
||||||
|
{nodes.filter((n) => n.type === "vm" || n.type === "ct").length}
|
||||||
|
</span>{" "}
|
||||||
|
VMs/CTs
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Scrollable grid */}
|
{/* Diagram area */}
|
||||||
<div className="flex-1 overflow-y-auto px-16 py-8 space-y-8">
|
<div className="flex-1 overflow-y-auto">
|
||||||
{categories.map((cat) => (
|
<div className="flex flex-col items-center py-8 px-8">
|
||||||
<section key={cat.label}>
|
|
||||||
<h3 className="text-lg font-bold text-text-muted uppercase tracking-widest mb-4">
|
{/* ── Level 1: Modem ── */}
|
||||||
{cat.label}
|
{modem && <InfraCard node={modem} isCenter />}
|
||||||
<span className="ml-3 font-normal">({cat.nodes.length})</span>
|
<VLine />
|
||||||
</h3>
|
|
||||||
|
{/* ── Level 2: Firewall ── */}
|
||||||
|
{firewall && <InfraCard node={firewall} isCenter />}
|
||||||
|
<VLine />
|
||||||
|
|
||||||
|
{/* ── Level 3: Switch ── */}
|
||||||
|
{switchNode && <InfraCard node={switchNode} isCenter />}
|
||||||
|
<VLine />
|
||||||
|
|
||||||
|
{/* ── Branch lines to Proxmox servers ── */}
|
||||||
|
<div className="flex items-start justify-center w-full">
|
||||||
|
{/* Horizontal bar spanning all columns */}
|
||||||
|
<div className="relative flex justify-center" style={{ width: "100%", maxWidth: "3600px" }}>
|
||||||
|
{/* Horizontal line */}
|
||||||
<div
|
<div
|
||||||
className="grid gap-4"
|
className="absolute top-0 h-0.5 bg-border-light"
|
||||||
style={{
|
style={{
|
||||||
gridTemplateColumns: "repeat(auto-fill, minmax(520px, 1fr))",
|
left: `${100 / (proxmoxServers.length * 2)}%`,
|
||||||
|
right: `${100 / (proxmoxServers.length * 2)}%`,
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
{cat.nodes.map((node) => (
|
|
||||||
<NodeCard key={node.ip} node={node} />
|
{/* Proxmox columns */}
|
||||||
|
<div className="flex justify-center gap-8 w-full pt-0">
|
||||||
|
{proxmoxServers.map((server) => {
|
||||||
|
const vms = vmsByParent.get(server.name) || [];
|
||||||
|
return (
|
||||||
|
<div key={server.ip} className="flex-1 flex flex-col items-center max-w-[600px]">
|
||||||
|
{/* Vertical connector from horizontal bar */}
|
||||||
|
<div className="w-0.5 h-8 bg-border-light" />
|
||||||
|
<ProxmoxColumn server={server} vms={vms} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Other devices ── */}
|
||||||
|
{otherDevices.length > 0 && (
|
||||||
|
<div className="mt-8 w-full max-w-[3600px]">
|
||||||
|
<h3 className="text-base font-bold text-text-muted uppercase tracking-widest mb-4 text-center">
|
||||||
|
Otros dispositivos conectados al switch
|
||||||
|
</h3>
|
||||||
|
<div className="flex justify-center gap-4 flex-wrap">
|
||||||
|
{otherDevices.map((node) => (
|
||||||
|
<InfraCard key={node.ip} node={node} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
))}
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ export interface NetworkNode {
|
|||||||
icon: string;
|
icon: string;
|
||||||
status: "up" | "down" | "unknown";
|
status: "up" | "down" | "unknown";
|
||||||
connections: string[];
|
connections: string[];
|
||||||
|
type?: "proxmox" | "vm" | "ct" | string;
|
||||||
|
parent?: string;
|
||||||
auto_discovered?: boolean;
|
auto_discovered?: boolean;
|
||||||
vendor?: string;
|
vendor?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user