Add stop-all buttons to target sections, perf chart color reset, and TODO
- Add stop-all buttons to LED targets and KC targets section headers (visible only when targets are running, uses headerExtra on CardSection) - Add reset ability to performance chart color pickers (removes custom color from localStorage and reverts to default) - Remove CODEBASE_REVIEW.md - Add prioritized TODO.md with P1/P2/P3 feature roadmap Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,8 +33,8 @@ import { updateSubTabHash, updateTabBadge } from './tabs.js';
|
||||
// ── Card section instances ──
|
||||
const csDevices = new CardSection('led-devices', { titleKey: 'targets.section.devices', gridClass: 'devices-grid', addCardOnclick: "showAddDevice()", keyAttr: 'data-device-id' });
|
||||
const csColorStrips = new CardSection('led-css', { titleKey: 'targets.section.color_strips', gridClass: 'devices-grid', addCardOnclick: "showCSSEditor()", keyAttr: 'data-css-id' });
|
||||
const csLedTargets = new CardSection('led-targets', { titleKey: 'targets.section.targets', gridClass: 'devices-grid', addCardOnclick: "showTargetEditor()", keyAttr: 'data-target-id' });
|
||||
const csKCTargets = new CardSection('kc-targets', { titleKey: 'targets.section.key_colors', gridClass: 'devices-grid', addCardOnclick: "showKCEditor()", keyAttr: 'data-kc-target-id' });
|
||||
const csLedTargets = new CardSection('led-targets', { titleKey: 'targets.section.targets', gridClass: 'devices-grid', addCardOnclick: "showTargetEditor()", keyAttr: 'data-target-id', headerExtra: `<button class="btn btn-sm btn-danger" onclick="event.stopPropagation(); stopAllLedTargets()" data-stop-all="led">${ICON_STOP}</button>` });
|
||||
const csKCTargets = new CardSection('kc-targets', { titleKey: 'targets.section.key_colors', gridClass: 'devices-grid', addCardOnclick: "showKCEditor()", keyAttr: 'data-kc-target-id', headerExtra: `<button class="btn btn-sm btn-danger" onclick="event.stopPropagation(); stopAllKCTargets()" data-stop-all="kc">${ICON_STOP}</button>` });
|
||||
const csPatternTemplates = new CardSection('kc-patterns', { titleKey: 'targets.section.pattern_templates', gridClass: 'templates-grid', addCardOnclick: "showPatternTemplateEditor()", keyAttr: 'data-pattern-template-id' });
|
||||
|
||||
// Re-render targets tab when language changes (only if tab is active)
|
||||
@@ -621,6 +621,14 @@ export async function loadTargetsTab() {
|
||||
CardSection.bindAll([csDevices, csColorStrips, csLedTargets, csKCTargets, csPatternTemplates]);
|
||||
}
|
||||
|
||||
// Show/hide stop-all buttons based on running state
|
||||
const ledRunning = ledTargets.some(t => t.state && t.state.processing);
|
||||
const kcRunning = kcTargets.some(t => t.state && t.state.processing);
|
||||
const ledStopBtn = container.querySelector('[data-stop-all="led"]');
|
||||
const kcStopBtn = container.querySelector('[data-stop-all="kc"]');
|
||||
if (ledStopBtn) ledStopBtn.style.display = ledRunning ? '' : 'none';
|
||||
if (kcStopBtn) kcStopBtn.style.display = kcRunning ? '' : 'none';
|
||||
|
||||
// Patch volatile metrics in-place (avoids full card replacement on polls)
|
||||
for (const tgt of ledTargets) {
|
||||
if (tgt.state && tgt.state.processing) _patchTargetMetrics(tgt);
|
||||
@@ -983,6 +991,40 @@ export async function stopTargetProcessing(targetId) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function stopAllLedTargets() {
|
||||
await _stopAllByType('led');
|
||||
}
|
||||
|
||||
export async function stopAllKCTargets() {
|
||||
await _stopAllByType('key_colors');
|
||||
}
|
||||
|
||||
async function _stopAllByType(targetType) {
|
||||
try {
|
||||
const [targetsResp, statesResp] = await Promise.all([
|
||||
fetchWithAuth('/picture-targets'),
|
||||
fetchWithAuth('/picture-targets/batch/states'),
|
||||
]);
|
||||
const data = await targetsResp.json();
|
||||
const statesData = statesResp.ok ? await statesResp.json() : { states: {} };
|
||||
const states = statesData.states || {};
|
||||
const typeMatch = targetType === 'led' ? t => t.target_type === 'led' || t.target_type === 'wled' : t => t.target_type === targetType;
|
||||
const running = (data.targets || []).filter(t => typeMatch(t) && states[t.id]?.processing);
|
||||
if (!running.length) {
|
||||
showToast(t('targets.stop_all.none_running'), 'info');
|
||||
return;
|
||||
}
|
||||
await Promise.all(running.map(t =>
|
||||
fetchWithAuth(`/picture-targets/${t.id}/stop`, { method: 'POST' }).catch(() => {})
|
||||
));
|
||||
showToast(t('targets.stop_all.stopped', { count: running.length }), 'success');
|
||||
loadTargetsTab();
|
||||
} catch (error) {
|
||||
if (error.isAuth) return;
|
||||
showToast(t('targets.stop_all.error'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
export async function startTargetOverlay(targetId) {
|
||||
await _targetAction(async () => {
|
||||
const response = await fetchWithAuth(`/picture-targets/${targetId}/overlay/start`, {
|
||||
|
||||
Reference in New Issue
Block a user