@enigmax/dashboard 0.1.108 → 0.1.109

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 +47 -23
  2. package/package.json +1 -1
package/assets/index.html CHANGED
@@ -3580,7 +3580,8 @@ export {
3580
3580
  + s.choices.map((c) => '<option value="' + esc(c) + '"' + (c === s.choice ? " selected" : "") + ">" + esc(prettyChoice(c)) + "</option>").join("")
3581
3581
  + "</select>"
3582
3582
  : '<button type="button" class="toggle' + (s.value ? " on" : "") + '" data-skey="' + esc(s.key)
3583
- + '" data-kind="bool" data-on="' + (s.value ? 1 : 0) + '">' + (s.value ? "On" : "Off") + "</button>";
3583
+ + '" data-kind="bool" role="switch" aria-checked="' + (s.value ? "true" : "false")
3584
+ + '" data-on="' + (s.value ? 1 : 0) + '">' + (s.value ? "On" : "Off") + "</button>";
3584
3585
  return '<div class="set-row"><div class="set-meta"><div class="set-name">' + settingIcon(s.key) + labelWithBadges(s.label) + "</div>"
3585
3586
  + '<div class="set-hint">' + linkify(s.hint) + (s.globalOnly ? " · global" : "") + "</div></div>"
3586
3587
  + '<div class="set-ctl">' + ctl + "</div></div>";
@@ -3598,7 +3599,19 @@ export {
3598
3599
  + '<div class="set-grid">' + c.settings.map(settingRow).join("") + "</div></div>").join("");
3599
3600
  }
3600
3601
 
3601
- function applyBool(ctl, on) { ctl.classList.toggle("on", on); ctl.textContent = on ? "On" : "Off"; ctl.dataset.on = on ? 1 : 0; }
3602
+ // The one painter for every switch on this page: the class the CSS reads, the ARIA state a
3603
+ // screen reader reads, the data-on the click handlers read, and the label when the switch
3604
+ // carries one. Painted before the write lands and rolled back if the server refuses - every
3605
+ // switch here writes through something slow (re-rendering skills, rewriting each agent's
3606
+ // settings and hooks), so one that only moves once the write returns reads as dead.
3607
+ function paintSwitch(btn, on, onLabel, offLabel) {
3608
+ if (!btn) return;
3609
+ btn.classList.toggle("on", !!on);
3610
+ btn.setAttribute("aria-checked", on ? "true" : "false");
3611
+ btn.dataset.on = on ? "1" : "0";
3612
+ if (onLabel != null) btn.textContent = on ? onLabel : offLabel;
3613
+ }
3614
+ function applyBool(ctl, on) { paintSwitch(ctl, on, "On", "Off"); }
3602
3615
 
3603
3616
  // One place that turns an /api/* call into parsed JSON, or an Error naming the real
3604
3617
  // cause. res.json() throws on any reply that is not JSON - an empty 405, or an HTML
@@ -4561,12 +4574,7 @@ export {
4561
4574
  }
4562
4575
  // The two on/off switches at the top of the page. Both are optimistic: the switch flips
4563
4576
  // first and rolls back if the server refuses, like every other control here.
4564
- function gateBool(btn, on) {
4565
- btn.textContent = on ? "on" : "off";
4566
- btn.classList.toggle("on", !!on);
4567
- btn.dataset.on = on ? "1" : "0";
4568
- btn.setAttribute("aria-checked", on ? "true" : "false");
4569
- }
4577
+ function gateBool(btn, on) { paintSwitch(btn, on, "on", "off"); }
4570
4578
  // Defaults for every gate setting, straight from the gate's own config loader (the
4571
4579
  // server resolves an empty config rather than keeping a second copy of the numbers).
4572
4580
  // They drive the "default N" hint and the per-row reset below.
