Complete QF100 ops commands and detail UI
This commit is contained in:
@ -181,6 +181,26 @@
|
||||
<span class="text-sm font-semibold text-slate-600">Export worker</span>
|
||||
<span id="export-worker" class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-bold text-slate-600">-</span>
|
||||
</div>
|
||||
<div class="rounded-lg border border-slate-200 bg-white p-4">
|
||||
<div class="mb-3 flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<p class="text-sm font-extrabold text-slate-950">Remote Actions</p>
|
||||
<p class="mt-0.5 text-xs text-slate-500">Send operational command to a selected soundbox</p>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-blue-700">settings_remote</span>
|
||||
</div>
|
||||
<label class="block">
|
||||
<span class="mb-1 block text-xs font-bold uppercase text-slate-500">Device</span>
|
||||
<select id="command-device-select" class="w-full rounded-lg border-slate-200 bg-white py-2 text-sm focus:border-blue-600 focus:ring-blue-600">
|
||||
<option value="">Select device</option>
|
||||
</select>
|
||||
</label>
|
||||
<button id="send-reboot-command" class="mt-3 inline-flex w-full items-center justify-center gap-2 rounded-lg border border-slate-200 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50" disabled>
|
||||
<span class="material-symbols-outlined text-[20px]">restart_alt</span>
|
||||
Reboot Device
|
||||
</button>
|
||||
<p id="command-status" class="mt-2 min-h-5 text-xs font-semibold text-slate-500"></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -346,6 +366,27 @@
|
||||
$("export-worker").className = `rounded-full px-2.5 py-1 text-xs font-bold ${worker?.enabled === false ? "bg-amber-50 text-amber-700" : "bg-emerald-50 text-emerald-700"}`;
|
||||
}
|
||||
|
||||
function renderCommandDevices() {
|
||||
const select = $("command-device-select");
|
||||
const rebootButton = $("send-reboot-command");
|
||||
if (!select || !rebootButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
const current = select.value;
|
||||
select.innerHTML = '<option value="">Select device</option>';
|
||||
state.devices.forEach((device) => {
|
||||
const option = document.createElement("option");
|
||||
option.value = device.id;
|
||||
option.textContent = `${device.device_code || device.serial_number || device.id} · ${device.serial_number || device.model || "soundbox"}`;
|
||||
select.appendChild(option);
|
||||
});
|
||||
if (current && state.devices.some((device) => device.id === current)) {
|
||||
select.value = current;
|
||||
}
|
||||
rebootButton.disabled = !select.value;
|
||||
}
|
||||
|
||||
function renderMqtt() {
|
||||
const list = $("mqtt-list");
|
||||
const messages = Array.isArray(state.mqtt?.last_messages) ? state.mqtt.last_messages : [];
|
||||
@ -373,6 +414,7 @@
|
||||
renderKpis();
|
||||
renderTable();
|
||||
renderOps();
|
||||
renderCommandDevices();
|
||||
renderMqtt();
|
||||
}
|
||||
|
||||
@ -517,9 +559,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function sendRebootCommand() {
|
||||
const select = $("command-device-select");
|
||||
const button = $("send-reboot-command");
|
||||
const status = $("command-status");
|
||||
const deviceId = select?.value || "";
|
||||
const device = state.devices.find((item) => item.id === deviceId);
|
||||
if (!deviceId || !button || !status) {
|
||||
return;
|
||||
}
|
||||
|
||||
button.disabled = true;
|
||||
button.classList.add("opacity-60");
|
||||
status.textContent = `Sending reboot to ${device?.device_code || device?.serial_number || deviceId}...`;
|
||||
status.className = "mt-2 min-h-5 text-xs font-semibold text-slate-500";
|
||||
try {
|
||||
const result = await api.createDeviceCommand(deviceId, {
|
||||
command: "device.reboot",
|
||||
payload: { requested_from: "soundbox_ops" }
|
||||
});
|
||||
const topic = result?.result_payload?.topic || "-";
|
||||
status.textContent = `Reboot command ${result.status || "queued"} · ${topic}`;
|
||||
status.className = "mt-2 min-h-5 text-xs font-semibold text-emerald-700";
|
||||
await refresh();
|
||||
} catch (error) {
|
||||
status.textContent = error?.message || "Unable to send reboot command.";
|
||||
status.className = "mt-2 min-h-5 text-xs font-semibold text-red-700";
|
||||
} finally {
|
||||
button.classList.remove("opacity-60");
|
||||
button.disabled = !select.value;
|
||||
}
|
||||
}
|
||||
|
||||
$("refresh-button").addEventListener("click", refresh);
|
||||
$("search-input").addEventListener("input", renderTable);
|
||||
$("status-filter").addEventListener("change", renderTable);
|
||||
$("command-device-select")?.addEventListener("change", () => {
|
||||
$("send-reboot-command").disabled = !$("command-device-select").value;
|
||||
$("command-status").textContent = "";
|
||||
});
|
||||
$("send-reboot-command")?.addEventListener("click", sendRebootCommand);
|
||||
$("logout-button").addEventListener("click", () => {
|
||||
api.clearToken();
|
||||
window.location.href = "/ui/admin-login";
|
||||
|
||||
Reference in New Issue
Block a user