@parallelworks/ui 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +65 -26
  2. package/dist/access/AccessDrawer.d.ts +30 -19
  3. package/dist/access/AccessDrawer.js +92 -67
  4. package/dist/access/AccessList.d.ts +17 -16
  5. package/dist/access/AccessList.js +218 -114
  6. package/dist/access/GrantView.d.ts +9 -8
  7. package/dist/access/GrantView.js +34 -36
  8. package/dist/access/PrincipalPicker.d.ts +38 -0
  9. package/dist/access/{GroupPicker.js → PrincipalPicker.js} +173 -80
  10. package/dist/access/index.d.ts +1 -1
  11. package/dist/access/model.d.ts +67 -24
  12. package/dist/access/model.js +111 -47
  13. package/dist/access/strings.d.ts +63 -39
  14. package/dist/access/strings.js +114 -84
  15. package/dist/access/types.d.ts +32 -14
  16. package/dist/ai/adapter/mock/mockAdapter.js +1 -1
  17. package/dist/ai/core/useSSEStream.d.ts +1 -1
  18. package/dist/components/Checkbox.js +1 -1
  19. package/dist/components/Combobox.js +25 -20
  20. package/dist/components/DatePicker.js +62 -58
  21. package/dist/components/Drawer.js +3 -1
  22. package/dist/components/Field.d.ts +8 -3
  23. package/dist/components/Field.js +32 -12
  24. package/dist/components/HoverCard.js +15 -10
  25. package/dist/components/InfoTip.d.ts +3 -1
  26. package/dist/components/InfoTip.js +2 -1
  27. package/dist/components/Menu.js +3 -0
  28. package/dist/components/Modal.js +32 -27
  29. package/dist/components/Popover.d.ts +4 -1
  30. package/dist/components/Popover.js +31 -26
  31. package/dist/components/Radio.js +1 -1
  32. package/dist/components/Select.js +47 -42
  33. package/dist/components/Slider.js +3 -3
  34. package/dist/components/Switch.js +1 -1
  35. package/dist/components/Tooltip.js +16 -11
  36. package/dist/components/fieldBox.js +1 -1
  37. package/dist/components/fullscreen.d.ts +4 -0
  38. package/dist/components/fullscreen.js +18 -0
  39. package/dist/editor/EditorField.js +1 -2
  40. package/dist/editor/Monaco.js +26 -2
  41. package/dist/editor/themes.js +1 -1
  42. package/dist/graph/GraphEditorDialogs.d.ts +1 -1
  43. package/dist/index.d.ts +1 -1
  44. package/dist/index.js +2 -2
  45. package/dist/styles/theme.css +10 -10
  46. package/dist/styles.css +1 -1
  47. package/dist/theme/derive.d.ts +2 -0
  48. package/dist/theme/derive.js +25 -14
  49. package/package.json +2 -2
  50. package/dist/access/GroupPicker.d.ts +0 -35
@@ -1,44 +1,87 @@
1
- import type { AccessChange, AccessGrant, AccessGroup, AccessPermission, AccessRole } from './types.js';
1
+ import type { AccessChange, AccessGrant, AccessInheritedGrant, AccessPermission, AccessPrincipal, AccessRole } from './types.js';
2
+ /** A role someone has without holding it here themselves. */
3
+ export interface Holding {
4
+ role: AccessRole;
5
+ /** The group, or everyone, it comes through; undefined when it is their own. */
6
+ through?: AccessPrincipal | undefined;
7
+ /** Where it was granted, when it was granted above the resource. */
8
+ from?: string | undefined;
9
+ }
2
10
  /** The grants indexed for the questions the drawer asks of them. */
