@enigmax/dashboard 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/assets/index.html +35 -15
  2. package/package.json +1 -1
package/assets/index.html CHANGED
@@ -13,7 +13,7 @@
13
13
  body {
14
14
  margin: 0; background: var(--bg); color: var(--text);
15
15
  font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
16
- -webkit-font-smoothing: antialiased; padding: 24px; max-width: 1040px; margin: 0 auto;
16
+ -webkit-font-smoothing: antialiased; padding: 24px; max-width: 2200px; margin: 0 auto;
17
17
  }
18
18
  a { color: var(--accent2); }
19
19
  header { display: flex; align-items: center; gap: 20px; margin-bottom: 24px; flex-wrap: wrap; }
@@ -108,6 +108,10 @@
108
108
  border-radius: 7px; padding: 5px 10px; font-size: 12px; font-family: inherit; cursor: pointer;
109
109
  }
110
110
  .set-note { color: var(--accent); font-size: 12px; min-height: 16px; margin-top: 10px; }
111
+ /* Settings: two-column grid of rows on wide screens, so a long config list stays compact. */
112
+ .set-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 0 32px; }
113
+ .set-grid .set-row { padding: 10px 0; }
114
+ .panel > .set-cat-h { margin-top: 0; }
111
115
  .tag {
112
116
  display: inline-block; font-size: 11px; color: var(--muted); background: var(--surface2);
113
117
  border: 1px solid var(--border); border-radius: 6px; padding: 1px 7px; margin-left: 6px; vertical-align: middle;
@@ -175,7 +179,10 @@
175
179
  <div class="panel">
176
180
  <div class="panel-head">
177
181
  <h2>Enigma Systems <small>what's active - configuration, not savings</small></h2>
178
- <div class="ctrls"><button id="updateBtn" type="button" class="toggle on">Check &amp; update</button></div>
182
+ <div class="ctrls">
183
+ <button id="refreshBtn" type="button" class="toggle">Refresh</button>
184
+ <button id="updateBtn" type="button" class="toggle on">Check &amp; update</button>
185
+ </div>
179
186
  </div>
180
187
  <div class="sub" style="margin-bottom:14px">Only Context Compression and (opt-in) real tool-usage are measured for savings below. The rest is shown as state: enigma can't measure their effect because they run inside the agent, not through enigma - so it reports their configuration honestly instead of inventing a number.</div>
181
188
  <div id="systems" class="sys-grid"><div class="empty" style="padding:16px 0">Loading...</div></div>
@@ -293,11 +300,9 @@
293
300
  <div class="page-head">
294
301
  <h1>Settings</h1>
295
302
  <p>Everything you can configure with <code>enigma config</code> or the terminal UI, editable here. Changes apply at global scope and take effect immediately; toggles that change agent memory need an agent restart.</p>
296
- </div>
297
- <div class="panel">
298
- <div id="settingsBody"><div class="empty" style="padding:24px 0">Loading settings...</div></div>
299
303
  <div id="settingsNote" class="set-note"></div>
300
304
  </div>
305
+ <div id="settingsBody"><div class="empty" style="padding:24px 0">Loading settings...</div></div>
301
306
  </section>
302
307
 
303
308
  <footer>
@@ -644,9 +649,14 @@
644
649
  $("updated").textContent = "Updated " + new Date(data.generatedAt || Date.now()).toLocaleTimeString();
645
650
  }
646
651
 
