Skip to content

Commit fe6e900

Browse files
Copilotdorkmo
andcommitted
Remove % Full, Relays columns, PIN status, refresh buttons; simplify status display
Co-authored-by: dorkmo <[email protected]>
1 parent ce7e5f6 commit fe6e900

File tree

1 file changed

+26
-209
lines changed

1 file changed

+26
-209
lines changed

TankAlarm-112025-Server-BluesOpta/TankAlarm-112025-Server-BluesOpta.ino

Lines changed: 26 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -896,40 +896,6 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
896896
margin-top: 8px;
897897
font-size: 1.8rem;
898898
}
899-
.filter-bar {
900-
display: flex;
901-
flex-wrap: wrap;
902-
gap: 16px;
903-
align-items: flex-end;
904-
background: var(--surface);
905-
border: 1px solid var(--card-border);
906-
border-radius: 20px;
907-
padding: 16px;
908-
box-shadow: 0 18px 40px var(--card-shadow);
909-
margin-bottom: 20px;
910-
}
911-
.filter-bar label {
912-
display: flex;
913-
flex-direction: column;
914-
font-size: 0.9rem;
915-
color: var(--muted);
916-
min-width: 220px;
917-
}
918-
select {
919-
appearance: none;
920-
border-radius: 10px;
921-
border: 1px solid var(--card-border);
922-
padding: 10px 12px;
923-
margin-top: 6px;
924-
background: var(--bg);
925-
color: var(--text);
926-
}
927-
.filter-actions {
928-
display: flex;
929-
gap: 12px;
930-
flex-wrap: wrap;
931-
align-items: center;
932-
}
933899
.btn {
934900
border: none;
935901
border-radius: 999px;
@@ -1046,32 +1012,6 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
10461012
#toast.show {
10471013
opacity: 1;
10481014
}
1049-
.relay-btn {
1050-
padding: 4px 8px;
1051-
margin: 0 2px;
1052-
border: 1px solid var(--card-border);
1053-
border-radius: 4px;
1054-
background: var(--surface);
1055-
color: var(--text);
1056-
font-size: 0.75rem;
1057-
cursor: pointer;
1058-
transition: all 0.2s ease;
1059-
}
1060-
.relay-btn:hover {
1061-
background: var(--accent);
1062-
color: var(--accent-contrast);
1063-
border-color: var(--accent);
1064-
}
1065-
.relay-btn.active {
1066-
background: var(--accent);
1067-
color: var(--accent-contrast);
1068-
border-color: var(--accent);
1069-
font-weight: bold;
1070-
}
1071-
.relay-btn:disabled {
1072-
opacity: 0.5;
1073-
cursor: not-allowed;
1074-
}
10751015
</style>
10761016
</head>
10771017
<body data-theme="light">
@@ -1107,10 +1047,6 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
11071047
<span>Last Time Sync</span>
11081048
<strong id="lastSync">--</strong>
11091049
</div>
1110-
<div class="meta-card">
1111-
<span>PIN Status</span>
1112-
<strong id="pinStatus">--</strong>
1113-
</div>
11141050
<div class="meta-card">
11151051
<span>Last Dashboard Refresh</span>
11161052
<strong id="lastRefresh">--</strong>
@@ -1136,19 +1072,6 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
11361072
<strong id="statStale">0</strong>
11371073
</div>
11381074
</div>
1139-
<section class="filter-bar">
1140-
<label>
1141-
Site Filter
1142-
<select id="siteFilter">
1143-
<option value="">All Sites</option>
1144-
</select>
1145-
</label>
1146-
<div class="filter-actions">
1147-
<button class="btn" id="refreshSiteBtn">Refresh Selected Site</button>
1148-
<button class="btn secondary" id="refreshAllBtn">Refresh All Sites</button>
1149-
<span class="badge" id="autoRefreshHint">UI refresh 60 s · Server cadence 6 h</span>
1150-
</div>
1151-
</section>
11521075
<section class="card">
11531076
<div class="card-head">
11541077
<h2 style="margin:0;">Fleet Telemetry</h2>
@@ -1161,10 +1084,9 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
11611084
<th>Site</th>
11621085
<th>Tank</th>
11631086
<th>Level (in)</th>
1164-
<th>% Full</th>
11651087
<th>Status</th>
11661088
<th>Updated</th>
1167-
<th>Relays</th>
1089+
<th>Refresh</th>
11681090
</tr>
11691091
</thead>
11701092
<tbody id="tankBody"></tbody>
@@ -1186,11 +1108,6 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
11861108
nextEmail: document.getElementById('nextEmail'),
11871109
lastSync: document.getElementById('lastSync'),
11881110
lastRefresh: document.getElementById('lastRefresh'),
1189-
pinStatus: document.getElementById('pinStatus'),
1190-
autoRefreshHint: document.getElementById('autoRefreshHint'),
1191-
siteFilter: document.getElementById('siteFilter'),
1192-
refreshSiteBtn: document.getElementById('refreshSiteBtn'),
1193-
refreshAllBtn: document.getElementById('refreshAllBtn'),
11941111
tankBody: document.getElementById('tankBody'),
11951112
statClients: document.getElementById('statClients'),
11961113
statTanks: document.getElementById('statTanks'),
@@ -1202,7 +1119,6 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
12021119
const state = {
12031120
clients: [],
12041121
tanks: [],
1205-
selected: '',
12061122
refreshing: false,
12071123
timer: null,
12081124
uiRefreshSeconds: DEFAULT_REFRESH_SECONDS
@@ -1283,40 +1199,10 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
12831199
return rows;
12841200
}
12851201
1286-
function populateSiteFilter(preferredUid) {
1287-
const select = els.siteFilter;
1288-
const map = new Map();
1289-
state.clients.forEach(client => {
1290-
if (!client.client) return;
1291-
const suffix = client.client.length > 6 ? client.client.slice(-6) : client.client;
1292-
const label = client.site ? `${client.site} (${suffix})` : `Client ${suffix}`;
1293-
map.set(client.client, label);
1294-
});
1295-
const previous = select.value;
1296-
select.innerHTML = '<option value="">All Sites</option>';
1297-
map.forEach((label, uid) => {
1298-
const option = document.createElement('option');
1299-
option.value = uid;
1300-
option.textContent = label;
1301-
select.appendChild(option);
1302-
});
1303-
const desired = preferredUid || previous;
1304-
if (desired && map.has(desired)) {
1305-
select.value = desired;
1306-
state.selected = desired;
1307-
} else if (!map.has(state.selected)) {
1308-
state.selected = '';
1309-
select.value = '';
1310-
} else {
1311-
select.value = state.selected || '';
1312-
}
1313-
updateButtonState();
1314-
}
1315-
13161202
function renderTankRows() {
13171203
const tbody = els.tankBody;
13181204
tbody.innerHTML = '';
1319-
const rows = state.selected ? state.tanks.filter(t => t.client === state.selected) : state.tanks;
1205+
const rows = state.tanks;
13201206
if (!rows.length) {
13211207
const tr = document.createElement('tr');
13221208
tr.innerHTML = '<td colspan="7">No telemetry available</td>';
@@ -1331,10 +1217,9 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
13311217
<td>${row.site || '--'}</td>
13321218
<td>${row.label || 'Tank'} #${row.tank || '?'}</td>
13331219
<td>${formatNumber(row.levelInches)}</td>
1334-
<td>${formatNumber(row.percent)}</td>
13351220
<td>${statusBadge(row)}</td>
13361221
<td>${formatEpoch(row.lastUpdate)}</td>
1337-
<td>${relayButtons(row)}</td>`;
1222+
<td>${refreshButton(row)}</td>`;
13381223
tbody.appendChild(tr);
13391224
});
13401225
}
@@ -1343,8 +1228,13 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
13431228
if (!row.alarm) {
13441229
return '<span class="status-pill ok">Normal</span>';
13451230
}
1346-
const label = row.alarmType ? row.alarmType : 'Alarm';
1347-
return `<span class="status-pill alarm">${label}</span>`;
1231+
return '<span class="status-pill alarm">ALARM</span>';
1232+
}
1233+
1234+
function refreshButton(row) {
1235+
if (!row.client || row.client === '--') return '--';
1236+
const escapedClient = escapeHtml(row.client);
1237+
return `<button class="icon-button" onclick="refreshTank('${escapedClient}')" title="Refresh Tank" style="width:32px;height:32px;font-size:1rem;">🔄</button>`;
13481238
}
13491239
13501240
function escapeHtml(unsafe) {
@@ -1357,45 +1247,29 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
13571247
.replace(/'/g, '&#039;');
13581248
}
13591249
1360-
function relayButtons(row) {
1361-
if (!row.client || row.client === '--') return '--';
1362-
const MAX_RELAYS = 4;
1363-
const relays = Array.from({length: MAX_RELAYS}, (_, i) => i + 1);
1364-
const escapedClient = escapeHtml(row.client);
1365-
return relays.map(num =>
1366-
`<button class="relay-btn" onclick="toggleRelay('${escapedClient}', ${num}, event)" title="Toggle Relay ${num}">R${num}</button>`
1367-
).join(' ');
1368-
}
1369-
1370-
async function toggleRelay(clientUid, relayNum, event) {
1371-
const btn = event.target;
1372-
const wasActive = btn.classList.contains('active');
1373-
const newState = !wasActive;
1374-
1375-
btn.disabled = true;
1250+
async function refreshTank(clientUid) {
1251+
if (state.refreshing) return;
1252+
state.refreshing = true;
13761253
try {
1377-
const res = await fetch('/api/relay', {
1254+
const res = await fetch('/api/refresh', {
13781255
method: 'POST',
13791256
headers: { 'Content-Type': 'application/json' },
1380-
body: JSON.stringify({
1381-
clientUid: clientUid,
1382-
relay: relayNum,
1383-
state: newState
1384-
})
1257+
body: JSON.stringify({ client: clientUid })
13851258
});
13861259
if (!res.ok) {
13871260
const text = await res.text();
1388-
throw new Error(text || 'Relay command failed');
1261+
throw new Error(text || 'Refresh failed');
13891262
}
1390-
btn.classList.toggle('active', newState);
1391-
showToast(`Relay ${relayNum} ${newState ? 'ON' : 'OFF'} command sent`);
1263+
const data = await res.json();
1264+
applyServerData(data);
1265+
showToast('Tank refreshed');
13921266
} catch (err) {
1393-
showToast(err.message || 'Relay control failed', true);
1267+
showToast(err.message || 'Refresh failed', true);
13941268
} finally {
1395-
btn.disabled = false;
1269+
state.refreshing = false;
13961270
}
13971271
}
1398-
window.toggleRelay = toggleRelay;
1272+
window.refreshTank = refreshTank;
13991273
14001274
function updateStats() {
14011275
const clientIds = new Set();
@@ -1412,101 +1286,44 @@ static const char DASHBOARD_HTML[] PROGMEM = R"HTML(
14121286
els.statStale.textContent = stale;
14131287
}
14141288
1415-
function updateButtonState() {
1416-
els.refreshAllBtn.disabled = state.refreshing;
1417-
els.refreshSiteBtn.disabled = state.refreshing || !state.selected;
1418-
}
1419-
14201289
function scheduleUiRefresh() {
14211290
if (state.timer) {
14221291
clearInterval(state.timer);
14231292
}
14241293
state.timer = setInterval(() => {
1425-
refreshData(state.selected);
1294+
refreshData();
14261295
}, state.uiRefreshSeconds * 1000);
14271296
}
14281297
1429-
function updateRefreshHint(serverInfo) {
1430-
const cadence = describeCadence(serverInfo && serverInfo.webRefreshSeconds);
1431-
els.autoRefreshHint.textContent = `UI refresh ${state.uiRefreshSeconds} s · Server cadence ${cadence}`;
1432-
}
1433-
1434-
function applyServerData(data, preferredUid) {
1298+
function applyServerData(data) {
14351299
state.clients = data.clients || [];
14361300
state.tanks = flattenTanks(state.clients);
1437-
if (preferredUid) {
1438-
state.selected = preferredUid;
1439-
}
14401301
const serverInfo = data.server || {};
14411302
els.serverName.textContent = serverInfo.name || 'Tank Alarm Server';
14421303
els.serverUid.textContent = data.serverUid || '--';
14431304
els.fleetName.textContent = serverInfo.clientFleet || 'tankalarm-clients';
14441305
els.nextEmail.textContent = formatEpoch(data.nextDailyEmailEpoch);
14451306
els.lastSync.textContent = formatEpoch(data.lastSyncEpoch);
1446-
els.pinStatus.textContent = serverInfo.pinConfigured ? 'Configured' : 'Not Set';
14471307
els.lastRefresh.textContent = new Date().toLocaleString();
14481308
state.uiRefreshSeconds = DEFAULT_REFRESH_SECONDS;
1449-
updateRefreshHint(serverInfo);
1450-
populateSiteFilter(preferredUid);
14511309
renderTankRows();
14521310
updateStats();
14531311
scheduleUiRefresh();
14541312
}
14551313
1456-
async function refreshData(preferredUid) {
1314+
async function refreshData() {
14571315
try {
14581316
const res = await fetch('/api/clients');
14591317
if (!res.ok) {
14601318
throw new Error('Failed to fetch fleet data');
14611319
}
14621320
const data = await res.json();
1463-
applyServerData(data, preferredUid || state.selected);
1321+
applyServerData(data);
14641322
} catch (err) {
14651323
showToast(err.message || 'Fleet refresh failed', true);
14661324
}
14671325
}
14681326
1469-
async function triggerManualRefresh(targetUid) {
1470-
const payload = targetUid ? { client: targetUid } : {};
1471-
state.refreshing = true;
1472-
updateButtonState();
1473-
try {
1474-
const res = await fetch('/api/refresh', {
1475-
method: 'POST',
1476-
headers: { 'Content-Type': 'application/json' },
1477-
body: JSON.stringify(payload)
1478-
});
1479-
if (!res.ok) {
1480-
const text = await res.text();
1481-
throw new Error(text || 'Refresh failed');
1482-
}
1483-
const data = await res.json();
1484-
applyServerData(data, targetUid || state.selected);
1485-
showToast(targetUid ? 'Selected site refreshed' : 'Fleet refresh queued');
1486-
} catch (err) {
1487-
showToast(err.message || 'Refresh failed', true);
1488-
} finally {
1489-
state.refreshing = false;
1490-
updateButtonState();
1491-
}
1492-
}
1493-
1494-
els.siteFilter.addEventListener('change', event => {
1495-
state.selected = event.target.value;
1496-
renderTankRows();
1497-
updateButtonState();
1498-
});
1499-
els.refreshSiteBtn.addEventListener('click', () => {
1500-
if (!state.selected) {
1501-
showToast('Pick a site first.', true);
1502-
return;
1503-
}
1504-
triggerManualRefresh(state.selected);
1505-
});
1506-
els.refreshAllBtn.addEventListener('click', () => {
1507-
triggerManualRefresh(null);
1508-
});
1509-
15101327
refreshData();
15111328
})();
15121329
</script>

0 commit comments

Comments
 (0)