a0f47bf966
Ajoute les trois plans d'implémentation (agent Rust, serveur Go, dashboard), les consignes de design, les fichiers de brainstorming et le .gitignore. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
552 lines
43 KiB
HTML
552 lines
43 KiB
HTML
<!DOCTYPE html>
|
||
<html data-theme="dark">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Nanometrics — Layout v6 — Config agent</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Share+Tech+Mono:wght@400&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||
<script src="/helper.js"></script>
|
||
<style>
|
||
*, *::before, *::after { box-sizing:border-box; margin:0; padding:0; }
|
||
:root[data-theme="dark"] {
|
||
--accent:#fe8019; --accent-soft:#d65d0e; --accent-glow:rgba(254,128,25,0.28);
|
||
--bg-0:#1d1813; --bg-1:#2a231d; --bg-2:#32291f; --bg-3:#3c332a; --bg-4:#4a3f33; --bg-5:#57493c;
|
||
--ink-1:#f2e5c7; --ink-2:#d5c4a1; --ink-3:#a89984; --ink-4:#7c6f64;
|
||
--ok:#4dbb26; --warn:#fabd2f; --err:#fb4934; --info:#83a598; --blue:#3db0d1; --purple:#c882c8;
|
||
--border-1:rgba(255,255,255,0.06); --border-2:rgba(255,255,255,0.12); --border-3:rgba(255,255,255,0.26);
|
||
--tile-3d:0 1px 0 rgba(255,255,255,0.08) inset,0 -1px 0 rgba(0,0,0,0.3) inset,0 6px 20px rgba(0,0,0,0.5);
|
||
--tile-press:inset 0 2px 8px rgba(0,0,0,0.5),inset 0 1px 3px rgba(0,0,0,0.4);
|
||
--hover-glow:0 0 0 1px var(--accent-soft),0 0 24px var(--accent-glow),0 6px 20px rgba(0,0,0,0.5);
|
||
--font-ui:'Inter',system-ui,sans-serif; --font-mono:'JetBrains Mono',monospace; --font-terminal:'Share Tech Mono',monospace;
|
||
}
|
||
:root[data-theme="light"] {
|
||
--accent:#af3a03; --accent-soft:#d65d0e; --accent-glow:rgba(175,58,3,0.18);
|
||
--bg-0:#d5c4a1; --bg-1:#ebdbb2; --bg-2:#d5c4a1; --bg-3:#bdae93; --bg-4:#a89984; --bg-5:#928374;
|
||
--ink-1:#3c3836; --ink-2:#504945; --ink-3:#665c54; --ink-4:#7c6f64;
|
||
--ok:#3c911c; --warn:#b57614; --err:#9d0006; --blue:#2d82a3; --purple:#8c468c;
|
||
--border-1:rgba(0,0,0,0.08); --border-2:rgba(0,0,0,0.15); --border-3:rgba(0,0,0,0.3);
|
||
--tile-3d:0 1px 0 rgba(255,255,255,0.55) inset,0 -1px 0 rgba(0,0,0,0.08) inset,0 4px 14px rgba(0,0,0,0.13);
|
||
--tile-press:inset 0 2px 6px rgba(0,0,0,0.2);
|
||
--hover-glow:0 0 0 1px var(--accent-soft),0 0 18px var(--accent-glow),0 4px 14px rgba(0,0,0,0.13);
|
||
--font-ui:'Inter',system-ui,sans-serif; --font-mono:'JetBrains Mono',monospace; --font-terminal:'Share Tech Mono',monospace;
|
||
}
|
||
body { background:var(--bg-1); color:var(--ink-1); font-family:var(--font-ui); font-size:13px; height:100vh; display:flex; flex-direction:column; overflow:hidden; transition:background .2s,color .2s; }
|
||
|
||
/* TOOLTIP */
|
||
#tooltip { position:fixed; z-index:9999; pointer-events:none; background:var(--bg-0); color:var(--ink-1); border:1px solid var(--border-3); border-radius:5px; padding:4px 9px; font-size:11px; font-family:var(--font-ui); white-space:nowrap; opacity:0; transition:opacity .12s; box-shadow:0 4px 12px rgba(0,0,0,.4); }
|
||
#tooltip.show { opacity:1; }
|
||
|
||
/* HEADER */
|
||
.header { background:var(--bg-2); border-bottom:1px solid var(--border-2); padding:0 20px; height:48px; display:flex; align-items:center; gap:12px; flex-shrink:0; }
|
||
.logo { display:flex; align-items:center; gap:8px; }
|
||
.logo-led { width:9px; height:9px; border-radius:50%; background:var(--accent); box-shadow:0 0 8px var(--accent-glow); animation:blink 2s infinite; }
|
||
@keyframes blink{0%,100%{opacity:1}50%{opacity:.4}}
|
||
.logo-name { font-weight:700; font-size:14px; letter-spacing:.05em; font-family:var(--font-terminal); }
|
||
.logo-ver { font-size:10px; color:var(--ink-4); font-family:var(--font-terminal); }
|
||
.h-sep { width:1px; height:24px; background:var(--border-2); }
|
||
.h-spacer { flex:1; }
|
||
.h-stats { display:flex; gap:14px; }
|
||
.h-stat { display:flex; align-items:center; gap:5px; }
|
||
.h-stat .lbl { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.06em; }
|
||
.h-stat .val { font-family:var(--font-mono); font-weight:700; font-size:13px; }
|
||
.c-ok{color:var(--ok)}.c-warn{color:var(--warn)}.c-err{color:var(--err)}.c-n{color:var(--ink-2)}
|
||
.hbtn { width:34px; height:34px; border-radius:8px; border:1px solid var(--border-2); background:var(--bg-3); color:var(--ink-2); font-size:14px; display:flex; align-items:center; justify-content:center; cursor:pointer; user-select:none; transition:background .12s,color .12s,transform .08s,box-shadow .08s; }
|
||
.hbtn:hover { background:var(--bg-4); color:var(--accent); }
|
||
.hbtn:active { transform:translateY(1px) scale(.96); box-shadow:var(--tile-press); }
|
||
|
||
/* GRID */
|
||
.main { flex:1; padding:14px 16px; overflow-y:auto; }
|
||
.agents-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:10px; }
|
||
.tile { background:var(--bg-3); border-radius:10px; padding:12px 14px; border:1px solid var(--border-1); box-shadow:var(--tile-3d); cursor:pointer; user-select:none; display:flex; flex-direction:column; gap:9px; transition:box-shadow .15s,transform .08s,border-color .15s; }
|
||
.tile:hover { box-shadow:var(--hover-glow); border-color:var(--accent-soft); }
|
||
.tile:active { transform:translateY(2px) scale(.99); box-shadow:var(--tile-press); }
|
||
.tile.t-warn { border-color:rgba(250,189,47,.3); }
|
||
.tile.t-warn:hover { border-color:var(--warn); box-shadow:0 0 0 1px var(--warn),0 0 22px rgba(250,189,47,.22),0 6px 20px rgba(0,0,0,.5); }
|
||
.tile.t-err { border-color:rgba(251,73,52,.35); }
|
||
.tile.t-err:hover { border-color:var(--err); box-shadow:0 0 0 1px var(--err),0 0 22px rgba(251,73,52,.25),0 6px 20px rgba(0,0,0,.5); }
|
||
.tile.t-off { opacity:.5; cursor:default; }
|
||
.tile.t-off:hover,.tile.t-off:active { box-shadow:var(--tile-3d); border-color:var(--border-1); transform:none; }
|
||
.tile-head { display:flex; align-items:center; gap:8px; }
|
||
.t-icon { width:28px; height:28px; border-radius:7px; background:var(--bg-4); display:flex; align-items:center; justify-content:center; color:var(--accent); font-size:13px; flex-shrink:0; overflow:hidden; }
|
||
.t-names { flex:1; min-width:0; }
|
||
.t-host { font-weight:600; font-size:13px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||
.t-ip { font-family:var(--font-mono); font-size:10px; color:var(--ink-4); }
|
||
.t-led { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
|
||
.s-ok{background:var(--ok);box-shadow:0 0 6px var(--ok)}.s-warn{background:var(--warn);box-shadow:0 0 6px var(--warn);animation:blink 1.5s infinite}.s-err{background:var(--err);box-shadow:0 0 8px var(--err);animation:blink 1s infinite}.s-off{background:var(--ink-4)}
|
||
.tile-gauges { display:flex; flex-direction:column; gap:5px; }
|
||
.g-row { display:flex; align-items:center; gap:7px; }
|
||
.g-ico { width:18px; height:18px; display:flex; align-items:center; justify-content:center; font-size:11px; color:var(--ink-3); flex-shrink:0; cursor:help; }
|
||
.g-bar { flex:1; height:5px; border-radius:3px; background:var(--bg-1); overflow:hidden; }
|
||
.g-fill { height:100%; border-radius:3px; background:var(--ok); }
|
||
.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); width:34px; text-align:right; }
|
||
.tile-foot { font-family:var(--font-terminal); font-size:10px; color:var(--ink-4); display:flex; align-items:center; gap:5px; }
|
||
.tile-foot i { font-size:9px; }
|
||
|
||
/* FOOTER */
|
||
.footer { background:var(--bg-0); border-top:1px solid var(--border-2); height:26px; display:flex; align-items:center; font-family:var(--font-terminal); font-size:11px; color:var(--ink-4); flex-shrink:0; }
|
||
.f-mode { background:var(--accent); color:var(--bg-0); padding:0 12px; height:100%; display:flex; align-items:center; font-weight:700; letter-spacing:.04em; }
|
||
.f-cell { padding:0 12px; border-right:1px solid var(--border-1); display:flex; align-items:center; gap:5px; height:100%; }
|
||
.f-val { font-family:var(--font-mono); color:var(--ink-2); }
|
||
.f-val.w { color:var(--warn); }
|
||
.f-minibar { width:36px; height:4px; border-radius:2px; background:var(--bg-3); overflow:hidden; }
|
||
.f-minifill { height:100%; border-radius:2px; background:var(--ok); }
|
||
.f-minifill.w { background:var(--warn); }
|
||
.f-spacer { flex:1; }
|
||
.f-right { padding:0 12px; display:flex; align-items:center; gap:6px; color:var(--ink-3); }
|
||
.f-time { font-family:var(--font-mono); color:var(--ink-2); }
|
||
|
||
/* ══ OVERLAY / POPUP BASE ══ */
|
||
.overlay { position:fixed; inset:0; background:rgba(0,0,0,.65); z-index:100; display:flex; align-items:center; justify-content:center; backdrop-filter:blur(2px); }
|
||
.popup { background:var(--bg-2); border:1px solid var(--border-3); border-radius:12px; box-shadow:0 24px 64px rgba(0,0,0,.7); display:flex; flex-direction:column; overflow:hidden; }
|
||
.pop-close { width:28px; height:28px; border-radius:6px; background:var(--bg-5); color:var(--ink-3); display:flex; align-items:center; justify-content:center; cursor:pointer; font-size:12px; border:1px solid var(--border-1); transition:background .12s,color .12s,transform .08s; user-select:none; }
|
||
.pop-close:hover { background:var(--err); color:#fff; }
|
||
.pop-close:active { transform:translateY(1px) scale(.93); box-shadow:var(--tile-press); }
|
||
.sec-title { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.08em; margin-bottom:8px; }
|
||
.btn { padding:6px 14px; border-radius:8px; border:1px solid var(--border-2); background:var(--bg-4); color:var(--ink-2); font-size:12px; font-family:var(--font-ui); cursor:pointer; display:flex; align-items:center; gap:6px; user-select:none; transition:background .1s,transform .08s,box-shadow .08s; }
|
||
.btn:hover { background:var(--bg-5); }
|
||
.btn:active { transform:translateY(1px) scale(.97); box-shadow:var(--tile-press); }
|
||
.btn.primary { background:var(--accent); color:var(--bg-0); border-color:var(--accent-soft); font-weight:600; }
|
||
.btn.primary:hover { background:var(--accent-soft); }
|
||
.btn.danger { background:rgba(251,73,52,.15); color:var(--err); border-color:rgba(251,73,52,.3); }
|
||
.btn.danger:hover { background:rgba(251,73,52,.25); }
|
||
|
||
/* ══ POPUP DÉTAIL AGENT ══ */
|
||
#popup-detail { width:540px; max-width:96vw; max-height:92vh; }
|
||
.pop-head { background:var(--bg-3); padding:14px 18px; border-bottom:1px solid var(--border-2); display:flex; align-items:center; gap:12px; }
|
||
.agent-icon-wrap { position:relative; width:44px; height:44px; border-radius:10px; flex-shrink:0; cursor:pointer; overflow:hidden; background:var(--bg-4); display:flex; align-items:center; justify-content:center; color:var(--accent); font-size:18px; border:2px solid var(--border-2); transition:border-color .15s; }
|
||
.agent-icon-wrap:hover { border-color:var(--accent); }
|
||
.agent-icon-overlay { position:absolute; inset:0; background:rgba(0,0,0,.6); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px; opacity:0; transition:opacity .15s; font-size:10px; color:#fff; }
|
||
.agent-icon-overlay i { font-size:14px; }
|
||
.agent-icon-wrap:hover .agent-icon-overlay { opacity:1; }
|
||
#icon-upload { display:none; }
|
||
.pop-head-info { flex:1; }
|
||
.pop-host { font-weight:700; font-size:15px; }
|
||
.pop-ip { font-family:var(--font-mono); font-size:11px; color:var(--ink-4); }
|
||
.upload-hint { font-size:10px; color:var(--ink-4); font-family:var(--font-terminal); margin-top:2px; }
|
||
.pop-led { width:10px; height:10px; border-radius:50%; background:var(--ok); box-shadow:0 0 8px var(--ok); flex-shrink:0; }
|
||
.pop-body { padding:16px 18px; display:flex; flex-direction:column; gap:14px; overflow-y:auto; }
|
||
.kpi-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:7px; }
|
||
.kpi { background:var(--bg-3); border-radius:8px; padding:10px 12px; border:1px solid var(--border-1); box-shadow:var(--tile-3d); }
|
||
.kpi-lbl { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.06em; }
|
||
.kpi-val { font-family:var(--font-mono); font-size:20px; font-weight:700; line-height:1.1; margin-top:2px; }
|
||
.kpi-val .u { font-size:10px; color:var(--ink-3); font-weight:400; }
|
||
.kpi-sub { font-size:10px; color:var(--ink-4); font-family:var(--font-mono); margin-top:2px; }
|
||
.charts-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
|
||
.chart-card { background:var(--bg-3); border-radius:8px; padding:10px 12px; border:1px solid var(--border-1); box-shadow:var(--tile-3d); }
|
||
.chart-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
|
||
.chart-label { display:flex; align-items:center; gap:6px; font-size:10px; font-family:var(--font-terminal); letter-spacing:.06em; color:var(--ink-3); }
|
||
.chart-cur { font-family:var(--font-mono); font-size:16px; font-weight:700; }
|
||
.chart-svg { width:100%; height:52px; display:block; }
|
||
.chart-axis { display:flex; justify-content:space-between; margin-top:2px; font-family:var(--font-terminal); font-size:9px; color:var(--ink-4); }
|
||
.det-gauges { display:flex; flex-direction:column; gap:7px; }
|
||
.dg-row { display:flex; align-items:center; gap:10px; }
|
||
.dg-ico { width:22px; text-align:center; font-size:13px; cursor:help; }
|
||
.dg-bar { flex:1; height:7px; border-radius:4px; background:var(--bg-1); overflow:hidden; }
|
||
.dg-fill { height:100%; border-radius:4px; background:var(--ok); }
|
||
.dg-fill.b { background:var(--blue); }
|
||
.dg-val { font-family:var(--font-mono); font-size:12px; color:var(--ink-2); width:90px; text-align:right; }
|
||
.meta-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; }
|
||
.meta { background:var(--bg-3); border-radius:6px; padding:8px 10px; border:1px solid var(--border-1); }
|
||
.meta-lbl { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.06em; }
|
||
.meta-val { font-family:var(--font-mono); font-size:12px; color:var(--ink-2); margin-top:2px; }
|
||
|
||
/* badge protocoles dans meta */
|
||
.proto-badges { display:flex; gap:5px; margin-top:4px; flex-wrap:wrap; }
|
||
.proto-badge { display:inline-flex; align-items:center; gap:4px; padding:2px 7px; border-radius:999px; font-size:10px; font-family:var(--font-terminal); font-weight:600; }
|
||
.proto-badge.udp { background:rgba(61,176,209,.15); color:var(--blue); border:1px solid rgba(61,176,209,.3); }
|
||
.proto-badge.mqtt { background:rgba(200,130,200,.15); color:var(--purple); border:1px solid rgba(200,130,200,.3); }
|
||
|
||
/* footer popup détail — bouton config agent en bas à droite */
|
||
.pop-foot { padding:10px 18px; border-top:1px solid var(--border-2); background:var(--bg-3); display:flex; align-items:center; gap:8px; }
|
||
.pop-uptime { font-family:var(--font-terminal); font-size:11px; color:var(--ink-4); flex:1; }
|
||
/* bouton config agent — icon service */
|
||
.btn-agent-cfg {
|
||
width:34px; height:34px; border-radius:8px; border:1px solid var(--border-2);
|
||
background:var(--bg-4); color:var(--ink-3); font-size:15px;
|
||
display:flex; align-items:center; justify-content:center;
|
||
cursor:pointer; user-select:none;
|
||
transition:background .12s,color .12s,transform .08s,box-shadow .08s;
|
||
}
|
||
.btn-agent-cfg:hover { background:var(--bg-5); color:var(--accent); }
|
||
.btn-agent-cfg:active { transform:translateY(1px) scale(.93); box-shadow:var(--tile-press); }
|
||
|
||
/* ══ POPUP CONFIG AGENT ══ */
|
||
#popup-agentcfg { width:480px; max-width:96vw; max-height:90vh; z-index:200; }
|
||
.cfg-head { background:var(--bg-3); padding:14px 18px; border-bottom:1px solid var(--border-2); display:flex; align-items:center; gap:10px; }
|
||
.cfg-head-icon { width:32px; height:32px; border-radius:8px; background:var(--bg-4); display:flex; align-items:center; justify-content:center; color:var(--accent); font-size:15px; }
|
||
.cfg-head-info { flex:1; }
|
||
.cfg-head-title { font-weight:700; font-size:14px; }
|
||
.cfg-head-sub { font-size:11px; color:var(--ink-4); font-family:var(--font-terminal); }
|
||
.cfg-body { padding:18px; display:flex; flex-direction:column; gap:18px; overflow-y:auto; max-height:60vh; }
|
||
.cfg-section { display:flex; flex-direction:column; gap:10px; }
|
||
.cfg-sec-title { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.08em; padding-bottom:6px; border-bottom:1px solid var(--border-1); }
|
||
|
||
/* checkboxes custom */
|
||
.check-row { display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:8px; background:var(--bg-3); border:1px solid var(--border-1); cursor:pointer; transition:background .12s,border-color .12s; }
|
||
.check-row:hover { background:var(--bg-4); border-color:var(--border-2); }
|
||
.check-row.active { border-color:var(--accent-soft); background:rgba(254,128,25,.08); }
|
||
.check-row.mqtt-active { border-color:rgba(200,130,200,.4); background:rgba(200,130,200,.07); }
|
||
.chk-box { width:18px; height:18px; border-radius:4px; border:2px solid var(--border-3); background:var(--bg-1); display:flex; align-items:center; justify-content:center; font-size:11px; color:var(--accent); flex-shrink:0; transition:background .12s,border-color .12s; }
|
||
.check-row.active .chk-box { background:var(--accent); border-color:var(--accent); color:var(--bg-0); }
|
||
.check-row.mqtt-active .chk-box { background:var(--purple); border-color:var(--purple); color:var(--bg-0); }
|
||
.chk-label { flex:1; }
|
||
.chk-name { font-weight:600; font-size:13px; }
|
||
.chk-desc { font-size:11px; color:var(--ink-4); font-family:var(--font-terminal); margin-top:1px; }
|
||
.chk-badge { font-size:10px; font-family:var(--font-terminal); font-weight:700; padding:1px 7px; border-radius:999px; }
|
||
.chk-badge.udp { background:rgba(61,176,209,.15); color:var(--blue); }
|
||
.chk-badge.mqtt { background:rgba(200,130,200,.15); color:var(--purple); }
|
||
|
||
/* MQTT sub-options */
|
||
.mqtt-opts { background:var(--bg-3); border-radius:8px; border:1px solid rgba(200,130,200,.2); padding:12px 14px; display:flex; flex-direction:column; gap:10px; }
|
||
.mqtt-field { display:flex; align-items:center; gap:10px; }
|
||
.mqtt-field label { font-size:11px; color:var(--ink-3); font-family:var(--font-terminal); width:90px; flex-shrink:0; }
|
||
.mqtt-input { flex:1; background:var(--bg-1); border:1px solid var(--border-2); border-radius:6px; color:var(--ink-1); padding:6px 10px; font-size:12px; font-family:var(--font-mono); }
|
||
.mqtt-input:focus { outline:none; border-color:var(--purple); }
|
||
.mqtt-check-row { display:flex; align-items:center; justify-content:space-between; padding:4px 0; }
|
||
.mqtt-check-row label { font-size:12px; color:var(--ink-2); display:flex; align-items:center; gap:7px; cursor:pointer; }
|
||
.mqtt-check-row label i { color:var(--purple); font-size:11px; }
|
||
/* toggle switch */
|
||
.toggle { position:relative; width:34px; height:18px; flex-shrink:0; }
|
||
.toggle input { opacity:0; width:0; height:0; }
|
||
.toggle-slider { position:absolute; inset:0; border-radius:9px; background:var(--bg-4); border:1px solid var(--border-2); cursor:pointer; transition:background .2s; }
|
||
.toggle-slider::before { content:''; position:absolute; width:12px; height:12px; border-radius:50%; background:var(--ink-4); top:2px; left:2px; transition:transform .2s, background .2s; }
|
||
.toggle input:checked + .toggle-slider { background:rgba(200,130,200,.3); border-color:var(--purple); }
|
||
.toggle input:checked + .toggle-slider::before { transform:translateX(16px); background:var(--purple); }
|
||
|
||
/* Métriques toggles */
|
||
.metrics-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; }
|
||
.metric-row { display:flex; align-items:center; gap:8px; padding:7px 10px; border-radius:7px; background:var(--bg-3); border:1px solid var(--border-1); }
|
||
.metric-ico { width:22px; text-align:center; font-size:12px; color:var(--ink-3); }
|
||
.metric-name { flex:1; font-size:12px; color:var(--ink-2); font-family:var(--font-terminal); }
|
||
.tog-ok { }
|
||
.tog-ok input:checked + .toggle-slider { background:rgba(77,187,38,.3); border-color:var(--ok); }
|
||
.tog-ok input:checked + .toggle-slider::before { background:var(--ok); }
|
||
|
||
/* Commandes futures */
|
||
.cmds-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:6px; }
|
||
.cmd-btn { display:flex; flex-direction:column; align-items:center; gap:4px; padding:10px 8px; border-radius:8px; background:var(--bg-3); border:1px solid var(--border-1); cursor:not-allowed; opacity:.45; }
|
||
.cmd-btn i { font-size:16px; color:var(--ink-3); }
|
||
.cmd-btn span { font-size:10px; color:var(--ink-4); font-family:var(--font-terminal); }
|
||
.cmd-btn.enabled { cursor:pointer; opacity:1; }
|
||
.cmd-btn.enabled:hover { background:var(--bg-4); border-color:var(--border-2); }
|
||
.cmd-btn.enabled:hover i { color:var(--accent); }
|
||
.cmd-btn.danger-cmd { }
|
||
.cmd-btn.danger-cmd.enabled:hover { background:rgba(251,73,52,.12); border-color:rgba(251,73,52,.3); }
|
||
.cmd-btn.danger-cmd.enabled:hover i { color:var(--err); }
|
||
.soon-tag { font-size:8px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.04em; }
|
||
|
||
/* cfg footer */
|
||
.cfg-foot { padding:12px 18px; border-top:1px solid var(--border-2); background:var(--bg-3); display:flex; align-items:center; gap:8px; }
|
||
.cfg-status { flex:1; display:flex; align-items:center; gap:6px; font-family:var(--font-terminal); font-size:11px; color:var(--ink-4); }
|
||
.cfg-status .dot { width:6px; height:6px; border-radius:50%; background:var(--ok); }
|
||
|
||
::-webkit-scrollbar{width:5px}::-webkit-scrollbar-track{background:var(--bg-1)}::-webkit-scrollbar-thumb{background:var(--bg-4);border-radius:3px}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="tooltip"></div>
|
||
|
||
<!-- HEADER -->
|
||
<div class="header">
|
||
<div class="logo"><div class="logo-led"></div><span class="logo-name">NANOMETRICS</span><span class="logo-ver">v1.0</span></div>
|
||
<div class="h-sep"></div>
|
||
<div class="h-stats">
|
||
<div class="h-stat"><span class="lbl">AGENTS</span><span class="val c-n">8</span></div>
|
||
<div class="h-stat"><span class="lbl">OK</span><span class="val c-ok">5</span></div>
|
||
<div class="h-stat"><span class="lbl">WARN</span><span class="val c-warn">2</span></div>
|
||
<div class="h-stat"><span class="lbl">ERR</span><span class="val c-err">1</span></div>
|
||
</div>
|
||
<div class="h-spacer"></div>
|
||
<div class="hbtn" onclick="toggleTheme()" data-tip="Thème clair / sombre"><i class="fa-solid fa-moon" id="theme-icon"></i></div>
|
||
<div class="hbtn" data-tip="Configuration interface"><i class="fa-solid fa-sliders"></i></div>
|
||
</div>
|
||
|
||
<!-- GRID -->
|
||
<div class="main">
|
||
<div class="agents-grid">
|
||
<div class="tile" onclick="showDetail()">
|
||
<div class="tile-head"><div class="t-icon"><i class="fa-solid fa-server"></i></div><div class="t-names"><div class="t-host">srv-prod-01</div><div class="t-ip">10.0.0.11</div></div><div class="t-led s-ok"></div></div>
|
||
<div class="tile-gauges">
|
||
<div class="g-row"><div class="g-ico" data-tip="Processeur (CPU)"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"><div class="g-fill" style="width:42%"></div></div><span class="g-val">42%</span></div>
|
||
<div class="g-row"><div class="g-ico" data-tip="Mémoire RAM"><i class="fa-solid fa-memory"></i></div><div class="g-bar"><div class="g-fill" style="width:58%"></div></div><span class="g-val">58%</span></div>
|
||
<div class="g-row"><div class="g-ico" data-tip="Espace disque"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"><div class="g-fill" style="width:31%"></div></div><span class="g-val">31%</span></div>
|
||
</div>
|
||
<div class="tile-foot"><i class="fa-solid fa-clock"></i>14j 6h</div>
|
||
</div>
|
||
<div class="tile t-warn">
|
||
<div class="tile-head"><div class="t-icon"><i class="fa-solid fa-server"></i></div><div class="t-names"><div class="t-host">srv-backup-02</div><div class="t-ip">10.0.0.12</div></div><div class="t-led s-warn"></div></div>
|
||
<div class="tile-gauges">
|
||
<div class="g-row"><div class="g-ico" data-tip="CPU — élevé" style="color:var(--warn)"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"><div class="g-fill w" style="width:78%"></div></div><span class="g-val" style="color:var(--warn)">78%</span></div>
|
||
<div class="g-row"><div class="g-ico" data-tip="RAM — élevée" style="color:var(--warn)"><i class="fa-solid fa-memory"></i></div><div class="g-bar"><div class="g-fill w" style="width:72%"></div></div><span class="g-val" style="color:var(--warn)">72%</span></div>
|
||
<div class="g-row"><div class="g-ico" data-tip="Espace disque"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"><div class="g-fill" style="width:20%"></div></div><span class="g-val">20%</span></div>
|
||
</div>
|
||
<div class="tile-foot"><i class="fa-solid fa-clock"></i>3j 14h</div>
|
||
</div>
|
||
<div class="tile t-err">
|
||
<div class="tile-head"><div class="t-icon" style="color:var(--err)"><i class="fa-solid fa-microchip"></i></div><div class="t-names"><div class="t-host">rpi-sensor-03</div><div class="t-ip">10.0.0.23</div></div><div class="t-led s-err"></div></div>
|
||
<div class="tile-gauges">
|
||
<div class="g-row"><div class="g-ico" data-tip="CPU"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"><div class="g-fill" style="width:12%"></div></div><span class="g-val">12%</span></div>
|
||
<div class="g-row"><div class="g-ico" data-tip="RAM"><i class="fa-solid fa-memory"></i></div><div class="g-bar"><div class="g-fill" style="width:38%"></div></div><span class="g-val">38%</span></div>
|
||
<div class="g-row"><div class="g-ico" data-tip="Disque critique !" style="color:var(--err)"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"><div class="g-fill e" style="width:94%"></div></div><span class="g-val" style="color:var(--err)">94%</span></div>
|
||
</div>
|
||
<div class="tile-foot"><i class="fa-solid fa-clock"></i>62j 1h</div>
|
||
</div>
|
||
<div class="tile"><div class="tile-head"><div class="t-icon"><i class="fa-solid fa-hard-drive"></i></div><div class="t-names"><div class="t-host">nas-storage-04</div><div class="t-ip">10.0.0.30</div></div><div class="t-led s-ok"></div></div><div class="tile-gauges"><div class="g-row"><div class="g-ico" data-tip="CPU"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"><div class="g-fill" style="width:8%"></div></div><span class="g-val">8%</span></div><div class="g-row"><div class="g-ico" data-tip="RAM"><i class="fa-solid fa-memory"></i></div><div class="g-bar"><div class="g-fill" style="width:45%"></div></div><span class="g-val">45%</span></div><div class="g-row"><div class="g-ico" data-tip="Disque"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"><div class="g-fill" style="width:66%"></div></div><span class="g-val">66%</span></div></div><div class="tile-foot"><i class="fa-solid fa-clock"></i>128j 3h</div></div>
|
||
<div class="tile"><div class="tile-head"><div class="t-icon"><i class="fa-solid fa-database"></i></div><div class="t-names"><div class="t-host">db-primary-05</div><div class="t-ip">10.0.0.40</div></div><div class="t-led s-ok"></div></div><div class="tile-gauges"><div class="g-row"><div class="g-ico" data-tip="CPU"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"><div class="g-fill" style="width:25%"></div></div><span class="g-val">25%</span></div><div class="g-row"><div class="g-ico" data-tip="RAM"><i class="fa-solid fa-memory"></i></div><div class="g-bar"><div class="g-fill" style="width:61%"></div></div><span class="g-val">61%</span></div><div class="g-row"><div class="g-ico" data-tip="Disque"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"><div class="g-fill" style="width:48%"></div></div><span class="g-val">48%</span></div></div><div class="tile-foot"><i class="fa-solid fa-clock"></i>7j 22h</div></div>
|
||
<div class="tile t-off"><div class="tile-head"><div class="t-icon" style="color:var(--ink-4)"><i class="fa-solid fa-server"></i></div><div class="t-names"><div class="t-host">srv-dev-07</div><div class="t-ip">10.0.0.60</div></div><div class="t-led s-off"></div></div><div class="tile-gauges"><div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"></div><span class="g-val" style="color:var(--ink-4)">—</span></div><div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i></div><div class="g-bar"></div><span class="g-val" style="color:var(--ink-4)">—</span></div><div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"></div><span class="g-val" style="color:var(--ink-4)">—</span></div></div><div class="tile-foot" style="color:var(--err)"><i class="fa-solid fa-circle-xmark"></i>Hors ligne · vu il y a 2h</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- FOOTER -->
|
||
<div class="footer">
|
||
<div class="f-mode">LIVE</div>
|
||
<div class="f-cell"><i class="fa-solid fa-server" style="font-size:10px"></i><span>SERVEUR</span></div>
|
||
<div class="f-cell"><i class="fa-solid fa-microchip" style="font-size:10px"></i><span class="f-val">18%</span><div class="f-minibar"><div class="f-minifill" style="width:18%"></div></div></div>
|
||
<div class="f-cell"><i class="fa-solid fa-memory" style="font-size:10px"></i><span class="f-val w">71%</span><div class="f-minibar"><div class="f-minifill w" style="width:71%"></div></div></div>
|
||
<div class="f-spacer"></div>
|
||
<div class="f-right"><i class="fa-solid fa-rotate"></i><span>Actualisation : <span class="f-time">22:14:07</span></span></div>
|
||
</div>
|
||
|
||
<!-- ══ POPUP DÉTAIL AGENT ══ -->
|
||
<div class="overlay" id="overlay-detail" style="display:flex" onclick="if(event.target===this)this.style.display='none'">
|
||
<div class="popup" id="popup-detail" onclick="event.stopPropagation()">
|
||
<div class="pop-head">
|
||
<div class="agent-icon-wrap" onclick="document.getElementById('icon-upload').click()" data-tip="Changer l'icône">
|
||
<i class="fa-solid fa-server"></i>
|
||
<div class="agent-icon-overlay"><i class="fa-solid fa-camera"></i><span>Changer</span></div>
|
||
</div>
|
||
<input type="file" id="icon-upload" accept=".svg,.jpg,.jpeg,.png,.webp">
|
||
<div class="pop-head-info">
|
||
<div class="pop-host">srv-prod-01</div>
|
||
<div class="pop-ip">10.0.0.11</div>
|
||
<div class="upload-hint">Cliquer sur l'icône pour personnaliser · SVG JPG PNG WEBP · max 128×128 px</div>
|
||
</div>
|
||
<div class="pop-led"></div>
|
||
<div class="pop-close" onclick="document.getElementById('overlay-detail').style.display='none'" data-tip="Fermer"><i class="fa-solid fa-xmark"></i></div>
|
||
</div>
|
||
|
||
<div class="pop-body">
|
||
<div>
|
||
<div class="sec-title">MÉTRIQUES ACTUELLES</div>
|
||
<div class="kpi-grid">
|
||
<div class="kpi"><div class="kpi-lbl">CPU</div><div class="kpi-val c-ok">42<span class="u">%</span></div><div class="kpi-sub">4 cœurs</div></div>
|
||
<div class="kpi"><div class="kpi-lbl">MÉMOIRE</div><div class="kpi-val">3.7<span class="u">Go</span></div><div class="kpi-sub">/ 8 Go · 46%</div></div>
|
||
<div class="kpi"><div class="kpi-lbl">DISQUE</div><div class="kpi-val">62<span class="u">Go</span></div><div class="kpi-sub">/ 200 Go · 31%</div></div>
|
||
<div class="kpi"><div class="kpi-lbl">UPTIME</div><div class="kpi-val" style="font-size:15px;color:var(--ink-1)">14j 6h</div><div class="kpi-sub">depuis boot</div></div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="sec-title">HISTORIQUE — 30 DERNIÈRES MINUTES</div>
|
||
<div class="charts-grid">
|
||
<div class="chart-card">
|
||
<div class="chart-header"><div class="chart-label" style="color:var(--accent)"><i class="fa-solid fa-microchip"></i>CPU</div><span class="chart-cur c-ok">42%</span></div>
|
||
<svg class="chart-svg" viewBox="0 0 200 52" preserveAspectRatio="none" id="cpu-chart"></svg>
|
||
<div class="chart-axis"><span>−30min</span><span>−15min</span><span>now</span></div>
|
||
</div>
|
||
<div class="chart-card">
|
||
<div class="chart-header"><div class="chart-label" style="color:var(--blue)"><i class="fa-solid fa-memory"></i>RAM</div><span class="chart-cur" style="color:var(--blue)">46%</span></div>
|
||
<svg class="chart-svg" viewBox="0 0 200 52" preserveAspectRatio="none" id="ram-chart"></svg>
|
||
<div class="chart-axis"><span>−30min</span><span>−15min</span><span>now</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="sec-title">STOCKAGE</div>
|
||
<div class="det-gauges">
|
||
<div class="dg-row"><div class="dg-ico" data-tip="Utilisé"><i class="fa-solid fa-hard-drive"></i></div><div class="dg-bar"><div class="dg-fill" style="width:31%"></div></div><span class="dg-val">62 / 200 Go</span></div>
|
||
<div class="dg-row"><div class="dg-ico" data-tip="Libre" style="color:var(--blue)"><i class="fa-solid fa-floppy-disk"></i></div><div class="dg-bar"><div class="dg-fill b" style="width:69%"></div></div><span class="dg-val">138 Go libre</span></div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="sec-title">INFORMATIONS</div>
|
||
<div class="meta-grid">
|
||
<div class="meta"><div class="meta-lbl">HOSTNAME</div><div class="meta-val">srv-prod-01</div></div>
|
||
<div class="meta"><div class="meta-lbl">ADRESSE IP</div><div class="meta-val">10.0.0.11</div></div>
|
||
<div class="meta"><div class="meta-lbl">PROTOCOLES ACTIFS</div>
|
||
<div class="proto-badges">
|
||
<span class="proto-badge udp"><i class="fa-solid fa-arrow-up"></i>UDP</span>
|
||
<span class="proto-badge mqtt"><i class="fa-brands fa-mqtt" style="font-family:var(--font-terminal)">M</i>MQTT</span>
|
||
</div>
|
||
</div>
|
||
<div class="meta"><div class="meta-lbl">DERNIER CONTACT</div><div class="meta-val">22:14:07</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- footer — bouton config agent en bas à droite -->
|
||
<div class="pop-foot">
|
||
<span class="pop-uptime"><i class="fa-solid fa-clock" style="margin-right:4px"></i>En ligne depuis 14 jours 6 heures</span>
|
||
<button class="btn"><i class="fa-solid fa-chart-line"></i> Historique</button>
|
||
<div class="btn-agent-cfg" onclick="showAgentCfg()" data-tip="Configurer l'agent">
|
||
<i class="fa-solid fa-gears"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══ POPUP CONFIG AGENT ══ -->
|
||
<div class="overlay" id="overlay-agentcfg" style="display:none;z-index:200" onclick="if(event.target===this)this.style.display='none'">
|
||
<div class="popup" id="popup-agentcfg" onclick="event.stopPropagation()">
|
||
|
||
<div class="cfg-head">
|
||
<div class="cfg-head-icon"><i class="fa-solid fa-gears"></i></div>
|
||
<div class="cfg-head-info">
|
||
<div class="cfg-head-title">Configuration de l'agent</div>
|
||
<div class="cfg-head-sub">srv-prod-01 · 10.0.0.11 · config récupérée à 22:14:05</div>
|
||
</div>
|
||
<div class="pop-close" onclick="document.getElementById('overlay-agentcfg').style.display='none'" data-tip="Fermer"><i class="fa-solid fa-xmark"></i></div>
|
||
</div>
|
||
|
||
<div class="cfg-body">
|
||
|
||
<!-- PROTOCOLES -->
|
||
<div class="cfg-section">
|
||
<div class="cfg-sec-title">PROTOCOLES DE TRANSPORT</div>
|
||
|
||
<!-- UDP -->
|
||
<div class="check-row active" id="row-udp" onclick="toggleProto('udp')">
|
||
<div class="chk-box" id="chk-udp"><i class="fa-solid fa-check"></i></div>
|
||
<div class="chk-label">
|
||
<div class="chk-name">UDP <span class="chk-badge udp">UDP</span></div>
|
||
<div class="chk-desc">Fire-and-forget · serveur 10.0.0.50 · port 9999</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MQTT -->
|
||
<div class="check-row mqtt-active" id="row-mqtt" onclick="toggleProto('mqtt')">
|
||
<div class="chk-box" id="chk-mqtt" style="background:var(--purple);border-color:var(--purple);color:var(--bg-0)"><i class="fa-solid fa-check"></i></div>
|
||
<div class="chk-label">
|
||
<div class="chk-name">MQTT <span class="chk-badge mqtt">MQTT</span></div>
|
||
<div class="chk-desc">Bidirectionnel · broker 10.0.0.3 · port 1883</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MQTT sub-options -->
|
||
<div class="mqtt-opts" id="mqtt-opts">
|
||
<div class="mqtt-field">
|
||
<label>Broker</label>
|
||
<input class="mqtt-input" type="text" value="10.0.0.3">
|
||
</div>
|
||
<div class="mqtt-field">
|
||
<label>Port</label>
|
||
<input class="mqtt-input" type="number" value="1883" style="width:90px;flex:none">
|
||
</div>
|
||
<div class="mqtt-field">
|
||
<label>Topic base</label>
|
||
<input class="mqtt-input" type="text" value="nanometrics/agents">
|
||
</div>
|
||
<div style="border-top:1px solid var(--border-1);padding-top:8px;display:flex;flex-direction:column;gap:6px;">
|
||
<div class="mqtt-check-row">
|
||
<label><i class="fa-solid fa-satellite-dish"></i> Auto-discovery (Home Assistant)</label>
|
||
<label class="toggle"><input type="checkbox" checked><span class="toggle-slider"></span></label>
|
||
</div>
|
||
<div class="mqtt-check-row">
|
||
<label><i class="fa-solid fa-arrow-right-to-bracket"></i> Birth message (connexion)</label>
|
||
<label class="toggle"><input type="checkbox" checked><span class="toggle-slider"></span></label>
|
||
</div>
|
||
<div class="mqtt-check-row">
|
||
<label><i class="fa-solid fa-skull"></i> Last Will message (déconnexion)</label>
|
||
<label class="toggle"><input type="checkbox" checked><span class="toggle-slider"></span></label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MÉTRIQUES -->
|
||
<div class="cfg-section">
|
||
<div class="cfg-sec-title">MÉTRIQUES ACTIVES</div>
|
||
<div class="metrics-grid">
|
||
<div class="metric-row"><div class="metric-ico"><i class="fa-solid fa-microchip"></i></div><span class="metric-name">cpu</span><label class="toggle tog-ok"><input type="checkbox" checked><span class="toggle-slider"></span></label></div>
|
||
<div class="metric-row"><div class="metric-ico"><i class="fa-solid fa-memory"></i></div><span class="metric-name">memory</span><label class="toggle tog-ok"><input type="checkbox" checked><span class="toggle-slider"></span></label></div>
|
||
<div class="metric-row"><div class="metric-ico"><i class="fa-solid fa-hard-drive"></i></div><span class="metric-name">disk</span><label class="toggle tog-ok"><input type="checkbox" checked><span class="toggle-slider"></span></label></div>
|
||
<div class="metric-row"><div class="metric-ico"><i class="fa-solid fa-network-wired"></i></div><span class="metric-name">network</span><label class="toggle tog-ok"><input type="checkbox"><span class="toggle-slider"></span></label></div>
|
||
<div class="metric-row"><div class="metric-ico"><i class="fa-solid fa-clock"></i></div><span class="metric-name">uptime</span><label class="toggle tog-ok"><input type="checkbox" checked><span class="toggle-slider"></span></label></div>
|
||
<div class="metric-row"><div class="metric-ico"><i class="fa-solid fa-thermometer-half"></i></div><span class="metric-name">temperature</span><label class="toggle tog-ok"><input type="checkbox"><span class="toggle-slider"></span></label></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- COMMANDES -->
|
||
<div class="cfg-section">
|
||
<div class="cfg-sec-title">COMMANDES DISTANTES <span style="color:var(--ink-4);font-size:8px;margin-left:6px">— BIENTÔT DISPONIBLE</span></div>
|
||
<div class="cmds-grid">
|
||
<div class="cmd-btn"><i class="fa-solid fa-rotate-right"></i><span>reboot</span><span class="soon-tag">bientôt</span></div>
|
||
<div class="cmd-btn"><i class="fa-solid fa-power-off"></i><span>shutdown</span><span class="soon-tag">bientôt</span></div>
|
||
<div class="cmd-btn"><i class="fa-solid fa-display"></i><span>screen off</span><span class="soon-tag">bientôt</span></div>
|
||
<div class="cmd-btn"><i class="fa-solid fa-arrow-up-from-bracket"></i><span>update</span><span class="soon-tag">bientôt</span></div>
|
||
<div class="cmd-btn"><i class="fa-solid fa-arrow-up-right-dots"></i><span>upgrade</span><span class="soon-tag">bientôt</span></div>
|
||
<div class="cmd-btn"><i class="fa-solid fa-terminal"></i><span>shell cmd</span><span class="soon-tag">bientôt</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="cfg-foot">
|
||
<div class="cfg-status">
|
||
<div class="dot"></div>
|
||
<span>Config synchronisée avec l'agent</span>
|
||
</div>
|
||
<button class="btn" onclick="document.getElementById('overlay-agentcfg').style.display='none'">Annuler</button>
|
||
<button class="btn primary"><i class="fa-solid fa-paper-plane"></i> Envoyer à l'agent</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
/* tooltip */
|
||
const tip=document.getElementById('tooltip');let tt;
|
||
document.addEventListener('mouseover',e=>{const el=e.target.closest('[data-tip]');if(!el)return;clearTimeout(tt);tt=setTimeout(()=>{tip.textContent=el.dataset.tip;tip.classList.add('show');mv(e);},120);});
|
||
document.addEventListener('mousemove',e=>{if(tip.classList.contains('show'))mv(e);});
|
||
document.addEventListener('mouseout',e=>{const el=e.target.closest('[data-tip]');if(!el)return;clearTimeout(tt);tip.classList.remove('show');});
|
||
function mv(e){const w=tip.offsetWidth,h=tip.offsetHeight;let x=e.clientX-w/2,y=e.clientY-h-10;x=Math.max(6,Math.min(x,window.innerWidth-w-6));if(y<6)y=e.clientY+18;tip.style.left=x+'px';tip.style.top=y+'px';}
|
||
|
||
/* thème */
|
||
function toggleTheme(){const h=document.documentElement;h.dataset.theme=h.dataset.theme==='dark'?'light':'dark';document.getElementById('theme-icon').className=h.dataset.theme==='dark'?'fa-solid fa-moon':'fa-solid fa-sun';drawCharts();}
|
||
|
||
/* proto toggle */
|
||
function toggleProto(p){
|
||
const row=document.getElementById('row-'+p);
|
||
const chk=document.getElementById('chk-'+p);
|
||
const active=row.classList.contains('active')||row.classList.contains('mqtt-active');
|
||
if(p==='udp'){row.classList.toggle('active',!active);chk.innerHTML=active?'':'';}
|
||
if(p==='mqtt'){
|
||
row.classList.toggle('mqtt-active',!active);
|
||
chk.innerHTML=active?'':'<i class="fa-solid fa-check"></i>';
|
||
if(!active){chk.style.cssText='background:var(--purple);border-color:var(--purple);color:var(--bg-0)';}
|
||
else{chk.style.cssText='background:var(--bg-1);border-color:var(--border-3);color:var(--accent)';}
|
||
document.getElementById('mqtt-opts').style.display=active?'none':'flex';
|
||
}
|
||
}
|
||
|
||
/* popups */
|
||
function showDetail(){document.getElementById('overlay-detail').style.display='flex';drawCharts();}
|
||
function showAgentCfg(){document.getElementById('overlay-agentcfg').style.display='flex';}
|
||
|
||
/* courbes */
|
||
function makeCurve(pts,stroke,fill,w,h){
|
||
const xs=pts.map((_,i)=>(i/(pts.length-1))*w);
|
||
const ys=pts.map(v=>h-(v/100)*(h-6)-3);
|
||
const wy=h-(70/100)*(h-6)-3;
|
||
let d=`M${xs[0]} ${ys[0]}`;
|
||
for(let i=1;i<pts.length;i++){const cx=(xs[i-1]+xs[i])/2;d+=` C${cx} ${ys[i-1]},${cx} ${ys[i]},${xs[i]} ${ys[i]}`;}
|
||
const uid=Math.random().toString(36).slice(2);
|
||
return `<defs><linearGradient id="g${uid}" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="${fill}" stop-opacity=".4"/><stop offset="100%" stop-color="${fill}" stop-opacity=".02"/></linearGradient></defs>
|
||
<line x1="0" y1="${wy}" x2="${w}" y2="${wy}" stroke="var(--warn)" stroke-width=".8" stroke-dasharray="3,3" opacity=".5"/>
|
||
<path d="${d} L${xs.at(-1)} ${h} L${xs[0]} ${h}Z" fill="url(#g${uid})"/>
|
||
<path d="${d}" fill="none" stroke="${stroke}" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
||
<circle cx="${xs.at(-1)}" cy="${ys.at(-1)}" r="2.5" fill="${stroke}"/>`;
|
||
}
|
||
function drawCharts(){
|
||
const cpu=[38,41,35,40,44,42,39,45,50,48,43,42,44,41,40,43,47,45,42,44,41,43,42,40,43,41,44,43,41,42];
|
||
const ram=[44,44,45,45,46,46,47,47,46,46,45,46,46,47,47,46,46,45,46,46,46,46,46,46,46,46,46,46,46,46];
|
||
const cs=getComputedStyle(document.documentElement);
|
||
const ac=cs.getPropertyValue('--accent').trim(),bl=cs.getPropertyValue('--blue').trim();
|
||
document.getElementById('cpu-chart').innerHTML=makeCurve(cpu,ac,ac,200,52);
|
||
document.getElementById('ram-chart').innerHTML=makeCurve(ram,bl,bl,200,52);
|
||
}
|
||
window.addEventListener('load',()=>{drawCharts();});
|
||
</script>
|
||
</body>
|
||
</html>
|