Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: forms share one submit flow, result line and field column

useSubmit holds the idle, sending, done and error state and the request
flow that six forms each wrote out; FormResult shows the success line and
the problem panel; FormStack is the column the link, claude-login,
inference and limits forms each styled by hand. The create-agent, link
account, backend-env and agent-input forms use the submit flow; the link,
claude-login, inference and limits forms use FormStack.
This commit is contained in:
iris 2026-11-06 18:47:34 +01:00 • committed by mara
commit 811b23cd6b
2 changed files with 517 additions and 377 deletions

View file

@ -13,5 +13,4 @@
}
.ui-agent-input-sent {
margin-block-start: 0.25rem;
color: var(--green);
}

View file

@ -5,42 +5,27 @@
// sender from the gateway, not from this request).
import { useState } from "preact/hooks";
import { ApiErrorPanel } from "@hive/shared/api-error-panel.js";
import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js";
import { TextField } from "../../ui/text-field/TextField.js";
import { Button } from "../../ui/button/Button.js";
import { Hint } from "../../ui/hint/Hint.js";
import { useSubmit } from "../../ui/submit/useSubmit.js";
import "./AgentInputForm.css";
type SubmitState =
| { status: "idle" }
| { status: "submitting" }
| { status: "sent" }
| { status: "error"; problem: ProblemDetails };
export function AgentInputForm({ agentName }: { agentName: string }) {
const [body, setBody] = useState("");
const [result, setResult] = useState<SubmitState>({ status: "idle" });
const { state, submitting, run } = useSubmit();
async function submit(e: Event) {
function submit(e: Event) {
e.preventDefault();
setResult({ status: "submitting" });
try {
const r = await fetch(
`/api/agents/${encodeURIComponent(agentName)}/input`,
{
void run(
() =>
fetch(`/api/agents/${encodeURIComponent(agentName)}/input`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ body }),
},
);
if (!r.ok) {
setResult({ status: "error", problem: await readApiError(r) });
return;
}
setResult({ status: "sent" });
setBody("");
} catch (err) {
setResult({ status: "error", problem: { detail: String(err) } });
}
}),
{ onDone: () => setBody("") },
);
}
return (
@ -53,17 +38,17 @@ export function AgentInputForm({ agentName }: { agentName: string }) {
required
onInput={setBody}
/>
<Button
variant="primary"
type="submit"
disabled={result.status === "submitting"}
>
{result.status === "submitting" ? "sending…" : "send"}
<Button variant="primary" type="submit" disabled={submitting}>
{submitting ? "sending…" : "send"}
</Button>
</form>
{result.status === "sent" && <p class="ui-agent-input-sent">sent</p>}
{result.status === "error" && (
<ApiErrorPanel context="failed to send" problem={result.problem} />
{state.status === "done" && (
<Hint tone="ok" class="ui-agent-input-sent">
sent
</Hint>
)}
{state.status === "error" && (
<ApiErrorPanel context="failed to send" problem={state.problem} />
)}
</div>
);