Volver a la wiki

Terminal: listar todos los dispositivos + filtro por tipo

Resumen

La página Terminal ahora muestra todos los dispositivos de red registrados, no solo los que están colocados en un rack con Network Management. Incluye un nuevo filtro primario por tipo de dispositivo (Todos / Rack / Wireless / UPS / Digital Signage / Otros).

Sesión 114 · Merge PR #80 edu/terminal-all-devices · 2026-06-08


Cambio de comportamiento

Antes

Ahora


Implementación

Nuevo servicio: terminal_hosts(org)

Ubicación: terminal/services.py

Normaliza y deduplica dos fuentes:

  1. racks.Device.has_network_management → source="device", category="rack".
  2. network.DeviceProfile → source="profile", category según DeviceProfile.assigned_page (wireless/ups/signage; sin asignar → rack u other).

Devuelve un dict con hosts[] (unificado, deduplicado por IP) y racks[] (para el filtro).

Código:

def terminal_hosts(org):
    devices, taken_ips, racks_by_id = _device_hosts(org)
    profiles = _profile_hosts(org, taken_ips)
    racks = sorted(racks_by_id.values(), key=lambda r: r.name)
    return {"hosts": devices + profiles, "racks": racks}

Véase entity--terminal--service--terminal-hosts para detalles de estructura.


Refactor de la vista: terminal/views.py::index(request)

Antes:

all_devices = Device.objects.filter(rack__organization=org, ...)
devices = [d for d in all_devices if d.has_network_management]
# renderizar devices

Ahora:

result = terminal_hosts(org)
hosts = result["hosts"]
device_racks = result["racks"]

context = {
    "hosts": hosts,
    "total_nm_devices": len(hosts),
    "device_racks": device_racks,
    ...
}

La vista delega toda la lógica de unión + dedup al servicio.


Frontend: nuevo filtro y handler

static/js/utils/DeviceFilterService.js:

const typeFilter = document.getElementById('device-type-filter')?.value || 'all';
const matchesType = typeFilter === 'all' || category === typeFilter;
item.style.display = (matchesSearch && matchesType && matchesStatus && matchesGroup && matchesRack) ? '' : 'none';

static/js/pages/terminal.js:

quickConnectHost(ip, name) {
    const host = document.getElementById('manual-ssh-host');
    if (host) host.value = ip || '';
    const portEl = document.getElementById('manual-ssh-port');
    if (portEl && !portEl.value) portEl.value = '22';
    this.openManualConnectionModal();
}

Template: templates/terminal/index.html

Cambios estructurales:

  1. Nuevo dropdown de tipo (filtro primario):

    <select id="device-type-filter" data-on-change="DeviceManager.filterDevices"
        aria-label="Filter devices by type">
        <option value="all">All Types</option>
        <option value="rack">Rack</option>
        <option value="wireless">Wireless</option>
        <option value="ups">UPS</option>
        <option value="signage">Digital Signage</option>
        <option value="other">Other</option>
    </select>
  2. Iteración bifurcada sobre hosts:

    {% for host in hosts %}
        {% if host.source == "device" %}
            <li data-id="{{ host.device_id }}" ... data-action="TerminalApp.openSession" ...>
                <!-- Equipo de rack: clic directo en SSH -->
            </li>
        {% else %}
            <li class="device-item-detected" ... data-action="TerminalApp.quickConnectHost" ...>
                <!-- Detectado: clic abre modal manual -->
                <span class="device-derived">{{ host.derived_to }}</span>
            </li>
        {% endif %}
    {% endfor %}
  3. Mensaje vacío actualizado:

    {% empty %}
    <li class="empty-state">No network devices registered yet</li>

Testing

tests/api/test_terminal_hosts.py · 7 tests:

Suite terminal/racks/network: 100 passed, 0 regresiones.


Notas de diseño

Sin credenciales inventadas (Regla 13)

Deduplicación por IP (transparente)

Filtro primario vs secundarios


Impacto en otros módulos


Véase también

Subir