3
11
  export interface AccessModel {
4
12
  roles: readonly AccessRole[];
13
+ /** The roles that can be granted here, in the roles' order. */
14
+ grantable: readonly AccessRole[];
5
15
  roleById: ReadonlyMap<string, AccessRole>;
6
- groupById: ReadonlyMap<string, AccessGroup>;
7
- everyone: AccessGroup | undefined;
8
- /** The roles each group holds itself, in the roles' order. */
16
+ principalById: ReadonlyMap<string, AccessPrincipal>;
17
+ everyone: AccessPrincipal | undefined;
18
+ /** Holds every permission and can't be removed. */
19
+ owner: AccessPrincipal | undefined;
20
+ /** The roles each principal holds itself, here, in the roles' order. */
9
21
  held: ReadonlyMap<string, readonly AccessRole[]>;
10
- /** The groups holding each role, in the order the host gave the groups. */
11
- holders: ReadonlyMap<string, readonly AccessGroup[]>;
22
+ /** The principals holding each role here, in the order the host gave the principals. */
23
+ holders: ReadonlyMap<string, readonly AccessPrincipal[]>;
24
+ /** The roles each principal holds through somewhere above the resource, in the roles' order. */
25
+ inherited: ReadonlyMap<string, readonly {
26
+ role: AccessRole;
27
+ from: string;
28
+ }[]>;
29
+ /** The principals holding each role through somewhere above the resource. */
30
+ inheritedHolders: ReadonlyMap<string, readonly {
31
+ principal: AccessPrincipal;
32
+ from: string;
33
+ }[]>;
12
34
  permissionLabel: (id: string) => string;
13
35
  }
14
- export declare function buildModel(roles: readonly AccessRole[], groups: readonly AccessGroup[], grants: readonly AccessGrant[], permissions?: readonly AccessPermission[]): AccessModel;
36
+ export interface ModelInput {
37
+ roles: readonly AccessRole[];
38
+ principals: readonly AccessPrincipal[];
39
+ grants: readonly AccessGrant[];
40
+ permissions?: readonly AccessPermission[] | undefined;
41
+ inherited?: readonly AccessInheritedGrant[] | undefined;
42
+ owner?: string | undefined;
43
+ }
44
+ export declare function buildModel({ roles, principals, grants, permissions, inherited, owner, }: ModelInput): AccessModel;
15
45
  export declare const key: (grant: AccessGrant) => string;
16
46
  /** Whether `by` gives every permission `role` does. A role with no permissions covers nothing
17
47
  * and is covered by nothing, so two empty placeholders never read as duplicates. */
18
48
  export declare function covers(by: AccessRole, role: AccessRole): boolean;
19
- /** The roles a group's members have through everyone, which it doesn't hold itself. */
20
- export declare function inheritedRoles(model: AccessModel, groupId: string): AccessRole[];
21
- /** Why a role a group holds is redundant: its other roles that already give everything this one
22
- * does, and whether everyone has it already. */
49
+ export declare const isOwner: (model: AccessModel, principalId: string) => boolean;
50
+ /** Who has access in the order the list shows them: the owner, everyone, then the rest in the
51
+ * host's order. */
52
+ export declare function principalsWithAccess(model: AccessModel): AccessPrincipal[];
53
+ /** The groups, and everyone, whose roles a principal has as well as its own. */
54
+ export declare function sourcesOf(model: AccessModel, principalId: string): AccessPrincipal[];
55
+ /** Every role a principal has besides those it holds here itself: its own granted above the
56
+ * resource, then its groups', then everyone's. */
57
+ export declare function alsoHas(model: AccessModel, principalId: string): Holding[];
58
+ /** The first holding of each role, so a role reached two ways is named once. */
59
+ export declare function firstOfEach(holdings: readonly Holding[]): Holding[];
60
+ /** Why a role a principal holds is redundant: it owns the resource, its other roles here give
61
+ * everything this one does, or it has this one, or one that covers it, somewhere else. */
23
62
  export interface Overlap {
63
+ owner: boolean;
24
64
  coveredBy: AccessRole[];
25
- everyone: boolean;
65
+ elsewhere: Holding[];
26
66
  }
27
- export declare function overlapOf(model: AccessModel, groupId: string, role: AccessRole): Overlap;
28
- /** What taking roles from a group does to its members. */
67
+ export declare function overlapOf(model: AccessModel, principalId: string, role: AccessRole): Overlap;
68
+ /** What taking roles from a principal does to whoever it stands for. */
29
69
  export interface Removal {
30
- /** The permissions they no longer have from any role, in the order the roles list them. */
70
+ /** The permissions no longer given by any role they keep, in the order the roles list them. */
31
71
  lost: string[];
32
- /** Roles still giving them some of what the removed roles gave: their own others, then
33
- * everyone's. */
72
+ /** Its own roles here still giving some of what the removed roles gave. */
34
73
  keep: AccessRole[];
35
- keepThroughEveryone: AccessRole[];
74
+ /** Roles it has elsewhere still giving some of it: granted above, or through its groups or
75
+ * everyone. */
76
+ keepElsewhere: Holding[];
77
+ /** The owner loses nothing, as owning gives every permission. */
78
+ owner: boolean;
36
79
  }
