Updates tab (apt list/refresh/upgrade/changelog, reboot flag) on a new background tasks package with live WS streaming; header power button with hostname confirmation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
41c2f05535
commit
acb11193b9
@@ -0,0 +1,47 @@
|
||||
import { useState } from 'react'
|
||||
import { api } from './api'
|
||||
|
||||
// Header power control: a small button, a dialog that needs the hostname typed back.
|
||||
export default function Power({ host, rebootNeeded }: { host: string; rebootNeeded?: boolean }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [typed, setTyped] = useState('')
|
||||
const [busy, setBusy] = useState('')
|
||||
const [err, setErr] = useState('')
|
||||
const ok = typed.trim() === host
|
||||
|
||||
async function go(action: 'reboot' | 'poweroff') {
|
||||
setBusy(action); setErr('')
|
||||
try { await api.power(action, typed.trim()); setBusy('sent') }
|
||||
catch (e) { setErr(e instanceof Error ? e.message : 'failed'); setBusy('') }
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button className={'icon-btn power' + (rebootNeeded ? ' attn' : '')} title={rebootNeeded ? 'reboot required' : 'power'} onClick={() => { setOpen(true); setTyped(''); setBusy(''); setErr('') }}>⏻</button>
|
||||
{open && (
|
||||
<div className="modal-back" onClick={() => busy !== 'sent' && setOpen(false)}>
|
||||
<div className="modal" onClick={(e) => e.stopPropagation()}>
|
||||
<h3>Power · {host}</h3>
|
||||
{rebootNeeded && <div className="notice">A reboot is pending from package updates.</div>}
|
||||
{busy === 'sent' ? (
|
||||
<div className="muted">Command sent. The console will reconnect when the host is back.</div>
|
||||
) : (
|
||||
<>
|
||||
<label className="muted">Type the hostname to confirm
|
||||
<input autoFocus value={typed} onChange={(e) => setTyped(e.target.value)} placeholder={host} />
|
||||
</label>
|
||||
{err && <div className="error">{err}</div>}
|
||||
<div className="svc-actions">
|
||||
<button className="btn on" disabled={!ok || !!busy} onClick={() => go('reboot')}>{busy === 'reboot' ? '…' : 'Reboot'}</button>
|
||||
<button className="btn danger" disabled={!ok || !!busy} onClick={() => go('poweroff')}>{busy === 'poweroff' ? '…' : 'Shut down'}</button>
|
||||
<span className="spacer" />
|
||||
<button className="btn" onClick={() => setOpen(false)}>Cancel</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user