Bump version to 1.0.9
Fix Wake-on-LAN: set SO_BROADCAST on UDP socket, send 3 magic packets, expose broadcast_addr and wake timeout fields in UI, add Test Wake endpoint, surface send errors in job status, bump default wake timeout to 180s.
This commit is contained in:
@@ -26,7 +26,7 @@ import {
|
||||
import { EmptyState } from '@/components/ui/EmptyState';
|
||||
import { CopyButton } from '@/components/ui/CopyButton';
|
||||
import { Card } from '@/components/ui/Card';
|
||||
import { Pencil, Trash2, Plus, Server } from 'lucide-react';
|
||||
import { Pencil, Trash2, Plus, Server, Zap } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -39,6 +39,7 @@ type MachineForm = {
|
||||
ssh_key_id: number | null;
|
||||
mac_address: string;
|
||||
wol_enabled: boolean;
|
||||
broadcast_addr: string;
|
||||
wake_timeout_seconds: number;
|
||||
wake_check_interval_seconds: number;
|
||||
};
|
||||
@@ -52,7 +53,8 @@ const defaultForm: MachineForm = {
|
||||
ssh_key_id: null,
|
||||
mac_address: '',
|
||||
wol_enabled: false,
|
||||
wake_timeout_seconds: 120,
|
||||
broadcast_addr: '',
|
||||
wake_timeout_seconds: 180,
|
||||
wake_check_interval_seconds: 5,
|
||||
};
|
||||
|
||||
@@ -94,8 +96,9 @@ export default function Machines() {
|
||||
ssh_key_id: m.ssh_key_id,
|
||||
mac_address: m.mac_address || '',
|
||||
wol_enabled: m.wol_enabled,
|
||||
wake_timeout_seconds: m.wake_timeout_seconds,
|
||||
wake_check_interval_seconds: m.wake_check_interval_seconds,
|
||||
broadcast_addr: m.broadcast_addr || '',
|
||||
wake_timeout_seconds: m.wake_timeout_seconds || 180,
|
||||
wake_check_interval_seconds: m.wake_check_interval_seconds || 5,
|
||||
});
|
||||
setModalOpen(true);
|
||||
}
|
||||
@@ -124,6 +127,7 @@ export default function Machines() {
|
||||
ssh_key_id: form.ssh_key_id,
|
||||
mac_address: form.mac_address || null,
|
||||
wol_enabled: Boolean(form.wol_enabled),
|
||||
broadcast_addr: form.broadcast_addr || null,
|
||||
wake_timeout_seconds: Number(form.wake_timeout_seconds),
|
||||
wake_check_interval_seconds: Number(form.wake_check_interval_seconds),
|
||||
};
|
||||
@@ -153,6 +157,15 @@ export default function Machines() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTestWol(m: Machine) {
|
||||
try {
|
||||
await api<{ ok: boolean; sent: number }>(`/api/machines/${m.id}/test-wol`, { method: 'POST' });
|
||||
toast.success(`Magic packet sent (${m.mac_address})`);
|
||||
} catch (e: unknown) {
|
||||
toast.error(`Wake failed: ${(e as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function keyLabel(id: number | null) {
|
||||
if (!id) return 'Server Key';
|
||||
const k = sshKeys.find(k => k.id === id);
|
||||
@@ -194,6 +207,7 @@ export default function Machines() {
|
||||
<TableHead>Host</TableHead>
|
||||
<TableHead>SSH Key</TableHead>
|
||||
<TableHead>WoL</TableHead>
|
||||
<TableHead>WoL Timeout</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead className="w-24">Actions</TableHead>
|
||||
</TableRow>
|
||||
@@ -217,6 +231,15 @@ export default function Machines() {
|
||||
<span className="text-fg-subtle text-xs">No</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{m.wol_enabled ? (
|
||||
<span className="text-xs text-fg-muted">
|
||||
{m.wake_timeout_seconds}s
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-fg-subtle text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<StatusBadge status={m.status} />
|
||||
</TableCell>
|
||||
@@ -230,6 +253,16 @@ export default function Machines() {
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
{m.wol_enabled && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={() => handleTestWol(m)}
|
||||
title="Test Wake-on-LAN"
|
||||
>
|
||||
<Zap className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
@@ -364,6 +397,60 @@ export default function Machines() {
|
||||
Enable Wake-on-LAN
|
||||
</Label>
|
||||
</div>
|
||||
{form.wol_enabled && (
|
||||
<div className="space-y-3 p-3 border border-border rounded-card bg-surface-raised">
|
||||
<p className="text-xs text-fg-subtle font-medium">Wake-on-LAN Settings</p>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="broadcast_addr">Broadcast Address</Label>
|
||||
<Input
|
||||
id="broadcast_addr"
|
||||
placeholder="255.255.255.255"
|
||||
value={form.broadcast_addr}
|
||||
onChange={e =>
|
||||
setForm({ ...form, broadcast_addr: e.target.value })
|
||||
}
|
||||
/>
|
||||
<p className="text-xs text-fg-subtle">
|
||||
Leave blank to use 255.255.255.255. Set to your subnet broadcast
|
||||
address if the server has multiple interfaces.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="wake_timeout_seconds">Wake timeout (s)</Label>
|
||||
<Input
|
||||
id="wake_timeout_seconds"
|
||||
type="number"
|
||||
min={10}
|
||||
max={600}
|
||||
value={form.wake_timeout_seconds}
|
||||
onChange={e =>
|
||||
setForm({ ...form, wake_timeout_seconds: Number(e.target.value) })
|
||||
}
|
||||
/>
|
||||
<p className="text-xs text-fg-subtle">
|
||||
HP Microservers typically need ~180s.
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="wake_check_interval_seconds">Check interval (s)</Label>
|
||||
<Input
|
||||
id="wake_check_interval_seconds"
|
||||
type="number"
|
||||
min={1}
|
||||
max={60}
|
||||
value={form.wake_check_interval_seconds}
|
||||
onChange={e =>
|
||||
setForm({ ...form, wake_check_interval_seconds: Number(e.target.value) })
|
||||
}
|
||||
/>
|
||||
<p className="text-xs text-fg-subtle">
|
||||
How often to poll SSH readiness.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user