webui: organize config page with subtabs
This commit is contained in:
@@ -33,7 +33,7 @@ body{margin:0;background:var(--bg);color:var(--text);font-family:-apple-system,B
|
||||
.weatherBadge{font-size:20px;font-weight:900;color:var(--text);padding:8px 12px}
|
||||
h1{font-size:21px;margin:0}.sub{color:var(--muted);font-size:13px;margin-top:4px}
|
||||
.pill{border:1px solid var(--line);border-radius:999px;padding:7px 10px;color:var(--muted);font-size:12px;white-space:nowrap}
|
||||
.tabs{position:fixed;left:0;right:0;bottom:0;background:#080c11;border-top:1px solid var(--line);display:grid;grid-template-columns:repeat(3,1fr);z-index:10}
|
||||
.tabs{position:fixed;left:0;right:0;bottom:0;background:#080c11;border-top:1px solid var(--line);display:grid;grid-template-columns:repeat(3,1fr);z-index:10}\n.subtabs{display:flex;gap:8px;overflow-x:auto;padding:2px 0 12px;margin-bottom:4px}.subtabbtn{width:auto;white-space:nowrap;border:1px solid var(--line);background:#101722;color:var(--muted);padding:10px 12px;border-radius:999px;font-size:13px}.subtabbtn.active{background:#1f2b3c;color:var(--text);border-color:#3b536f}.configSubpage{display:none}.configSubpage.active{display:block}
|
||||
.tabbtn{border:0;border-radius:0;background:#080c11;color:var(--muted);padding:13px 8px;font-weight:800}
|
||||
.tabbtn.active{color:var(--text);background:#111923}
|
||||
.page{display:none}.page.active{display:block}
|
||||
@@ -173,6 +173,16 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
</div>
|
||||
|
||||
<div id="configPage" class="page">
|
||||
<div class="subtabs">
|
||||
<button id="configTab-general" class="subtabbtn active" onclick="showConfigSubtab('general')">General</button>
|
||||
<button id="configTab-wifi" class="subtabbtn" onclick="showConfigSubtab('wifi')">WiFi / AP</button>
|
||||
<button id="configTab-relays" class="subtabbtn" onclick="showConfigSubtab('relays')">Relays</button>
|
||||
<button id="configTab-temps" class="subtabbtn" onclick="showConfigSubtab('temps')">Temperatures</button>
|
||||
<button id="configTab-bms" class="subtabbtn" onclick="showConfigSubtab('bms')">BMS</button>
|
||||
<button id="configTab-maintenance" class="subtabbtn" onclick="showConfigSubtab('maintenance')">Maintenance</button>
|
||||
</div>
|
||||
|
||||
<div id="config-general" class="configSubpage active">
|
||||
<div class="grid">
|
||||
<section class="card span12 configIntro">
|
||||
<div class="configGroupHeader">
|
||||
@@ -183,6 +193,35 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card span12">
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
<div class="configGroupTitle">General</div>
|
||||
<div class="configGroupHelp">Controller identity shown in the WebUI and dashboard.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list">
|
||||
<input id="deviceNameInput" placeholder="Device name">
|
||||
<button class="on" onclick="saveDeviceConfig()">Save Device Name</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card span12">
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
<div class="configGroupTitle">System</div>
|
||||
<div class="configGroupHelp">Read-only firmware and network status.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row"><span class="muted">Firmware</span><span class="v" id="fw">--</span></div>
|
||||
<div class="row"><span class="muted">Uptime</span><span class="v" id="uptime">--</span></div>
|
||||
<div class="row"><span class="muted">AP IP</span><span class="v" id="apIp">--</span></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="config-wifi" class="configSubpage">
|
||||
<div class="grid">
|
||||
<section class="card span12">
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
@@ -226,7 +265,11 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
<button onclick="connectWifi()">Connect Now</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="config-relays" class="configSubpage">
|
||||
<div class="grid">
|
||||
<section class="card span12">
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
@@ -237,12 +280,16 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
<div class="list" id="relayConfigList"></div>
|
||||
<button onclick="saveRelayConfig()">Save Relay Names</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="config-temps" class="configSubpage">
|
||||
<div class="grid">
|
||||
<section class="card span12">
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
<div class="configGroupTitle">Temperature Assignment</div>
|
||||
<div class="configGroupHelp">Scan probes, then assign a discovered sensor to a configured temp slot.</div>
|
||||
<div class="configGroupHelp">Scan probes, then assign discovered sensors to configured temp slots.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list">
|
||||
@@ -252,31 +299,30 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
</section>
|
||||
|
||||
<section class="card span12">
|
||||
<div class="label">Temperature Sensor Config</div>
|
||||
<div class="sub">Set how many temp sensors are enabled and rename each slot.</div>
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
<div class="configGroupTitle">Temperature Sensor Config</div>
|
||||
<div class="configGroupHelp">Set how many temp sensors are enabled, rename each slot, and pick the weather badge sensor.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list">
|
||||
<input id="tempEnabledCount" placeholder="Enabled sensor count, 0-8" inputmode="numeric">
|
||||
<div id="tempConfigList" class="list"></div>
|
||||
<button onclick="saveTempConfig()">Save Temperature Config</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="config-bms" class="configSubpage">
|
||||
<div class="grid">
|
||||
<section class="card span12">
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
<div class="configGroupTitle">Device</div>
|
||||
<div class="configGroupHelp">Controller identity and BMS connection settings.</div>
|
||||
<div class="configGroupTitle">BMS Config</div>
|
||||
<div class="configGroupHelp">JBD/Xiaoxiang BLE settings. Use this for initial setup, bench mode, or replacing the battery/BMS.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list">
|
||||
<input id="deviceNameInput" placeholder="Device name">
|
||||
<button onclick="saveDeviceConfig()">Save Device Name</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card span12">
|
||||
<div class="label">BMS Config</div>
|
||||
<div class="sub">Use this for initial setup, bench mode, or replacing the battery/BMS.</div>
|
||||
<div class="list">
|
||||
<input id="bmsNameInput" placeholder="BMS name">
|
||||
<input id="bmsAddressInput" placeholder="BMS BLE address">
|
||||
@@ -288,23 +334,25 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
<div class="btnrow">
|
||||
<button onclick="setBmsEnabled(true)">Enable BMS</button>
|
||||
</div>
|
||||
<div class="row"><span class="muted">BMS Polling</span><span class="v" id="bmsEnabledText">--</span></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="config-maintenance" class="configSubpage">
|
||||
<div class="grid">
|
||||
<section class="card span12">
|
||||
<div class="label">System Actions</div>
|
||||
<div class="sub">Use carefully. Factory reset clears install-specific configuration.</div>
|
||||
<div class="configGroupHeader">
|
||||
<div>
|
||||
<div class="configGroupTitle">Maintenance</div>
|
||||
<div class="configGroupHelp">Reset and recovery actions. These can disrupt the controller.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnrow">
|
||||
<button class="off" onclick="factoryReset()">Factory Reset</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card span12">
|
||||
<div class="label">System</div>
|
||||
<div class="row"><span class="muted">Firmware</span><span class="v" id="fw">--</span></div>
|
||||
<div class="row"><span class="muted">Uptime</span><span class="v" id="uptime">--</span></div>
|
||||
<div class="row"><span class="muted">AP IP</span><span class="v" id="apIp">--</span></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -474,6 +522,15 @@ function batteryTimeInfo(b){
|
||||
|
||||
return {label:"Battery time", value:"Idle"};
|
||||
}
|
||||
function showConfigSubtab(name){
|
||||
["general","wifi","relays","temps","bms","maintenance"].forEach(t=>{
|
||||
const page=$("config-"+t);
|
||||
const btn=$("configTab-"+t);
|
||||
if(page) page.classList.toggle("active",t===name);
|
||||
if(btn) btn.classList.toggle("active",t===name);
|
||||
});
|
||||
}
|
||||
|
||||
function showTab(name){
|
||||
["overview","battery","config"].forEach(t=>{
|
||||
$(t+"Page").classList.toggle("active",t===name);
|
||||
|
||||
@@ -375,3 +375,29 @@ def test_embedded_webui_api_badge_labels_are_clear():
|
||||
assert "API Live" in source
|
||||
assert "API Error" in source
|
||||
assert 'textContent="Offline"' not in source
|
||||
|
||||
|
||||
def test_embedded_webui_config_page_is_grouped():
|
||||
source = firmware_source()
|
||||
|
||||
assert "configGroupTitle" in source
|
||||
assert "General" in source
|
||||
assert "Home / Starlink WiFi" in source
|
||||
assert "Relay Outputs" in source
|
||||
assert "Temperature Assignment" in source
|
||||
assert "BMS Config" in source
|
||||
assert "Maintenance" in source
|
||||
|
||||
|
||||
def test_embedded_webui_config_subtabs():
|
||||
source = firmware_source()
|
||||
|
||||
assert "function showConfigSubtab(name)" in source
|
||||
assert "config-general" in source
|
||||
assert "config-wifi" in source
|
||||
assert "config-relays" in source
|
||||
assert "config-temps" in source
|
||||
assert "config-bms" in source
|
||||
assert "config-maintenance" in source
|
||||
assert "WiFi / AP" in source
|
||||
assert "subtabbtn active" in source
|
||||
|
||||
Reference in New Issue
Block a user