imaging: persist tile expanded state across page refresh

localStorage-backed set of serials at key 'imaging-expanded'. On
DOMContentLoaded, walk each .imaging-card; if its data-serial is in
the set, set card.open=true. On every <details> toggle, update the
set. Refresh no longer collapses the tile the operator was looking
at.

Per-browser state (localStorage), no server round-trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-15 07:29:45 -04:00
parent b9f66687ac
commit 036090348c

View File

@@ -64,6 +64,7 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
{% set border = 'danger' if is_failed else ('success' if is_done else 'primary') %} {% set border = 'danger' if is_failed else ('success' if is_done else 'primary') %}
{% set friendly = stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %} {% set friendly = stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %}
<details class="card border-{{ border }} mb-2 shadow-sm imaging-card" <details class="card border-{{ border }} mb-2 shadow-sm imaging-card"
data-serial="{{ s.serial }}"
data-filter="{{ s.serial|lower }} {{ (s.hostname_target or '')|lower }} {{ (s.pctype or '')|lower }} {{ (s.machinenumber or '')|lower }} {{ (s.intune_device_id or '')|lower }} {{ friendly[0]|lower }} stage-{{ stage_idx }} {{ (s.status or 'in_progress')|lower }}"> data-filter="{{ s.serial|lower }} {{ (s.hostname_target or '')|lower }} {{ (s.pctype or '')|lower }} {{ (s.machinenumber or '')|lower }} {{ (s.intune_device_id or '')|lower }} {{ friendly[0]|lower }} stage-{{ stage_idx }} {{ (s.status or 'in_progress')|lower }}">
<summary class="card-body py-2" style="cursor:pointer; list-style:none;"> <summary class="card-body py-2" style="cursor:pointer; list-style:none;">
<div class="d-flex flex-wrap gap-3 align-items-center"> <div class="d-flex flex-wrap gap-3 align-items-center">
@@ -340,6 +341,32 @@ window.addEventListener('DOMContentLoaded', function() {
}); });
}); });
// Persist tile expanded/collapsed state across page refresh via
// localStorage. Set of expanded serials lives at 'imaging-expanded'.
(function() {
var KEY = 'imaging-expanded';
function loadSet() {
try { return new Set(JSON.parse(localStorage.getItem(KEY) || '[]')); }
catch (e) { return new Set(); }
}
function saveSet(set) {
try { localStorage.setItem(KEY, JSON.stringify(Array.from(set))); }
catch (e) {}
}
window.addEventListener('DOMContentLoaded', function() {
var expanded = loadSet();
document.querySelectorAll('.imaging-card').forEach(function(card) {
var serial = card.getAttribute('data-serial');
if (serial && expanded.has(serial)) card.open = true;
card.addEventListener('toggle', function() {
var s = loadSet();
if (card.open) s.add(serial); else s.delete(serial);
saveSet(s);
});
});
});
})();
// Client-side filter: hide imaging-card elements whose data-filter doesn't // Client-side filter: hide imaging-card elements whose data-filter doesn't
// match the search query. Live as user types. Pauses auto-reload while // match the search query. Live as user types. Pauses auto-reload while
// the input is focused or non-empty so typing isn't interrupted by refresh. // the input is focused or non-empty so typing isn't interrupted by refresh.