This commit is contained in:
Alex Holliday committed 2025-12-13 23:12:02 +00:00
1 parent 9aa87f57ae
commit 6f99249d62
4 files changed
+76 -20

No files matched your search

+2 -2
View File
@@ -2,6 +2,6 @@ window.__ENV = {
GLOBAL_REFRESH: "60000",
APP_HOST: "http://localhost:5173",
APP_API_BASE_URL: "http://localhost:52345/api/v1",
// APP_DEPLOYMENT_MODE: "self_hosted",
APP_DEPLOYMENT_MODE: "saas",
APP_DEPLOYMENT_MODE: "self_hosted",
// APP_DEPLOYMENT_MODE: "saas",
};
@@ -1,5 +1,6 @@
import { useAppSelector } from "@/hooks/AppHooks";
import { Navigate } from "react-router";
import NotFound from "@/pages/errors/NotFound";
export const ProtectedRoute: React.FC<React.PropsWithChildren> = ({
children,
@@ -20,3 +21,24 @@ export const ProtectedRoute: React.FC<React.PropsWithChildren> = ({
return <>{children}</>;
};
export const MasterRoute: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const user = useAppSelector((state) => state.auth.user);
if (user?.teams.length === 0) {
return <Navigate to="/no-team" replace />;
}
const perms: string[] = (user?.org?.permissions || []).map((p: any) =>
(p ?? "").toString().trim().toLowerCase()
);
const hasMaster = perms.includes("master");
if (!hasMaster) {
return <NotFound />;
}
return <>{children}</>;
};
@@ -1,5 +1,11 @@
import { Box, Typography, Paper, Stack, Divider } from "@mui/material";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Divider from "@mui/material/Divider";
import Box from "@mui/material/Box";
import { useTheme } from "@mui/material/styles";
import { useGet } from "@/hooks/UseApi";
import { StatBox } from "@/components/design-elements";
import { config as clientConfig } from "@/config";
type EnvConfig = {
NODE_ENV: string;
@@ -18,26 +24,24 @@ type EnvConfig = {
};
export default function DiagnosticsConfigTab() {
const theme = useTheme();
const { response, loading, error } = useGet<{
message: string;
data: EnvConfig;
}>("/diagnostic/env");
}>("/diagnostic/env", {}, { refreshInterval: clientConfig.GLOBAL_REFRESH });
const data = response?.data;
const clientEntries = Object.entries(clientConfig as Record<string, any>);
if (!data && !loading && !error) return null;
const totalKeys = data ? Object.keys(data).length : 0;
return (
<Box p={2}>
<Typography variant="h6" gutterBottom>
Environment Configuration
</Typography>
{loading && <Typography variant="body2">Loading…</Typography>}
{error && (
<Typography color="error" variant="body2">
{error}
</Typography>
)}
<Stack spacing={theme.spacing(8)}>
{data && (
<Paper variant="outlined">
<Stack spacing={theme.spacing(3)}>
<Typography variant="h1">Server environment</Typography>
<Stack divider={<Divider />}>
{Object.entries(data).map(([key, value]) => (
<Box key={key} px={2} py={1.5} display="flex" gap={2}>
@@ -50,8 +54,24 @@ export default function DiagnosticsConfigTab() {
</Box>
))}
</Stack>
</Paper>
</Stack>
)}
</Box>
<Stack spacing={theme.spacing(3)}>
<Typography variant="h1">Client runtime config</Typography>
<Stack divider={<Divider />}>
{clientEntries.map(([key, value]) => (
<Box key={key} px={2} py={1.5} display="flex" gap={2}>
<Typography sx={{ minWidth: 220 }} color="text.secondary">
{key}
</Typography>
<Typography sx={{ wordBreak: "break-all" }}>
{String(value)}
</Typography>
</Box>
))}
</Stack>
</Stack>
</Stack>
);
}
+17 -3
View File
@@ -57,7 +57,7 @@ import BillingPage from "@/pages/billing/Billing";
import BillingSuccessPage from "@/pages/billing/Success";
import RootLayout from "@/components/layouts/RootLayout";
import { ProtectedRoute } from "@/components/protected-route";
import { ProtectedRoute, MasterRoute } from "@/components/protected-route";
const Router = () => {
return (
@@ -84,7 +84,14 @@ const Router = () => {
<Route path="uptime/:id" element={<UptimeDetailsPage />} />
<Route path="uptime" element={<UptimeMonitorsPage />} />
<Route path="settings" element={<SettingsPage />} />
<Route path="settings/admin" element={<AdminSettingsPage />} />
<Route
path="settings/admin"
element={
<MasterRoute>
<AdminSettingsPage />
</MasterRoute>
}
/>
<Route path="teams/create" element={<TeamsCreatePage />} />
<Route
path="teams/:id/member/:memberId/configure"
@@ -143,7 +150,14 @@ const Router = () => {
element={<StatusConfigPage />}
/>
<Route path="diagnostics" element={<DiagnosticPage />} />
<Route
path="diagnostics"
element={
<MasterRoute>
<DiagnosticPage />
</MasterRoute>
}
/>
<Route path="profile" element={<ProfilePage />} />
<Route path="export" element={<ExportPage />} />