CreaRack-SL

Servicio Frontend: LivePanel (descubrimiento en vivo)

Descripción general

LivePanel es un módulo JavaScript vanilla que gestiona la visualización en tiempo real del descubrimiento de dispositivos en el modal de Auto-Provision. Muestra:

  1. Timeline de fases — Ping, ARP, SNMP, HTTP, Enrich con estados y hitos.
  2. Feed de dispositivos — lista scrollable que se rellena progresivamente.
  3. Micro-animaciones — latidos, anillos expansivos, entrada de items (con respeto a prefers-reduced-motion).

Ubicación: static/js/network/auto_provision/live_panel.js

Integración: cableado en discovery.js (métodos discoverSingleDevice() y discoverSubnet()). Se invoca por cada evento de fase/dispositivo del backend o el escaneo local.

API pública

El módulo exporta un objeto LivePanel con 5 métodos:

LivePanel.setPhaseActive(phase)
LivePanel.setPhaseDone(phase, milestone)
LivePanel.setPhaseSkipped(phase, milestone)
LivePanel.addDevice(dev)
LivePanel.reset()

setPhaseActive(phase)

Marca una fase como “activa” (en progreso). Aplica:

  • data-state="active" al <li class="ap-phase" data-phase="...">.
  • Animación de latido (pulsación azul con anillo expansivo).
  • Color accent en el nombre de la fase.

Parámetro:

  • phase (string): "ping", "arp", "snmp", "http", "enrich".
LivePanel.setPhaseActive('snmp');
// → <li data-phase="snmp" data-state="active">...</li>

setPhaseDone(phase, milestone)

Fija una fase como completada y actualiza su hito (p.ej. “3 hosts alive”).

Parámetros:

  • phase (string): clave de fase.
  • milestone (string | null): texto que aparece debajo del nombre (p.ej. “3 hosts alive · 4 ms”).
LivePanel.setPhaseDone('ping', '127 hosts alive');
// → <li data-phase="ping" data-state="done">
//     <span class="ap-phase__name">Ping</span>
//     <span class="ap-phase__milestone">127 hosts alive</span>
//   </li>

Efecto visual:

  • Check verde (✓) en el nodo.
  • Borde + fondo verde.
  • Hito fijado en text-secondary (visible permanentemente).

setPhaseSkipped(phase, milestone)

Marca una fase como omitida (p.ej. HTTP sin respuesta, fase opcional saltada).

Parámetros: igual que setPhaseDone().

LivePanel.setPhaseSkipped('http', 'no web UI detected');
// → <li data-phase="http" data-state="skipped">
//     <span class="ap-phase__milestone">no web UI detected</span>
//   </li>

Efecto visual:

  • Borde punteado (dashed).
  • Opacidad reducida (opacity: 0.7).
  • Hito en text-muted (discreto).

addDevice(dev)

Inserta un dispositivo en el feed con micro-animación de entrada.

Parámetro:

  • dev (object):
    {
      ip: "192.168.1.10",        // string, requerido
      vendor: "Cisco",           // string, requerido
      type: "Switch",            // string, optional
      method: "snmp"             // string: 'snmp' | 'ssh' | 'ping'
    }

Comportamiento:

  • Crea un <div class="ap-device"> con la IP (monospace), vendor + tipo, y badge de método.
  • Lo inserta al inicio del feed (lo más reciente primero, sin obligar scroll).
  • Elimina el placeholder vacío si estaba.
  • Incrementa el contador #discovery-found-count.
  • Aplica animación de entrada (.34s cubic-bezier(...)).
LivePanel.addDevice({
  ip: "10.0.0.5",
  vendor: "Ubiquiti",
  type: "AP",
  method: "ssh"
});

Badge de método:

  • snmp → azul claro con borde, texto “SNMP”.
  • ssh → verde claro, texto “SSH”.
  • ping → gris neutro, texto “PING”.

El badge no es únicamente color; incluye texto que lo discrimina (accesibilidad).

reset()

Limpia el panel para iniciar un nuevo escaneo.

