From fdf76477e5675cc0c43cc1d4a853c770c8d313df Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Sat, 23 May 2026 05:10:28 +0200 Subject: [PATCH] feat: type de jauge configurable (compact / standard) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ServerConfig: champ gauge_type (défaut "compact") - CSS: classes .gs-* pour la BatteryGauge standard (label + bar 9px + gloss interne) - Grid: helper renderGaugeRow() — sélectionne compact ou standard selon la config - Grid: rerenderAll() pour appliquer le changement sans recharger la page - Popup config serveur: select "Type de jauge" dans la section Affichage des tuiles Co-Authored-By: Claude Sonnet 4.6 --- dashboard/css/app.css | 11 ++++++++ dashboard/js/grid.js | 61 ++++++++++++++++++++++++++++------------- dashboard/js/popups.js | 8 ++++++ server/models/models.go | 24 ++++++++-------- 4 files changed, 74 insertions(+), 30 deletions(-) diff --git a/dashboard/css/app.css b/dashboard/css/app.css index 594949a..8dc3f38 100644 --- a/dashboard/css/app.css +++ b/dashboard/css/app.css @@ -117,6 +117,17 @@ body{background:var(--bg-1);color:var(--ink-1);font-family:var(--font-ui);font-s .g-fill.w{background:var(--warn)}.g-fill.e{background:var(--err)} .g-val{font-family:var(--font-mono);font-size:11px;color:var(--ink-2); min-width:34px;white-space:nowrap;flex-shrink:0;text-align:right} +/* Jauge standard (BatteryGauge) */ +.gs-row{display:flex;flex-direction:column;gap:3px} +.gs-header{display:flex;align-items:center;gap:6px} +.gs-ico{width:14px;text-align:center;font-size:10px;color:var(--ink-3);flex-shrink:0;cursor:help} +.gs-lbl{flex:1;font-family:var(--font-terminal);font-size:10px;color:var(--ink-3);letter-spacing:.04em} +.gs-val{font-family:var(--font-mono);font-size:11px;color:var(--ink-2);white-space:nowrap;flex-shrink:0} +.gs-bar{position:relative;height:9px;border-radius:3px;background:var(--bg-1); + border:1px solid var(--border-1);overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.3)} +.gs-fill{height:100%;border-radius:2px;background:var(--ok);transition:width .3s} +.gs-fill.w{background:var(--warn)}.gs-fill.e{background:var(--err)} +.gs-gloss{position:absolute;inset:0;background:linear-gradient(180deg,rgba(255,255,255,.12),transparent);pointer-events:none} .tile-foot{font-family:var(--font-terminal);font-size:10px;color:var(--ink-4); display:flex;align-items:center;justify-content:space-between;user-select:none} .tile-foot-info{display:flex;align-items:center;gap:5px;min-width:0;overflow:hidden} diff --git a/dashboard/js/grid.js b/dashboard/js/grid.js index 1bd187c..e0cf66b 100644 --- a/dashboard/js/grid.js +++ b/dashboard/js/grid.js @@ -36,6 +36,28 @@ const Grid = (() => { return ''; } + function renderGaugeRow(faIcon, tip, label, pct, fillClass, valStr, extra) { + const standard = (App.serverConfig?.gauge_type ?? 'compact') === 'standard'; + if (standard) { + return `
+
+ + ${label} + ${valStr}${extra || ''} +
+
+
+
+
+
`; + } + return `
+
+
+ ${valStr}${extra || ''} +
`; + } + function renderTile(agent, metrics) { const id = agent.id; const sc = statusClass(agent); @@ -77,24 +99,19 @@ const Grid = (() => {
-
-
-
- ${offline ? '—' : fmtPct(cpu)} -
-
-
-
- ${offline ? '—' : (metrics?.memory_used && metrics?.memory_total ? fmt(metrics.memory_used) + '/' + fmt(metrics.memory_total) : '—')} -
-
-
-
- ${offline ? '—' : (metrics?.hdd_used && metrics?.hdd_total ? fmt(metrics.hdd_used) + '/' + fmt(metrics.hdd_total) : '—')}${smartIco} -
+ ${renderGaugeRow('microchip', 'CPU', 'CPU', + offline ? 0 : (cpu ?? 0), + offline ? '' : gFill(cpu ?? 0), + offline ? '—' : fmtPct(cpu))} + ${renderGaugeRow('memory', 'RAM', 'MÉMOIRE', + offline ? 0 : (memPct ?? 0), + offline ? '' : gFill(memPct ?? 0), + offline ? '—' : (metrics?.memory_used && metrics?.memory_total ? fmt(metrics.memory_used) + '/' + fmt(metrics.memory_total) : '—'))} + ${renderGaugeRow('hard-drive', 'Disque', 'DISQUE', + offline ? 0 : (diskPct ?? 0), + offline ? '' : (diskPct >= (App.serverConfig?.warn_disk ?? 75) ? 'w' : ''), + offline ? '—' : (metrics?.hdd_used && metrics?.hdd_total ? fmt(metrics.hdd_used) + '/' + fmt(metrics.hdd_total) : '—'), + smartIco)}
@@ -173,6 +190,12 @@ const Grid = (() => { document.getElementById('stat-err').textContent = err; } + function rerenderAll() { + const grid = document.getElementById('agents-grid'); + if (!grid) return; + grid.innerHTML = [..._agents.values()].map(({ agent, metrics }) => renderTile(agent, metrics)).join(''); + } + function removeAgent(id) { _agents.delete(id); const el = document.getElementById('tile-' + id); @@ -191,5 +214,5 @@ const Grid = (() => { updateStats(); } - return { refresh, update, updateStatus, removeAgent, getAgent, fmt, fmtPct }; + return { refresh, update, updateStatus, removeAgent, rerenderAll, getAgent, fmt, fmtPct }; })(); diff --git a/dashboard/js/popups.js b/dashboard/js/popups.js index b95a21c..4305935 100644 --- a/dashboard/js/popups.js +++ b/dashboard/js/popups.js @@ -312,6 +312,11 @@ const Popups = (() => { ${cfg.font_size ?? 13}px
+
+
SEUILS D'ALERTE
@@ -372,11 +377,14 @@ const Popups = (() => { warn_disk: parseInt(document.getElementById('s-warn-disk')?.value ?? 75), retention_days: parseInt(document.getElementById('s-retention')?.value ?? 30), chart_duration_min: parseInt(document.getElementById('s-chart-dur')?.value ?? 30), + gauge_type: document.getElementById('s-gauge-type')?.value ?? 'compact', }; + const prevGaugeType = App.serverConfig?.gauge_type ?? 'compact'; await API.putServerConfig(cfg); App.serverConfig = cfg; document.documentElement.style.setProperty('--tile-min', cfg.tile_min_width + 'px'); document.body.style.fontSize = cfg.font_size + 'px'; + if (cfg.gauge_type !== prevGaugeType) Grid.rerenderAll(); hideSrvCfg(); } diff --git a/server/models/models.go b/server/models/models.go index 60463aa..857e55e 100644 --- a/server/models/models.go +++ b/server/models/models.go @@ -77,17 +77,18 @@ type MetricProto struct { } type ServerConfig struct { - TileMinWidth int `json:"tile_min_width"` - FontSize int `json:"font_size"` - WarnCPU int `json:"warn_cpu"` - ErrCPU int `json:"err_cpu"` - WarnDisk int `json:"warn_disk"` - RetentionDays int `json:"retention_days"` - ChartDurationMin int `json:"chart_duration_min"` - HideOffline bool `json:"hide_offline"` - Notifications bool `json:"notifications"` - PopupDetailW int `json:"popup_detail_w"` - PopupDetailH int `json:"popup_detail_h"` + TileMinWidth int `json:"tile_min_width"` + FontSize int `json:"font_size"` + WarnCPU int `json:"warn_cpu"` + ErrCPU int `json:"err_cpu"` + WarnDisk int `json:"warn_disk"` + RetentionDays int `json:"retention_days"` + ChartDurationMin int `json:"chart_duration_min"` + HideOffline bool `json:"hide_offline"` + Notifications bool `json:"notifications"` + PopupDetailW int `json:"popup_detail_w"` + PopupDetailH int `json:"popup_detail_h"` + GaugeType string `json:"gauge_type"` } func DefaultAgentConfig() *AgentConfig { @@ -111,6 +112,7 @@ func DefaultServerConfig() ServerConfig { RetentionDays: 30, ChartDurationMin: 30, HideOffline: false, Notifications: true, PopupDetailW: 560, PopupDetailH: 600, + GaugeType: "compact", } }