diagnostics access
This commit is contained in:
1 parent
6f99249d62
commit
2eb6850cb9
3 files changed
+186
-1
No files matched your search
@@ -2,7 +2,8 @@ import { BasePage, Tab, Tabs, InfoBox } from "@/components/design-elements";
|
||||
import { DiagnosticsLogTab } from "@/pages/diagnostic/DiagnosticsLogTab";
|
||||
import { DiagnosticsQueueTab } from "@/pages/diagnostic/DiagnosticsQueueTab";
|
||||
import DiagnosticsConfigTab from "@/pages/diagnostic/DiagnosticsConfigTab";
|
||||
import { FileText, ListTodo, Settings } from "lucide-react";
|
||||
import DiagnosticsAccessTab from "@/pages/diagnostic/DiagnosticsAccessTab";
|
||||
import { FileText, ListTodo, Settings, Shield } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
const DiagnosticPage = () => {
|
||||
@@ -34,10 +35,16 @@ const DiagnosticPage = () => {
|
||||
value="config"
|
||||
icon={<Settings size={18} strokeWidth={1.5} />}
|
||||
/>
|
||||
<Tab
|
||||
label="Access"
|
||||
value="access"
|
||||
icon={<Shield size={18} strokeWidth={1.5} />}
|
||||
/>
|
||||
</Tabs>
|
||||
{tabValue === "logs" && <DiagnosticsLogTab />}
|
||||
{tabValue === "jobs" && <DiagnosticsQueueTab />}
|
||||
{tabValue === "config" && <DiagnosticsConfigTab />}
|
||||
{tabValue === "access" && <DiagnosticsAccessTab />}
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Box from "@mui/material/Box";
|
||||
import { StatBox, Table } from "@/components/design-elements";
|
||||
import type { Header } from "@/components/design-elements/Table";
|
||||
import { useGet } from "@/hooks/UseApi";
|
||||
import { useAppSelector } from "@/hooks/AppHooks";
|
||||
import type { Entitlements } from "@/types/entitlements";
|
||||
|
||||
type PermissionsResponse = {
|
||||
message: string;
|
||||
data: {
|
||||
org: string[];
|
||||
team: { teamId: string; permission: string }[];
|
||||
};
|
||||
};
|
||||
|
||||
type EntitlementRow = { id?: string | number; key: string; value: any };
|
||||
type PermissionRow = {
|
||||
id?: string | number;
|
||||
scope: "org" | "team";
|
||||
team?: string;
|
||||
permission: string;
|
||||
};
|
||||
|
||||
export default function DiagnosticsAccessTab() {
|
||||
const theme = useTheme();
|
||||
const user = useAppSelector((s: any) => s.auth?.user);
|
||||
const selectedTeamId = useAppSelector((s: any) => s.auth?.selectedTeamId);
|
||||
const { response: permsRes } = useGet<PermissionsResponse>(
|
||||
"/me/permissions",
|
||||
{},
|
||||
{ refreshInterval: 10000 }
|
||||
);
|
||||
const { response: entsRes } = useGet<{ entitlements: Entitlements }>(
|
||||
"/me/entitlements",
|
||||
{},
|
||||
{ refreshInterval: 30000 }
|
||||
);
|
||||
|
||||
const orgPerms = permsRes?.data?.org || [];
|
||||
const teamPerms = permsRes?.data?.team || [];
|
||||
|
||||
const entitlementsObj = entsRes?.entitlements as Entitlements | undefined;
|
||||
const entitlements: EntitlementRow[] = entitlementsObj
|
||||
? (Object.entries(entitlementsObj) as [keyof Entitlements, any][]).map(
|
||||
([key, value]) => ({ id: String(key), key: String(key), value })
|
||||
)
|
||||
: [];
|
||||
|
||||
const teamIdToName = new Map<string, string>(
|
||||
(Array.isArray(user?.teams) ? user?.teams : []).map((t: any) => [
|
||||
String(t?.id ?? t?._id ?? ""),
|
||||
String(t?.name ?? t?.id ?? t?._id ?? "unknown"),
|
||||
])
|
||||
);
|
||||
const permissionRows: PermissionRow[] = [
|
||||
...orgPerms.map((p, idx) => ({
|
||||
id: `org-${idx}-${String(p)}`,
|
||||
scope: "org" as const,
|
||||
team: "-",
|
||||
permission: String(p),
|
||||
})),
|
||||
...teamPerms.map((tp, idx) => ({
|
||||
id: `team-${idx}-${String(tp?.teamId ?? idx)}-${String(tp?.permission)}`,
|
||||
scope: "team" as const,
|
||||
team: teamIdToName.get(String(tp?.teamId)) ?? String(tp?.teamId ?? "-"),
|
||||
permission: String(tp?.permission),
|
||||
})),
|
||||
];
|
||||
|
||||
const permHeaders: Header<PermissionRow>[] = [
|
||||
{ id: "scope", content: "Scope", render: (r) => r.scope },
|
||||
{ id: "team", content: "Team", render: (r) => r.team ?? "-" },
|
||||
{ id: "permission", content: "Permission", render: (r) => r.permission },
|
||||
];
|
||||
|
||||
const entHeaders: Header<EntitlementRow>[] = [
|
||||
{ id: "key", content: "Entitlement", render: (r) => r.key },
|
||||
{ id: "value", content: "Value", render: (r) => r.value },
|
||||
];
|
||||
|
||||
const clientOrgPermsArr: string[] = Array.isArray(user?.org?.permissions)
|
||||
? (user?.org?.permissions as any[]).map((p) => String(p))
|
||||
: [];
|
||||
const clientTeamsArr: any[] = Array.isArray(user?.teams)
|
||||
? user?.teams.filter(
|
||||
(t: any) =>
|
||||
String(t?.id ?? t?._id ?? "") === String(selectedTeamId ?? "")
|
||||
)
|
||||
: [];
|
||||
|
||||
const clientEntitlementsObj = (user?.entitlements || {}) as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
const clientEntitlements: EntitlementRow[] = Object.entries(
|
||||
clientEntitlementsObj
|
||||
).map(([key, value]) => ({ id: key, key, value }));
|
||||
|
||||
const clientPermissionRows: PermissionRow[] = [
|
||||
...clientOrgPermsArr.map((p, idx) => ({
|
||||
id: `c-org-${idx}-${p}`,
|
||||
scope: "org" as const,
|
||||
team: "-",
|
||||
permission: p,
|
||||
})),
|
||||
...clientTeamsArr.flatMap((t) => {
|
||||
const perms = t?.permissions;
|
||||
if (Array.isArray(perms))
|
||||
return perms.map((p: any, i: number) => ({
|
||||
id: `c-team-${t?.id}-${i}-${String(p)}`,
|
||||
scope: "team" as const,
|
||||
team: String(t?.name ?? t?.id ?? "unknown"),
|
||||
permission: String(p),
|
||||
}));
|
||||
if (typeof perms === "string")
|
||||
return [
|
||||
{
|
||||
id: `c-team-${t?.id}-0-${String(perms)}`,
|
||||
scope: "team" as const,
|
||||
team: String(t?.name ?? t?.id ?? "unknown"),
|
||||
permission: String(perms),
|
||||
},
|
||||
];
|
||||
return [];
|
||||
}),
|
||||
];
|
||||
|
||||
const clientPermHeaders: Header<PermissionRow>[] = [
|
||||
{ id: "scope", content: "Scope", render: (r) => r.scope },
|
||||
{ id: "team", content: "Team", render: (r) => r.team ?? "-" },
|
||||
{ id: "permission", content: "Permission", render: (r) => r.permission },
|
||||
];
|
||||
|
||||
return (
|
||||
<Stack spacing={theme.spacing(8)}>
|
||||
<Stack spacing={theme.spacing(3)}>
|
||||
<Typography variant="h1">Server permissions</Typography>
|
||||
<Table headers={permHeaders} data={permissionRows} />
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={theme.spacing(3)}>
|
||||
<Typography variant="h1">Server entitlements</Typography>
|
||||
<Table headers={entHeaders} data={entitlements} />
|
||||
</Stack>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Stack spacing={theme.spacing(3)}>
|
||||
<Typography variant="h1">Client permissions</Typography>
|
||||
<Table headers={clientPermHeaders} data={clientPermissionRows} />
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={theme.spacing(3)}>
|
||||
<Typography variant="h1">Client entitlements</Typography>
|
||||
<Table headers={entHeaders} data={clientEntitlements} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -19,6 +19,21 @@ class MeRoutes {
|
||||
return res.json({ entitlements });
|
||||
}
|
||||
);
|
||||
|
||||
this.router.get("/permissions", verifyToken, addUserContext, (req, res) => {
|
||||
const orgPerms = req.user?.roles?.orgRole?.permissions || [];
|
||||
const teamPerms = req.user?.roles?.teamRole?.permissions || [];
|
||||
const currentTeamId = req.user?.currentTeamId;
|
||||
return res.json({
|
||||
message: "OK",
|
||||
data: {
|
||||
org: orgPerms,
|
||||
team: Array.isArray(teamPerms)
|
||||
? teamPerms.map((p: string) => ({ teamId: currentTeamId, permission: p }))
|
||||
: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
getRouter() {
|
||||
|
||||
Reference in new issue
Block a user