From ffd5e437094b3cfa7485302730717320eaeb09d4 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Mar 2026 05:26:48 -0500 Subject: [PATCH] Fix demo/showcase toggle: separate buttons, distinct modes Problem: plain toggle set showcase=true, so demo always became showcase. No way to enable basic demo mode separately. Fix: - Three explicit buttons: [Demo] [Showcase] [Off] - Demo mode: active=true, showcase=false (team UI only) - Showcase mode: active=true, showcase=true (full read-only admin) - Off: both false - Plain toggle cycles demo on/off without touching showcase - Clear status text shows which mode and what it means Co-Authored-By: Claude Opus 4.6 (1M context) --- llm_team_ui.py | 60 +++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/llm_team_ui.py b/llm_team_ui.py index 5e258f6..a93f5c2 100644 --- a/llm_team_ui.py +++ b/llm_team_ui.py @@ -461,7 +461,7 @@ def demo_toggle(): if not session.get("user_id") or not is_admin(): return jsonify({"error": "admin only"}), 403 data = request.json if request.is_json else {} - mode = data.get("mode", "toggle") # toggle, showcase, off + mode = data.get("mode", "toggle") # demo, showcase, off if mode == "off": _demo_mode["active"] = False _demo_mode["showcase"] = False @@ -470,10 +470,20 @@ def demo_toggle(): _demo_mode["active"] = True _demo_mode["showcase"] = True _demo_mode["started_by"] = session.get("username") + elif mode == "demo": + _demo_mode["active"] = True + _demo_mode["showcase"] = False + _demo_mode["started_by"] = session.get("username") else: - _demo_mode["active"] = not _demo_mode["active"] - _demo_mode["showcase"] = _demo_mode["active"] - _demo_mode["started_by"] = session.get("username") if _demo_mode["active"] else None + # plain toggle: cycle off → demo → off + if _demo_mode["active"]: + _demo_mode["active"] = False + _demo_mode["showcase"] = False + _demo_mode["started_by"] = None + else: + _demo_mode["active"] = True + _demo_mode["showcase"] = False + _demo_mode["started_by"] = session.get("username") return jsonify({"active": _demo_mode["active"], "showcase": _demo_mode["showcase"]}) @@ -3000,13 +3010,15 @@ ADMIN_HTML = r"""
-

Showcase Mode -
- - +

Demo / Showcase +
+ + +

-

Showcase mode gives visitors full read-only access to everything — Admin, Monitor, Logs, Threat Intel, Lab, History. They can run teams, view enrichments, and trigger self-analysis reports. They cannot change settings, ban IPs, delete data, or modify configs. Perfect for demos.

+

Demo — public can use Team UI and run modes. No admin access.

+

Showcase — full read-only access to everything: Admin, Monitor, Logs, Threat Intel, Lab, History. Cannot change settings or delete data.

Status: Off
@@ -3251,39 +3263,21 @@ function switchTab(name) { async function loadDemoStatus() { var r = await fetch('/api/demo/status'); var d = await r.json(); - var btn = document.getElementById('admin-showcase-btn'); - var offBtn = document.getElementById('admin-demo-off'); var st = document.getElementById('demo-status-admin'); if (d.active && d.showcase) { - btn.textContent = 'Showcase Active'; - btn.className = 'btn'; - btn.style.cssText = 'margin-left:auto;border-color:#d946ef;color:#d946ef'; - offBtn.style.display = ''; - st.innerHTML = 'Status: SHOWCASE MODE — full read-only access for visitors' + (d.started_by ? ' (by ' + d.started_by + ')' : ''); + st.innerHTML = 'Status: SHOWCASE — full read-only admin access' + (d.started_by ? ' (by ' + d.started_by + ')' : ''); } else if (d.active) { - btn.textContent = 'Demo Active'; - btn.className = 'btn btn-g'; - offBtn.style.display = ''; - st.innerHTML = 'Status: DEMO ON' + (d.started_by ? ' (by ' + d.started_by + ')' : ''); + st.innerHTML = 'Status: DEMO — team UI only' + (d.started_by ? ' (by ' + d.started_by + ')' : ''); } else { - btn.textContent = 'Enable Showcase'; - btn.className = 'btn'; - btn.style.cssText = 'border-color:rgba(217,70,239,0.3);color:#d946ef'; - offBtn.style.display = 'none'; st.innerHTML = 'Status: Off'; } } -async function toggleShowcase() { - await fetch('/api/demo/toggle', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({mode:'showcase'})}); +async function setDemoMode(mode) { + await fetch('/api/demo/toggle', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({mode:mode})}); loadDemoStatus(); - toast('Showcase mode enabled', true); -} - -async function demoOff() { - await fetch('/api/demo/toggle', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({mode:'off'})}); - loadDemoStatus(); - toast('Demo mode disabled', true); + var labels = {demo:'Demo enabled',showcase:'Showcase enabled',off:'Turned off'}; + toast(labels[mode] || mode, true); } async function loadAllowlist() {