Overlay: fix 404, crash on repeat, missing edge test colors, device reset on stop

- Target overlay works without active processing: route pre-loads calibration
  and display info from the CSS store, passes to processor as fallback
- Fix server crash on repeated overlay: replace per-window tk.Tk() with single
  persistent hidden root; each overlay is a Toplevel child dispatched via
  root.after() — eliminates Tcl interpreter crashes on Windows
- Fix edge test colors not lighting up: always call set_test_mode regardless
  of processing state (was guarded by 'not proc.is_running'); pass calibration
  so _send_test_pixels knows which LEDs map to which edges
- Fix device reset on overlay stop: keep idle serial client cached after
  clearing test mode; start_processing() already closes it before connecting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 17:16:10 +03:00
parent a3aeafef13
commit 018bedf9f6
7 changed files with 349 additions and 476 deletions

View File

@@ -222,3 +222,41 @@ export async function deleteColorStrip(cssId) {
showToast('Failed to delete color strip source', 'error');
}
}
/* ── Overlay ──────────────────────────────────────────────────── */
export async function startCSSOverlay(cssId) {
try {
const response = await fetchWithAuth(`/color-strip-sources/${cssId}/overlay/start`, {
method: 'POST',
});
if (response.ok) {
showToast(t('overlay.started'), 'success');
if (window.loadTargetsTab) window.loadTargetsTab();
} else {
const error = await response.json();
showToast(t('overlay.error.start') + ': ' + error.detail, 'error');
}
} catch (error) {
if (error.isAuth) return;
showToast(t('overlay.error.start'), 'error');
}
}
export async function stopCSSOverlay(cssId) {
try {
const response = await fetchWithAuth(`/color-strip-sources/${cssId}/overlay/stop`, {
method: 'POST',
});
if (response.ok) {
showToast(t('overlay.stopped'), 'success');
if (window.loadTargetsTab) window.loadTargetsTab();
} else {
const error = await response.json();
showToast(t('overlay.error.stop') + ': ' + error.detail, 'error');
}
} catch (error) {
if (error.isAuth) return;
showToast(t('overlay.error.stop'), 'error');
}
}