Same move as Docker: each was buried inside the generic Integrations
browsing view, sharing one "pick any integration" dropdown across six
unrelated types. Give them dedicated pages instead.
New web/src/pages/{Tailscale,Semaphore,Gitea}.tsx each reuse the
existing, unchanged API routes and adapters (no server changes) with
their own integration picker scoped to just that type. Added matching
nav items (Tailscale, Semaphore, Gitea, right after Docker) and routes.
Removed the corresponding state/handlers/tables from Integrations.tsx
entirely (374 lines). Adding, editing, enabling/disabling, and
deleting each credential itself still happens under Integrations ->
Manage integrations, same as Proxmox and Synology, which stay on the
Integrations page. Selecting one of these three types in Integrations'
generic browsing dropdown now points to its new page instead of
rendering a table there too.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
117 lines
3.8 KiB
TypeScript
117 lines
3.8 KiB
TypeScript
import { useEffect, useState, type ReactNode } from "react";
|
|
import { Routes, Route, Navigate } from "react-router-dom";
|
|
import { api, type CurrentUser, type UserRole, UnauthorizedError } from "./api/client";
|
|
import Login from "./pages/Login";
|
|
import Dashboard from "./pages/Dashboard";
|
|
import Users from "./pages/Users";
|
|
import AuditLog from "./pages/AuditLog";
|
|
import Secrets from "./pages/Secrets";
|
|
import Ipam from "./pages/Ipam";
|
|
import Dns from "./pages/Dns";
|
|
import ServersTasks from "./pages/ServersTasks";
|
|
import ServerDetail from "./pages/ServerDetail";
|
|
import Integrations from "./pages/Integrations";
|
|
import Docker from "./pages/Docker";
|
|
import Tailscale from "./pages/Tailscale";
|
|
import Semaphore from "./pages/Semaphore";
|
|
import Gitea from "./pages/Gitea";
|
|
import Settings from "./pages/Settings";
|
|
import NotificationSettings from "./pages/settings/NotificationSettings";
|
|
import BadgeSettings from "./pages/settings/BadgeSettings";
|
|
import DateTimeSettings from "./pages/settings/DateTimeSettings";
|
|
import CacheSettings from "./pages/settings/CacheSettings";
|
|
import AppShell from "./layout/AppShell";
|
|
import { setDateTimeSettings } from "./utils/date";
|
|
|
|
const roleRank: Record<UserRole, number> = { viewer: 0, operator: 1, admin: 2 };
|
|
|
|
function RequireRole({
|
|
user,
|
|
minRole,
|
|
children,
|
|
}: {
|
|
user: CurrentUser;
|
|
minRole: UserRole;
|
|
children: ReactNode;
|
|
}) {
|
|
if (roleRank[user.role] < roleRank[minRole]) {
|
|
return (
|
|
<div className="alert alert-danger">You don't have permission to view this page.</div>
|
|
);
|
|
}
|
|
return <>{children}</>;
|
|
}
|
|
|
|
export default function App() {
|
|
const [user, setUser] = useState<CurrentUser | null | undefined>(undefined);
|
|
|
|
useEffect(() => {
|
|
api.me().then(
|
|
(res) => setUser(res.user),
|
|
(err) => {
|
|
if (!(err instanceof UnauthorizedError)) {
|
|
console.error(err);
|
|
}
|
|
setUser(null);
|
|
},
|
|
);
|
|
api.settings.display().then((res) => setDateTimeSettings(res.display)).catch(() => {});
|
|
}, []);
|
|
|
|
if (user === undefined) {
|
|
return <div className="loading-screen">Loading…</div>;
|
|
}
|
|
|
|
if (user === null) {
|
|
return <Login />;
|
|
}
|
|
|
|
return (
|
|
<AppShell user={user}>
|
|
<Routes>
|
|
<Route path="/" element={<Dashboard user={user} />} />
|
|
<Route path="/servers" element={<ServersTasks user={user} />} />
|
|
<Route path="/servers/:id" element={<ServerDetail user={user} />} />
|
|
<Route path="/dns" element={<Dns user={user} />} />
|
|
<Route path="/ipam" element={<Ipam user={user} />} />
|
|
<Route path="/secrets" element={<Secrets user={user} />} />
|
|
<Route path="/integrations" element={<Integrations user={user} />} />
|
|
<Route path="/docker" element={<Docker user={user} />} />
|
|
<Route path="/tailscale" element={<Tailscale user={user} />} />
|
|
<Route path="/semaphore" element={<Semaphore user={user} />} />
|
|
<Route path="/gitea" element={<Gitea user={user} />} />
|
|
<Route
|
|
path="/users"
|
|
element={
|
|
<RequireRole user={user} minRole="admin">
|
|
<Users />
|
|
</RequireRole>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/audit-log"
|
|
element={
|
|
<RequireRole user={user} minRole="operator">
|
|
<AuditLog />
|
|
</RequireRole>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/settings"
|
|
element={
|
|
<RequireRole user={user} minRole="admin">
|
|
<Settings />
|
|
</RequireRole>
|
|
}
|
|
>
|
|
<Route index element={<Navigate to="notifications" replace />} />
|
|
<Route path="notifications" element={<NotificationSettings />} />
|
|
<Route path="badges" element={<BadgeSettings />} />
|
|
<Route path="date-time" element={<DateTimeSettings />} />
|
|
<Route path="cache" element={<CacheSettings />} />
|
|
</Route>
|
|
</Routes>
|
|
</AppShell>
|
|
);
|
|
}
|