37
- /** What the group loses: the removed roles' permissions that no role it keeps, its own or
38
- * everyone's, still gives. */
39
- export declare function removalOf(model: AccessModel, groupId: string, roleIds: readonly string[]): Removal;
40
- /** Granting each role to each group: the grants that add something, and the pairs held already. */
41
- export declare function grantPlan(model: AccessModel, groupIds: readonly string[], roleIds: readonly string[]): {
80
+ /** What the principal loses: the removed roles' permissions that nothing it keeps still gives. */
81
+ export declare function removalOf(model: AccessModel, principalId: string, roleIds: readonly string[]): Removal;
82
+ /** Granting each role to each principal: the grants that add something, and the pairs held
83
+ * already. The owner holds every role already. */
84
+ export declare function grantPlan(model: AccessModel, principalIds: readonly string[], roleIds: readonly string[]): {
42
85
  grant: AccessGrant[];
43
86
  held: AccessGrant[];
44
87
  };
@@ -46,4 +89,4 @@ export declare function grantPlan(model: AccessModel, groupIds: readonly string[
46
89
  export declare function invert(change: AccessChange): AccessChange;
47
90
  /** Warns, in a development build, about props that would make the drawer wrong in a way that
48
91
  * is easy to miss: a duplicate id shows one of two, and an unknown id shows nothing. */
49
- export declare function warnAboutMisuse(roles: readonly AccessRole[], groups: readonly AccessGroup[], grants: readonly AccessGrant[], permissions: readonly AccessPermission[] | undefined): void;
92
+ export declare function warnAboutMisuse({ roles, principals, grants, permissions, inherited, owner, }: ModelInput): void;
@@ -1,31 +1,52 @@
1
1
  import { isDev } from "../dev.js";
2
2
  //#region src/access/model.ts
3
- function buildModel(roles, groups, grants, permissions = []) {
3
+ function buildModel({ roles, principals, grants, permissions = [], inherited = [], owner }) {
4
4
  const roleById = new Map(roles.map((role) => [role.id, role]));
5
- const groupById = new Map(groups.map((group) => [group.id, group]));
5
+ const principalById = new Map(principals.map((principal) => [principal.id, principal]));
6
6
  const granted = new Set(grants.map(key));
7
+ const inheritedFrom = /* @__PURE__ */ new Map();
8
+ for (const grant of inherited) if (!inheritedFrom.has(key(grant))) inheritedFrom.set(key(grant), grant.from);
7
9
  const held = /* @__PURE__ */ new Map();
8
10
  const holders = /* @__PURE__ */ new Map();
9
- for (const group of groups) {
10
- const own = roles.filter((role) => granted.has(key({
11
- groupId: group.id,
11
+ const inheritedOf = /* @__PURE__ */ new Map();
12
+ const inheritedHolders = /* @__PURE__ */ new Map();
13
+ for (const principal of principals) for (const role of roles) {
14
+ const k = key({
15
+ principalId: principal.id,
12
16
  roleId: role.id
13
- })));
14
- if (own.length > 0) held.set(group.id, own);
15
- for (const role of own) holders.set(role.id, [...holders.get(role.id) ?? [], group]);
17
+ });
18
+ if (granted.has(k)) {
19
+ held.set(principal.id, [...held.get(principal.id) ?? [], role]);
20
+ holders.set(role.id, [...holders.get(role.id) ?? [], principal]);
21
+ }
22
+ const from = inheritedFrom.get(k);
23
+ if (from !== void 0) {
24
+ inheritedOf.set(principal.id, [...inheritedOf.get(principal.id) ?? [], {
25
+ role,
26
+ from
27
+ }]);
28
+ inheritedHolders.set(role.id, [...inheritedHolders.get(role.id) ?? [], {
29
+ principal,
30
+ from
31
+ }]);
32
+ }
16
33
  }
17
34
  const labels = new Map(permissions.map((p) => [p.id, p.label]));
18
35
  return {
19
36
  roles,
37
+ grantable: roles.filter((role) => role.grantable !== false),
20
38
  roleById,
21
- groupById,
22
- everyone: groups.find((group) => group.kind === "everyone"),
39
+ principalById,
40
+ everyone: principals.find((principal) => principal.kind === "everyone"),
41
+ owner: owner === void 0 ? void 0 : principalById.get(owner),
23
42
  held,
24
43
  holders,
44
+ inherited: inheritedOf,
45
+ inheritedHolders,
25
46
  permissionLabel: (id) => labels.get(id) ?? id
26
47
  };
27
48
  }
28
- var key = (grant) => `${grant.groupId}\u0000${grant.roleId}`;
49
+ var key = (grant) => `${grant.principalId}\u0000${grant.roleId}`;
29
50
  var permissionsOf = (roles) => new Set(roles.flatMap((role) => role.permissions));
30
51
  /** Whether `by` gives every permission `role` does. A role with no permissions covers nothing
31
52
  * and is covered by nothing, so two empty placeholders never read as duplicates. */
@@ -34,32 +55,71 @@ function covers(by, role) {
34
55
  const given = new Set(by.permissions);
35
56
  return role.permissions.every((p) => given.has(p));
36
57
  }
37
- var isEveryone = (model, groupId) => model.everyone?.id === groupId;
38
- /** The roles a group's members have through everyone, which it doesn't hold itself. */
39
- function inheritedRoles(model, groupId) {
40
- if (!model.everyone || isEveryone(model, groupId)) return [];
41
- const own = new Set((model.held.get(groupId) ?? []).map((role) => role.id));
42
- return (model.held.get(model.everyone.id) ?? []).filter((role) => !own.has(role.id));
58
+ var isOwner = (model, principalId) => model.owner !== void 0 && model.owner.id === principalId;
59
+ /** Who has access in the order the list shows them: the owner, everyone, then the rest in the
60
+ * host's order. */
61
+ function principalsWithAccess(model) {
62
+ const rest = [...model.principalById.values()].filter((principal) => principal.id !== model.owner?.id && principal.id !== model.everyone?.id && (model.held.has(principal.id) || model.inherited.has(principal.id)));
63
+ const everyone = model.everyone && model.everyone.id !== model.owner?.id && (model.held.has(model.everyone.id) || model.inherited.has(model.everyone.id)) ? [model.everyone] : [];
64
+ return [
65
+ ...model.owner ? [model.owner] : [],
66
+ ...everyone,
67
+ ...rest
68
+ ];
69
+ }
70
+ /** The groups, and everyone, whose roles a principal has as well as its own. */
71
+ function sourcesOf(model, principalId) {
72
+ const principal = model.principalById.get(principalId);
73
+ if (!principal || principal.kind === "everyone") return [];
74
+ const groups = principal.kind === "user" ? (principal.groupIds ?? []).map((id) => model.principalById.get(id)).filter((group) => group?.kind === "group") : [];
75
+ return model.everyone ? [...groups, model.everyone] : groups;
76
+ }
77
+ /** Every role a principal has besides those it holds here itself: its own granted above the
78
+ * resource, then its groups', then everyone's. */
79
+ function alsoHas(model, principalId) {
80
+ const own = (model.inherited.get(principalId) ?? []).map(({ role, from }) => ({
81
+ role,
82
+ from
83
+ }));
84
+ const through = sourcesOf(model, principalId).flatMap((source) => [...(model.held.get(source.id) ?? []).map((role) => ({
85
+ role,
86
+ through: source
87
+ })), ...(model.inherited.get(source.id) ?? []).map(({ role, from }) => ({
88
+ role,
89
+ through: source,
90
+ from
91
+ }))]);
92
+ return [...own, ...through];
93
+ }
94
+ /** The first holding of each role, so a role reached two ways is named once. */
95
+ function firstOfEach(holdings) {
96
+ const seen = /* @__PURE__ */ new Set();
97
+ return holdings.filter((holding) => {
98
+ if (seen.has(holding.role.id)) return false;
99
+ seen.add(holding.role.id);
100
+ return true;
101
+ });
43
102
  }
44
- function overlapOf(model, groupId, role) {
45
- const own = (model.held.get(groupId) ?? []).filter((other) => other.id !== role.id);
46
- const everyoneRoles = model.everyone && !isEveryone(model, groupId) ? model.held.get(model.everyone.id) ?? [] : [];
103
+ function overlapOf(model, principalId, role) {
104
+ const own = (model.held.get(principalId) ?? []).filter((other) => other.id !== role.id);
47
105
  return {
106
+ owner: isOwner(model, principalId),
48
107
  coveredBy: own.filter((other) => covers(other, role)),
49
- everyone: everyoneRoles.some((other) => other.id === role.id || covers(other, role))
108
+ elsewhere: alsoHas(model, principalId).filter((holding) => holding.role.id === role.id || covers(holding.role, role))
50
109
  };
51
110
  }
52
- /** What the group loses: the removed roles' permissions that no role it keeps, its own or
53
- * everyone's, still gives. */
54
- function removalOf(model, groupId, roleIds) {
111
+ /** What the principal loses: the removed roles' permissions that nothing it keeps still gives. */
112
+ function removalOf(model, principalId, roleIds) {
55
113
  const removing = new Set(roleIds);
56
- const removed = (model.held.get(groupId) ?? []).filter((role) => removing.has(role.id));
57
- const keep = (model.held.get(groupId) ?? []).filter((role) => !removing.has(role.id));
58
- const throughEveryone = inheritedRoles(model, groupId);
59
- const still = permissionsOf([...keep, ...throughEveryone]);
114
+ const own = model.held.get(principalId) ?? [];
115
+ const removed = own.filter((role) => removing.has(role.id));
116
+ const keep = own.filter((role) => !removing.has(role.id));
117
+ const elsewhere = firstOfEach(alsoHas(model, principalId)).filter((holding) => !keep.some((role) => role.id === holding.role.id));
118
+ const owner = isOwner(model, principalId);
119
+ const still = permissionsOf([...keep, ...elsewhere.map((holding) => holding.role)]);
60
120
  const taken = permissionsOf(removed);
61
- const lost = [...taken].filter((p) => !still.has(p));
62
- const share = new Map([...keep, ...throughEveryone].map((role) => [role.id, new Set(role.permissions.filter((p) => taken.has(p)))]));
121
+ const lost = owner ? [] : [...taken].filter((p) => !still.has(p));
122
+ const share = new Map([...keep, ...elsewhere.map((holding) => holding.role)].map((role) => [role.id, new Set(role.permissions.filter((p) => taken.has(p)))]));
63
123
  const worth = (role) => {
64
124
  const mine = share.get(role.id) ?? /* @__PURE__ */ new Set();
65
125
  return mine.size > 0 && ![...share].some(([id, theirs]) => id !== role.id && [...mine].every((p) => theirs.has(p)) && (theirs.size > mine.size || id < role.id));
@@ -67,17 +127,20 @@ function removalOf(model, groupId, roleIds) {
67
127
  return {
68
128
  lost,
69
129
  keep: keep.filter(worth),
70
- keepThroughEveryone: throughEveryone.filter(worth)
130
+ keepElsewhere: elsewhere.filter((holding) => worth(holding.role)),
131
+ owner
71
132
  };
72
133
  }
73
- /** Granting each role to each group: the grants that add something, and the pairs held already. */
74
- function grantPlan(model, groupIds, roleIds) {
134
+ /** Granting each role to each principal: the grants that add something, and the pairs held
135
+ * already. The owner holds every role already. */
136
+ function grantPlan(model, principalIds, roleIds) {
75
137
  const grant = [];
76
138
  const held = [];
77
- for (const groupId of groupIds) {
78
- const own = new Set((model.held.get(groupId) ?? []).map((role) => role.id));
79
- for (const roleId of roleIds) (own.has(roleId) ? held : grant).push({
80
- groupId,
139
+ for (const principalId of principalIds) {
140
+ const own = new Set((model.held.get(principalId) ?? []).map((role) => role.id));
141
+ const owner = isOwner(model, principalId);
142
+ for (const roleId of roleIds) (owner || own.has(roleId) ? held : grant).push({
143
+ principalId,
81
144
  roleId
82
145
  });
83
146
  }
@@ -95,21 +158,22 @@ function invert(change) {
95
158
  }
96
159
  /** Warns, in a development build, about props that would make the drawer wrong in a way that
97
160
  * is easy to miss: a duplicate id shows one of two, and an unknown id shows nothing. */
98
- function warnAboutMisuse(roles, groups, grants, permissions) {
161
+ function warnAboutMisuse({ roles, principals, grants, permissions, inherited = [], owner }) {
99
162
  if (!isDev()) return;
100
163
  const warn = (message) => console.warn(`AccessDrawer: ${message}`);
101
164
  for (const id of duplicates(roles.map((role) => role.id))) warn(`two roles share the id "${id}"; ids must be unique.`);
102
- for (const id of duplicates(groups.map((group) => group.id))) warn(`two groups share the id "${id}"; ids must be unique.`);
103
- if (groups.filter((group) => group.kind === "everyone").length > 1) warn("more than one group is everyone; only the first counts.");
165
+ for (const id of duplicates(principals.map((principal) => principal.id))) warn(`two principals share the id "${id}"; ids must be unique.`);
166
+ if (principals.filter((principal) => principal.kind === "everyone").length > 1) warn("more than one principal is everyone; only the first counts.");
104
167
  const roleIds = new Set(roles.map((role) => role.id));
105
- const groupIds = new Set(groups.map((group) => group.id));
106
- for (const grant of grants) {
107
- if (!roleIds.has(grant.roleId)) warn(`a grant names the unknown role "${grant.roleId}"; it isn't shown.`);
108
- if (!groupIds.has(grant.groupId)) warn(`a grant names the unknown group "${grant.groupId}"; pass every granted group.`);
168
+ const principalIds = new Set(principals.map((principal) => principal.id));
169
+ if (owner !== void 0 && !principalIds.has(owner)) warn(`the owner "${owner}" isn't among the principals; pass the owner too.`);
170
+ for (const [kind, list] of [["grant", grants], ["inherited grant", inherited]]) for (const grant of list) {
171
+ if (!roleIds.has(grant.roleId)) warn(`a ${kind} names the unknown role "${grant.roleId}"; it isn't shown.`);
172
+ if (!principalIds.has(grant.principalId)) warn(`a ${kind} names the unknown principal "${grant.principalId}"; pass everyone who holds a role.`);
109
173
  }
110
174
  for (const k of duplicates(grants.map(key))) {
111
- const [groupId, roleId] = k.split("\0");
112
- warn(`the grant of "${roleId}" to "${groupId}" is listed twice.`);
175
+ const [principalId, roleId] = k.split("\0");
176
+ warn(`the grant of "${roleId}" to "${principalId}" is listed twice.`);
113
177
  }
114
178
  if (permissions) {
115
179
  const known = new Set(permissions.map((p) => p.id));
@@ -126,4 +190,4 @@ function duplicates(ids) {
126
190
  return [...repeated];
127
191
  }
128
192
  //#endregion
129
- export { buildModel, covers, grantPlan, inheritedRoles, invert, key, overlapOf, removalOf, warnAboutMisuse };
193
+ export { alsoHas, buildModel, covers, firstOfEach, grantPlan, invert, isOwner, key, overlapOf, principalsWithAccess, removalOf, sourcesOf, warnAboutMisuse };
@@ -2,19 +2,20 @@ import { type ReactNode } from 'react';
2
2
  import { type UIStrings } from '../components/Provider.js';
3
3
  export declare const ACCESS_STRINGS: {
4
4
  title: string;
5
- /** Under the title: the resource, and how many groups have a role on it. */
6
- summary: (resource: string, groups: number, everyone: boolean) => string;
5
+ /** Under the title: the resource, and who has a role on it. */
6
+ summary: (resource: string, people: number, groups: number, everyone: boolean) => string;
7
7
  /** Names the switch between the two ways of listing who has access. */
8
8
  arrange: string;
9
9
  byRole: string;
10
- byGroup: string;
10
+ byPrincipal: string;
11
11
  filter: string;
12
12
  grantAccess: string;
13
- highImpact: string;
13
+ privileged: string;
14
14
  loading: string;
15
- groups: (n: number) => string;
16
- /** How many of a role's groups a filter left. */
17
- groupsShown: (shown: number, total: number) => string;
15
+ /** Who holds a role: "1 person, 2 groups". */
16
+ holders: (people: number, groups: number) => string;
17
+ /** How many of a role's holders a filter left. */
18
+ holdersShown: (shown: number, total: number) => string;
18
19
  members: (n: number) => string;
19
20
  people: (n: number) => string;
20
21
  /** Everyone, where it is short: a tag or a picker row. */
@@ -22,38 +23,55 @@ export declare const ACCESS_STRINGS: {
22
23
  /** Everyone, where it stands as a row of its own. */
23
24
  everyoneInOrganization: string;
24
25
  everyoneJoinLater: string;
25
- /** Read with the badges a group row folds away: "+2". */
26
+ owner: string;
27
+ /** Under the owner section and row. */
28
+ ownerDescription: string;
29
+ /** Read with the badges a row folds away: "+2". */
26
30
  moreRoles: (n: number) => string;
27
31
  moreRolesLabel: (roles: readonly string[]) => string;
28
- /** Beside a group whose other role gives everything this one does. */
32
+ /** Beside someone whose other role gives everything this one does. */
29
33
  coveredBy: (roles: readonly string[]) => string;
30
- /** Beside a group that has this through everyone as well. */
34
+ /** Beside the owner, who has every role's permissions anyway. */
35
+ ownerHasAll: string;
36
+ /** Beside someone who has this through everyone as well. */
31
37
  everyoneHasThisToo: string;
32
- /** A role a group holds that another of its roles already gives. */
38
+ /** Beside someone who has this through their groups, or an inherited role, as well. */
39
+ throughToo: (from: readonly string[]) => string;
40
+ /** A role someone holds that another of their roles already gives. */
33
41
  redundant: (roles: readonly string[]) => string;
34
- /** A role a group has only because everyone does. */
42
+ redundantOwner: string;
43
+ /** A role someone has only because everyone does. */
35
44
  throughEveryone: string;
36
- removeRole: (group: string, role: string) => string;
45
+ /** A role someone has through one of their groups, or an inherited role. */
46
+ through: (from: string) => string;
47
+ /** A role granted somewhere else, which can't be removed here. */
48
+ inheritedFrom: (from: string) => string;
49
+ removeRole: (principal: string, role: string) => string;
37
50
  grantMoreRoles: string;
38
51
  removeAllAccess: string;
39
- removeTitle: (group: string, roles: readonly string[]) => string;
40
- removeAllTitle: (group: string) => string;
41
- /** Leads the list of what a group loses; `members` is undefined when the count isn't known. */
42
- losesIntro: (members: number | undefined, everyone: boolean) => string;
43
- /** After the list: why these are lost, and what they keep. */
44
- keeps: (own: readonly string[], throughEveryone: readonly string[]) => string;
45
- /** When the roles it keeps give everything the removed ones did. */
46
- losesNothing: (own: readonly string[], throughEveryone: readonly string[]) => string;
52
+ removeTitle: (principal: string, roles: readonly string[]) => string;
53
+ removeAllTitle: (principal: string) => string;
54
+ /** Heads the list of what is lost; `members` is undefined when a group's size isn't known. */
55
+ losesIntro: (kind: 'user' | 'group' | 'everyone', members: number | undefined) => string;
56
+ /** After the list: what they keep, their own roles and those through their groups, inherited
57
+ * roles or everyone. Empty when they keep nothing. */
58
+ keeps: (own: readonly string[], throughEveryone: readonly string[], through: readonly {
59
+ from: string;
60
+ roles: readonly string[];
61
+ }[]) => string;
62
+ /** When the roles they keep give everything the removed ones did. */
63
+ losesNothing: (roles: readonly string[]) => string;
64
+ ownerLosesNothing: string;
47
65
  confirmRemove: (roles: readonly string[]) => string;
48
- removeFailed: (group: string, roles: readonly string[]) => string;
49
- grantFailed: (groups: readonly string[], roles: readonly string[]) => string;
66
+ removeFailed: (principal: string, roles: readonly string[]) => string;
67
+ grantFailed: (principals: readonly string[], roles: readonly string[]) => string;
50
68
  undoFailed: string;
51
69
  /** Under a failed save; `reason` is the host's error message, when it gave one. */
52
70
  nothingChanged: (reason: string | undefined) => string;
53
71
  /** The toast after a grant. */
54
- granted: (groups: readonly string[], roles: readonly string[]) => string;
72
+ granted: (principals: readonly string[], roles: readonly string[]) => string;
55
73
  /** The toast after a removal. */
56
- removed: (groups: readonly string[], roles: readonly string[]) => string;
74
+ removed: (principals: readonly string[], roles: readonly string[]) => string;
57
75
  undone: string;
58
76
  readOnly: string;
59
77
  /** After `readOnly` when the host gives no reason. */
@@ -63,30 +81,33 @@ export declare const ACCESS_STRINGS: {
63
81
  noMatches: string;
64
82
  clearFilter: string;
65
83
  back: string;
66
- groupsLabel: string;
67
- addGroup: string;
68
- /** Under the groups field; `count` is undefined when the host doesn't say how many there are. */
69
- groupsHint: (count: number | undefined, everyone: boolean) => string;
84
+ principalsLabel: string;
85
+ addPrincipal: string;
86
+ /** Under the people and groups field; a count is undefined when the host doesn't give it. */
87
+ pickerHint: (people: number | undefined, groups: number | undefined, everyone: boolean) => string;
70
88
  everyoneCoversGroups: string;
71
89
  organization: string;
72
90
  recent: string;
73
- allGroups: string;
74
- /** On a group's row in the picker: the roles it holds here. */
91
+ peopleSection: string;
92
+ groupsSection: string;
93
+ /** On a row in the picker: the roles it holds here. */
75
94
  hasRoles: (roles: readonly string[]) => string;
76
95
  /** Read with a group's row: its size, where it comes from and its roles here. */
77
96
  groupSummary: (members: number | undefined, everyone: boolean, source: 'synced' | 'manual' | undefined, roles: readonly string[]) => string;
97
+ /** Read with a person's row: what tells them apart, and their roles here. */
98
+ personSummary: (detail: string | undefined, owner: boolean, roles: readonly string[]) => string;
78
99
  rolesLabel: string;
79
100
  searchRoles: string;
80
101
  /** On a role's row in the picker. */
81
- alreadyHave: (groups: readonly string[]) => string;
102
+ alreadyHave: (principals: readonly string[]) => string;
82
103
  alreadyCovered: (roles: readonly string[]) => string;
83
104
  everyoneHasIt: string;
84
105
  /** The footer's account of what pressing Grant does. */
85
- grantSummary: (groups: readonly string[], roles: readonly string[]) => ReactNode;
86
- /** Why Grant can't be pressed: every group has every role already. */
87
- nothingToGrant: (groups: readonly string[], roles: readonly string[]) => string;
88
- pickGroupsAndRoles: string;
89
- pickGroups: string;
106
+ grantSummary: (principals: readonly string[], roles: readonly string[]) => ReactNode;
107
+ /** Why Grant can't be pressed: everyone picked has every role picked already. */
108
+ nothingToGrant: (principals: readonly string[], roles: readonly string[]) => string;
109
+ pickPrincipalsAndRoles: string;
110
+ pickPrincipals: string;
90
111
  pickRoles: string;
91
112
  grant: (roles: readonly string[]) => string;
92
113
  grantToEveryone: string;
@@ -98,12 +119,15 @@ export declare const ACCESS_STRINGS: {
98
119
  manual: string;
99
120
  wholeOrganization: string;
100
121
  joinLater: string;
122
+ /** Heads the groups a person is in that hold a role here. */
123
+ inGroups: string;
101
124
  /** The first few members by name, and how many more there are. */
102
125
  memberNames: (names: readonly string[], more: number) => string;
103
126
  moreMembers: (n: number) => string;
104
- onResource: (resource: string) => string;
127
+ /** Heads the roles the highlighted one holds on this resource. */
128
+ currentRoles: string;
105
129
  noRolesHere: string;
106
- /** When a role being granted gives everything one the group holds does. */
130
+ /** When a role being granted gives everything one already held does. */
107
131
  becomesRedundant: (granting: readonly string[], held: readonly string[]) => string;
108
132
  alreadyHas: (roles: readonly string[]) => string;
109
133
  everyoneReach: (roles: readonly string[], people: number | undefined) => string;