feat: nettoyage menu + suppression modules inexistants + log viewer
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
07af66ad81
commit
88831e3967
9 changed files with 200 additions and 27 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
53
backend/internal/logbuffer/buffer.go
Normal file
53
backend/internal/logbuffer/buffer.go
Normal file
|
|
@ -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{}
|
||||
Loading…
Add table
Add a link
Reference in a new issue