Expose administration View surfaces
This commit is contained in:
@@ -42,6 +42,7 @@ from govoplan_core.core.modules import (
|
|||||||
RoleTemplate,
|
RoleTemplate,
|
||||||
)
|
)
|
||||||
from govoplan_core.core.people import CAPABILITY_ACCESS_PEOPLE_SEARCH
|
from govoplan_core.core.people import CAPABILITY_ACCESS_PEOPLE_SEARCH
|
||||||
|
from govoplan_core.core.views import ViewSurface
|
||||||
|
|
||||||
|
|
||||||
def _permission(scope: str, label: str, description: str, category: str, level: str) -> PermissionDefinition:
|
def _permission(scope: str, label: str, description: str, category: str, level: str) -> PermissionDefinition:
|
||||||
@@ -254,6 +255,10 @@ ADMIN_READ_SCOPES = (
|
|||||||
"access:account:read",
|
"access:account:read",
|
||||||
"access:governance:read",
|
"access:governance:read",
|
||||||
"access:function:read",
|
"access:function:read",
|
||||||
|
"views:definition:read",
|
||||||
|
"views:assignment:read",
|
||||||
|
"views:system_definition:read",
|
||||||
|
"views:system_assignment:read",
|
||||||
)
|
)
|
||||||
|
|
||||||
ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
||||||
@@ -676,6 +681,22 @@ manifest = ModuleManifest(
|
|||||||
package_name="@govoplan/access-webui",
|
package_name="@govoplan/access-webui",
|
||||||
routes=(FrontendRoute(path="/admin", component="AdminPage", required_any=ADMIN_READ_SCOPES, order=900),),
|
routes=(FrontendRoute(path="/admin", component="AdminPage", required_any=ADMIN_READ_SCOPES, order=900),),
|
||||||
nav_items=(NavItem(path="/admin", label="Admin", icon="admin", required_any=ADMIN_READ_SCOPES, order=900),),
|
nav_items=(NavItem(path="/admin", label="Admin", icon="admin", required_any=ADMIN_READ_SCOPES, order=900),),
|
||||||
|
view_surfaces=(
|
||||||
|
ViewSurface(id="access.admin.system-tenants", module_id="access", kind="section", label="System tenants", order=10),
|
||||||
|
ViewSurface(id="access.admin.system-roles", module_id="access", kind="section", label="System roles", order=20),
|
||||||
|
ViewSurface(id="access.admin.system-users", module_id="access", kind="section", label="System users", order=50),
|
||||||
|
ViewSurface(id="access.admin.system-credentials", module_id="access", kind="section", label="System credentials", order=80),
|
||||||
|
ViewSurface(id="access.admin.tenant-roles", module_id="access", kind="section", label="Tenant roles", order=10),
|
||||||
|
ViewSurface(id="access.admin.tenant-function-mappings", module_id="access", kind="section", label="Function mappings", order=20),
|
||||||
|
ViewSurface(id="access.admin.tenant-groups", module_id="access", kind="section", label="Tenant groups", order=30),
|
||||||
|
ViewSurface(id="access.admin.tenant-users", module_id="access", kind="section", label="Tenant users", order=40),
|
||||||
|
ViewSurface(id="access.admin.tenant-credentials", module_id="access", kind="section", label="Tenant credentials", order=70),
|
||||||
|
ViewSurface(id="access.admin.tenant-api-keys", module_id="access", kind="section", label="Tenant API keys", order=80),
|
||||||
|
ViewSurface(id="access.admin.tenant-settings", module_id="access", kind="section", label="Tenant settings", order=90),
|
||||||
|
ViewSurface(id="access.admin.group-credentials", module_id="access", kind="section", label="Group credentials", order=30),
|
||||||
|
ViewSurface(id="access.admin.user-credentials", module_id="access", kind="section", label="User credentials", order=30),
|
||||||
|
ViewSurface(id="access.settings.credentials", module_id="access", kind="section", label="Personal credentials", order=30),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
capability_factories={
|
capability_factories={
|
||||||
CAPABILITY_AUTH_API_PRINCIPAL_PROVIDER: _api_principal_provider,
|
CAPABILITY_AUTH_API_PRINCIPAL_PROVIDER: _api_principal_provider,
|
||||||
|
|||||||
@@ -26,7 +26,13 @@ import ApiKeysPanel from "./ApiKeysPanel";
|
|||||||
import FileConnectorsPanel from "./FileConnectorsPanel";
|
import FileConnectorsPanel from "./FileConnectorsPanel";
|
||||||
import MailProfilesPanel from "./MailProfilesPanel";
|
import MailProfilesPanel from "./MailProfilesPanel";
|
||||||
import CredentialEnvelopesPanel from "./CredentialEnvelopesPanel";
|
import CredentialEnvelopesPanel from "./CredentialEnvelopesPanel";
|
||||||
import { usePlatformUiCapabilities, usePlatformUiCapability } from "@govoplan/core-webui";
|
import {
|
||||||
|
isViewSurfaceVisible,
|
||||||
|
useEffectiveView,
|
||||||
|
usePlatformUiCapabilities,
|
||||||
|
usePlatformUiCapability,
|
||||||
|
useViewSurfaces
|
||||||
|
} from "@govoplan/core-webui";
|
||||||
|
|
||||||
type AdminSection = string;
|
type AdminSection = string;
|
||||||
type OrderedAdminNavItem = { id: AdminSection; label: string; order: number };
|
type OrderedAdminNavItem = { id: AdminSection; label: string; order: number };
|
||||||
@@ -62,6 +68,28 @@ const handledAdminSectionIds = new Set<string>([
|
|||||||
"tenant-user-credentials"
|
"tenant-user-credentials"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const builtInAdminSurfaceIds: Record<string, string> = {
|
||||||
|
"system-tenants": "access.admin.system-tenants",
|
||||||
|
"system-roles": "access.admin.system-roles",
|
||||||
|
"system-users": "access.admin.system-users",
|
||||||
|
"system-credentials": "access.admin.system-credentials",
|
||||||
|
"tenant-roles": "access.admin.tenant-roles",
|
||||||
|
"tenant-function-role-mappings": "access.admin.tenant-function-mappings",
|
||||||
|
"tenant-groups": "access.admin.tenant-groups",
|
||||||
|
"tenant-users": "access.admin.tenant-users",
|
||||||
|
"tenant-credentials": "access.admin.tenant-credentials",
|
||||||
|
"tenant-api-keys": "access.admin.tenant-api-keys",
|
||||||
|
"tenant-settings": "access.admin.tenant-settings",
|
||||||
|
"tenant-group-credentials": "access.admin.group-credentials",
|
||||||
|
"tenant-user-credentials": "access.admin.user-credentials",
|
||||||
|
"system-mail-servers": "mail.admin.system-servers",
|
||||||
|
"tenant-mail-servers": "mail.admin.tenant-servers",
|
||||||
|
"tenant-group-mail-servers": "mail.admin.group-servers",
|
||||||
|
"tenant-user-mail-servers": "mail.admin.user-servers",
|
||||||
|
"tenant-group-file-connectors": "files.admin.group-connectors",
|
||||||
|
"tenant-user-file-connectors": "files.admin.user-connectors"
|
||||||
|
};
|
||||||
|
|
||||||
export default function AdminPage({
|
export default function AdminPage({
|
||||||
settings,
|
settings,
|
||||||
auth,
|
auth,
|
||||||
@@ -75,14 +103,23 @@ export default function AdminPage({
|
|||||||
const fileConnectorsUi = usePlatformUiCapability<FilesConnectorsUiCapability>("files.connectors");
|
const fileConnectorsUi = usePlatformUiCapability<FilesConnectorsUiCapability>("files.connectors");
|
||||||
const organizationFunctionPicker = usePlatformUiCapability<OrganizationFunctionPickerUiCapability>("organizations.functionPicker");
|
const organizationFunctionPicker = usePlatformUiCapability<OrganizationFunctionPickerUiCapability>("organizations.functionPicker");
|
||||||
const adminSectionCapabilities = usePlatformUiCapabilities<AdminSectionsUiCapability>("admin.sections");
|
const adminSectionCapabilities = usePlatformUiCapabilities<AdminSectionsUiCapability>("admin.sections");
|
||||||
|
const effectiveView = useEffectiveView();
|
||||||
|
const viewSurfaces = useViewSurfaces();
|
||||||
const mailProfilesAvailable = Boolean(mailProfilesUi);
|
const mailProfilesAvailable = Boolean(mailProfilesUi);
|
||||||
const fileConnectorsAvailable = Boolean(fileConnectorsUi);
|
const fileConnectorsAvailable = Boolean(fileConnectorsUi);
|
||||||
const contributedSections = useMemo(
|
const contributedSections = useMemo(
|
||||||
() =>
|
() =>
|
||||||
adminSectionCapabilities
|
adminSectionCapabilities
|
||||||
.flatMap((capability) => capability.sections)
|
.flatMap((capability) => capability.sections)
|
||||||
|
.filter((section) =>
|
||||||
|
isViewSurfaceVisible(
|
||||||
|
effectiveView,
|
||||||
|
section.surfaceId,
|
||||||
|
viewSurfaces
|
||||||
|
)
|
||||||
|
)
|
||||||
.sort((left, right) => (left.order ?? 100) - (right.order ?? 100)),
|
.sort((left, right) => (left.order ?? 100) - (right.order ?? 100)),
|
||||||
[adminSectionCapabilities]
|
[adminSectionCapabilities, effectiveView, viewSurfaces]
|
||||||
);
|
);
|
||||||
const contributionById = useMemo(() => {
|
const contributionById = useMemo(() => {
|
||||||
const mapped = new Map<string, AdminSectionContribution>();
|
const mapped = new Map<string, AdminSectionContribution>();
|
||||||
@@ -126,8 +163,16 @@ export default function AdminPage({
|
|||||||
if (hasScope(auth, "admin:users:read")) sections.add("tenant-user-credentials");
|
if (hasScope(auth, "admin:users:read")) sections.add("tenant-user-credentials");
|
||||||
if (hasScope(auth, "admin:groups:read")) sections.add("tenant-group-credentials");
|
if (hasScope(auth, "admin:groups:read")) sections.add("tenant-group-credentials");
|
||||||
}
|
}
|
||||||
return sections;
|
return new Set(
|
||||||
}, [auth, contributedSections, fileConnectorsAvailable, mailProfilesAvailable, organizationFunctionPicker]);
|
[...sections].filter((sectionId) =>
|
||||||
|
isViewSurfaceVisible(
|
||||||
|
effectiveView,
|
||||||
|
builtInAdminSurfaceIds[sectionId],
|
||||||
|
viewSurfaces
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, [auth, contributedSections, effectiveView, fileConnectorsAvailable, mailProfilesAvailable, organizationFunctionPicker, viewSurfaces]);
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const requestedSection = searchParams.get("section") as AdminSection | null;
|
const requestedSection = searchParams.get("section") as AdminSection | null;
|
||||||
const fallbackSection = available.has("overview") ? "overview" : (Array.from(available)[0] ?? "overview");
|
const fallbackSection = available.has("overview") ? "overview" : (Array.from(available)[0] ?? "overview");
|
||||||
|
|||||||
@@ -10,6 +10,23 @@ const translations = {
|
|||||||
de: generatedTranslations.de
|
de: generatedTranslations.de
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const accessAdminSurfaces = [
|
||||||
|
{ id: "access.admin.system-tenants", moduleId: "access", kind: "section" as const, label: "System tenants", order: 10 },
|
||||||
|
{ id: "access.admin.system-roles", moduleId: "access", kind: "section" as const, label: "System roles", order: 20 },
|
||||||
|
{ id: "access.admin.system-users", moduleId: "access", kind: "section" as const, label: "System users", order: 50 },
|
||||||
|
{ id: "access.admin.system-credentials", moduleId: "access", kind: "section" as const, label: "System credentials", order: 80 },
|
||||||
|
{ id: "access.admin.tenant-roles", moduleId: "access", kind: "section" as const, label: "Tenant roles", order: 10 },
|
||||||
|
{ id: "access.admin.tenant-function-mappings", moduleId: "access", kind: "section" as const, label: "Function mappings", order: 20 },
|
||||||
|
{ id: "access.admin.tenant-groups", moduleId: "access", kind: "section" as const, label: "Tenant groups", order: 30 },
|
||||||
|
{ id: "access.admin.tenant-users", moduleId: "access", kind: "section" as const, label: "Tenant users", order: 40 },
|
||||||
|
{ id: "access.admin.tenant-credentials", moduleId: "access", kind: "section" as const, label: "Tenant credentials", order: 70 },
|
||||||
|
{ id: "access.admin.tenant-api-keys", moduleId: "access", kind: "section" as const, label: "Tenant API keys", order: 80 },
|
||||||
|
{ id: "access.admin.tenant-settings", moduleId: "access", kind: "section" as const, label: "Tenant settings", order: 90 },
|
||||||
|
{ id: "access.admin.group-credentials", moduleId: "access", kind: "section" as const, label: "Group credentials", order: 30 },
|
||||||
|
{ id: "access.admin.user-credentials", moduleId: "access", kind: "section" as const, label: "User credentials", order: 30 },
|
||||||
|
{ id: "access.settings.credentials", moduleId: "access", kind: "section" as const, label: "Personal credentials", order: 30 }
|
||||||
|
];
|
||||||
|
|
||||||
function renderAdminRoute({ settings, auth, onAuthChange }: PlatformRouteContext) {
|
function renderAdminRoute({ settings, auth, onAuthChange }: PlatformRouteContext) {
|
||||||
if (!onAuthChange) {
|
if (!onAuthChange) {
|
||||||
throw new Error("i18n:govoplan-access.the_access_admin_route_requires_the_platform_aut.0173a45f");
|
throw new Error("i18n:govoplan-access.the_access_admin_route_requires_the_platform_aut.0173a45f");
|
||||||
@@ -22,6 +39,7 @@ export const accessModule: PlatformWebModule = {
|
|||||||
label: "i18n:govoplan-access.access.2f81a22d",
|
label: "i18n:govoplan-access.access.2f81a22d",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
translations,
|
translations,
|
||||||
|
viewSurfaces: accessAdminSurfaces,
|
||||||
navItems: [
|
navItems: [
|
||||||
{ to: "/admin", label: "i18n:govoplan-access.admin.4e7afebc", iconName: "admin", anyOf: adminReadScopes, order: 900 }],
|
{ to: "/admin", label: "i18n:govoplan-access.admin.4e7afebc", iconName: "admin", anyOf: adminReadScopes, order: 900 }],
|
||||||
|
|
||||||
@@ -30,4 +48,4 @@ export const accessModule: PlatformWebModule = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default accessModule;
|
export default accessModule;
|
||||||
|
|||||||
Reference in New Issue
Block a user