feat(api): parallel group sends and batch identify
- asyncio.gather for group brightness and driver-config Wi-Fi pushes - Batch identify envelope for group members Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -326,6 +326,16 @@ function renderGroupsList(groups) {
|
||||
}
|
||||
});
|
||||
|
||||
const identifyBtn = document.createElement('button');
|
||||
identifyBtn.className = 'btn btn-secondary btn-small';
|
||||
identifyBtn.type = 'button';
|
||||
identifyBtn.textContent = 'Identify';
|
||||
identifyBtn.title =
|
||||
'Identify all devices in this group at once (red blink at 10 Hz)';
|
||||
identifyBtn.addEventListener('click', async () => {
|
||||
await identifyGroupById(gid);
|
||||
});
|
||||
|
||||
const delBtn = document.createElement('button');
|
||||
delBtn.className = 'btn btn-danger btn-small';
|
||||
delBtn.textContent = 'Delete';
|
||||
@@ -348,11 +358,40 @@ function renderGroupsList(groups) {
|
||||
row.appendChild(editBtn);
|
||||
row.appendChild(brightBtn);
|
||||
row.appendChild(applyBtn);
|
||||
row.appendChild(identifyBtn);
|
||||
row.appendChild(delBtn);
|
||||
container.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
async function identifyGroupById(gid) {
|
||||
if (!gid) return;
|
||||
try {
|
||||
const res = await fetch(`/groups/${encodeURIComponent(gid)}/identify`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { Accept: 'application/json' },
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) {
|
||||
alert(data.error || 'Identify failed');
|
||||
return;
|
||||
}
|
||||
const n = typeof data.sent === 'number' ? data.sent : 0;
|
||||
const errs = Array.isArray(data.errors) ? data.errors : [];
|
||||
const failed = errs.filter((e) => e && e.error).length;
|
||||
let msg = n ? `Identify sent to ${n} device(s).` : 'No devices received identify.';
|
||||
if (failed) {
|
||||
msg += ` ${failed} failed — see console for details.`;
|
||||
console.warn('Group identify errors', errs);
|
||||
}
|
||||
alert(msg);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert('Identify failed');
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const groupsBtn = document.getElementById('groups-btn');
|
||||
const groupsModal = document.getElementById('groups-modal');
|
||||
@@ -381,6 +420,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
const editIdentifyBtn = document.getElementById('edit-group-identify-btn');
|
||||
if (editIdentifyBtn) {
|
||||
editIdentifyBtn.addEventListener('click', async () => {
|
||||
const idInput = document.getElementById('edit-group-id');
|
||||
const gid = idInput && idInput.value;
|
||||
if (!gid) return;
|
||||
await identifyGroupById(gid);
|
||||
});
|
||||
}
|
||||
|
||||
const createHandler = async () => {
|
||||
const name = newNameInput && newNameInput.value.trim();
|
||||
if (!name) return;
|
||||
@@ -449,4 +498,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (editCloseBtn && editModal) {
|
||||
editCloseBtn.addEventListener('click', () => editModal.classList.remove('active'));
|
||||
}
|
||||
|
||||
window.openDeviceGroupsModal = async () => {
|
||||
const gm = document.getElementById('groups-modal');
|
||||
if (!gm) return;
|
||||
gm.classList.add('active');
|
||||
try {
|
||||
await loadGroupsModal();
|
||||
} catch (e) {
|
||||
console.error('openDeviceGroupsModal', e);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user