swarm-ui: extract ConfirmDialog, use it for the destroy confirm

mara, reviewing the swarm-ui destroy-trigger PR: "why the extra
styling? shouldnt there be a component that does this already?" There
wasnt one -- Dialog is deliberately content-agnostic (see its own
file-top comment), so the destroy confirm had grown its own
page-scoped .agents-destroy-confirm/-actions CSS for what is really a
generic "message + cancel/confirm button row" shape.

Extracted ui/confirm-dialog/ConfirmDialog.tsx: wraps Dialog, owns the
button row, leaves the message body to the caller via children.
AgentsPage now uses it instead of a bare Dialog + bespoke CSS; deleted
the now-unused AgentsPage.css.
This commit is contained in:
iris 2026-09-07 19:02:23 +02:00
commit 82a4324b17
4 changed files with 81 additions and 39 deletions

View file

@ -1,17 +0,0 @@
/* <AgentsPage> the destroy-confirm dialog's own layout. Everything
else on this page (the table, the wanted/destroy badges) draws chrome
from the shared `ui/` kit and needs nothing page-scoped; this file
exists only because the confirm dialog's copy + button row needed
somewhere to live, same reasoning as CreateAgentForm.css owning its
own layout next to the shared form-kit chrome it wraps. */
.agents-destroy-confirm {
display: flex;
flex-direction: column;
gap: 1em;
max-width: 28em;
}
.agents-destroy-confirm-actions {
display: flex;
justify-content: flex-end;
gap: 0.75em;
}

View file

@ -33,6 +33,7 @@ import { ApiErrorPanel } from "@hive/shared/api-error-panel.js";
import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js";
import { Badge, type BadgeTone } from "@hive/shared/badge.js";
import { Button } from "../ui/button/Button.js";
import { ConfirmDialog } from "../ui/confirm-dialog/ConfirmDialog.js";
import { Dialog } from "../ui/dialog/Dialog.js";
import { Panel } from "../ui/panel/Panel.js";
import { RelativeTime } from "../ui/relative-time/RelativeTime.js";
@ -43,7 +44,6 @@ import {
} from "../ui/refresh-interval/RefreshInterval.js";
import { Table, type TableColumn } from "../ui/table/Table.js";
import { CreateAgentForm } from "./CreateAgentForm.js";
import "./AgentsPage.css";
interface ConfigPrStatus {
pr_number: number;
@ -415,32 +415,23 @@ export function AgentsPage() {
>
<CreateAgentForm />
</Dialog>
<Dialog
<ConfirmDialog
open={destroyTarget !== null}
onClose={() => setDestroyTarget(null)}
label="destroy agent"
onCancel={() => setDestroyTarget(null)}
onConfirm={() => destroyTarget && void destroyAgent(destroyTarget)}
confirmLabel="destroy"
>
{destroyTarget ? (
<div class="agents-destroy-confirm">
<p>
Destroy <strong>{destroyTarget.name}</strong>? The hive tears its
container down on its next reconcile sweep. This is not reversible
from here bringing it back means redeploying via "+ agent",
which reuses the agent's existing identity, config repo, and forge
collaborator access rather than starting over.
</p>
<div class="agents-destroy-confirm-actions">
<Button onClick={() => setDestroyTarget(null)}>cancel</Button>
<Button
variant="primary"
onClick={() => void destroyAgent(destroyTarget)}
>
destroy
</Button>
</div>
</div>
<p>
Destroy <strong>{destroyTarget.name}</strong>? The hive tears its
container down on its next reconcile sweep. This is not reversible
from here bringing it back means redeploying via "+ agent", which
reuses the agent's existing identity, config repo, and forge
collaborator access rather than starting over.
</p>
) : null}
</Dialog>
</ConfirmDialog>
</Panel>
);
}