Phase 9: network management + stack delete in UI (0.9.0)

- Networks: network_service (list w/ subnet/containers/in-use/owning-stack,
  create bridge/macvlan/ipvlan/overlay + optional subnet/gateway/internal,
  delete with default-network guard, prune) + routers/networks.py; real
  Networks page replaces the placeholder.
- Fix: local stacks can now be deleted from the UI — Delete button on stack
  detail (with optional keep-files-on-disk) and a trash action on stack cards,
  via a shared ConfirmDialog. (Backend DELETE existed; no UI surfaced it.)

Verified: py_compile, frontend tsc build, live network list smoke test
(defaults flagged, compose nets + in-use detected); main 104 routes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
menzeljandClaude Opus 4.8 committed 2026-06-07 22:37:30 +00:00
1 parent 5cd55382ed
commit a4e26f880a
12 files changed
+641 -10

No files matched your search

@@ -0,0 +1,46 @@
import type { ReactNode } from "react";
import { Button } from "@/components/ui";
export function ConfirmDialog({
title,
message,
confirmLabel = "Confirm",
danger = false,
busy = false,
onConfirm,
onCancel,
children,
}: {
title: string;
message?: string;
confirmLabel?: string;
danger?: boolean;
busy?: boolean;
onConfirm: () => void;
onCancel: () => void;
children?: ReactNode;
}) {
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
onClick={() => !busy && onCancel()}
>
<div
className="w-full max-w-md rounded-xl border border-slate-200 bg-card p-5 shadow-xl dark:border-slate-700 dark:bg-card-dark"
onClick={(e) => e.stopPropagation()}
>
<h2 className="text-lg font-semibold">{title}</h2>
{message && <p className="mt-2 text-sm text-slate-500">{message}</p>}
{children && <div className="mt-3">{children}</div>}
<div className="mt-4 flex justify-end gap-2">
<Button variant="outline" onClick={onCancel} disabled={busy}>
Cancel
</Button>
<Button variant={danger ? "danger" : "primary"} onClick={onConfirm} loading={busy}>
{confirmLabel}
</Button>
</div>
</div>
</div>
);
}