Skip to content

Commit f9e8915

Browse files
committed
Plugin owns permission display groups
Adds an optional `group` field to Permission so the plugin labels and orders permission sections rather than the OSS hardcoding a name → group map. Section order on the Roles page now follows the order permissions appear in `allPermissions()` — first group seen, first rendered. Drops the previous PERMISSION_GROUP_BY_NAME / GROUP_ORDER constants from the webapp.
1 parent 1552420 commit f9e8915

2 files changed

Lines changed: 14 additions & 50 deletions

File tree

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.roles
  • packages/plugins/src

apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.roles/route.tsx

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -83,52 +83,10 @@ type LoaderRole = LoaderData["roles"][number];
8383
type LoaderPermission = LoaderData["allPermissions"][number];
8484
type RolePermission = LoaderRole["permissions"][number];
8585

86-
// Permission name → display group. The wire-format Permission only
87-
// carries `name` and `description`, so this lives client-side.
88-
const PERMISSION_GROUP_BY_NAME: Record<string, string> = {
89-
"read:runs": "Runs",
90-
"write:runs": "Runs",
91-
"read:tags": "Runs",
92-
"read:batch": "Runs",
93-
"write:batch": "Runs",
94-
"read:tasks": "Tasks",
95-
"write:tasks": "Tasks",
96-
"trigger:tasks": "Tasks",
97-
"batchTrigger:tasks": "Tasks",
98-
"deploy:tasks": "Tasks",
99-
"read:waitpoints": "Waitpoints",
100-
"write:waitpoints": "Waitpoints",
101-
"read:inputStreams": "Realtime",
102-
"write:inputStreams": "Realtime",
103-
"read:deployments": "Deployments",
104-
"read:prompts": "Prompts",
105-
"write:prompts": "Prompts",
106-
"update:prompts": "Prompts",
107-
"read:query": "Query",
108-
"read:tokens": "Tokens",
109-
"write:tokens": "Tokens",
110-
"read:envvars": "Environment",
111-
"write:envvars": "Environment",
112-
"read:apiKeys": "Environment",
113-
"write:apiKeys": "Environment",
114-
"read:members": "Organisation",
115-
"manage:members": "Organisation",
116-
"manage:billing": "Organisation",
117-
};
118-
119-
const GROUP_ORDER = [
120-
"Runs",
121-
"Tasks",
122-
"Waitpoints",
123-
"Realtime",
124-
"Deployments",
125-
"Prompts",
126-
"Query",
127-
"Tokens",
128-
"Environment",
129-
"Organisation",
130-
"Other",
131-
] as const;
86+
// Permissions are bucketed by `permission.group` from the plugin.
87+
// Section order = first-seen order in `allPermissions()`. Permissions
88+
// without a group fall into "Other" at the bottom.
89+
const FALLBACK_GROUP = "Other";
13290

13391
export default function Page() {
13492
const { roles, assignableRoleIds, allPermissions, systemRoles } =
@@ -353,16 +311,17 @@ function conditionLabel(conditions: Record<string, unknown>): string {
353311
function groupPermissions(
354312
permissions: LoaderPermission[]
355313
): { group: string; permissions: LoaderPermission[] }[] {
314+
// Insertion-ordered map: groups appear in the order their first
315+
// permission was seen. Plugins that want a specific section order
316+
// just emit permissions in that order from `allPermissions()`.
356317
const buckets = new Map<string, LoaderPermission[]>();
357318
for (const permission of permissions) {
358-
const group = PERMISSION_GROUP_BY_NAME[permission.name] ?? "Other";
319+
const group = permission.group ?? FALLBACK_GROUP;
359320
const list = buckets.get(group) ?? [];
360321
list.push(permission);
361322
buckets.set(group, list);
362323
}
363-
return GROUP_ORDER.flatMap((group) =>
364-
buckets.has(group) ? [{ group, permissions: buckets.get(group)! }] : []
365-
);
324+
return Array.from(buckets, ([group, permissions]) => ({ group, permissions }));
366325
}
367326

368327
function CreateRoleUpsell() {

packages/plugins/src/rbac.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ export type Permission = {
2323
// `<action>:<subject>` — display name, derived from the ability rule.
2424
name: string;
2525
description: string;
26+
// Display bucket for the Roles page (e.g. "Runs", "Tasks"). The page
27+
// groups permissions by this string and lists groups in the order they
28+
// first appear in `allPermissions()`, so the plugin owns both the
29+
// bucket label and the section ordering. Omit for "no grouping".
30+
group?: string;
2631
// Inverted rules (CASL `cannot`) surface as ✗ in the Roles page.
2732
inverted?: boolean;
2833
// CASL conditions (e.g. `{ envType: "PRODUCTION" }`) — when present,

0 commit comments

Comments
 (0)