From 88831e39675c8444b9e1522ff3af4aaf8cb36e0b Mon Sep 17 00:00:00 2001 From: enzo Date: Fri, 20 Mar 2026 23:57:07 +0100 Subject: [PATCH] feat: nettoyage menu + suppression modules inexistants + log viewer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Sidebar : retrait des liens files, logs, services (non implémentés) - Migration 001 : suppression des inserts files/logs/services - Migration 002 : DELETE des modules inexistants en DB existante - logbuffer : ring buffer mémoire branché sur log.SetOutput - GET /api/settings/logs : retourne les 300 dernières lignes de log - Settings : onglet Logs avec auto-refresh (5s/10s/30s/60s/désactivé, défaut 10s) Co-Authored-By: Claude Sonnet 4.6 --- backend/internal/api/settings.go | 18 +++ backend/internal/db/migrations/001_init.sql | 5 +- .../002_remove_unimplemented_modules.sql | 3 + backend/internal/logbuffer/buffer.go | 53 +++++++++ backend/main.go | 6 + frontend/src/components/Sidebar.vue | 18 --- frontend/src/locales/en.json | 6 +- frontend/src/locales/fr.json | 6 +- frontend/src/views/Settings.vue | 112 +++++++++++++++++- 9 files changed, 200 insertions(+), 27 deletions(-) create mode 100644 backend/internal/db/migrations/002_remove_unimplemented_modules.sql create mode 100644 backend/internal/logbuffer/buffer.go diff --git a/backend/internal/api/settings.go b/backend/internal/api/settings.go index b828cce..7dbbe5e 100644 --- a/backend/internal/api/settings.go +++ b/backend/internal/api/settings.go @@ -3,9 +3,11 @@ package api import ( "net/http" + "strconv" "git.geronzi.fr/proxmoxPanel/core/backend/internal/audit" "git.geronzi.fr/proxmoxPanel/core/backend/internal/db" + "git.geronzi.fr/proxmoxPanel/core/backend/internal/logbuffer" "github.com/go-chi/chi/v5" ) @@ -168,6 +170,22 @@ func (h *SettingsHandler) DisableModule(w http.ResponseWriter, r *http.Request) JSONResponse(w, http.StatusOK, map[string]string{"message": "Module désactivé"}) } +// GetLogs retourne les dernières lignes du log applicatif (tampon mémoire). +// GET /api/settings/logs?lines=200 +func (h *SettingsHandler) GetLogs(w http.ResponseWriter, r *http.Request) { + n := 200 + if s := r.URL.Query().Get("lines"); s != "" { + if v, err := strconv.Atoi(s); err == nil && v > 0 { + n = v + } + } + lines := logbuffer.Global.Lines(n) + if lines == nil { + lines = []string{} + } + JSONResponse(w, http.StatusOK, lines) +} + // GetAuditLog retourne le journal d'audit paginé. // GET /api/settings/audit func (h *SettingsHandler) GetAuditLog(w http.ResponseWriter, r *http.Request) { diff --git a/backend/internal/db/migrations/001_init.sql b/backend/internal/db/migrations/001_init.sql index b8868a1..5080893 100644 --- a/backend/internal/db/migrations/001_init.sql +++ b/backend/internal/db/migrations/001_init.sql @@ -93,8 +93,5 @@ INSERT OR IGNORE INTO modules (id, name, description, version, is_core, is_enabl ('dashboard', 'Dashboard', 'Tableau de bord avec widgets configurables', '1.0.0', 1, 1), ('proxmox', 'Proxmox', 'Gestion des LXC et VM Proxmox', '1.0.0', 1, 1), ('updates', 'Mises à jour', 'Mises à jour de paquets apt avec streaming', '1.0.0', 1, 1), - ('settings', 'Paramètres', 'Configuration de l''application', '1.0.0', 1, 1), - ('files', 'Fichiers', 'Navigateur de fichiers SFTP', '1.0.0', 0, 0), ('terminal', 'Terminal', 'Terminal SSH interactif', '1.0.0', 0, 0), - ('logs', 'Logs', 'Streaming de logs en temps réel', '1.0.0', 0, 0), - ('services', 'Services', 'Gestion des services systemd', '1.0.0', 0, 0); + ('settings', 'Paramètres', 'Configuration de l''application', '1.0.0', 1, 1); diff --git a/backend/internal/db/migrations/002_remove_unimplemented_modules.sql b/backend/internal/db/migrations/002_remove_unimplemented_modules.sql new file mode 100644 index 0000000..e92e537 --- /dev/null +++ b/backend/internal/db/migrations/002_remove_unimplemented_modules.sql @@ -0,0 +1,3 @@ +-- Migration 002 : Suppression des modules non implémentés +-- Les modules files, logs et services n'ont pas d'implémentation backend. +DELETE FROM modules WHERE id IN ('files', 'logs', 'services'); diff --git a/backend/internal/logbuffer/buffer.go b/backend/internal/logbuffer/buffer.go new file mode 100644 index 0000000..9ee5e90 --- /dev/null +++ b/backend/internal/logbuffer/buffer.go @@ -0,0 +1,53 @@ +// Package logbuffer maintient un tampon circulaire en mémoire des lignes de log. +// Il implémente io.Writer pour être branché sur log.SetOutput via io.MultiWriter. +package logbuffer + +import ( + "bytes" + "sync" +) + +const maxLines = 500 + +// Buffer est un tampon circulaire thread-safe de lignes de log. +type Buffer struct { + mu sync.RWMutex + lines []string +} + +// Write implémente io.Writer. Découpe p en lignes et les ajoute au tampon. +func (b *Buffer) Write(p []byte) (int, error) { + b.mu.Lock() + defer b.mu.Unlock() + + for _, line := range bytes.Split(p, []byte("\n")) { + s := string(bytes.TrimRight(line, "\r")) + if s == "" { + continue + } + b.lines = append(b.lines, s) + if len(b.lines) > maxLines { + b.lines = b.lines[len(b.lines)-maxLines:] + } + } + return len(p), nil +} + +// Lines retourne les n dernières lignes (ou toutes si n <= 0 ou n > taille). +func (b *Buffer) Lines(n int) []string { + b.mu.RLock() + defer b.mu.RUnlock() + + total := len(b.lines) + if n <= 0 || n >= total { + result := make([]string, total) + copy(result, b.lines) + return result + } + result := make([]string, n) + copy(result, b.lines[total-n:]) + return result +} + +// Global est l'instance partagée utilisée par main.go et les handlers. +var Global = &Buffer{} diff --git a/backend/main.go b/backend/main.go index 3aab031..2060b11 100644 --- a/backend/main.go +++ b/backend/main.go @@ -4,6 +4,7 @@ package main import ( + "io" "log" "net/http" "os" @@ -12,6 +13,7 @@ import ( "git.geronzi.fr/proxmoxPanel/core/backend/internal/auth" "git.geronzi.fr/proxmoxPanel/core/backend/internal/crypto" "git.geronzi.fr/proxmoxPanel/core/backend/internal/db" + "git.geronzi.fr/proxmoxPanel/core/backend/internal/logbuffer" sshpool "git.geronzi.fr/proxmoxPanel/core/backend/internal/ssh" "git.geronzi.fr/proxmoxPanel/core/backend/internal/websocket" "git.geronzi.fr/proxmoxPanel/core/backend/modules" @@ -21,6 +23,9 @@ import ( ) func main() { + // Brancher le buffer de logs (stderr + mémoire) avant tout autre log + log.SetOutput(io.MultiWriter(os.Stderr, logbuffer.Global)) + // Répertoire de données persistantes (volume Docker) dataDir := getEnv("DATA_DIR", "/app/data") @@ -150,6 +155,7 @@ func main() { r.Get("/api/settings", settingsHandler.GetAll) r.Put("/api/settings/{key}", settingsHandler.UpdateSetting) r.Get("/api/settings/audit", settingsHandler.GetAuditLog) + r.Get("/api/settings/logs", settingsHandler.GetLogs) }) // Modules diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue index dff0fcf..cace0ae 100644 --- a/frontend/src/components/Sidebar.vue +++ b/frontend/src/components/Sidebar.vue @@ -101,24 +101,6 @@ const navItems = computed(() => { label: 'nav.terminal', icon: ``, }, - { - name: 'files', - path: '/files', - label: 'nav.files', - icon: ``, - }, - { - name: 'logs', - path: '/logs', - label: 'nav.logs', - icon: ``, - }, - { - name: 'services', - path: '/services', - label: 'nav.services', - icon: ``, - }, { name: 'settings', path: '/settings', diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index fbc419b..ec80fda 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -118,7 +118,11 @@ "sidebarPosition": "Sidebar position", "left": "Left", "right": "Right", - "noAuditLog": "No audit log entries" + "noAuditLog": "No audit log entries", + "logs": "Logs", + "logsRefresh": "Auto-refresh", + "logsNoRefresh": "Disabled", + "noLogs": "No logs available" }, "modules": { "desc": "Manage installed modules on ProxmoxPanel.", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index f7386e9..4205b3c 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -118,7 +118,11 @@ "sidebarPosition": "Position de la sidebar", "left": "Gauche", "right": "Droite", - "noAuditLog": "Aucune entrée dans le journal" + "noAuditLog": "Aucune entrée dans le journal", + "logs": "Logs", + "logsRefresh": "Rafraîchissement", + "logsNoRefresh": "Désactivé", + "noLogs": "Aucun log disponible" }, "modules": { "desc": "Gérez les modules installés sur ProxmoxPanel.", diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index db45b68..27c1165 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -101,8 +101,32 @@ - -
+ +
+
+

{{ t('settings.logs') }}

+
+ + + +
+
+
+

{{ t('settings.noLogs') }}

+
+ {{ line }} +
+
+
+ + +
@@ -114,7 +138,7 @@