mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 22:03:13 -06:00
fix(dashboard): liveness badge filter regression + list-view legibility
Two follow-ups from the alpha diagnosis: - FIX A (regression): filterDevices() compared badge TEXT to the option values 'online'/'offline', but the badge text is now "Healthy"/"Reconnecting"/"Offline" — so selecting a status filter matched nothing and emptied the dashboard. Now compares the liveness STATE via a data-liveness attribute, and the filter is upgraded to All / Healthy / Reconnecting / Offline (an admin can filter TO reconnecting devices — the point of the Degraded distinction). - FIX B (legibility): the list rendered liveness as a status-dot where healthy=green/offline=red were visually identical to the old indicator, so it didn't read as new. The list now renders the same device-status-badge PILL as device-detail (3 distinct colors; amber Reconnecting visible on the list), scoped with an is-liveness modifier so video-wall cards keep their dark "NxN wall" pill. Frontend-only. 14/14 filter+render tests; full ES-module parse clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a458c8f96a
commit
2772d1fc4d
|
|
@ -421,6 +421,19 @@ body {
|
|||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
/* Device cards render the reused liveness pill (.device-status-badge from device-detail), which brings
|
||||
its own bg/padding/shape — so neutralize the dark wrapper for those. Wall cards keep the dark pill
|
||||
above for their "NxN wall" label (they share .device-card-status but have no .is-liveness). */
|
||||
.device-card-status.is-liveness {
|
||||
background: none;
|
||||
backdrop-filter: none;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
/* Lift the list pill off the screenshot so it stays legible over any image. */
|
||||
.device-card-status.is-liveness .device-status-badge {
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
.device-card-select {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ function renderDeviceCard(device) {
|
|||
<span>${t('dashboard.no_preview')}</span>
|
||||
</div>`
|
||||
}
|
||||
<div class="device-card-status">
|
||||
${(() => { const b = livenessBadge(device); return `<span class="status-dot ${b.state}"></span><span>${esc(b.label)}</span>`; })()}
|
||||
<div class="device-card-status is-liveness">
|
||||
${(() => { const b = livenessBadge(device); return `<span class="device-status-badge ${b.state}" data-liveness="${b.state}">${esc(b.label)}</span>`; })()}
|
||||
</div>
|
||||
${device.status === 'provisioning' && device.pairing_code ? `
|
||||
<div style="position:absolute;bottom:8px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.85);color:#f59e0b;padding:4px 12px;border-radius:6px;font-size:13px;font-weight:600;letter-spacing:2px;font-family:monospace">
|
||||
|
|
@ -268,10 +268,11 @@ export function render(container) {
|
|||
<div id="dashStats" class="dash-stats-row" style="display:flex;gap:12px;margin-bottom:16px"></div>
|
||||
<div style="display:flex;gap:12px;margin-bottom:16px;align-items:center">
|
||||
<input type="text" id="deviceSearch" class="input" placeholder="${t('dashboard.search')}" style="max-width:300px">
|
||||
<select id="deviceFilter" class="input" style="width:140px;background:var(--bg-input)">
|
||||
<select id="deviceFilter" class="input" style="width:160px;background:var(--bg-input)">
|
||||
<option value="">${t('dashboard.all_status')}</option>
|
||||
<option value="online">${t('dashboard.online')}</option>
|
||||
<option value="offline">${t('dashboard.offline')}</option>
|
||||
<option value="healthy">${t('device.liveness.healthy')}</option>
|
||||
<option value="degraded">${t('device.liveness.degraded')}</option>
|
||||
<option value="offline">${t('device.liveness.offline')}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="groupedDevices"></div>
|
||||
|
|
@ -291,13 +292,16 @@ export function render(container) {
|
|||
|
||||
function filterDevices() {
|
||||
const search = document.getElementById('deviceSearch').value.toLowerCase();
|
||||
const status = document.getElementById('deviceFilter').value;
|
||||
// Compare against the liveness STATE ('healthy'|'degraded'|'offline'), NOT the display label:
|
||||
// the badge text is now "Healthy"/"Reconnecting"/"Offline", so the old text-vs-'online' compare
|
||||
// matched nothing and emptied the list. data-liveness carries the state for a robust match.
|
||||
const state = document.getElementById('deviceFilter').value;
|
||||
document.querySelectorAll('.device-card').forEach(card => {
|
||||
const name = card.querySelector('.device-card-name')?.textContent.toLowerCase() || '';
|
||||
const deviceStatus = card.querySelector('.device-card-status span:last-child')?.textContent || '';
|
||||
const cardState = card.querySelector('.device-card-status [data-liveness]')?.dataset.liveness || '';
|
||||
const matchSearch = !search || name.includes(search);
|
||||
const matchStatus = !status || deviceStatus === status;
|
||||
card.style.display = (matchSearch && matchStatus) ? '' : 'none';
|
||||
const matchState = !state || cardState === state;
|
||||
card.style.display = (matchSearch && matchState) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -362,7 +366,7 @@ export function render(container) {
|
|||
const cards = document.querySelectorAll(`[data-device-id="${data.device_id}"]`);
|
||||
cards.forEach(card => {
|
||||
const statusEl = card.querySelector('.device-card-status');
|
||||
if (statusEl) statusEl.innerHTML = `<span class="status-dot ${b.state}"></span><span>${esc(b.label)}</span>`;
|
||||
if (statusEl) statusEl.innerHTML = `<span class="device-status-badge ${b.state}" data-liveness="${b.state}">${esc(b.label)}</span>`;
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue