Files
stackpilot/frontend/src/App.tsx
T
menzeljandClaude Opus 4.8 a4e26f880a 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>
2026-06-07 22:37:30 +00:00

60 lines
2.2 KiB
TypeScript

import { useEffect } from "react";
import { BrowserRouter, Navigate, Outlet, Route, Routes } from "react-router-dom";
import { Layout } from "@/components/layout/Layout";
import { Login } from "@/pages/Login";
import { Dashboard } from "@/pages/Dashboard";
import { Stacks } from "@/pages/Stacks";
import { StackDetail } from "@/pages/StackDetail";
import { StackEditor } from "@/pages/StackEditor";
import { RemoteStackDetail } from "@/pages/RemoteStackDetail";
import { Images } from "@/pages/Images";
import { Templates } from "@/pages/Templates";
import { Settings } from "@/pages/Settings";
import { Audit } from "@/pages/Audit";
import { Networks } from "@/pages/Networks";
import { useAuthStore } from "@/store/auth";
import { useThemeStore } from "@/store/theme";
function RequireAuth() {
const token = useAuthStore((s) => s.accessToken);
return token ? <Outlet /> : <Navigate to="/login" replace />;
}
export default function App() {
const applyTheme = useThemeStore((s) => s.apply);
const fetchMe = useAuthStore((s) => s.fetchMe);
const token = useAuthStore((s) => s.accessToken);
useEffect(() => {
applyTheme();
}, [applyTheme]);
useEffect(() => {
if (token) fetchMe().catch(() => {});
}, [token, fetchMe]);
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<RequireAuth />}>
<Route element={<Layout />}>
<Route path="/" element={<Dashboard />} />
<Route path="/stacks" element={<Stacks />} />
<Route path="/stacks/new" element={<StackEditor />} />
<Route path="/stacks/:id" element={<StackDetail />} />
<Route path="/stacks/:id/edit" element={<StackEditor />} />
<Route path="/hosts/:agentId/stacks/:id" element={<RemoteStackDetail />} />
<Route path="/networks" element={<Networks />} />
<Route path="/images" element={<Images />} />
<Route path="/templates" element={<Templates />} />
<Route path="/audit" element={<Audit />} />
<Route path="/settings" element={<Settings />} />
</Route>
</Route>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
);
}