@@ -5573,8 +5581,7 @@ export {
5573
5581
  function renderCodeGraph(view) {
5574
5582
  view = view || {};
5575
5583
  const on = !!view.enabled;
5576
- const t = $("cgToggle");
5577
- t.classList.toggle("on", on); t.setAttribute("aria-checked", on ? "true" : "false"); t.textContent = on ? "On" : "Off";
5584
+ paintSwitch($("cgToggle"), on, "On", "Off");
5578
5585
  const projects = view.projects || [];
5579
5586
  const projHtml = projects.length
5580
5587
  ? projects.map((p) => {
@@ -5622,9 +5629,19 @@ export {
5622
5629
  } catch { setNote("cgNote", "Could not reach the server.", "err"); return null; }
5623
5630
  }
5624
5631
  async function cgToggleAction() {
5625
- const turnOn = $("cgToggle").getAttribute("aria-checked") !== "true";
5626
- const out = await cgPost({ op: "toggle", on: turnOn, project: cgProject || undefined }, "Saving...");
5627
- if (out) setNote("cgNote", out.ok ? (turnOn ? "Code graph enabled - tools exposed to your agents (restart them to load it)." : "Code graph disabled.") : (out.error || "Action failed."), out.ok ? "ok" : "err");
5632
+ const btn = $("cgToggle");
5633
+ const was = btn.getAttribute("aria-checked") === "true";
5634
+ paintSwitch(btn, !was, "On", "Off");
5635
+ const out = await cgPost({ op: "toggle", on: !was }, was ? "Disabling..." : "Enabling...");
5636
+ if (!out || !out.ok) {
5637
+ paintSwitch(btn, was, "On", "Off");
5638
+ if (out) setNote("cgNote", out.error || "Action failed.", "err"); // cgPost already reported an unreachable server
5639
+ return;
5640
+ }
5641
+ paintSwitch(btn, !!out.enabled, "On", "Off"); // the server's answer wins over the optimistic paint
5642
+ setNote("cgNote", out.enabled
5643
+ ? "Code graph enabled - tools and session hooks wired; agents pick it up on their next session."
5644
+ : "Code graph disabled - tools and session hooks removed.", "ok");
5628
5645
  }
5629
5646
  async function cgIndexAction() {
5630
5647
  const root = $("cgRoot").value.trim();
@@ -5766,7 +5783,7 @@ export {
5766
5783
  $("pgSend").addEventListener("click", pgSend);
5767
5784
  $("pgSaveDefault").addEventListener("click", pgSaveDefault);
5768
5785
  const tog = $("pgTools");
5769
- tog.addEventListener("click", () => { const on = tog.getAttribute("aria-checked") !== "true"; tog.classList.toggle("on", on); tog.setAttribute("aria-checked", on ? "true" : "false"); tog.textContent = on ? "On" : "Off"; });
5786
+ tog.addEventListener("click", () => paintSwitch(tog, tog.getAttribute("aria-checked") !== "true", "On", "Off"));
5770
5787
  $("pgMode").addEventListener("change", pgSyncMode);
5771
5788
  const copyBtn = $("pgCopyCurl");
5772
5789
  // The button is an icon, so the toast is not the only confirmation: swap the icon for a
@@ -5859,11 +5876,7 @@ export {
5859
5876
  $("recallKey").disabled = !!p.keyFromEnv;
5860
5877
  // claude-local needs no base/key; hide that row for it.
5861
5878
  $("recallKeyRow").style.display = p.provider === "claude-local" ? "none" : "";
5862
- const llmBtn = $("recallLlmBtn");
5863
- llmBtn.textContent = p.llm ? "on" : "off";
5864
- llmBtn.classList.toggle("on", !!p.llm);
5865
- llmBtn.dataset.on = p.llm ? "1" : "0";
5866
- llmBtn.setAttribute("aria-checked", p.llm ? "true" : "false");
5879
+ paintSwitch($("recallLlmBtn"), p.llm, "on", "off");
5867
5880
  }
5868
5881
  let recallItemsById = {};
5869
5882
  // Multi-select state for the Recall list: a Set of selected ids, the ordered ids as
@@ -5958,14 +5971,25 @@ export {
5958
5971
  setNote("recallNote", out.ok ? (op === "sync" ? "Synced." : "Cleared.") : (out.error || "Action failed."), out.ok ? "ok" : "err");
5959
5972
  } catch { setNote("recallNote", "Could not reach the server.", "err"); }
5960
5973
  }
5961
- async function setRecallEnabled(on) {
5974
+ // The recall switch carries its state in its own label ("Enable recall" when off, "Disable"
5975
+ // when on), in its title and in what the next click asks for - so an optimistic paint has to
5976
+ // move all three. Painting the switch alone left a button reading "Enable recall" while
5977
+ // already on, offering to turn on what it had just turned on, until loadRecall() re-rendered.
5978
+ function paintRecallSwitch(btn, on) {
5979
+ paintSwitch(btn, on, "Disable", "Enable recall");
5980
+ if (!btn) return;
5981
+ btn.dataset.recallOn = on ? "0" : "1";
5982
+ btn.title = on ? "Turn session memory off" : "Turn session memory on";
5983
+ }
5984
+ async function setRecallEnabled(on, btn) {
5985
+ paintRecallSwitch(btn, on);
5962
5986
  setNote("recallNote", on ? "Enabling recall..." : "Disabling recall...");
5963
5987
  try {
5964
5988
  const out = await (await fetch("/api/settings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key: "recall", value: on }) })).json();
5965
- if (!out.ok) { setNote("recallNote", "Could not change recall: " + (out.error || "error"), "err"); return; }
5989
+ if (!out.ok) { paintRecallSwitch(btn, !on); setNote("recallNote", "Could not change recall: " + (out.error || "error"), "err"); return; }
5966
5990
  setNote("recallNote", out.restartNote || (on ? "Recall enabled." : "Recall disabled."), out.restartNote ? "warn" : "ok");
5967
5991
  loadRecall();
5968
- } catch { setNote("recallNote", "Could not reach the server.", "err"); }
5992
+ } catch { paintRecallSwitch(btn, !on); setNote("recallNote", "Could not reach the server.", "err"); }
5969
5993
  }
5970
5994
  async function recallProviderPost(extra, msg) {
5971
5995
  setNote("recallNote", msg || "Saving provider...");
@@ -5990,7 +6014,7 @@ export {
5990
6014
  $("recallClear").addEventListener("click", () => recallAction("clear", "Delete all stored session memory? This cannot be undone."));
5991
6015
  $("recallBody").addEventListener("click", (e) => {
5992
6016
  const t = e.target.closest("[data-recall-on]");
5993
- if (t) setRecallEnabled(t.dataset.recallOn === "1");
6017
+ if (t) setRecallEnabled(t.dataset.recallOn === "1", t);
5994
6018
  });
5995
6019
  // Provider panel: save provider; flip LLM curation. The provider picker is the
5996
6020
  // custom icon dropdown (recallProvVal), wired in renderRecallProvider.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enigmax/dashboard",
3
- "version": "0.1.108",
3
+ "version": "0.1.109",
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": [