diff --git a/demo/static/app.js b/demo/static/app.js index 90a9399..89d86a6 100644 --- a/demo/static/app.js +++ b/demo/static/app.js @@ -88,7 +88,7 @@ function render(state) { ${r.method} · cap ${stroops(r.max_spend_per_period)} (${xlm(r.max_spend_per_period)}) · max ${r.max_calls_per_period} calls ` ) - .join(""); + .join("") || `
No policy rules installed.
`; $("market").innerHTML = (state.resources || []) .map( @@ -98,7 +98,7 @@ function render(state) { ${r.price} stroops / call · ${xlm(r.price)} ` ) - .join(""); + .join("") || `Marketplace is empty.
`; $("bars").innerHTML = (state.rules || []) .map( @@ -107,7 +107,7 @@ function render(state) { ` ) - .join(""); + .join("") || `No spend yet this period.
`; $("audit").innerHTML = (state.audit || []) .map((e) => { @@ -115,7 +115,7 @@ function render(state) { const extra = e.tx_hash ? ` tx ${e.tx_hash}` : ""; return `No auth_decision events yet.
`; } async function refresh() { @@ -173,6 +173,9 @@ async function pay(id) { $("discover").onclick = discover; $("budget-btn").onclick = budget; $("reset").onclick = async () => { + if (!window.confirm("Reset the live pitch demo? Current spend and audit events will be wiped.")) { + return; + } await api("/api/reset", { method: "POST" }); consoleEl.innerHTML = ""; $("script").innerHTML = "Demo reset. Policy regenerated from 75 synthetic transactions."; diff --git a/demo/static/styles.css b/demo/static/styles.css index 68425af..99e3f4c 100644 --- a/demo/static/styles.css +++ b/demo/static/styles.css @@ -139,7 +139,7 @@ input { .err { color: var(--deny); } .dim { color: var(--muted); } -.cards { display: flex; flex-direction: column; gap: 8px; } +.empty { color: var(--muted); font-size: 13px; padding: 8px 0; } .card { border: 1px solid var(--line); border-radius: 10px; diff --git a/demo/tests/test_empty_reset.py b/demo/tests/test_empty_reset.py new file mode 100644 index 0000000..a9aae8b --- /dev/null +++ b/demo/tests/test_empty_reset.py @@ -0,0 +1,12 @@ +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + + +def test_empty_states_and_reset_confirm(): + js = (ROOT / "static" / "app.js").read_text(encoding="utf-8") + css = (ROOT / "static" / "styles.css").read_text(encoding="utf-8") + assert "No auth_decision events yet." in js + assert "Marketplace is empty." in js + assert "window.confirm" in js + assert ".empty" in css