Bump version to 1.0.10

Smart WoL: TCP pre-check before sending magic packet (3s timeout).
Machine status updates via SSE: online/offline tracked in DB and
broadcast to all connected browser tabs in real-time.
- Pre-check: if machine already reachable, skip WoL and mark online
- WoL path: send 3 magic packets, wait for SSH, mark online/offline
- Backend: setMachineStatus() helper + machine_status SSE event
- Frontend: subscribeMachineStatus() SSE helper for Machines + Dashboard
- IsReachable() helper in wol package for TCP reachability checks
This commit is contained in:
2026-07-08 19:56:08 -04:00
parent ad3e879c42
commit a77f84ad34
8 changed files with 166 additions and 35 deletions
+22
View File
@@ -0,0 +1,22 @@
export interface MachineStatusEvent {
type: 'machine_status';
machine_id: number;
status: string;
key?: string;
value?: string;
}
export function subscribeMachineStatus(
onUpdate: (evt: MachineStatusEvent) => void
): () => void {
const es = new EventSource('/api/jobs/stream');
es.addEventListener('machine_status', (ev) => {
try {
const data = JSON.parse((ev as MessageEvent).data);
onUpdate(data as MachineStatusEvent);
} catch {
// ignore parse errors
}
});
return () => es.close();
}
+12
View File
@@ -11,6 +11,7 @@ import { EmptyState } from '@/components/ui/EmptyState';
import { Skeleton } from '@/components/ui/Skeleton';
import { statusVariant, statusLabel } from '@/lib/status';
import { formatRelativeTime } from '@/lib/utils';
import { subscribeMachineStatus } from '@/lib/sse';
export default function Dashboard() {
const [machines, setMachines] = useState<Machine[]>([]);
@@ -33,6 +34,17 @@ export default function Dashboard() {
.finally(() => setLoading(false));
}, []);
useEffect(() => {
const unsub = subscribeMachineStatus((evt) => {
setMachines((prev) =>
prev.map((m) =>
m.id === evt.machine_id ? { ...m, status: evt.status } : m
)
);
});
return unsub;
}, []);
const pairName = (id: number) => pairs.find(p => p.id === id)?.name ?? `Pair ${id}`;
const online = machines.filter(m => m.status.startsWith('online')).length;
+12
View File
@@ -29,6 +29,7 @@ import { Card } from '@/components/ui/Card';
import { Pencil, Trash2, Plus, Server, Zap } from 'lucide-react';
import { toast } from 'sonner';
import { cn } from '@/lib/utils';
import { subscribeMachineStatus } from '@/lib/sse';
type MachineForm = {
id: number | undefined;
@@ -70,6 +71,17 @@ export default function Machines() {
load();
}, []);
useEffect(() => {
const unsub = subscribeMachineStatus((evt) => {
setMachines((prev) =>
prev.map((m) =>
m.id === evt.machine_id ? { ...m, status: evt.status } : m
)
);
});
return unsub;
}, []);
async function load() {
try {
const [ms, ks] = await Promise.all([