Volver a la wiki

Servicio agent_onboarding — Onboarding guiado de descarga del Local Agent

Descripción

Módulo JavaScript (static/js/modules/agent_onboarding.js, 114 LOC) que proporciona una interfaz de usuario guiada para descargar el CreaRack Local Agent cuando no está instalado en la máquina del usuario.

Se carga en base.html con atributo defer, tras agent_lna_notice.js y antes de auth.js.

API pública

El módulo expone un objeto global window.CreaRackAgentOnboarding con los siguientes métodos:

offer(context)

Parámetros:

Comportamiento:

downloadAgent()

Parámetros: ninguno.

Comportamiento:

agentRunning()

Parámetros: ninguno.

Retorna: Promise<boolean> — true si el Agent responde a GET /info con 200 en <1.5s, false en caso contrario.

Implementación:

async function agentRunning() {
    try {
        const ctrl = new AbortController();
        const to = setTimeout(() => ctrl.abort(), 1500);
        const r = await fetch(`${AGENT_URL}/info`, { 
            signal: ctrl.signal, 
            mode: 'cors' 
        });
        clearTimeout(to);
        return r.ok;
    } catch {
        return false;
    }
}

Comportamiento detallado

Flujo principal: offer() → banner → polling

  1. Validar que no hay banner existente: Si #agent-install-notice ya existe, salir.

  2. Priorizar Agent no instalado: Si #lna-notice (permiso) está visible, removerlo.

  3. Crear y renderizar banner:

    • ID: agent-install-notice
    • Clase: lna-notice agent-install-notice (reutiliza estilos de aviso).
    • HTML:
      <div class="lna-notice-body">
        <strong class="lna-notice-title">Install the Local Agent</strong>
        <p>[intro dinámico] Download it and run the installer...</p>
      </div>
      <div class="agent-install-actions">
        <button id="agent-install-download" class="btn btn-action btn-sm">
          Download Local Agent
        </button>
        <button id="agent-install-dismiss" class="btn btn-neutral btn-sm">
          Not now
        </button>
      </div>
    • Role: status (para lectura de pantalla).
    • Se añade al final del <body>.
  4. Event listeners:

    • Download:
      • Llama a downloadAgent().
      • Cambia el texto del párrafo a “Downloading… run the installer when it finishes. This will close once the Agent connects.”
      • Deshabilita el botón Download (disabled = true).
      • Inicia polling con startConnectPolling(el).
    • Not now: Llama a removeNotice(el) para cerrar el banner.

startConnectPolling(el)

removeNotice(el)

Configuración

Variables globales esperadas

Funciones globales esperadas

Integración en flujos existentes

discovery.js (~línea 255)

catch (e) {
    // En vez de un error seco: ofrecer la descarga guiada del Agente (tarea #182).
    if (window.CreaRackAgentOnboarding) window.CreaRackAgentOnboarding.offer('discovery');
    throw new Error(t('Local Agent not available. Please start CreaRackAgent.exe'));
}

agent_probe.js (~línea 27)

catch (e) {
    // En vez de un error seco: ofrecer la descarga guiada del Agente (tarea #182).
    if (window.CreaRackAgentOnboarding) window.CreaRackAgentOnboarding.offer('discovery');
    throw new Error(t('Local Agent not available. Please start CreaRackAgent.exe'));
}

Ambos flujos llaman a offer('discovery') si window.CreaRackAgentOnboarding existe (defensive programming).

Estilos CSS asociados

components.css (~línea 1010)

/* Banner "Install the Local Agent" (agent_onboarding.js, tarea #182):
   fila de acciones horizontal en vez de botones apilados. */
.agent-install-actions {
    display: flex;
    gap: 10px;
    justify-content: center;
}

.agent-install-notice .agent-install-actions .btn {
    align-self: auto;
    min-width: 130px;
}

Clases reutilizadas:

IIFE y scope

El módulo es una IIFE (Immediately Invoked Function Expression) para encapsular variables locales y evitar contaminación del scope global:

(function () {
    'use strict';
    const AGENT_URL = window.AGENT_URL || 'http://127.0.0.1:5050';
    let pollTimer = null;
    
    // Funciones privadas...
    
    window.CreaRackAgentOnboarding = { ... }; // Única exposición global
})();

Variables privadas:

Modelo “just-in-time”

No hay auto-disparo al cargar la app. Razones:

  1. Hay usuarios sin Agent local: El Sentinel 24/7 (Agent Primary) entrega monitorización central. Usuarios que solo leen datos del Sentinel no necesitan Agent local.
  2. Contexto importa: El banner solo se muestra cuando el usuario intenta una acción que necesita el Agent (e.g., auto-discovery de red).
  3. Menos ruido: Evita avisos intrusivos si el usuario no planea usar discovery.

Deuda técnica

Véase también

Subir