feat(ui): render the CCTV frame preview, source badge and summary from the store

The frame lifecycle keeps its request state in an object instead of the
image's dataset and publishes it; the panel binds the image's src, class
and data attributes and the wrapper's loading and has-frame classes from
it, so preload tokens, kept pixels on a failed refresh and clearing on a
camera change are unchanged. The source badge is the pure
presentCctvSourceBadge(), the live switch and the typed summary are
published too. The video surface still draws into the panel's canvas.
This commit is contained in:
Sameh Khamis committed 2026-10-30 21:54:42 -07:00
1 parent 6c7035f617
commit eef3dec759
10 files changed
+306 -177

No files matched your search

+7 -7
View File
@@ -55,8 +55,8 @@ test('a late image completion cannot replace a newer camera preview', (t) => {
assert.equal(requests[0].onload, null);
requests[1].onload();
stale();
assert.equal(controls._cctvFrame.src, 'second.jpg');
assert.equal(controls._cctvFrame.dataset.cameraId, 'b');
assert.equal(controls._frame.src, 'second.jpg');
assert.equal(controls._frame.cameraId, 'b');
});
test('failed refresh preserves settled pixels, but changing cameras clears them', (t) => {
@@ -65,11 +65,11 @@ test('failed refresh preserves settled pixels, but changing cameras clears them'
requests[0].onload();
controls._queueCctvFrame('refresh.jpg', 'a', false);
requests[1].onerror();
assert.equal(controls._cctvFrame.src, 'first.jpg');
assert.equal(controls._cctvFrameWrap.classList.contains('has-frame'), true);
assert.equal(controls._frame.src, 'first.jpg');
assert.equal(controls._frame.hasFrame, true);
controls._queueCctvFrame('other.jpg', 'b', true);
assert.equal(controls._cctvFrame.src, '');
assert.equal(controls._cctvFrameWrap.classList.contains('has-frame'), false);
assert.equal(controls._frame.src, '');
assert.equal(controls._frame.hasFrame, false);
});
test('destroy invalidates image callbacks and releases each subscription once', (t) => {
@@ -90,7 +90,7 @@ test('destroy invalidates image callbacks and releases each subscription once',
assert.equal(unsubscribed, 2);
assert.equal(requests[0].onload, null);
assert.equal(requests[0].onerror, null);
assert.equal(controls._cctvFrame.src, '');
assert.equal(controls._frame.src, '');
controls._queueCctvFrame('late.jpg', 'b', true);
assert.equal(requests.length, 1);
});