swarm ui: a log in button in the claude login row of an agent's settings
An agent with no stored login, or one to log in again, can be logged in from the settings panel instead of waiting for its turns to fail with a login needed badge first. The button opens the same dialog as the card's.
This commit is contained in:
parent
c7d7f0df55
commit
e9ddfd61ec
1 changed files with 34 additions and 5 deletions
|
|
@ -1,13 +1,15 @@
|
|||
// <AgentClaudeLogin> — the swarm's stored claude login for one agent: when it
|
||||
// was written (`GET …/claude-login`, read from the secret store's metadata),
|
||||
// or that none is, and a delete that removes every version of it
|
||||
// (`DELETE …/claude-login/stored`) after a confirmation.
|
||||
// or that none is, a button that logs the agent in (or in again) without
|
||||
// waiting for its turns to fail first, and a delete that removes every version
|
||||
// of it (`DELETE …/claude-login/stored`) after a confirmation.
|
||||
//
|
||||
// Its state belongs to one agent: callers key it by agent name.
|
||||
import { useCallback, useEffect, useState } from "preact/hooks";
|
||||
import { ApiErrorPanel } from "@hive/shared/api-error-panel.js";
|
||||
import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js";
|
||||
import { Badge } from "@hive/shared/badge.js";
|
||||
import { ClaudeLoginDialog } from "../claude-login/ClaudeLoginDialog.js";
|
||||
import { ConfirmDialog } from "../../ui/confirm-dialog/ConfirmDialog.js";
|
||||
import { Hint } from "../../ui/hint/Hint.js";
|
||||
import { RelativeTime } from "../../ui/relative-time/RelativeTime.js";
|
||||
|
|
@ -26,6 +28,7 @@ export function AgentClaudeLogin({ agent }: { agent: string }) {
|
|||
const [confirming, setConfirming] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [deleteError, setDeleteError] = useState<ProblemDetails | null>(null);
|
||||
const [loggingIn, setLoggingIn] = useState(false);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
try {
|
||||
|
|
@ -75,17 +78,37 @@ export function AgentClaudeLogin({ agent }: { agent: string }) {
|
|||
return errorPanel ?? <Hint as="span">…</Hint>;
|
||||
}
|
||||
const at = storedAtMs(login);
|
||||
const loginBadge = (
|
||||
<Badge
|
||||
variant="quiet"
|
||||
value={login.stored_at === null ? "log in" : "log in again"}
|
||||
title={`log ${agent} in to claude from here`}
|
||||
onClick={() => setLoggingIn(true)}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{errorPanel}
|
||||
{loggingIn ? (
|
||||
<ClaudeLoginDialog
|
||||
agent={agent}
|
||||
onClose={() => {
|
||||
setLoggingIn(false);
|
||||
void load();
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{login.stored_at === null ? (
|
||||
<Hint as="span">none stored</Hint>
|
||||
<>
|
||||
<Hint as="span">none stored</Hint> {loginBadge}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span title={login.stored_at}>
|
||||
stored{" "}
|
||||
{at === null ? login.stored_at : <RelativeTime epochMs={at} />}
|
||||
</span>{" "}
|
||||
{loginBadge}{" "}
|
||||
<Badge
|
||||
variant="quiet"
|
||||
value="delete login"
|
||||
|
|
|
|||
Loading…
Reference in a new issue