From f276ccd5f7d7fc81f285dbbce3a8e246b9764f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriele=20Vigan=C3=B2?= Date: Wed, 21 Oct 2026 19:36:25 +0000 Subject: [PATCH 1/4] feat(access): group permissions by application --- src/components/rbac/catalog-search.tsx | 2 +- src/routes/access/permissions/index.tsx | 192 ++++++++++++++---------- 2 files changed, 112 insertions(+), 82 deletions(-) diff --git a/src/components/rbac/catalog-search.tsx b/src/components/rbac/catalog-search.tsx index a5f67a6..2ea49df 100644 --- a/src/components/rbac/catalog-search.tsx +++ b/src/components/rbac/catalog-search.tsx @@ -82,7 +82,7 @@ export function CatalogSearch({ className="flex-1 basis-56 sm:max-w-lg" />

- {query.trim() ? `${count} of ${total}` : total} {kind} + {query.trim() || count !== total ? `${count} of ${total}` : total} {kind}

{children} diff --git a/src/routes/access/permissions/index.tsx b/src/routes/access/permissions/index.tsx index 4760548..2b74f08 100644 --- a/src/routes/access/permissions/index.tsx +++ b/src/routes/access/permissions/index.tsx @@ -16,6 +16,19 @@ export const Route = createFileRoute("/access/permissions/")({ component: PermissionsIndex, }); +function applicationKey(permission: PermissionSummary) { + return permission.key.split(":")[0]; +} + +function applicationLabel(key: string) { + if (key === "idp") return "PoliNetwork Auth"; + if (key === "tg") return "Telegram"; + if (key === "wa") return "WhatsApp"; + if (key === "web") return "Website"; + if (key === "azure") return "Microsoft Entra"; + return key.charAt(0).toUpperCase() + key.slice(1); +} + function PermissionRow({ permission, implied, @@ -40,6 +53,9 @@ function PermissionRow({

{permission.name}

+ {permission.managed && ( + Built-in + )} {implied.length > 0 && ( Also grants {implied.length} )} @@ -63,16 +79,29 @@ function PermissionsIndex() { const { can } = useAccess(); const catalog = Route.useLoaderData(); const [query, setQuery] = useState(""); + const [application, setApplication] = useState(null); + const applications = [...new Set(catalog.permissions.map(applicationKey))].sort(); const search = query.trim().toLowerCase(); - const filtered = catalog.permissions.filter((permission) => - [permission.name, permission.key, permission.description].some((value) => - value?.toLowerCase().includes(search), - ), + const filtered = catalog.permissions.filter( + (permission) => + (application === null || applicationKey(permission) === application) && + [ + permission.name, + permission.key, + permission.description, + applicationLabel(applicationKey(permission)), + ].some((value) => value?.toLowerCase().includes(search)), ); const impliedBy = (permission: PermissionSummary) => expandPermissionKeys(catalog, permission.implies).filter((key) => key !== permission.key); - const managed = filtered.filter((permission) => permission.managed); - const custom = filtered.filter((permission) => !permission.managed); + const groups = applications + .map((key) => ({ + key, + permissions: filtered + .filter((permission) => applicationKey(permission) === key) + .sort((a, b) => a.key.localeCompare(b.key)), + })) + .filter((group) => group.permissions.length > 0); return (
@@ -103,85 +132,86 @@ function PermissionsIndex() { )} - {search && filtered.length === 0 && } + {applications.length > 0 && ( +
+ + {applications.map((key) => ( + + ))} +
+ )} - { -
- {(managed.length > 0 || !search) && ( - - - Built into the identity provider + {filtered.length === 0 && + (search ? ( + + ) : ( + + + + + ))} + +
+ {groups.map(({ key, permissions }) => ( + + +
+ {applicationLabel(key)} + {key}:* + + {permissions.length} {permissions.length === 1 ? "permission" : "permissions"} + +
+ {key === "idp" && ( - These permissions control this service itself. They always exist and cannot be - deleted, because the code checks for these exact keys. Give them to a role to let - someone administer part of PoliNetwork Auth. + Permissions for administering PoliNetwork Auth. Built-in permissions always exist + and cannot be deleted. -
- - {managed.length === 0 ? ( -

- No built-in permissions match your search. -

- ) : ( -
    - {managed.map((permission) => ( - - ))} -
- )} -
-
- )} - - {(custom.length > 0 || !search) && ( -
-

- Permissions you created -

- {custom.length === 0 ? ( - - -
-
-
-

No permissions of your own yet

-

- Name the first thing one of your applications should be able to check for, - such as reading the member list. -

-
- {can("idp:permissions:write") && ( - - )} -
-
- ) : ( - -
    - {custom.map((permission) => ( - - ))} -
-
)} -
- )} -
- } +
+ +
    + {permissions.map((permission) => ( + + ))} +
+
+
+ ))} +
); } From 8b53b9495fef8ff326d14fc28aa23f22a9cd53d1 Mon Sep 17 00:00:00 2001 From: Tommaso Morganti Date: Thu, 22 Oct 2026 17:31:54 +0200 Subject: [PATCH 2/4] fix: coniglios --- pnpm-lock.yaml | 19 ----------------- src/routes/access/permissions/index.tsx | 28 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9087243..513a4cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,9 +6,6 @@ importers: .: configDependencies: {} packageManagerDependencies: - '@pnpm/exe': - specifier: 12.3.4 - version: 12.3.4 pnpm: specifier: 12.3.4 version: 12.3.4 @@ -59,11 +56,6 @@ packages: cpu: [x64] os: [win32] - '@pnpm/exe@12.3.4': - resolution: {integrity: sha512-Rq7JokWAyYF9IFfn8zofB/q2AgnZlmoMuH5fMHB2+Ta61I9aD7sNm+woZpx6iH+5vb38chdSoYRvOtSqlH72YQ==} - engines: {node: '>=18.*'} - hasBin: true - pnpm@12.3.4: resolution: {integrity: sha512-lhqkH7B32joEpEHZ+OFevAyW2o73ELLrZ7+e58sGEOq9SPH9hfUc/+c4RnhfoPh8VqOocqHYk/hEZ0G1zORUVw==} engines: {node: '>=18.*'} @@ -95,17 +87,6 @@ snapshots: '@pnpm/exe.win32-x64@12.3.4': optional: true - '@pnpm/exe@12.3.4': - optionalDependencies: - '@pnpm/exe.darwin-arm64': 12.3.4 - '@pnpm/exe.darwin-x64': 12.3.4 - '@pnpm/exe.linux-arm64': 12.3.4 - '@pnpm/exe.linux-arm64-musl': 12.3.4 - '@pnpm/exe.linux-x64': 12.3.4 - '@pnpm/exe.linux-x64-musl': 12.3.4 - '@pnpm/exe.win32-arm64': 12.3.4 - '@pnpm/exe.win32-x64': 12.3.4 - pnpm@12.3.4: optionalDependencies: '@pnpm/exe.darwin-arm64': 12.3.4 diff --git a/src/routes/access/permissions/index.tsx b/src/routes/access/permissions/index.tsx index 2b74f08..b377528 100644 --- a/src/routes/access/permissions/index.tsx +++ b/src/routes/access/permissions/index.tsx @@ -29,6 +29,21 @@ function applicationLabel(key: string) { return key.charAt(0).toUpperCase() + key.slice(1); } +/** Labels for each application, suffixed with the key where two would otherwise read the same. */ +function applicationLabels(keys: string[]) { + const counts = new Map(); + for (const key of keys) { + const label = applicationLabel(key); + counts.set(label, (counts.get(label) ?? 0) + 1); + } + return new Map( + keys.map((key) => { + const label = applicationLabel(key); + return [key, (counts.get(label) ?? 0) > 1 ? `${label} (${key})` : label]; + }), + ); +} + function PermissionRow({ permission, implied, @@ -81,6 +96,7 @@ function PermissionsIndex() { const [query, setQuery] = useState(""); const [application, setApplication] = useState(null); const applications = [...new Set(catalog.permissions.map(applicationKey))].sort(); + const labels = applicationLabels(applications); const search = query.trim().toLowerCase(); const filtered = catalog.permissions.filter( (permission) => @@ -150,7 +166,7 @@ function PermissionsIndex() { aria-pressed={application === key} onClick={() => setApplication(key)} > - {applicationLabel(key)} + {labels.get(key)} { catalog.permissions.filter((permission) => applicationKey(permission) === key) @@ -185,8 +201,12 @@ function PermissionsIndex() {
- {applicationLabel(key)} - {key}:* + {labels.get(key)} + + {permissions.some((permission) => permission.key.includes(":")) + ? `${key}:*` + : key} + {permissions.length} {permissions.length === 1 ? "permission" : "permissions"} @@ -199,7 +219,7 @@ function PermissionsIndex() { )} -
    +
      {permissions.map((permission) => ( Date: Thu, 22 Oct 2026 21:57:33 +0200 Subject: [PATCH 3/4] style(auth): format the package manifest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c59357a..fc05a1d 100644 --- a/package.json +++ b/package.json @@ -86,4 +86,4 @@ "*" ] } -} \ No newline at end of file +} From 6e5b4e5196b78e29f48da6e78f6e3813b0bb1cc2 Mon Sep 17 00:00:00 2001 From: Lorenzo Corallo Date: Thu, 22 Oct 2026 22:05:55 +0200 Subject: [PATCH 4/4] fix(access): search the displayed application labels --- src/routes/access/permissions/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/access/permissions/index.tsx b/src/routes/access/permissions/index.tsx index b377528..9cd0672 100644 --- a/src/routes/access/permissions/index.tsx +++ b/src/routes/access/permissions/index.tsx @@ -105,7 +105,7 @@ function PermissionsIndex() { permission.name, permission.key, permission.description, - applicationLabel(applicationKey(permission)), + labels.get(applicationKey(permission)), ].some((value) => value?.toLowerCase().includes(search)), ); const impliedBy = (permission: PermissionSummary) =>