From 29327d0f162809a457370a0f0fe804de0be2bc20 Mon Sep 17 00:00:00 2001 From: maziggy Date: Sun, 7 Dec 2025 10:42:41 +0000 Subject: [PATCH] Added power switch dropdown to printer card for offline printers --- frontend/src/pages/PrintersPage.tsx | 143 ++++ static/assets/index-CVJMI5JU.css | 1 - static/assets/index-Cx4S-qVJ.css | 1 + .../{index-DRrbGWbR.js => index-zCm77ErN.js} | 798 +++++++++--------- static/index.html | 4 +- 5 files changed, 545 insertions(+), 402 deletions(-) delete mode 100644 static/assets/index-CVJMI5JU.css create mode 100644 static/assets/index-Cx4S-qVJ.css rename static/assets/{index-DRrbGWbR.js => index-zCm77ErN.js} (76%) diff --git a/frontend/src/pages/PrintersPage.tsx b/frontend/src/pages/PrintersPage.tsx index b5149b178..cae865a70 100644 --- a/frontend/src/pages/PrintersPage.tsx +++ b/frontend/src/pages/PrintersPage.tsx @@ -17,6 +17,7 @@ import { PowerOff, Zap, Wrench, + ChevronDown, } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { api } from '../api/client'; @@ -710,11 +711,81 @@ function AddPrinterModal({ ); } +// Component to check if a printer is offline (for power dropdown) +function usePrinterOfflineStatus(printerId: number) { + const { data: status } = useQuery({ + queryKey: ['printerStatus', printerId], + queryFn: () => api.getPrinterStatus(printerId), + refetchInterval: 30000, + }); + return !status?.connected; +} + +// Power dropdown item for an offline printer +function PowerDropdownItem({ + printer, + plug, + onPowerOn, + isPowering, +}: { + printer: Printer; + plug: { id: number; name: string }; + onPowerOn: (plugId: number) => void; + isPowering: boolean; +}) { + const isOffline = usePrinterOfflineStatus(printer.id); + + // Fetch plug status + const { data: plugStatus } = useQuery({ + queryKey: ['smartPlugStatus', plug.id], + queryFn: () => api.getSmartPlugStatus(plug.id), + refetchInterval: 10000, + }); + + // Only show if printer is offline + if (!isOffline) { + return null; + } + + return ( +
+
+ {printer.name} + {plugStatus && ( + + {plugStatus.state || '?'} + + )} +
+ +
+ ); +} + export function PrintersPage() { const [showAddModal, setShowAddModal] = useState(false); const [hideDisconnected, setHideDisconnected] = useState(() => { return localStorage.getItem('hideDisconnectedPrinters') === 'true'; }); + const [showPowerDropdown, setShowPowerDropdown] = useState(false); + const [poweringOn, setPoweringOn] = useState(null); const queryClient = useQueryClient(); const { data: printers, isLoading } = useQuery({ @@ -722,6 +793,12 @@ export function PrintersPage() { queryFn: api.getPrinters, }); + // Fetch all smart plugs to know which printers have them + const { data: smartPlugs } = useQuery({ + queryKey: ['smart-plugs'], + queryFn: api.getSmartPlugs, + }); + // Fetch maintenance overview for all printers to show badges const { data: maintenanceOverview } = useQuery({ queryKey: ['maintenanceOverview'], @@ -742,6 +819,17 @@ export function PrintersPage() { {} as Record ) || {}; + // Create a map of printer_id -> smart plug + const smartPlugByPrinter = smartPlugs?.reduce( + (acc, plug) => { + if (plug.printer_id) { + acc[plug.printer_id] = plug; + } + return acc; + }, + {} as Record + ) || {}; + const addMutation = useMutation({ mutationFn: api.createPrinter, onSuccess: () => { @@ -750,6 +838,17 @@ export function PrintersPage() { }, }); + const powerOnMutation = useMutation({ + mutationFn: (plugId: number) => api.controlSmartPlug(plugId, 'on'), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['smart-plugs'] }); + setPoweringOn(null); + }, + onError: () => { + setPoweringOn(null); + }, + }); + const toggleHideDisconnected = () => { const newValue = !hideDisconnected; setHideDisconnected(newValue); @@ -773,6 +872,50 @@ export function PrintersPage() { /> Hide offline + {/* Power dropdown for offline printers with smart plugs */} + {hideDisconnected && Object.keys(smartPlugByPrinter).length > 0 && ( +
+ + {showPowerDropdown && ( + <> + {/* Backdrop to close dropdown */} +
setShowPowerDropdown(false)} + /> +
+
+ Offline printers with smart plugs +
+ {printers?.filter(p => smartPlugByPrinter[p.id]).map(printer => ( + { + setPoweringOn(plugId); + powerOnMutation.mutate(plugId); + }} + isPowering={poweringOn === smartPlugByPrinter[printer.id]?.id} + /> + ))} + {printers?.filter(p => smartPlugByPrinter[p.id]).length === 0 && ( +
+ No printers with smart plugs +
+ )} +
+ + )} +
+ )}