Acciones:

  • Reset data-state de todas las fases a "pending".
  • Limpia hitos (data-milestone).
  • Vacía el feed y muestra placeholder.
  • Reset contador a 0.
  • Reset barra de progreso a 0%.
LivePanel.reset();

Estructura del DOM (IDs requeridos)

El módulo asume la siguiente estructura HTML (en #discovery-progress):

<ul id="discovery-phase-list">
  <li class="ap-phase" data-phase="ping" data-state="pending">
    <span class="ap-phase__node" aria-hidden="true">
      <svg><!-- check icon --></svg>
    </span>
    <span class="ap-phase__body">
      <span class="ap-phase__name">Ping</span>
      <span class="ap-phase__milestone" data-milestone></span>
    </span>
  </li>
  <!-- ... (arp, snmp, http, enrich) -->
</ul>

<div id="discovery-live-feed" aria-live="polite">
  <div class="ap-feed-empty" data-empty>No devices yet…</div>
</div>

<span id="discovery-found-count" aria-live="polite">
  <b>0</b> found
</span>

IDs críticos:

  • #discovery-phase-list — UL de fases.
  • #discovery-live-feed — contenedor scrollable de dispositivos.
  • #discovery-found-count — contador (actualizado por addDevice()).

Atributos especiales:

  • data-phase en <li> — clave de fase (discrimina en setPhaseActive() etc.).
  • data-state — estado actual (pending|active|done|skipped).
  • data-milestone — span que recibe el hito.
  • aria-live="polite" — anuncio accesible en feed y contador.

Animaciones

Latido de fase activa

@keyframes ap-pulse { /* pulsación caja sombra */ }
@keyframes ap-ring   { /* anillo expansivo */ }

Dura 1.6s, infinita. Pausa automática si prefers-reduced-motion: reduce.

Entrada de dispositivo

@keyframes ap-device-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* duración: .34s cubic-bezier(.2, .7, .3, 1) */

Suave y rápida. Deshabilitada si prefers-reduced-motion: reduce.

Integración con discovery.js

En discovery.js, los métodos discoverSingleDevice() y discoverSubnet() llaman a LivePanel.* en cada fase:

// Ejemplo pseudocódigo:
async function discoverSingleDevice(ip) {
  LivePanel.reset();
  
  LivePanel.setPhaseActive('ping');
  // ... ping logic ...
  LivePanel.setPhaseDone('ping', 'host alive');
  
  LivePanel.setPhaseActive('arp');
  // ... arp logic ...
  LivePanel.setPhaseDone('arp', 'MAC matched');
  
  // etc.
  
  LivePanel.setPhaseActive('enrich');
  // ... enrich logic ...
  const discovered = await fetchDevicesFromBackend();
  discovered.forEach(dev => LivePanel.addDevice(dev));
  LivePanel.setPhaseDone('enrich', `${discovered.length} devices enriched`);
}

Estilos (CSS)

Ubicados en static/css/pages/auto_provision.css. Incluyen:

  • Paleta: variables CSS de --accent, --success, --bg-tertiary, etc.
  • Grid layout: columna izquierda (fases) + derecha (feed).
  • Timeline: línea vertical con nodos (SVG check en done, animaciones en active).
  • Scrollbar customizado: thin, color --border-color.
  • Media queries: en pantallas <720px, feed cae debajo de fases.

Todos los colores tienen contraste ≥ 4.5:1 a 12-14px (accesibilidad WCAG AA).

Notas de implementación

  • Vanilla JS: sin frameworks, sin dependencias externas.
  • No mutación de métodos: cada set* es idempotente (llamar 2x la misma operación da el mismo resultado).
  • Accesibilidad: aria-live en feed y contador, textos de badge no solo color.
  • Performance: .prepend() en feed evita repintado de toda la lista (inserta al inicio).
  • Mock funcional: _design/autoprovision-live-panel.html es autónomo (716 líneas), incluye lógica DEMO que permite simular el escaneo sin backend.

Véase también

  • [[feature—network—autoprovision-ux-panel-assign-s115]]
  • [[entity—network—endpoint—assign-types]]
  • [[concept—ux—animations-and-transitions]]
  • [[concept—ux—accessibility]]