Volver a la wiki

Reorganización de menú CONFIGURATION con acordeón (tarea #182)

Descripción

Refactorización del menú desplegable “CONFIGURATION” (anteriormente “Config”) en el header del dashboard, reorganizando 7 botones sueltos en 6 secciones acordeón auto-colapsables con gestión CSP-safe mediante Alpine.js.

Motivación

Antes de esta refactorización, el header del dashboard contenía múltiples botones sueltos (Agent, Wide View, Shine, Guide, Help, Logout, Users Management) distribuidos en varios grupos visuales, lo que reducía legibilidad y ocupaba mucho espacio. La tarea #182 (UX del header) buscaba consolidar estas acciones en una única ubicación jerárquica.

Cambios principales

1. Visibilidad e inclusión

2. Estructura de secciones

CONFIGURATION (menú desplegable)
├── LOCAL AGENT [admin]
│   ├── Agent
│   ├── Download Agent [nuevo]
│   └── Uninstall Local Agent
├── NAVIGATION [todos]
│   ├── Wide View
│   ├── Shine
│   └── Open modules in new tab (checkbox)
├── USERS [todos, Users Management admin]
│   ├── Users Management [admin]
│   └── Logout ({{ user.username }})
├── HELP [todos]
│   ├── Guide
│   └── Help
├── FILE OPERATIONS [admin]
│   ├── Export to CSV
│   ├── System Logs
│   ├── Project Report
│   ├── Full System Backup
│   └── Full System Restore [peligro]
└── SETTINGS [admin]
    ├── Company Data
    ├── Third-Party Licenses
    ├── Stored Credentials
    └── Re-run Welcome Wizard

3. Comportamiento del acordeón

Implementación

CSS (.dropdown-section, .dropdown-section-body)

Archivo: static/css/components.css (+45 líneas)

Componente Alpine (refactorización completa)

Cambios en static/js/alpine-components.js:

Alpine.data('configDropdown', () => ({
  open: false,                        // estado del dropdown
  section: null,                      // sección abierta ('agent', 'nav', 'users', 'help', 'files', 'settings', null)
  
  // Control básico
  toggle() { this.open = !this.open; if (!this.open) this.section = null; }
  close()  { this.open = false; this.section = null; }
  
  // Toggles por sección (CSP-safe: sin args)
  toggleAgent()    { this.section = this.section === 'agent' ? null : 'agent'; }
  toggleNav()      { this.section = this.section === 'nav' ? null : 'nav'; }
  toggleUsers()    { this.section = this.section === 'users' ? null : 'users'; }
  toggleHelpSec()  { this.section = this.section === 'help' ? null : 'help'; }
  toggleFiles()    { this.section = this.section === 'files' ? null : 'files'; }
  toggleSettings() { this.section = this.section === 'settings' ? null : 'settings'; }
  
  // Getters de visibilidad (:x-show)
  get secAgent()    { return this.section === 'agent'; }
  get secNav()      { return this.section === 'nav'; }
  get secUsers()    { return this.section === 'users'; }
  get secHelp()     { return this.section === 'help'; }
  get secFiles()    { return this.section === 'files'; }
  get secSettings() { return this.section === 'settings'; }
  
  // Getters de clase (:class - aplicar 'active' a cabecero)
  get clsAgent()    { return this.section === 'agent' ? 'dropdown-section active' : 'dropdown-section'; }
  get clsNav()      { return this.section === 'nav' ? 'dropdown-section active' : 'dropdown-section'; }
  // ... (6 en total)
  
  // Acciones desplegadas desde header a menú
  openAgentFleet()  { this.close(); openAgentFleetModal(); }
  toggleWidth()     { this.close(); toggleWidthMode(); }
  cycleShineNow()   { this.close(); cycleShine(); }
  openGuide()       { this.close(); openGuideModal(); }
  toggleHelp()      { this.close(); toggleHelpPanel(); }
  
  // Acciones existentes refactorizadas (all call this.close() antes)
  exportCsv()       { this.close(); ... }
  // ... etc
}))

Archivo: static/js/alpine-components.js (+63 líneas, 39 líneas de métodos/getters)

Principios CSP:

Template (reestructuración)

Archivo: templates/base.html (~+110 líneas)

Cambios principales:

  1. Botón “Config” → “CONFIGURATION” (uppercase, letter-spacing 0.03em)
  2. Estructura de secciones: <button :class="cls..."> + <div class="dropdown-section-body" x-show="sec..."> con items anidados
  3. Permisos templated: {% if user.role == 'admin' %} rodea secciones sensibles
  4. IDs preservados: id="agent-fleet-btn", id="width-toggle-btn", id="shine-toggle-btn", id="logout-btn", id="settings-users-item", id="settings-company-item" para mantener compatibilidad con listeners existentes
  5. Nuevo elemento: Download Agent link si AGENT_DOWNLOAD_URL está configurada (env/settings)

Compatibilidad

Notas técnicas

Véase también

Subir