647
- async function poll() {
648
- // Headroom pattern: never hit the server while the tab is hidden.
652
+ // Auto-refresh is on by default while the tab is focused; `live` mirrors the
653
+ // dashboard-live config (read from /api/status). A forced refresh (button / view
654
+ // change) always runs so the user can refresh even with auto-refresh off.
655
+ let live = true;
656
+ async function poll(force) {
657
+ // Never hit the server while the tab is hidden, or when auto-refresh is off (unless forced).
649
658
  if (document.hidden) return;
659
+ if (!live && !force) return;
650
660
  try {
651
661
  const res = await fetch("/api/stats", { cache: "no-store" });
652
662
  render(await res.json());
@@ -674,9 +684,11 @@
674
684
  function renderSettings(cats) {
675
685
  const el = $("settingsBody");
676
686
  if (!cats.length) { el.innerHTML = '<div class="empty" style="padding:24px 0">No settings available.</div>'; return; }
677
- el.innerHTML = cats.map((c) => '<div class="set-cat"><div class="set-cat-h">' + esc(c.title) + "</div>"
687
+ // One panel per category; settings laid out in a responsive 2-column grid so a
688
+ // long config list stays scannable on a wide screen.
689
+ el.innerHTML = cats.map((c) => '<div class="panel"><div class="set-cat-h">' + esc(c.title) + "</div>"
678
690
  + (c.blurb ? '<div class="set-cat-b">' + esc(c.blurb) + "</div>" : "")
679
- + c.settings.map(settingRow).join("") + "</div>").join("");
691
+ + '<div class="set-grid">' + c.settings.map(settingRow).join("") + "</div></div>").join("");
680
692
  }
681
693
 
682
694
  async function postSetting(key, value, ctl) {
@@ -759,13 +771,20 @@
759
771
  } catch { $("updateNote").textContent = "Could not reach the server to update."; }
760
772
  }
761
773
 
762
- async function loadSystems() {
774
+ async function loadSystems(force) {
775
+ if (!live && !force) return;
763
776
  try {
764
777
  const r = await fetch("/api/status", { cache: "no-store" });
765
- renderSystems((await r.json()).systems);
778
+ const sys = (await r.json()).systems;
779
+ if (sys) live = sys.live !== false; // pick up the dashboard-live config
780
+ renderSystems(sys);
766
781
  } catch { $("systems").innerHTML = '<div class="empty" style="padding:16px 0">Status unavailable.</div>'; }
767
782
  }
768
783
 
784
+ function onSavings() { const h = (location.hash || "").replace(/^#\/?/, ""); return h !== "settings" && h !== "skills"; }
785
+ // One refresh of everything visible on the Savings view; `force` ignores auto-refresh-off.
786
+ function refreshAll(force) { poll(force); if (onSavings()) loadSystems(force); }
787
+
769
788
  // --- skills subpage (lists enigma + external skills over /api/skills) ---
770
789
  function skillRow(s) {
771
790
  const ver = s.version ? '<span class="tag">v' + esc(s.version) + "</span>" : "";
@@ -871,16 +890,17 @@
871
890
  if (v === "settings" && !settingsLoaded) { settingsLoaded = true; loadSettings(); }
872
891
  if (v === "skills" && !skillsLoaded) { skillsLoaded = true; loadSkills(); }
873
892
  // The chart was sized while its view may have been hidden; nudge it on return.
874
- if (v === "savings") { loadSystems(); if (chart) { try { applyRange(); } catch { /* not ready */ } } }
893
+ if (v === "savings") { loadSystems(true); if (chart) { try { applyRange(); } catch { /* not ready */ } } }
875
894
  }
876
895
 
877
896
  initChart();
878
- poll();
879
- setInterval(poll, POLL_MS);
880
- document.addEventListener("visibilitychange", () => { if (!document.hidden) poll(); });
897
+ poll(true);
898
+ setInterval(() => refreshAll(false), POLL_MS);
899
+ document.addEventListener("visibilitychange", () => { if (!document.hidden) refreshAll(true); });
881
900
  wireSettings();
882
901
  wireSkills();
883
902
  $("updateBtn").addEventListener("click", runUpdate);
903
+ $("refreshBtn").addEventListener("click", () => refreshAll(true));
884
904
  window.addEventListener("hashchange", route);
885
905
  route();
886
906
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enigmax/dashboard",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Local browser dashboard UI for enigma: the static page and chart assets enigma serves on its loopback dashboard (savings, real tool usage, in-browser settings). Installed on demand by enigma-cli; not a runtime dependency.",
5
5
  "type": "module",
6
6
  "files": [