import { useState, useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import api from "../api/client"; const QUICK_ACTIONS = [ { label: "Ping", cmd: "ping", contents: {} }, { label: "Report Status", cmd: "system_info", contents: { action: "report_status" } }, { label: "Get Settings", cmd: "system_info", contents: { action: "get_full_settings" } }, { label: "Network Info", cmd: "system_info", contents: { action: "network_info" } }, { label: "Device Time", cmd: "system_info", contents: { action: "get_device_time" } }, { label: "Clock Time", cmd: "system_info", contents: { action: "get_clock_time" } }, { label: "Firmware Status", cmd: "system_info", contents: { action: "get_firmware_status" } }, { label: "List Melodies", cmd: "file_manager", contents: { action: "list_melodies" } }, { label: "Restart", cmd: "system", contents: { action: "restart" }, danger: true }, ]; const STATUS_STYLES = { success: { bg: "var(--success-bg)", color: "var(--success-text)" }, error: { bg: "var(--danger-bg)", color: "var(--danger-text)" }, pending: { bg: "var(--badge-blue-bg)", color: "var(--badge-blue-text)" }, timeout: { bg: "var(--danger-bg)", color: "var(--danger-text)" }, }; export default function CommandPanel() { const [searchParams] = useSearchParams(); const [devices, setDevices] = useState([]); const [selectedDevice, setSelectedDevice] = useState(searchParams.get("device") || ""); const [customCmd, setCustomCmd] = useState(""); const [customContents, setCustomContents] = useState("{}"); const [commands, setCommands] = useState([]); const [commandsTotal, setCommandsTotal] = useState(0); const [loading, setLoading] = useState(false); const [sending, setSending] = useState(false); const [error, setError] = useState(""); const [lastResponse, setLastResponse] = useState(null); const [expandedCmd, setExpandedCmd] = useState(null); useEffect(() => { api.get("/devices").then((data) => { setDevices(data.devices || []); if (!selectedDevice && data.devices?.length > 0) { setSelectedDevice(data.devices[0].device_id || ""); } }).catch(() => {}); }, []); useEffect(() => { if (selectedDevice) fetchCommands(); }, [selectedDevice]); const fetchCommands = async () => { setLoading(true); try { const data = await api.get(`/mqtt/commands/${selectedDevice}?limit=50`); setCommands(data.commands || []); setCommandsTotal(data.total || 0); } catch (err) { setError(err.message); } finally { setLoading(false); } }; const sendCommand = async (cmd, contents) => { if (!selectedDevice) { setError("Select a device first"); return; } setSending(true); setError(""); setLastResponse(null); try { const result = await api.post(`/mqtt/command/${selectedDevice}`, { cmd, contents }); setLastResponse(result); // Wait briefly then refresh commands to see response setTimeout(fetchCommands, 2000); } catch (err) { setError(err.message); } finally { setSending(false); } }; const sendCustomCommand = () => { if (!customCmd.trim()) { setError("Enter a command name"); return; } let parsed; try { parsed = JSON.parse(customContents); } catch { setError("Invalid JSON in contents"); return; } sendCommand(customCmd.trim(), parsed); }; const formatPayload = (jsonStr) => { if (!jsonStr) return null; try { return JSON.stringify(JSON.parse(jsonStr), null, 2); } catch { return jsonStr; } }; return (

Command Panel

{/* Device Selector */}
{error && (
{error}
)} {/* Quick Actions */}

Quick Actions

{QUICK_ACTIONS.map((action) => ( ))}
{/* Custom Command */}

Custom Command

setCustomCmd(e.target.value)} placeholder="e.g. system_info" className="w-full max-w-md px-3 py-2 rounded-md text-sm border" />