({ user, onClose }: { user: OrgUser; onClose: () => void })
| 365 | <Label>Username</Label> |
| 366 | <Input value={username} onChange={(e) => setUsername(e.target.value)} className="font-mono" /> |
| 367 | </div> |
| 368 | </div> |
| 369 | <div className="space-y-1"> |
| 370 | <Label>Password</Label> |
| 371 | <Input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> |
| 372 | </div> |
| 373 | <div className="space-y-1"> |
| 374 | <Label>Max vCPUs (0 = unbounded)</Label> |
| 375 | <Input type="number" min={0} value={maxVCPUs} onChange={(e) => setMaxVCPUs(e.target.value)} /> |
| 376 | </div> |
| 377 | <div className="flex items-center gap-6"> |
| 378 | <label className="flex items-center gap-2 text-sm"> |
| 379 | <Switch checked={passthrough} onCheckedChange={setPassthrough} /> Passthrough |
| 380 | </label> |
| 381 | </div> |
| 382 | {err && <p className="text-xs text-destructive">{err}</p>} |
| 383 | </div> |
| 384 | <DialogFooter> |
| 385 | <Button variant="outline" size="sm" onClick={onClose}> |
| 386 | Cancel |
| 387 | </Button> |
| 388 | <Button size="sm" onClick={submit} disabled={create.isPending || !org || !username || !password}> |
| 389 | {create.isPending ? "Creating…" : "Create user"} |
| 390 | </Button> |
| 391 | </DialogFooter> |
| 392 | </DialogContent> |
| 393 | </Dialog> |
| 394 | ); |
| 395 | } |
| 396 | |
| 397 | function EditUserDialog({ user, orgLabel, onClose }: { user: OrgUser; orgLabel?: string; onClose: () => void }) { |
| 398 | const update = useUpdateUser(); |
| 399 | const [password, setPassword] = useState(""); |
| 400 | const [passthrough, setPassthrough] = useState(user.passthrough); |
| 401 | const [maxVCPUs, setMaxVCPUs] = useState(String(user.max_vcpus)); |
| 402 | const [err, setErr] = useState<string | null>(null); |
| 403 | |
| 404 | const submit = async () => { |
| 405 | setErr(null); |
| 406 | try { |
| 407 | await update.mutateAsync({ |
| 408 | org: user.org_id, |
| 409 | username: user.username, |
| 410 | body: { |
| 411 | ...(password ? { password } : {}), |
| 412 | passthrough, |
| 413 | max_vcpus: Number(maxVCPUs) || 0, |
| 414 | }, |
| 415 | }); |
| 416 | onClose(); |
| 417 | } catch (e) { |
| 418 | setErr(e instanceof Error ? e.message : "Update failed"); |
| 419 | } |
| 420 | }; |
| 421 | |
| 422 | return ( |
| 423 | <Dialog open onOpenChange={(o) => !o && onClose()}> |
| 424 | <DialogContent> |
nothing calls this directly
no test coverage detected