Files
hamlab/web/src/Power.tsx
T

50 lines
2.3 KiB
TypeScript

import { useState } from 'react'
import { api } from './api'
import { Btn, Spinner } from './ui'
// Header power control: a small button, a dialog that needs the hostname typed back.
// `label` is what the user types (the machine name on a remote); `host` is what the node checks.
export default function Power({ host, label, rebootNeeded }: { host: string; label: string; rebootNeeded?: boolean }) {
const [open, setOpen] = useState(false)
const [typed, setTyped] = useState('')
const [sent, setSent] = useState<'' | 'reboot' | 'poweroff'>('')
const [err, setErr] = useState('')
const ok = typed.trim() === label
async function go(action: 'reboot' | 'poweroff') {
setErr('')
try { await api.power(action, host); setSent(action) }
catch (e) { setErr(e instanceof Error ? e.message : 'failed') }
}
return (
<>
<button className={'icon-btn power' + (rebootNeeded ? ' attn' : '')} title={rebootNeeded ? 'reboot required' : 'power'} onClick={() => { setOpen(true); setTyped(''); setSent(''); setErr('') }}>⏻</button>
{open && (
<div className="modal-back" onClick={() => !sent && setOpen(false)}>
<div className="modal" onClick={(e) => e.stopPropagation()}>
<h3>Power · {label}</h3>
{rebootNeeded && <div className="notice">A reboot is pending from package updates.</div>}
{sent ? (
<div className="muted"><Spinner /> {sent === 'reboot' ? 'Rebooting. The console will reconnect when the host is back.' : 'Shutting down. Power it back on by hand.'}</div>
) : (
<>
<label className="muted">Type <b>{label}</b> to confirm
<input autoFocus value={typed} onChange={(e) => setTyped(e.target.value)} placeholder={label} />
</label>
{err && <div className="error">{err}</div>}
<div className="svc-actions">
<Btn className="btn on" disabled={!ok} onClick={() => go('reboot')}>Reboot</Btn>
<Btn className="btn danger" disabled={!ok} onClick={() => go('poweroff')}>Shut down</Btn>
<span className="spacer" />
<button className="btn" onClick={() => setOpen(false)}>Cancel</button>
</div>
</>
)}
</div>
</div>
)}
</>
)
}