Users, with their own settings, and a list of where each is signed in
The login is a user name and a password. The old single password becomes the account named after the OS user on first boot, along with its sessions and the machine-wide look. Settings gains Users (add, remove, reset a password — your own password confirms) and Sessions (device, IP, last seen; revoke one or sign out everywhere else). Theme, accents and the dashboard layout follow the account; the refresh rate, graph history and alerts stay the machine's. Pairing a machine takes a user on it. Log lines name the actor. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
db214ebc2b
commit
2b54a06821
@@ -14,6 +14,7 @@ export default function Machines({ hub, onChanged, onOpen }: { hub: Me; onChange
|
||||
const [err, setErr] = useState('')
|
||||
const [name, setName] = useState('')
|
||||
const [url, setUrl] = useState('https://')
|
||||
const [user, setUser] = useState('')
|
||||
const [pw, setPw] = useState('')
|
||||
const [adding, setAdding] = useState(false)
|
||||
const [addErr, setAddErr] = useState('')
|
||||
@@ -30,9 +31,9 @@ export default function Machines({ hub, onChanged, onOpen }: { hub: Me; onChange
|
||||
e.preventDefault()
|
||||
setAdding(true); setAddErr('')
|
||||
try {
|
||||
const st = await api.addMachine(name.trim().toLowerCase(), url.trim(), pw)
|
||||
const st = await api.addMachine(name.trim().toLowerCase(), url.trim(), user.trim(), pw)
|
||||
toast(`${st.name} added${st.online ? ` · ${st.host} v${st.version}` : ' (offline)'}`)
|
||||
setName(''); setUrl('https://'); setPw('')
|
||||
setName(''); setUrl('https://'); setUser(''); setPw('')
|
||||
await load(); onChanged()
|
||||
} catch (e) { setAddErr(e instanceof Error ? e.message : 'failed') }
|
||||
finally { setAdding(false) }
|
||||
@@ -111,11 +112,12 @@ export default function Machines({ hub, onChanged, onOpen }: { hub: Me; onChange
|
||||
<form className="card addform" onSubmit={add}>
|
||||
<label>Name <input value={name} onChange={(e) => setName(e.target.value)} placeholder="grid" pattern="[a-z0-9][a-z0-9_\-]*" title="lower-case letters, digits, - and _" required /></label>
|
||||
<label>Address <input value={url} onChange={(e) => setUrl(e.target.value)} placeholder="https://10.0.0.214:8100" required /></label>
|
||||
<label>Its Ham Lab password <input type="password" value={pw} onChange={(e) => setPw(e.target.value)} autoComplete="off" required /></label>
|
||||
<label>A user on it <input value={user} onChange={(e) => setUser(e.target.value)} placeholder="core" autoComplete="off" spellCheck={false} autoCapitalize="off" /></label>
|
||||
<label>Their password <input type="password" value={pw} onChange={(e) => setPw(e.target.value)} autoComplete="off" required /></label>
|
||||
{addErr && <div className="error">{addErr}</div>}
|
||||
<div className="svc-actions">
|
||||
<button className="btn on" disabled={adding || !name || !pw}>{adding ? 'Pairing…' : 'Add machine'}</button>
|
||||
<span className="muted small">The password is used once to obtain an access token and is not stored. The machine's certificate is pinned on first contact.</span>
|
||||
<span className="muted small">The password is used once to obtain an access token and is not stored. The user may be left blank on a machine with a single account. The machine's certificate is pinned on first contact.</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user