@50arms/ui 35.2.0 → 35.3.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.
- package/dist/components/rbac/AccessRequestPanel.js +117 -100
- package/dist/components/rbac/AccessRequestPanel.js.map +1 -1
- package/dist/lib/i18n/areas/rbac.js +4 -1
- package/dist/lib/i18n/areas/rbac.js.map +1 -1
- package/dist/types/components/rbac/AccessRequestPanel.d.ts +18 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/lib/i18n/areas/rbac.d.ts +6 -0
- package/package.json +1 -1
|
@@ -1,150 +1,167 @@
|
|
|
1
|
-
import { jsxs as
|
|
1
|
+
import { jsxs as c, jsx as i, Fragment as k } from "react/jsx-runtime";
|
|
2
2
|
import { useState as p } from "react";
|
|
3
|
-
import { Button as
|
|
3
|
+
import { Button as R } from "../Button.js";
|
|
4
4
|
import { Callout as u } from "../Callout.js";
|
|
5
|
-
import { Dialog as
|
|
6
|
-
import { DescriptionList as
|
|
7
|
-
import { cn as
|
|
8
|
-
import { DateTimeText as
|
|
9
|
-
import { RelativeTime as
|
|
10
|
-
import { isRoleSelectable as K, leastPrivilegeRoleId as
|
|
11
|
-
import { confirmCodeMatches as
|
|
12
|
-
import { useUiStrings as
|
|
13
|
-
function
|
|
14
|
-
return
|
|
5
|
+
import { Dialog as U } from "../Dialog.js";
|
|
6
|
+
import { DescriptionList as W } from "../DescriptionList.js";
|
|
7
|
+
import { cn as z } from "../../lib/cn.js";
|
|
8
|
+
import { DateTimeText as F, useDateTimeText as J } from "../DateTimeText.js";
|
|
9
|
+
import { RelativeTime as Q } from "../RelativeTime.js";
|
|
10
|
+
import { isRoleSelectable as K, leastPrivilegeRoleId as X, RoleKeyPicker as Y } from "./RoleKeyPicker.js";
|
|
11
|
+
import { confirmCodeMatches as Z, useApprovalActions as $, ApprovalHeader as q, ConfirmCodeEntry as ee, ConfirmCodeCallout as ne, ApprovalError as ie, ApprovalButtons as oe, ExpiredNotice as re, TerminalCallout as b } from "./approvalPanelParts.js";
|
|
12
|
+
import { useUiStrings as v } from "../../lib/i18n/provider.js";
|
|
13
|
+
function C(e) {
|
|
14
|
+
return "fixedRole" in e && e.fixedRole !== void 0;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
function I(e) {
|
|
17
|
+
return e.request.kind === "machine" || C(e);
|
|
18
|
+
}
|
|
19
|
+
function te({ role: e, permissions: n }) {
|
|
20
|
+
const t = v().accessRequest, o = e.permissionKeys.map((r) => n.find((l) => l.key === r)?.label ?? r);
|
|
21
|
+
return /* @__PURE__ */ c("section", { "aria-label": t.fixedRoleTitle, className: "flex flex-col gap-2", children: [
|
|
22
|
+
/* @__PURE__ */ c("div", { className: "flex flex-col gap-0.5", children: [
|
|
23
|
+
/* @__PURE__ */ i("span", { className: "text-sm font-medium text-primary", children: t.fixedRoleTitle }),
|
|
24
|
+
/* @__PURE__ */ i("span", { className: "text-2xs text-tertiary", children: t.fixedRoleHint })
|
|
25
|
+
] }),
|
|
26
|
+
/* @__PURE__ */ c("div", { className: "flex flex-col gap-1 rounded-md border border-border bg-surface-raised p-3", children: [
|
|
27
|
+
/* @__PURE__ */ i("span", { className: "text-sm font-medium text-primary", children: e.label }),
|
|
28
|
+
e.description && /* @__PURE__ */ i("span", { className: "text-xs text-secondary", children: e.description }),
|
|
29
|
+
o.length > 0 && /* @__PURE__ */ i("ul", { className: "mt-1 flex list-disc flex-col gap-0.5 pl-4 text-xs text-secondary", children: o.map((r) => /* @__PURE__ */ i("li", { children: r }, r)) })
|
|
30
|
+
] })
|
|
31
|
+
] });
|
|
32
|
+
}
|
|
33
|
+
const le = {
|
|
34
|
+
session: (e) => e.kindSession,
|
|
35
|
+
worker: (e) => e.kindWorker,
|
|
36
|
+
machine: (e) => e.kindMachine
|
|
37
|
+
}, se = {
|
|
38
|
+
session: (e) => e.session,
|
|
39
|
+
worker: (e) => e.worker,
|
|
40
|
+
machine: (e) => e.machine
|
|
24
41
|
};
|
|
25
|
-
function
|
|
26
|
-
const { accessRequest:
|
|
42
|
+
function ae(e, n, t) {
|
|
43
|
+
const { accessRequest: o, approval: r } = e;
|
|
27
44
|
return [
|
|
28
|
-
{ key: "kind", term:
|
|
45
|
+
{ key: "kind", term: o.kind, value: le[n.kind](o) },
|
|
29
46
|
{
|
|
30
47
|
key: "label",
|
|
31
|
-
term:
|
|
32
|
-
value:
|
|
33
|
-
mono:
|
|
48
|
+
term: se[n.kind](o),
|
|
49
|
+
value: n.label,
|
|
50
|
+
mono: n.kind !== "session"
|
|
34
51
|
},
|
|
35
|
-
|
|
52
|
+
n.repo ? { key: "repo", term: o.repository, value: n.repo } : null,
|
|
36
53
|
// DXUI-15: a machine request's label row already names the machine, so its host is not shown a second time.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
54
|
+
n.machine && n.kind !== "machine" ? { key: "machine", term: o.machine, value: n.machine } : null,
|
|
55
|
+
n.requesterIp ? { key: "ip", term: o.address, value: n.requesterIp, mono: !0 } : null,
|
|
56
|
+
n.clientVersion ? { key: "version", term: o.clientVersion, value: n.clientVersion } : null,
|
|
40
57
|
{
|
|
41
58
|
key: "requested",
|
|
42
|
-
term:
|
|
43
|
-
value: /* @__PURE__ */
|
|
44
|
-
/* @__PURE__ */
|
|
59
|
+
term: r.requested,
|
|
60
|
+
value: /* @__PURE__ */ c(k, { children: [
|
|
61
|
+
/* @__PURE__ */ i(F, { at: n.requestedAt }),
|
|
45
62
|
" (",
|
|
46
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ i(Q, { at: n.requestedAt, tooltip: !1 }),
|
|
47
64
|
")"
|
|
48
65
|
] })
|
|
49
66
|
},
|
|
50
|
-
|
|
67
|
+
t && n.expiresAt ? { key: "expires", term: r.expires, value: /* @__PURE__ */ i(F, { at: n.expiresAt }) } : null
|
|
51
68
|
].filter((s) => s !== null);
|
|
52
69
|
}
|
|
53
|
-
function
|
|
54
|
-
const
|
|
55
|
-
async function
|
|
56
|
-
l(!0),
|
|
70
|
+
function ce({ onRevoke: e }) {
|
|
71
|
+
const n = v().accessRequest, [t, o] = p(!1), [r, l] = p(!1), [s, d] = p(null);
|
|
72
|
+
async function x() {
|
|
73
|
+
l(!0), d(null);
|
|
57
74
|
try {
|
|
58
|
-
await
|
|
59
|
-
} catch (
|
|
60
|
-
|
|
75
|
+
await e();
|
|
76
|
+
} catch (m) {
|
|
77
|
+
d(m instanceof Error ? m.message : n.revokeFailedMessage);
|
|
61
78
|
} finally {
|
|
62
|
-
l(!1),
|
|
79
|
+
l(!1), o(!1);
|
|
63
80
|
}
|
|
64
81
|
}
|
|
65
|
-
return /* @__PURE__ */
|
|
66
|
-
s !== null && /* @__PURE__ */
|
|
67
|
-
/* @__PURE__ */
|
|
68
|
-
/* @__PURE__ */
|
|
69
|
-
|
|
82
|
+
return /* @__PURE__ */ c("div", { className: "flex flex-col gap-3", children: [
|
|
83
|
+
s !== null && /* @__PURE__ */ i(u, { tone: "danger", live: !0, title: n.revokeFailedTitle, children: s }),
|
|
84
|
+
/* @__PURE__ */ i("div", { className: "flex sm:justify-end", children: /* @__PURE__ */ i(R, { variant: "danger", onClick: () => o(!0), className: "w-full sm:w-auto", children: n.revokeKey }) }),
|
|
85
|
+
/* @__PURE__ */ i(
|
|
86
|
+
U,
|
|
70
87
|
{
|
|
71
|
-
open:
|
|
72
|
-
onOpenChange: (
|
|
73
|
-
|
|
88
|
+
open: t,
|
|
89
|
+
onOpenChange: (m) => {
|
|
90
|
+
r || o(m);
|
|
74
91
|
},
|
|
75
|
-
title:
|
|
76
|
-
description:
|
|
77
|
-
actions: /* @__PURE__ */
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
/* @__PURE__ */
|
|
80
|
-
|
|
81
|
-
}, loading:
|
|
92
|
+
title: n.revokeTitle,
|
|
93
|
+
description: n.revokeBody,
|
|
94
|
+
actions: /* @__PURE__ */ c(k, { children: [
|
|
95
|
+
/* @__PURE__ */ i(R, { variant: "outline", onClick: () => o(!1), disabled: r, children: n.revokeCancel }),
|
|
96
|
+
/* @__PURE__ */ i(R, { variant: "danger", onClick: () => {
|
|
97
|
+
x();
|
|
98
|
+
}, loading: r, children: n.revokeKey })
|
|
82
99
|
] })
|
|
83
100
|
}
|
|
84
101
|
)
|
|
85
102
|
] });
|
|
86
103
|
}
|
|
87
|
-
function
|
|
88
|
-
const
|
|
89
|
-
return /* @__PURE__ */
|
|
104
|
+
function de({ revokedAt: e, revokedBy: n }) {
|
|
105
|
+
const t = v().accessRequest;
|
|
106
|
+
return /* @__PURE__ */ i(k, { children: t.revokedBody(J(e), n) });
|
|
90
107
|
}
|
|
91
|
-
function
|
|
92
|
-
state:
|
|
93
|
-
request:
|
|
94
|
-
expiredNote:
|
|
95
|
-
issuedKey:
|
|
96
|
-
revokedKey:
|
|
108
|
+
function me({
|
|
109
|
+
state: e,
|
|
110
|
+
request: n,
|
|
111
|
+
expiredNote: t,
|
|
112
|
+
issuedKey: o,
|
|
113
|
+
revokedKey: r
|
|
97
114
|
}) {
|
|
98
|
-
const l =
|
|
99
|
-
if (
|
|
100
|
-
return /* @__PURE__ */
|
|
101
|
-
switch (
|
|
115
|
+
const l = v().accessRequest;
|
|
116
|
+
if (r?.revokedAt)
|
|
117
|
+
return /* @__PURE__ */ i(u, { tone: "danger", title: l.revoked, children: /* @__PURE__ */ i(de, { revokedAt: r.revokedAt, revokedBy: r.revokedBy }) });
|
|
118
|
+
switch (e) {
|
|
102
119
|
case "approved":
|
|
103
|
-
return /* @__PURE__ */
|
|
120
|
+
return /* @__PURE__ */ i(b, { state: e, children: l.approved(n.roleLabel) });
|
|
104
121
|
case "claimed":
|
|
105
|
-
return /* @__PURE__ */
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
|
|
122
|
+
return /* @__PURE__ */ c("div", { className: "flex flex-col gap-4", children: [
|
|
123
|
+
/* @__PURE__ */ i(b, { state: e, children: l.claimed(n.roleLabel) }),
|
|
124
|
+
o?.onRevoke && /* @__PURE__ */ i(ce, { onRevoke: o.onRevoke })
|
|
108
125
|
] });
|
|
109
126
|
case "denied":
|
|
110
|
-
return /* @__PURE__ */
|
|
127
|
+
return /* @__PURE__ */ i(b, { state: e, children: l.denied });
|
|
111
128
|
case "expired":
|
|
112
|
-
return /* @__PURE__ */
|
|
129
|
+
return /* @__PURE__ */ i(re, { note: t, fallback: l.expiredFallback });
|
|
113
130
|
}
|
|
114
131
|
}
|
|
115
|
-
function Ae(
|
|
116
|
-
const { request:
|
|
117
|
-
return /* @__PURE__ */
|
|
118
|
-
/* @__PURE__ */
|
|
119
|
-
/* @__PURE__ */
|
|
120
|
-
P ? /* @__PURE__ */
|
|
121
|
-
s ? /* @__PURE__ */
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
function Ae(e) {
|
|
133
|
+
const { request: n, state: t, defaultRoleId: o, onDeny: r, expiredNote: l, confirmCodeEntry: s = !1, issuedKey: d, aboveActions: x, className: m } = e, S = I(e), f = e.roles ?? [], V = e.permissions ?? [], A = e.ownPermissionKeys ?? [], N = t === "claimed" && d?.revokedAt ? d : void 0, h = v(), a = h.accessRequest, y = new Set(A), T = o !== void 0 && K(o, f, y), w = T ? o : X(f, y), B = f.find((_) => _.id === w), [E, M] = p(""), g = K(E, f, y) ? E : w, [D, O] = p(""), j = !s || Z(D, n.confirmCode), { busy: L, error: H, run: G } = $(), P = t === "pending";
|
|
134
|
+
return /* @__PURE__ */ c("div", { className: z("flex flex-col gap-5", m), children: [
|
|
135
|
+
/* @__PURE__ */ i(q, { title: a.title, state: t, revokedLabel: N ? a.revoked : void 0 }),
|
|
136
|
+
/* @__PURE__ */ i(W, { entries: ae(h, n, P), className: "divide-y divide-border-subtle" }),
|
|
137
|
+
P ? /* @__PURE__ */ c(k, { children: [
|
|
138
|
+
s ? /* @__PURE__ */ i(ee, { expected: n.confirmCode, value: D, onValueChange: O }) : /* @__PURE__ */ i(ne, { code: n.confirmCode }),
|
|
139
|
+
/* @__PURE__ */ i(u, { tone: "warning", title: h.approval.approveOnlyTitle, children: C(e) ? a.approveBodyFixedRole(s) : a.approveBody(n.kind, s) }),
|
|
140
|
+
/* @__PURE__ */ i(ie, { error: H }),
|
|
141
|
+
C(e) ? /* @__PURE__ */ i(te, { role: e.fixedRole, permissions: e.permissions }) : n.kind === "machine" ? /* @__PURE__ */ i(u, { tone: "info", title: a.machineGrantTitle, children: a.machineGrant }) : B === void 0 ? /* @__PURE__ */ i(u, { tone: "danger", title: a.noRoleTitle, children: a.noRoleBody }) : /* @__PURE__ */ i(
|
|
142
|
+
Y,
|
|
126
143
|
{
|
|
127
|
-
roles:
|
|
128
|
-
permissions:
|
|
129
|
-
ownPermissionKeys:
|
|
130
|
-
value:
|
|
131
|
-
onValueChange:
|
|
132
|
-
description: a.roleHint(
|
|
144
|
+
roles: f,
|
|
145
|
+
permissions: V,
|
|
146
|
+
ownPermissionKeys: A,
|
|
147
|
+
value: g,
|
|
148
|
+
onValueChange: M,
|
|
149
|
+
description: a.roleHint(B.label, T),
|
|
133
150
|
disabled: L !== null
|
|
134
151
|
}
|
|
135
152
|
),
|
|
136
|
-
|
|
137
|
-
/* @__PURE__ */
|
|
153
|
+
x,
|
|
154
|
+
/* @__PURE__ */ i(
|
|
138
155
|
oe,
|
|
139
156
|
{
|
|
140
157
|
busy: L,
|
|
141
158
|
run: G,
|
|
142
|
-
onApprove: () =>
|
|
143
|
-
onDeny:
|
|
144
|
-
approveDisabled: !
|
|
159
|
+
onApprove: () => I(e) ? e.onApprove() : e.onApprove(g),
|
|
160
|
+
onDeny: r,
|
|
161
|
+
approveDisabled: !j || !S && g === ""
|
|
145
162
|
}
|
|
146
163
|
)
|
|
147
|
-
] }) : /* @__PURE__ */
|
|
164
|
+
] }) : /* @__PURE__ */ i(me, { state: t, request: n, expiredNote: l, issuedKey: d, revokedKey: N })
|
|
148
165
|
] });
|
|
149
166
|
}
|
|
150
167
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessRequestPanel.js","sources":["../../../src/components/rbac/AccessRequestPanel.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { Button } from \"../Button\";\nimport { Callout } from \"../Callout\";\nimport { Dialog } from \"../Dialog\";\nimport { DescriptionList, type DescriptionListEntry } from \"../DescriptionList\";\nimport { cn } from \"../../lib/cn\";\nimport { DateTimeText, useDateTimeText } from \"../DateTimeText\";\nimport { RelativeTime } from \"../RelativeTime\";\nimport { useUiStrings } from \"../../lib/i18n\";\nimport type { UiStrings } from \"../../lib/i18n\";\nimport type { AccessRequestKind } from \"../../lib/i18n/areas/rbac\";\nimport { isRoleSelectable, leastPrivilegeRoleId, RoleKeyPicker } from \"./RoleKeyPicker\";\nimport {\n ApprovalButtons,\n ApprovalError,\n ApprovalHeader,\n ConfirmCodeCallout,\n ConfirmCodeEntry,\n confirmCodeMatches,\n ExpiredNotice,\n TerminalCallout,\n type ExpiredNote,\n useApprovalActions,\n type AccessRequestState,\n} from \"./approvalPanelParts\";\nimport type { Permission, Role } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n ACCESS REQUEST PANEL\n\n THE SCREEN A PERSON SEES WHEN SOMETHING ELSE ASKS TO ACT AS THEM. An agent\n session or a worker holds no credential until a signed-in person approves its\n request; approving mints a key under that person with a role they choose.\n This panel is the whole decision: who is asking, the code to compare, the\n role to grant, approve or deny.\n\n PRESENTATIONAL. It fetches nothing and knows no endpoint. `state` is whatever\n the consumer's server derived: it is never computed here, and never assumed\n to follow a click. After `onApprove` resolves the panel stays \"pending\" until\n the consumer hands it `state=\"approved\"`. `onApprove` / `onDeny` return\n promises; a rejection shows its message in the panel and re-enables the\n buttons.\n\n THE CONFIRM CODE IS FOR COMPARING, NOT COPYING. The requester displays the\n same code in its own terminal and the person checks the two match. That is\n the defence against being sent a link to someone else's request, so the code\n is deliberately plain large text, with no copy control (which would invite\n pasting it somewhere instead of reading it against the requester's screen).\n The panel never authenticates anything with it.\n\n `confirmCodeEntry` TURNS COMPARING INTO TYPING (DX-4467). For a screen where a request may be junk someone\n addressed to the approver, a mis-click on the wrong request must not approve it: the code is then never shown,\n a field takes the code the requester displays, and Approve stays disabled until it matches (case and spaces\n ignored). Deny is always available, and every fact stays visible so the approver can refuse what they do not\n recognise. The match is a client-side gate, not authentication.\n\n THE ROLE STARTS AT THE NARROWEST ONE ALLOWED. Approval is a grant, so the\n default is the selectable role with the fewest permissions, never the\n approver's own role (which would make \"just click Approve\" the broadest\n choice). Roles holding a permission the approver lacks are disabled with the\n missing permissions named (`RoleKeyPicker`, shared with `ApiKeysPanel`).\n Approve stays disabled until a role is chosen, which only matters when no\n role is allowed at all; the panel then says so.\n\n Only a pending request has controls. Approved, denied, expired and claimed\n are terminal readouts: a `Callout` for what it means for the requester, a\n `Badge` for the state at a glance.\n ---------------------------------------------------------------------------- */\n\n/** DXUI-15: `machine` is a dev machine's unattended maintenance: a fixed read-only grant, so no role is chosen. */\nexport type { AccessRequestKind };\n\nexport type { AccessRequestState, ExpiredNote };\n\nexport interface AccessRequest {\n kind: AccessRequestKind;\n /** The session title or the worker id: what the requester calls itself. */\n label: string;\n repo?: string;\n machine?: string;\n /** The address the request came from. */\n requesterIp?: string;\n clientVersion?: string;\n /** ISO instant. */\n requestedAt: string;\n /** ISO instant. Shown while the request is pending. */\n expiresAt?: string;\n /** The short code the requester also displays. Compared by eye, or typed back when `confirmCodeEntry` is set. */\n confirmCode: string;\n /** The label of the role granted. Shown once the request is approved or claimed. */\n roleLabel?: string;\n}\n\n/**\n * DX-4856: the key a claim minted, and what a person may do with it. Pass it once the requester holds a key; omit it before that.\n * `revokedAt` set means the key was revoked: the panel reads Revoked and offers nothing. Otherwise `onRevoke` (pass it only for a\n * person allowed to revoke this key) adds a Revoke key button behind a confirmation dialog.\n */\nexport interface IssuedKey {\n /** ISO instant the key was revoked. */\n revokedAt?: string;\n /** Who revoked it, when a person did. */\n revokedBy?: string;\n /** Revokes the key. A rejection shows its message in the panel; a resolution leaves the panel as it was until the consumer hands it `revokedAt`. */\n onRevoke?: () => Promise<void>;\n}\n\ninterface AccessRequestPanelCommonProps {\n state: AccessRequestState;\n onDeny: () => Promise<void>;\n /**\n * Why an expired request expired and what its requester does next. Used only in the `expired` state; without it the readout says only\n * that nothing was granted.\n */\n expiredNote?: ExpiredNote;\n /**\n * Opt in to typing the confirm code instead of comparing it by eye: the code is not rendered, a field takes it, and Approve is\n * disabled until what was typed matches `request.confirmCode`, ignoring case and spaces. Deny stays available.\n */\n confirmCodeEntry?: boolean;\n /** DX-4856: the key this request minted, with its revoke. Used only in the `claimed` state. */\n issuedKey?: IssuedKey;\n /**\n * DXUI-95: the consumer's own control, drawn just above the Approve and Deny buttons while `state` is `pending`, on role and\n * machine requests alike (for example a switch for machine auto-approve). Never rendered in a terminal state. The panel\n * knows nothing of what it holds.\n */\n aboveActions?: ReactNode;\n className?: string;\n}\n\n/** A session or worker request: the approver chooses the role the key gets. */\nexport interface RoleAccessRequestPanelProps extends AccessRequestPanelCommonProps {\n request: AccessRequest & { kind: \"session\" | \"worker\" };\n /** The roles the approver may grant. */\n roles: Role[];\n /** The permission catalog, used to name the permissions that make a role unavailable. */\n permissions: Permission[];\n /** What the approver holds. A role holding anything outside this set cannot be chosen. */\n ownPermissionKeys: string[];\n /**\n * The role to start on instead of the narrowest allowed one (DX-4431: an agent session starts on the team's\n * default agent role). Used only while it is selectable; otherwise the narrowest allowed role applies.\n */\n defaultRoleId?: string;\n onApprove: (roleId: string) => Promise<void>;\n}\n\n/** DXUI-15: a machine request has a fixed read-only grant, so there is no role to choose and the role props are never read. */\nexport interface MachineAccessRequestPanelProps extends AccessRequestPanelCommonProps {\n request: AccessRequest & { kind: \"machine\" };\n roles?: Role[];\n permissions?: Permission[];\n ownPermissionKeys?: string[];\n defaultRoleId?: string;\n onApprove: () => Promise<void>;\n}\n\nexport type AccessRequestPanelProps = RoleAccessRequestPanelProps | MachineAccessRequestPanelProps;\n\nfunction isMachineProps(props: AccessRequestPanelProps): props is MachineAccessRequestPanelProps {\n return props.request.kind === \"machine\";\n}\n\ntype Strings = UiStrings[\"accessRequest\"];\nconst KIND_LABEL: Record<AccessRequestKind, (s: Strings) => string> = {\n session: (s) => s.kindSession,\n worker: (s) => s.kindWorker,\n machine: (s) => s.kindMachine,\n};\nconst LABEL_TERM: Record<AccessRequestKind, (s: Strings) => string> = {\n session: (s) => s.session,\n worker: (s) => s.worker,\n machine: (s) => s.machine,\n};\n\nfunction factEntries(strings: UiStrings, request: AccessRequest, pending: boolean): DescriptionListEntry[] {\n const { accessRequest, approval } = strings;\n const entries: (DescriptionListEntry | null)[] = [\n { key: \"kind\", term: accessRequest.kind, value: KIND_LABEL[request.kind](accessRequest) },\n {\n key: \"label\",\n term: LABEL_TERM[request.kind](accessRequest),\n value: request.label,\n mono: request.kind !== \"session\",\n },\n request.repo ? { key: \"repo\", term: accessRequest.repository, value: request.repo } : null,\n // DXUI-15: a machine request's label row already names the machine, so its host is not shown a second time.\n request.machine && request.kind !== \"machine\" ? { key: \"machine\", term: accessRequest.machine, value: request.machine } : null,\n request.requesterIp ? { key: \"ip\", term: accessRequest.address, value: request.requesterIp, mono: true } : null,\n request.clientVersion ? { key: \"version\", term: accessRequest.clientVersion, value: request.clientVersion } : null,\n {\n key: \"requested\",\n term: approval.requested,\n value: (\n <>\n <DateTimeText at={request.requestedAt} /> (<RelativeTime at={request.requestedAt} tooltip={false} />)\n </>\n ),\n },\n pending && request.expiresAt\n ? { key: \"expires\", term: approval.expires, value: <DateTimeText at={request.expiresAt} /> }\n : null,\n ];\n return entries.filter((entry): entry is DescriptionListEntry => entry !== null);\n}\n\n/** The Revoke key button, its confirmation and the error a failed revoke leaves (DX-4856). */\nfunction RevokeKey({ onRevoke }: { onRevoke: () => Promise<void> }) {\n const strings = useUiStrings().accessRequest;\n const [open, setOpen] = useState(false);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function confirm() {\n setBusy(true);\n setError(null);\n try {\n await onRevoke();\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : strings.revokeFailedMessage);\n } finally {\n setBusy(false);\n setOpen(false);\n }\n }\n\n return (\n <div className=\"flex flex-col gap-3\">\n {error !== null && (\n <Callout tone=\"danger\" live title={strings.revokeFailedTitle}>\n {error}\n </Callout>\n )}\n <div className=\"flex sm:justify-end\">\n <Button variant=\"danger\" onClick={() => setOpen(true)} className=\"w-full sm:w-auto\">\n {strings.revokeKey}\n </Button>\n </div>\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!busy) setOpen(next);\n }}\n title={strings.revokeTitle}\n description={strings.revokeBody}\n actions={\n <>\n <Button variant=\"outline\" onClick={() => setOpen(false)} disabled={busy}>\n {strings.revokeCancel}\n </Button>\n <Button variant=\"danger\" onClick={() => void confirm()} loading={busy}>\n {strings.revokeKey}\n </Button>\n </>\n }\n />\n </div>\n );\n}\n\n/** The revoked callout's sentence: its time is a hook's text, so it lives in a component of its own. */\nfunction RevokedBody({ revokedAt, revokedBy }: { revokedAt: string; revokedBy: string | undefined }) {\n const strings = useUiStrings().accessRequest;\n return <>{strings.revokedBody(useDateTimeText(revokedAt), revokedBy)}</>;\n}\n\nfunction TerminalNotice({\n state,\n request,\n expiredNote,\n issuedKey,\n revokedKey,\n}: {\n state: Exclude<AccessRequestState, \"pending\">;\n request: AccessRequest;\n expiredNote: ExpiredNote | undefined;\n issuedKey: IssuedKey | undefined;\n /** The key when it was revoked (`issuedKey` in the `claimed` state with `revokedAt` set), else undefined. */\n revokedKey: IssuedKey | undefined;\n}) {\n const strings = useUiStrings().accessRequest;\n if (revokedKey?.revokedAt) {\n return (\n <Callout tone=\"danger\" title={strings.revoked}>\n <RevokedBody revokedAt={revokedKey.revokedAt} revokedBy={revokedKey.revokedBy} />\n </Callout>\n );\n }\n switch (state) {\n case \"approved\":\n return <TerminalCallout state={state}>{strings.approved(request.roleLabel)}</TerminalCallout>;\n case \"claimed\":\n return (\n <div className=\"flex flex-col gap-4\">\n <TerminalCallout state={state}>{strings.claimed(request.roleLabel)}</TerminalCallout>\n {issuedKey?.onRevoke && <RevokeKey onRevoke={issuedKey.onRevoke} />}\n </div>\n );\n case \"denied\":\n return (\n <TerminalCallout state={state}>\n {strings.denied}\n </TerminalCallout>\n );\n case \"expired\":\n return <ExpiredNotice note={expiredNote} fallback={strings.expiredFallback} />;\n }\n}\n\nexport function AccessRequestPanel(props: AccessRequestPanelProps) {\n const { request, state, defaultRoleId, onDeny, expiredNote, confirmCodeEntry = false, issuedKey, aboveActions, className } = props;\n const isMachine = isMachineProps(props);\n const roles = props.roles ?? [];\n const permissions = props.permissions ?? [];\n const ownPermissionKeys = props.ownPermissionKeys ?? [];\n // DX-4856: a revoked key outranks the request's own state, which stays `claimed` for good.\n const revokedKey = state === \"claimed\" && issuedKey?.revokedAt ? issuedKey : undefined;\n const allStrings = useUiStrings();\n const strings = allStrings.accessRequest;\n const own = new Set(ownPermissionKeys);\n const usesDefault = defaultRoleId !== undefined && isRoleSelectable(defaultRoleId, roles, own);\n const narrowest = usesDefault ? defaultRoleId : leastPrivilegeRoleId(roles, own);\n // The hint names the role that is actually preselected: the consumer's default when it is selectable, else the narrowest allowed one (DX-4445).\n const preselected = roles.find((role) => role.id === narrowest);\n // \"\" until the person chooses. The effective role is derived, not stored: a pick that stops being selectable\n // (the approver's permissions narrowed, `roles` reloaded) falls back to the narrowest allowed role, so Approve\n // can never submit a role the picker shows as unavailable, and roles arriving after mount still preselect.\n const [picked, setPicked] = useState(\"\");\n const roleId = isRoleSelectable(picked, roles, own) ? picked : narrowest;\n const [typedCode, setTypedCode] = useState(\"\");\n const codeOk = !confirmCodeEntry || confirmCodeMatches(typedCode, request.confirmCode);\n const { busy, error, run } = useApprovalActions();\n\n const pending = state === \"pending\";\n\n return (\n <div className={cn(\"flex flex-col gap-5\", className)}>\n <ApprovalHeader title={strings.title} state={state} revokedLabel={revokedKey ? strings.revoked : undefined} />\n\n <DescriptionList entries={factEntries(allStrings, request, pending)} className=\"divide-y divide-border-subtle\" />\n\n {pending ? (\n <>\n {confirmCodeEntry ? (\n <ConfirmCodeEntry expected={request.confirmCode} value={typedCode} onValueChange={setTypedCode} />\n ) : (\n <ConfirmCodeCallout code={request.confirmCode} />\n )}\n\n <Callout tone=\"warning\" title={allStrings.approval.approveOnlyTitle}>\n {strings.approveBody(request.kind, confirmCodeEntry)}\n </Callout>\n\n <ApprovalError error={error} />\n\n {isMachine ? (\n <Callout tone=\"info\" title={strings.machineGrantTitle}>\n {strings.machineGrant}\n </Callout>\n ) : preselected === undefined ? (\n <Callout tone=\"danger\" title={strings.noRoleTitle}>\n {strings.noRoleBody}\n </Callout>\n ) : (\n <RoleKeyPicker\n roles={roles}\n permissions={permissions}\n ownPermissionKeys={ownPermissionKeys}\n value={roleId}\n onValueChange={setPicked}\n description={strings.roleHint(preselected.label, usesDefault)}\n disabled={busy !== null}\n />\n )}\n\n {aboveActions}\n\n <ApprovalButtons\n busy={busy}\n run={run}\n // The union does not narrow through `isMachine`, so the guard is repeated for the type system.\n onApprove={() => (isMachineProps(props) ? props.onApprove() : props.onApprove(roleId))}\n onDeny={onDeny}\n approveDisabled={!codeOk || (!isMachine && roleId === \"\")}\n />\n </>\n ) : (\n <TerminalNotice state={state} request={request} expiredNote={expiredNote} issuedKey={issuedKey} revokedKey={revokedKey} />\n )}\n </div>\n );\n}\n"],"names":["isMachineProps","props","KIND_LABEL","s","LABEL_TERM","factEntries","strings","request","pending","accessRequest","approval","jsxs","Fragment","jsx","DateTimeText","RelativeTime","entry","RevokeKey","onRevoke","useUiStrings","open","setOpen","useState","busy","setBusy","error","setError","confirm","cause","Callout","Button","Dialog","next","RevokedBody","revokedAt","revokedBy","useDateTimeText","TerminalNotice","state","expiredNote","issuedKey","revokedKey","TerminalCallout","ExpiredNotice","AccessRequestPanel","defaultRoleId","onDeny","confirmCodeEntry","aboveActions","className","isMachine","roles","permissions","ownPermissionKeys","allStrings","own","usesDefault","isRoleSelectable","narrowest","leastPrivilegeRoleId","preselected","role","picked","setPicked","roleId","typedCode","setTypedCode","codeOk","confirmCodeMatches","run","useApprovalActions","cn","ApprovalHeader","DescriptionList","ConfirmCodeEntry","ConfirmCodeCallout","ApprovalError","RoleKeyPicker","ApprovalButtons"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AccessRequestPanel.js","sources":["../../../src/components/rbac/AccessRequestPanel.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { Button } from \"../Button\";\nimport { Callout } from \"../Callout\";\nimport { Dialog } from \"../Dialog\";\nimport { DescriptionList, type DescriptionListEntry } from \"../DescriptionList\";\nimport { cn } from \"../../lib/cn\";\nimport { DateTimeText, useDateTimeText } from \"../DateTimeText\";\nimport { RelativeTime } from \"../RelativeTime\";\nimport { useUiStrings } from \"../../lib/i18n\";\nimport type { UiStrings } from \"../../lib/i18n\";\nimport type { AccessRequestKind } from \"../../lib/i18n/areas/rbac\";\nimport { isRoleSelectable, leastPrivilegeRoleId, RoleKeyPicker } from \"./RoleKeyPicker\";\nimport {\n ApprovalButtons,\n ApprovalError,\n ApprovalHeader,\n ConfirmCodeCallout,\n ConfirmCodeEntry,\n confirmCodeMatches,\n ExpiredNotice,\n TerminalCallout,\n type ExpiredNote,\n useApprovalActions,\n type AccessRequestState,\n} from \"./approvalPanelParts\";\nimport type { Permission, Role } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n ACCESS REQUEST PANEL\n\n THE SCREEN A PERSON SEES WHEN SOMETHING ELSE ASKS TO ACT AS THEM. An agent\n session or a worker holds no credential until a signed-in person approves its\n request; approving mints a key under that person with a role they choose.\n This panel is the whole decision: who is asking, the code to compare, the\n role to grant, approve or deny.\n\n PRESENTATIONAL. It fetches nothing and knows no endpoint. `state` is whatever\n the consumer's server derived: it is never computed here, and never assumed\n to follow a click. After `onApprove` resolves the panel stays \"pending\" until\n the consumer hands it `state=\"approved\"`. `onApprove` / `onDeny` return\n promises; a rejection shows its message in the panel and re-enables the\n buttons.\n\n THE CONFIRM CODE IS FOR COMPARING, NOT COPYING. The requester displays the\n same code in its own terminal and the person checks the two match. That is\n the defence against being sent a link to someone else's request, so the code\n is deliberately plain large text, with no copy control (which would invite\n pasting it somewhere instead of reading it against the requester's screen).\n The panel never authenticates anything with it.\n\n `confirmCodeEntry` TURNS COMPARING INTO TYPING (DX-4467). For a screen where a request may be junk someone\n addressed to the approver, a mis-click on the wrong request must not approve it: the code is then never shown,\n a field takes the code the requester displays, and Approve stays disabled until it matches (case and spaces\n ignored). Deny is always available, and every fact stays visible so the approver can refuse what they do not\n recognise. The match is a client-side gate, not authentication.\n\n THE ROLE STARTS AT THE NARROWEST ONE ALLOWED. Approval is a grant, so the\n default is the selectable role with the fewest permissions, never the\n approver's own role (which would make \"just click Approve\" the broadest\n choice). Roles holding a permission the approver lacks are disabled with the\n missing permissions named (`RoleKeyPicker`, shared with `ApiKeysPanel`).\n Approve stays disabled until a role is chosen, which only matters when no\n role is allowed at all; the panel then says so.\n\n Only a pending request has controls. Approved, denied, expired and claimed\n are terminal readouts: a `Callout` for what it means for the requester, a\n `Badge` for the state at a glance.\n ---------------------------------------------------------------------------- */\n\n/** DXUI-15: `machine` is a dev machine's unattended maintenance: a fixed read-only grant, so no role is chosen. */\nexport type { AccessRequestKind };\n\nexport type { AccessRequestState, ExpiredNote };\n\nexport interface AccessRequest {\n kind: AccessRequestKind;\n /** The session title or the worker id: what the requester calls itself. */\n label: string;\n repo?: string;\n machine?: string;\n /** The address the request came from. */\n requesterIp?: string;\n clientVersion?: string;\n /** ISO instant. */\n requestedAt: string;\n /** ISO instant. Shown while the request is pending. */\n expiresAt?: string;\n /** The short code the requester also displays. Compared by eye, or typed back when `confirmCodeEntry` is set. */\n confirmCode: string;\n /** The label of the role granted. Shown once the request is approved or claimed. */\n roleLabel?: string;\n}\n\n/**\n * DX-4856: the key a claim minted, and what a person may do with it. Pass it once the requester holds a key; omit it before that.\n * `revokedAt` set means the key was revoked: the panel reads Revoked and offers nothing. Otherwise `onRevoke` (pass it only for a\n * person allowed to revoke this key) adds a Revoke key button behind a confirmation dialog.\n */\nexport interface IssuedKey {\n /** ISO instant the key was revoked. */\n revokedAt?: string;\n /** Who revoked it, when a person did. */\n revokedBy?: string;\n /** Revokes the key. A rejection shows its message in the panel; a resolution leaves the panel as it was until the consumer hands it `revokedAt`. */\n onRevoke?: () => Promise<void>;\n}\n\ninterface AccessRequestPanelCommonProps {\n state: AccessRequestState;\n onDeny: () => Promise<void>;\n /**\n * Why an expired request expired and what its requester does next. Used only in the `expired` state; without it the readout says only\n * that nothing was granted.\n */\n expiredNote?: ExpiredNote;\n /**\n * Opt in to typing the confirm code instead of comparing it by eye: the code is not rendered, a field takes it, and Approve is\n * disabled until what was typed matches `request.confirmCode`, ignoring case and spaces. Deny stays available.\n */\n confirmCodeEntry?: boolean;\n /** DX-4856: the key this request minted, with its revoke. Used only in the `claimed` state. */\n issuedKey?: IssuedKey;\n /**\n * DXUI-95: the consumer's own control, drawn just above the Approve and Deny buttons while `state` is `pending`, on role and\n * machine requests alike (for example a switch for machine auto-approve). Never rendered in a terminal state. The panel\n * knows nothing of what it holds.\n */\n aboveActions?: ReactNode;\n className?: string;\n}\n\n/** A session or worker request: the approver chooses the role the key gets. */\nexport interface RoleAccessRequestPanelProps extends AccessRequestPanelCommonProps {\n request: AccessRequest & { kind: \"session\" | \"worker\" };\n /** The roles the approver may grant. */\n roles: Role[];\n /** The permission catalog, used to name the permissions that make a role unavailable. */\n permissions: Permission[];\n /** What the approver holds. A role holding anything outside this set cannot be chosen. */\n ownPermissionKeys: string[];\n /**\n * The role to start on instead of the narrowest allowed one (DX-4431: an agent session starts on the team's\n * default agent role). Used only while it is selectable; otherwise the narrowest allowed role applies.\n */\n defaultRoleId?: string;\n onApprove: (roleId: string) => Promise<void>;\n}\n\n/** DXUI-15: a machine request has a fixed read-only grant, so there is no role to choose and the role props are never read. */\nexport interface MachineAccessRequestPanelProps extends AccessRequestPanelCommonProps {\n request: AccessRequest & { kind: \"machine\" };\n roles?: Role[];\n permissions?: Permission[];\n ownPermissionKeys?: string[];\n defaultRoleId?: string;\n onApprove: () => Promise<void>;\n}\n\n/**\n * DXUI-102: a session request that itself names the role it wants. The approver grants that role or denies the request,\n * so there is no picker: the role is shown read-only with what it grants, and the role props are never read.\n */\nexport interface FixedRoleSessionAccessRequestPanelProps extends AccessRequestPanelCommonProps {\n request: AccessRequest & { kind: \"session\" };\n /** The role the request names. */\n fixedRole: Role;\n /** The permission catalog, used to name what `fixedRole` grants. */\n permissions: Permission[];\n roles?: Role[];\n ownPermissionKeys?: string[];\n defaultRoleId?: string;\n onApprove: () => Promise<void>;\n}\n\nexport type AccessRequestPanelProps =\n | RoleAccessRequestPanelProps\n | MachineAccessRequestPanelProps\n | FixedRoleSessionAccessRequestPanelProps;\n\ntype NoRoleChoiceProps = MachineAccessRequestPanelProps | FixedRoleSessionAccessRequestPanelProps;\n\nfunction isFixedRoleProps(props: AccessRequestPanelProps): props is FixedRoleSessionAccessRequestPanelProps {\n return \"fixedRole\" in props && props.fixedRole !== undefined;\n}\n\n/** A request whose role is not chosen by the approver: its `onApprove` takes no argument. */\nfunction isNoRoleChoiceProps(props: AccessRequestPanelProps): props is NoRoleChoiceProps {\n return props.request.kind === \"machine\" || isFixedRoleProps(props);\n}\n\n/** DXUI-102: the role a request names, read-only, with what it grants. */\nfunction FixedRole({ role, permissions }: { role: Role; permissions: Permission[] }) {\n const strings = useUiStrings().accessRequest;\n const names = role.permissionKeys.map((key) => permissions.find((p) => p.key === key)?.label ?? key);\n return (\n <section aria-label={strings.fixedRoleTitle} className=\"flex flex-col gap-2\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-sm font-medium text-primary\">{strings.fixedRoleTitle}</span>\n <span className=\"text-2xs text-tertiary\">{strings.fixedRoleHint}</span>\n </div>\n <div className=\"flex flex-col gap-1 rounded-md border border-border bg-surface-raised p-3\">\n <span className=\"text-sm font-medium text-primary\">{role.label}</span>\n {role.description && <span className=\"text-xs text-secondary\">{role.description}</span>}\n {names.length > 0 && (\n <ul className=\"mt-1 flex list-disc flex-col gap-0.5 pl-4 text-xs text-secondary\">\n {names.map((name) => (\n <li key={name}>{name}</li>\n ))}\n </ul>\n )}\n </div>\n </section>\n );\n}\n\ntype Strings = UiStrings[\"accessRequest\"];\nconst KIND_LABEL: Record<AccessRequestKind, (s: Strings) => string> = {\n session: (s) => s.kindSession,\n worker: (s) => s.kindWorker,\n machine: (s) => s.kindMachine,\n};\nconst LABEL_TERM: Record<AccessRequestKind, (s: Strings) => string> = {\n session: (s) => s.session,\n worker: (s) => s.worker,\n machine: (s) => s.machine,\n};\n\nfunction factEntries(strings: UiStrings, request: AccessRequest, pending: boolean): DescriptionListEntry[] {\n const { accessRequest, approval } = strings;\n const entries: (DescriptionListEntry | null)[] = [\n { key: \"kind\", term: accessRequest.kind, value: KIND_LABEL[request.kind](accessRequest) },\n {\n key: \"label\",\n term: LABEL_TERM[request.kind](accessRequest),\n value: request.label,\n mono: request.kind !== \"session\",\n },\n request.repo ? { key: \"repo\", term: accessRequest.repository, value: request.repo } : null,\n // DXUI-15: a machine request's label row already names the machine, so its host is not shown a second time.\n request.machine && request.kind !== \"machine\" ? { key: \"machine\", term: accessRequest.machine, value: request.machine } : null,\n request.requesterIp ? { key: \"ip\", term: accessRequest.address, value: request.requesterIp, mono: true } : null,\n request.clientVersion ? { key: \"version\", term: accessRequest.clientVersion, value: request.clientVersion } : null,\n {\n key: \"requested\",\n term: approval.requested,\n value: (\n <>\n <DateTimeText at={request.requestedAt} /> (<RelativeTime at={request.requestedAt} tooltip={false} />)\n </>\n ),\n },\n pending && request.expiresAt\n ? { key: \"expires\", term: approval.expires, value: <DateTimeText at={request.expiresAt} /> }\n : null,\n ];\n return entries.filter((entry): entry is DescriptionListEntry => entry !== null);\n}\n\n/** The Revoke key button, its confirmation and the error a failed revoke leaves (DX-4856). */\nfunction RevokeKey({ onRevoke }: { onRevoke: () => Promise<void> }) {\n const strings = useUiStrings().accessRequest;\n const [open, setOpen] = useState(false);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function confirm() {\n setBusy(true);\n setError(null);\n try {\n await onRevoke();\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : strings.revokeFailedMessage);\n } finally {\n setBusy(false);\n setOpen(false);\n }\n }\n\n return (\n <div className=\"flex flex-col gap-3\">\n {error !== null && (\n <Callout tone=\"danger\" live title={strings.revokeFailedTitle}>\n {error}\n </Callout>\n )}\n <div className=\"flex sm:justify-end\">\n <Button variant=\"danger\" onClick={() => setOpen(true)} className=\"w-full sm:w-auto\">\n {strings.revokeKey}\n </Button>\n </div>\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!busy) setOpen(next);\n }}\n title={strings.revokeTitle}\n description={strings.revokeBody}\n actions={\n <>\n <Button variant=\"outline\" onClick={() => setOpen(false)} disabled={busy}>\n {strings.revokeCancel}\n </Button>\n <Button variant=\"danger\" onClick={() => void confirm()} loading={busy}>\n {strings.revokeKey}\n </Button>\n </>\n }\n />\n </div>\n );\n}\n\n/** The revoked callout's sentence: its time is a hook's text, so it lives in a component of its own. */\nfunction RevokedBody({ revokedAt, revokedBy }: { revokedAt: string; revokedBy: string | undefined }) {\n const strings = useUiStrings().accessRequest;\n return <>{strings.revokedBody(useDateTimeText(revokedAt), revokedBy)}</>;\n}\n\nfunction TerminalNotice({\n state,\n request,\n expiredNote,\n issuedKey,\n revokedKey,\n}: {\n state: Exclude<AccessRequestState, \"pending\">;\n request: AccessRequest;\n expiredNote: ExpiredNote | undefined;\n issuedKey: IssuedKey | undefined;\n /** The key when it was revoked (`issuedKey` in the `claimed` state with `revokedAt` set), else undefined. */\n revokedKey: IssuedKey | undefined;\n}) {\n const strings = useUiStrings().accessRequest;\n if (revokedKey?.revokedAt) {\n return (\n <Callout tone=\"danger\" title={strings.revoked}>\n <RevokedBody revokedAt={revokedKey.revokedAt} revokedBy={revokedKey.revokedBy} />\n </Callout>\n );\n }\n switch (state) {\n case \"approved\":\n return <TerminalCallout state={state}>{strings.approved(request.roleLabel)}</TerminalCallout>;\n case \"claimed\":\n return (\n <div className=\"flex flex-col gap-4\">\n <TerminalCallout state={state}>{strings.claimed(request.roleLabel)}</TerminalCallout>\n {issuedKey?.onRevoke && <RevokeKey onRevoke={issuedKey.onRevoke} />}\n </div>\n );\n case \"denied\":\n return (\n <TerminalCallout state={state}>\n {strings.denied}\n </TerminalCallout>\n );\n case \"expired\":\n return <ExpiredNotice note={expiredNote} fallback={strings.expiredFallback} />;\n }\n}\n\nexport function AccessRequestPanel(props: AccessRequestPanelProps) {\n const { request, state, defaultRoleId, onDeny, expiredNote, confirmCodeEntry = false, issuedKey, aboveActions, className } = props;\n const noRoleChoice = isNoRoleChoiceProps(props);\n const roles = props.roles ?? [];\n const permissions = props.permissions ?? [];\n const ownPermissionKeys = props.ownPermissionKeys ?? [];\n // DX-4856: a revoked key outranks the request's own state, which stays `claimed` for good.\n const revokedKey = state === \"claimed\" && issuedKey?.revokedAt ? issuedKey : undefined;\n const allStrings = useUiStrings();\n const strings = allStrings.accessRequest;\n const own = new Set(ownPermissionKeys);\n const usesDefault = defaultRoleId !== undefined && isRoleSelectable(defaultRoleId, roles, own);\n const narrowest = usesDefault ? defaultRoleId : leastPrivilegeRoleId(roles, own);\n // The hint names the role that is actually preselected: the consumer's default when it is selectable, else the narrowest allowed one (DX-4445).\n const preselected = roles.find((role) => role.id === narrowest);\n // \"\" until the person chooses. The effective role is derived, not stored: a pick that stops being selectable\n // (the approver's permissions narrowed, `roles` reloaded) falls back to the narrowest allowed role, so Approve\n // can never submit a role the picker shows as unavailable, and roles arriving after mount still preselect.\n const [picked, setPicked] = useState(\"\");\n const roleId = isRoleSelectable(picked, roles, own) ? picked : narrowest;\n const [typedCode, setTypedCode] = useState(\"\");\n const codeOk = !confirmCodeEntry || confirmCodeMatches(typedCode, request.confirmCode);\n const { busy, error, run } = useApprovalActions();\n\n const pending = state === \"pending\";\n\n return (\n <div className={cn(\"flex flex-col gap-5\", className)}>\n <ApprovalHeader title={strings.title} state={state} revokedLabel={revokedKey ? strings.revoked : undefined} />\n\n <DescriptionList entries={factEntries(allStrings, request, pending)} className=\"divide-y divide-border-subtle\" />\n\n {pending ? (\n <>\n {confirmCodeEntry ? (\n <ConfirmCodeEntry expected={request.confirmCode} value={typedCode} onValueChange={setTypedCode} />\n ) : (\n <ConfirmCodeCallout code={request.confirmCode} />\n )}\n\n <Callout tone=\"warning\" title={allStrings.approval.approveOnlyTitle}>\n {isFixedRoleProps(props) ? strings.approveBodyFixedRole(confirmCodeEntry) : strings.approveBody(request.kind, confirmCodeEntry)}\n </Callout>\n\n <ApprovalError error={error} />\n\n {isFixedRoleProps(props) ? (\n <FixedRole role={props.fixedRole} permissions={props.permissions} />\n ) : request.kind === \"machine\" ? (\n <Callout tone=\"info\" title={strings.machineGrantTitle}>\n {strings.machineGrant}\n </Callout>\n ) : preselected === undefined ? (\n <Callout tone=\"danger\" title={strings.noRoleTitle}>\n {strings.noRoleBody}\n </Callout>\n ) : (\n <RoleKeyPicker\n roles={roles}\n permissions={permissions}\n ownPermissionKeys={ownPermissionKeys}\n value={roleId}\n onValueChange={setPicked}\n description={strings.roleHint(preselected.label, usesDefault)}\n disabled={busy !== null}\n />\n )}\n\n {aboveActions}\n\n <ApprovalButtons\n busy={busy}\n run={run}\n // The union does not narrow through `noRoleChoice`, so the guard is repeated for the type system.\n onApprove={() => (isNoRoleChoiceProps(props) ? props.onApprove() : props.onApprove(roleId))}\n onDeny={onDeny}\n approveDisabled={!codeOk || (!noRoleChoice && roleId === \"\")}\n />\n </>\n ) : (\n <TerminalNotice state={state} request={request} expiredNote={expiredNote} issuedKey={issuedKey} revokedKey={revokedKey} />\n )}\n </div>\n );\n}\n"],"names":["isFixedRoleProps","props","isNoRoleChoiceProps","FixedRole","role","permissions","strings","useUiStrings","names","key","p","jsxs","jsx","name","KIND_LABEL","s","LABEL_TERM","factEntries","request","pending","accessRequest","approval","Fragment","DateTimeText","RelativeTime","entry","RevokeKey","onRevoke","open","setOpen","useState","busy","setBusy","error","setError","confirm","cause","Callout","Button","Dialog","next","RevokedBody","revokedAt","revokedBy","useDateTimeText","TerminalNotice","state","expiredNote","issuedKey","revokedKey","TerminalCallout","ExpiredNotice","AccessRequestPanel","defaultRoleId","onDeny","confirmCodeEntry","aboveActions","className","noRoleChoice","roles","ownPermissionKeys","allStrings","own","usesDefault","isRoleSelectable","narrowest","leastPrivilegeRoleId","preselected","picked","setPicked","roleId","typedCode","setTypedCode","codeOk","confirmCodeMatches","run","useApprovalActions","cn","ApprovalHeader","DescriptionList","ConfirmCodeEntry","ConfirmCodeCallout","ApprovalError","RoleKeyPicker","ApprovalButtons"],"mappings":"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"}
|
|
@@ -23,8 +23,11 @@ const d = {
|
|
|
23
23
|
kindSession: "Agent session",
|
|
24
24
|
kindWorker: "Worker",
|
|
25
25
|
kindMachine: "Machine",
|
|
26
|
-
machineGrantTitle: "Read
|
|
26
|
+
machineGrantTitle: "Read access to cards, and permission to record test runs",
|
|
27
27
|
machineGrant: "This request cannot be given any other permission, so there is no role to choose.",
|
|
28
|
+
fixedRoleTitle: "Role requested",
|
|
29
|
+
approveBodyFixedRole: (e) => `Approving lets this session act as you with the role it requested, for as long as it keeps being used. ${e ? "If you did not ask for this, deny it." : "If the code does not match, or you did not ask for this, deny it."}`,
|
|
30
|
+
fixedRoleHint: "The request names this role. Approve it as it is, or deny the request. It cannot be changed here.",
|
|
28
31
|
kind: "Kind",
|
|
29
32
|
worker: "Worker",
|
|
30
33
|
session: "Session",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac.js","sources":["../../../../src/lib/i18n/areas/rbac.ts"],"sourcesContent":["import { plural } from \"../plural\";\nimport { createElement, Fragment, type ReactNode } from \"react\";\nimport type { Emphasis } from \"../emphasis\";\n\n/* DX-4740 — built-in strings of the RBAC components (`components/rbac`). Members are keyed by\n component; a function leaf carries an argument so the whole sentence is the translator's. */\n/** The kinds of requester `AccessRequestPanel` names; the panel's `AccessRequestKind` is this same union. */\nexport type AccessRequestKind = \"session\" | \"worker\" | \"machine\";\n\nexport interface RbacStrings {\n /** The pieces `AccessRequestPanel` and `PermissionRequestPanel` share (`approvalPanelParts.tsx`). */\n approval: {\n /** The badge in the request header, by request state. */\n state: { pending: string; approved: string; denied: string; expired: string; claimed: string };\n /** The title of the readout for a settled request, by state. */\n terminalTitle: { approved: string; claimed: string; denied: string; expired: string };\n /** Title of the callout that shows the confirm code to compare. */\n confirmCodeTitle: string;\n /** Line under the shown confirm code. */\n confirmCodeCompare: string;\n /** Label of the field the approver types the confirm code into. */\n confirmCodeLabel: string;\n /** Help text under the confirm code field. */\n confirmCodeEntryHint: string;\n /** Error under the confirm code field when what was typed is wrong. */\n confirmCodeMismatch: string;\n /** Fallback error text when an approve / deny call rejects without a message, by action. */\n failedMessage: { approve: string; deny: string };\n /** Title of the error callout when an approve / deny call rejects, by action. */\n failedTitle: { approve: string; deny: string };\n /** The Deny button. */\n deny: string;\n /** The Approve button. */\n approve: string;\n /** Last line of the Expired readout when the consumer gave a note. */\n expiredNothingGranted: string;\n /** Term of the fact row naming when the request was made. */\n requested: string;\n /** Term of the fact row naming when a pending request expires. */\n expires: string;\n /** Title of the warning callout above a pending request's decision. */\n approveOnlyTitle: string;\n };\n /** `AccessRequestPanel`. */\n accessRequest: {\n /** Heading of the panel. */\n title: string;\n /** Fact row \"Kind\" value for a request from an agent session. */\n kindSession: string;\n /** Fact row \"Kind\" value for a request from a worker. */\n kindWorker: string;\n /** DX-5809 / DXUI-15: fact row \"Kind\" value for a request from a dev machine's unattended maintenance. */\n kindMachine: string;\n /** DXUI-15: the grant a machine request gets in place of a role picker: fixed, read-only access to cards. */\n machineGrant: string;\n /** DXUI-15: title of the callout that shows the machine grant. */\n machineGrantTitle: string;\n /** Term of the fact row naming the kind of requester. */\n kind: string;\n /** Term of the fact row naming a worker requester. */\n worker: string;\n /** Term of the fact row naming a session requester. */\n session: string;\n /** Term of the fact row naming the repository. */\n repository: string;\n /** Term of the fact row naming the machine. */\n machine: string;\n /** Term of the fact row showing the requester's address. */\n address: string;\n /** Term of the fact row showing the requester's client version. */\n clientVersion: string;\n /** Readout for an approved request; `role` is the granted role's label, when known. */\n approved: (role: string | undefined) => string;\n /** Readout for a claimed request; `role` is the granted role's label, when known. */\n claimed: (role: string | undefined) => string;\n /** Readout for a denied request. */\n denied: string;\n /** Readout for an expired request when the consumer gave no note. */\n expiredFallback: string;\n /** Body of the \"Approve only if you started this\" callout. */\n approveBody: (kind: AccessRequestKind, typedCode: boolean) => string;\n /** Title of the callout shown when no role can be granted. */\n noRoleTitle: string;\n /** Body of the callout shown when no role can be granted. */\n noRoleBody: string;\n /** Description under the role picker; `isDefault` is true when the consumer's default role was preselected. */\n roleHint: (roleLabel: string, isDefault: boolean) => string;\n /** DX-4856: the header badge and readout title once the key this request minted was revoked. */\n revoked: string;\n /** DX-4856: readout body for a revoked key; `when` is the formatted instant, `by` the revoker's name when a person did it. */\n revokedBody: (when: string, by: string | undefined) => string;\n /** DX-4856: label of the button that starts revoking the key. */\n revokeKey: string;\n /** DX-4856: title of the confirmation dialog. */\n revokeTitle: string;\n /** DX-4856: body of the confirmation dialog. */\n revokeBody: string;\n /** DX-4856: the dialog's dismiss button. */\n revokeCancel: string;\n /** DX-4856: title of the error shown when the revoke failed. */\n revokeFailedTitle: string;\n /** DX-4856: message of that error when the rejection carried none. */\n revokeFailedMessage: string;\n };\n /** `PermissionRequestPanel`. */\n permissionRequest: {\n /** Heading of the panel. */\n title: string;\n /** Note under a requested permission the approver does not hold. */\n notHeld: string;\n /** Term of the fact row naming the key that is asking. */\n key: string;\n /** Caption above the agent's stated reason. */\n reasonGiven: string;\n /** Readout for an approved request that lists what was granted. */\n approvedWithList: string;\n /** Readout for an approved request with no list of what was granted. */\n approvedNoList: string;\n /** Readout for a claimed request that lists what was granted. */\n claimedWithList: string;\n /** Readout for a claimed request with no list of what was granted. */\n claimedNoList: string;\n /** Readout for a denied request. */\n denied: string;\n /** Readout for an expired request when the consumer gave no note. */\n expiredFallback: string;\n /** Body of the \"Approve only if you started this\" callout. */\n approveBody: string;\n /** Title of the callout shown when the approver holds none of the requested permissions. */\n emptyTitle: string;\n /** Body of the callout shown when the approver holds none of the requested permissions. */\n emptyDescription: string;\n /** Section heading for requested permissions that carry no category, when others do. */\n otherCategory: string;\n /** Legend of the list of requested permissions. */\n legend: string;\n /** Description under the legend of the list of requested permissions. */\n legendDescription: string;\n };\n /** `RoleKeyPicker`. */\n roleKeyPicker: {\n /** Default heading of the picker. */\n label: string;\n /** Default line under the heading. */\n description: string;\n /** Why a role cannot be chosen, naming the permissions the person lacks. */\n unavailable: (permissionLabels: string[]) => string;\n };\n /** `ApiKeysPanel`. */\n apiKeysPanel: {\n /** Heading of the panel. */\n title: string;\n /** The button that opens the create dialog. */\n createKey: string;\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n /** Title of the create dialog. */\n dialogTitle: string;\n /** Description of the create dialog. */\n dialogDescription: string;\n /** The create dialog's cancel button. */\n cancel: string;\n /** The create dialog's submit button. */\n create: string;\n /** Title of the error callout when creating fails. */\n failedTitle: string;\n /** Fallback error text when creating rejects without a message. */\n failedMessage: string;\n /** Label of the key name field. */\n nameLabel: string;\n /** Description of the key name field. */\n nameDescription: string;\n /** Placeholder of the key name field. */\n namePlaceholder: string;\n /** Label of the expiry days field. */\n expiresLabel: string;\n /** Description of the expiry days field. */\n expiresDescription: string;\n /** Placeholder of the expiry days field. */\n expiresPlaceholder: string;\n /** Title of the dialog that shows the new key once. */\n revealedTitle: string;\n /** Description of the dialog that shows the new key once. */\n revealedDescription: string;\n /** The button that closes the reveal dialog. */\n done: string;\n /** Label of the field showing the new key. */\n revealedLabel: string;\n /** Label of the button that copies the new key. */\n copyKey: string;\n };\n /** `ApiKeysTable` (also `AgentKeysList`). */\n apiKeysTable: {\n /** Column header: the key's name. */\n columnKey: string;\n /** Column header: who started or authorized the key's session (`AgentKeysList` `renderStartedBy`, DX-6801). */\n columnStartedBy: string;\n /** Column header: the key's role. */\n columnRole: string;\n /** Column header: when the key was last used. */\n columnLastUsed: string;\n /** Column header: when the key expires. */\n columnExpires: string;\n /** Cell text for a key never used or with no expiry. */\n never: string;\n /** Under a key's name: how long ago it was created; `age` is the formatted age. */\n created: (age: string) => string;\n /** Accessible name of a key's role selector. */\n roleOf: (keyName: string) => string;\n /** Refusal on a role the owner cannot assign. */\n roleNotAssignable: string;\n /** Accessible name of the revoke key button. */\n revoke: (keyName: string) => string;\n /** Tooltip on the revoke button while a revoke runs. */\n revoking: string;\n /** Title of the revoke key confirmation. */\n revokeTitle: (keyName: string) => string;\n /** Description of the revoke key confirmation. */\n revokeDescription: string;\n /** Confirm button of the revoke key confirmation. */\n revokeConfirm: string;\n /** Accessible name of the list of permissions added to a key. */\n grantsOf: (keyName: string) => string;\n /** Accessible name of the button that removes a granted permission. */\n removeGrant: (permissionLabel: string, keyName: string) => string;\n /** Tooltip on the remove-grant button while an update runs. */\n updating: string;\n /** Title of the remove-grant confirmation. */\n removeGrantTitle: (permissionLabel: string) => string;\n /** Description of the remove-grant confirmation. */\n removeGrantDescription: string;\n /** Confirm button of the remove-grant confirmation. */\n removeGrantConfirm: string;\n /** Line under a granted permission; `age` is the formatted age, `reason` the agent's reason when given. */\n granted: (age: string, reason: string | undefined) => string;\n };\n /** `AgentKeysList`. */\n agentKeysList: {\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n };\n /** `DevToolsPopover`. */\n devTools: {\n /** Visible label of the trigger button (hidden below the sm breakpoint). */\n trigger: string;\n /** Accessible name of the trigger button. */\n triggerLabel: string;\n /** Heading of the \"view as a role\" section. */\n viewAs: string;\n /** Accessible name of the role select. */\n viewAsLabel: string;\n /** Placeholder of the role select while no role is impersonated. */\n actualRole: string;\n /** Name used for the impersonated role when it cannot be found. */\n unknownRole: string;\n /** The impersonation notice; `emphasis` wraps the role's name in the caller's emphasis markup. */\n viewingAs: (role: string, emphasis: Emphasis) => ReactNode;\n /** The button that stops impersonating. */\n resetToActual: string;\n /** Heading and accessible name of the data source section. */\n dataSource: string;\n /** Label of each data source option. */\n dataSources: { simulated: string; live: string };\n /** Note shown when the data source is set to live. */\n liveNotConfigured: string;\n /** Heading and accessible name of the network speed section. */\n networkSpeed: string;\n /** Label of each network speed option. */\n networkSpeeds: { instant: string; fast: string; typical: string; flaky: string };\n /** The button that opens the regenerate confirmation. */\n regenerate: string;\n /** Title of the regenerate confirmation. */\n regenerateTitle: string;\n /** Description of the regenerate confirmation. */\n regenerateDescription: string;\n /** Confirm button of the regenerate confirmation. */\n regenerateConfirm: string;\n /** The button that opens the use-case ledger. */\n openLedger: string;\n };\n /** `InvitationsList`. */\n invitationsList: {\n /** Column header: who was invited. */\n columnInvitee: string;\n /** Column header: the invited role. */\n columnRole: string;\n /** Column header: the invitation's status. */\n columnStatus: string;\n /** Column header: how long ago the invitation was sent. */\n columnSent: string;\n /** Under the invitee's address: who sent the invitation. */\n invitedBy: (name: string) => string;\n /** Status badge by invitation status. */\n status: { pending: string; accepted: string; revoked: string; expired: string };\n /** Badge shown when the recipient complained about the email. */\n complaint: string;\n /** Badge shown when the email bounced. */\n bounced: string;\n /** Badge shown when sending the email failed or was suppressed. */\n deliveryFailed: string;\n /** Tooltip on a row's action buttons while that row is busy. */\n working: string;\n /** Accessible name of the copy-invite-link button. */\n copyLink: (email: string) => string;\n /** Accessible name of the resend button. */\n resend: (email: string) => string;\n /** Accessible name of the revoke button. */\n revoke: (email: string) => string;\n /** Title of the revoke confirmation. */\n revokeTitle: (email: string) => string;\n /** Description of the revoke confirmation. */\n revokeDescription: string;\n /** Confirm button of the revoke confirmation. */\n revokeConfirm: string;\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n };\n /** `InviteMembersDialog`. */\n inviteMembersDialog: {\n /** Title of the dialog. */\n title: string;\n /** Description of the dialog. */\n description: string;\n /** The cancel button. */\n cancel: string;\n /** The submit button; `count` is how many addresses will be invited. */\n send: (count: number) => string;\n /** Label of the email addresses field. */\n emailsLabel: string;\n /** Description of the email addresses field. */\n emailsDescription: string;\n /** Placeholder of the email input while no address has been added. */\n emailPlaceholder: string;\n /** Accessible name of the button that removes an added address. */\n removeEmail: (email: string) => string;\n /** Error under the field when what was typed is not an email address. */\n invalidEmail: (typed: string) => string;\n /** Label of the role select. */\n roleLabel: string;\n };\n /** `MembersPanel`. */\n membersPanel: {\n /** Column header: the member. */\n columnMember: string;\n /** Column header: the member's role. */\n columnRole: string;\n /** Column header: how long ago the member joined. */\n columnJoined: string;\n /** Accessible name of a member's role select. */\n roleFor: (name: string) => string;\n /** Tooltip on the remove button while a removal runs. */\n removing: string;\n /** Accessible name of the remove button. */\n remove: (name: string) => string;\n /** Title of the remove confirmation. */\n removeTitle: (name: string) => string;\n /** Description of the remove confirmation. */\n removeDescription: (name: string) => string;\n /** Confirm button of the remove confirmation. */\n removeConfirm: string;\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n };\n /** The save / discard row and staged-image note `ProfileForm` and `TeamSettingsForm` share. */\n stagedForm: {\n /** Default Save button text. */\n save: string;\n /** Default Discard button text. */\n discard: string;\n /** The note under a staged image; `kind` says which image, `saveLabel` is the Save button's text. */\n imageNote: (kind: \"avatar\" | \"logo\", saveLabel: string, removed: boolean) => string;\n };\n /** `ProfileForm`. */\n profileForm: {\n /** Callout shown after a successful save. */\n saved: string;\n /** Title of the error callout when saving fails. */\n failedTitle: string;\n /** Fallback error text when saving rejects without a message. */\n failedMessage: string;\n /** Label of the avatar field. */\n avatar: string;\n /** Label of the name field. */\n name: string;\n /** Label of the username field. */\n username: string;\n /** Label of the email field. */\n email: string;\n };\n /** `TeamSettingsForm`. */\n teamSettingsForm: {\n /** Callout shown after a successful save. */\n saved: string;\n /** Title of the error callout when saving fails. */\n failedTitle: string;\n /** Fallback error text when saving rejects without a message. */\n failedMessage: string;\n /** Title of the callout shown to a viewer who cannot edit. */\n readOnlyTitle: string;\n /** Body of the callout shown to a viewer who cannot edit. */\n readOnlyBody: string;\n /** Label of the logo field. */\n logo: string;\n /** Label of the team name field. */\n teamName: string;\n };\n /** `ProfilePage`. */\n profilePage: {\n /** The page heading. */\n title: string;\n /** Heading of the roles and permissions section. */\n rolesHeading: string;\n /** Notice while impersonating; `viewing` and `actual` are the two role names, each wrapped by `emphasis` (the caller's emphasis markup). */\n viewingAs: (viewing: string, actual: string, emphasis: Emphasis) => ReactNode;\n /** Sentence naming the person's role, wrapped by `emphasis`; `team` is the current team's name when there is one. */\n holdsRole: (role: string, team: string | undefined, emphasis: Emphasis) => ReactNode;\n /** Shown when the role grants no permissions. */\n noPermissions: string;\n /** Shown when no role is assigned for the team. */\n noRole: string;\n /** Label of the read-only identity's name field. */\n name: string;\n /** Label of the read-only identity's email field. */\n email: string;\n };\n /** `ChangePasswordForm`. */\n changePasswordForm: {\n /** Title of the error callout when the change fails. */\n failedTitle: string;\n /** Fallback error text when the change rejects without a message. */\n failedMessage: string;\n /** Label of the current password field. */\n current: string;\n /** Label of the new password field. */\n next: string;\n /** Label of the confirm new password field. */\n confirmPassword: string;\n /** Error under the confirm field when it differs from the new password. */\n mismatch: string;\n /** Default submit button text. */\n submit: string;\n /** Set-password mode (no current password yet): title of the error callout when it fails. */\n setFailedTitle: string;\n /** Set-password mode: fallback error text when it rejects without a message. */\n setFailedMessage: string;\n /** Set-password mode: default submit button text. */\n setSubmit: string;\n };\n /** `DangerZone`. */\n dangerZone: {\n /** Default heading of the section. */\n title: string;\n };\n /** `SessionsList`. */\n sessionsList: {\n /** Column header: the session. */\n columnSession: string;\n /** Column header: the browser the session was made in (DX-5247). */\n columnBrowser: string;\n /** Badge on a row made in the browser this screen is running in (DX-5247). */\n thisBrowser: string;\n /** Accessible name of the button that copies a browser id; receives the shown id (DX-5247). */\n copyBrowserId: (shownId: string) => string;\n /** Column header: when the session was last used. */\n columnLastUsed: string;\n /** Column header: when the session was created. */\n columnCreated: string;\n /** Column header: when the session expires. */\n columnExpires: string;\n /** Badge beside the session this screen is running in. */\n current: string;\n /** Cell text for a session with no expiry. */\n never: string;\n /** Replaces the revoke control on the current session. */\n thisSession: string;\n /** Accessible name of the revoke button. */\n revoke: (name: string) => string;\n /** Tooltip on the revoke button while a revoke runs. */\n revoking: string;\n /** Title of the revoke confirmation. */\n revokeTitle: (name: string) => string;\n /** Description of the revoke confirmation. */\n revokeDescription: string;\n /** Confirm button of the revoke confirmation. */\n revokeConfirm: string;\n /** Title of the empty state. */\n emptyTitle: string;\n };\n /** `TeamSwitcher`. */\n teamSwitcher: {\n /** Accessible name of the team shown when there is nothing to switch to. */\n currentTeam: string;\n /** Accessible name of the trigger that opens the team list. */\n switchFrom: (currentTeamName: string) => string;\n /** Heading of the team list. */\n switchTeam: string;\n };\n /** `AccountMenu`. */\n accountMenu: {\n /** Accessible name of the avatar button that opens the menu. */\n triggerLabel: (userName: string) => string;\n /** Menu item that opens the profile. */\n profile: string;\n /** Menu item that opens roles and permissions. */\n roles: string;\n /** Heading of the access section. */\n yourAccess: string;\n /** Sentence naming the person's role; `emphasis` wraps the role's name in the caller's emphasis markup. */\n hasRole: (role: string, emphasis: Emphasis) => ReactNode;\n /** Shown when no role is assigned for the team. */\n noRole: string;\n /** Heading of the team list. */\n switchTeam: string;\n /** Menu item that signs out. */\n signOut: string;\n };\n /** `RolePermissionMatrix`. */\n rolePermissionMatrix: {\n /** Screen-reader caption of the matrix. */\n caption: string;\n /** Header of the permission column. */\n permission: string;\n /** Section heading for permissions that carry no category, when others do. */\n otherCategory: string;\n /** Accessible name of the lock icon on a role column that cannot be edited. */\n locked: (roleLabel: string) => string;\n /** The sentence a screen reader gets for a cell, saying whether the role holds the permission. */\n cell: (roleLabel: string, permissionLabel: string, granted: boolean) => string;\n };\n /** `ToggleMatrix` (DX-4963), the grid `RolePermissionMatrix` is built on. */\n toggleMatrix: {\n /** The sentence a screen reader gets for a cell when the consumer gives none, saying whether the column has the row switched on. */\n cell: (columnLabel: string, rowLabel: string, on: boolean) => string;\n /** The muted badge in a cell that cannot be switched; the reason is printed under it. */\n unavailable: string;\n /** Accessible name of the checkbox in a column header that sets every switch in the column. */\n setColumn: (columnLabel: string) => string;\n /** Heading for rows with no group, when other rows have one. */\n otherGroup: string;\n /** Accessible name of the spinner in a cell that is being saved. */\n busy: string;\n };\n /** `RolesPermissionsPage`. */\n rolesPermissionsPage: {\n /** The page heading. */\n title: string;\n /** Line under the heading when roles can be edited. */\n subtitleEditable: string;\n /** Line under the heading when roles are read-only. */\n subtitleReadOnly: string;\n /** The button that opens the new role dialog. */\n newRole: string;\n /** Heading of the list of manageable roles. */\n manageRoles: string;\n /** Tooltip on a row's buttons while that role is busy. */\n working: string;\n /** Accessible name of the reset-to-defaults button. */\n reset: (roleLabel: string) => string;\n /** Accessible name of the edit button. */\n edit: (roleLabel: string) => string;\n /** Accessible name of the delete button. */\n delete: (roleLabel: string) => string;\n /** Title of the delete confirmation. */\n deleteTitle: (roleLabel: string) => string;\n /** Description of the delete confirmation. */\n deleteDescription: string;\n /** Confirm button of the delete confirmation. */\n deleteConfirm: string;\n };\n /** `RoleEditorDialog`. */\n roleEditorDialog: {\n /** Title when creating a role. */\n createTitle: string;\n /** Title when editing a role. */\n editTitle: string;\n /** Description when creating a role. */\n createDescription: string;\n /** Description when editing a role. */\n editDescription: string;\n /** The cancel button. */\n cancel: string;\n /** The submit button when creating. */\n create: string;\n /** The submit button when editing. */\n save: string;\n /** Label of the role label field. */\n label: string;\n /** Placeholder of the role label field. */\n labelPlaceholder: string;\n /** Label of the description field. */\n description: string;\n /** Help text under the description field. */\n descriptionHint: string;\n /** Label of the clone-from select. */\n cloneLabel: string;\n /** Description of the clone-from select. */\n cloneDescription: string;\n /** The clone-from option that clones nothing. */\n cloneNone: string;\n };\n}\n\nexport const rbacStrings: RbacStrings = {\n approval: {\n state: { pending: \"Pending\", approved: \"Approved\", denied: \"Denied\", expired: \"Expired\", claimed: \"Claimed\" },\n terminalTitle: { approved: \"Approved\", claimed: \"Already claimed\", denied: \"Denied\", expired: \"This request expired\" },\n confirmCodeTitle: \"Confirm code\",\n confirmCodeCompare: \"Check that this matches the code shown where the request was made.\",\n confirmCodeLabel: \"Confirm code\",\n confirmCodeEntryHint: \"Type the code shown where this request was made. Approve opens once it matches.\",\n confirmCodeMismatch: \"That code does not match this request.\",\n failedMessage: { approve: \"Couldn't approve the request. Try again.\", deny: \"Couldn't deny the request. Try again.\" },\n failedTitle: { approve: \"Couldn't approve the request\", deny: \"Couldn't deny the request\" },\n deny: \"Deny\",\n approve: \"Approve\",\n expiredNothingGranted: \"Nothing was granted, so there is nothing for you to approve or deny.\",\n requested: \"Requested\",\n expires: \"Expires\",\n approveOnlyTitle: \"Approve only if you started this\",\n },\n accessRequest: {\n title: \"Access request\",\n kindSession: \"Agent session\",\n kindWorker: \"Worker\",\n kindMachine: \"Machine\",\n machineGrantTitle: \"Read-only access to cards\",\n machineGrant: \"This request cannot be given any other permission, so there is no role to choose.\",\n kind: \"Kind\",\n worker: \"Worker\",\n session: \"Session\",\n repository: \"Repository\",\n machine: \"Machine\",\n address: \"Address\",\n clientVersion: \"Client version\",\n approved: (role) => `The requester is picking up its key${role ? ` with the ${role} role` : \"\"}. You can close this page.`,\n claimed: (role) =>\n `The requester has its key${role ? ` with the ${role} role` : \"\"}. If that was not you, revoke the key from your API keys.`,\n denied: \"The requester was refused and holds no key. It has to ask again to get access.\",\n expiredFallback: \"Nothing was granted. Ask the requester to start a new request.\",\n approveBody: (kind, typedCode) => {\n const lead = {\n session: \"Approving lets this session act as you with the role you pick, for as long as it keeps being used.\",\n worker: \"Approving lets this worker act as you with the role you pick, for as long as it keeps being used.\",\n // DX-5809: danxbot issues a machine key that lapses after 7 days without use; this copy states that lifetime.\n machine: \"Approving lets this machine read your cards. Its key stays valid while the machine keeps using it and lapses after 7 days unused.\",\n }[kind];\n const deny = typedCode ? \"If you did not ask for this, deny it.\" : \"If the code does not match, or you did not ask for this, deny it.\";\n return `${lead} ${deny}`;\n },\n noRoleTitle: \"No role available\",\n noRoleBody: \"Every role holds a permission you don't have, so you can't approve this request. You can still deny it.\",\n roleHint: (roleLabel, isDefault) =>\n `The key can do what this role can, never more than you can. ${\n isDefault ? `${roleLabel}, the default, is chosen for you.` : `The narrowest allowed role, ${roleLabel}, is chosen for you.`\n }`,\n revoked: \"Revoked\",\n revokedBody: (when, by) => `The key was revoked ${when}${by ? ` by ${by}` : \"\"}. The requester can no longer act with it and has to ask again.`,\n revokeKey: \"Revoke key\",\n revokeTitle: \"Revoke this key?\",\n revokeBody: \"The requester stops acting as you the moment the key is revoked, and has to ask for access again. This cannot be undone.\",\n revokeCancel: \"Cancel\",\n revokeFailedTitle: \"Couldn't revoke the key\",\n revokeFailedMessage: \"Couldn't revoke the key. Try again.\",\n },\n permissionRequest: {\n title: \"Permission request\",\n notHeld: \"You do not hold this permission\",\n key: \"Key\",\n reasonGiven: \"Reason given\",\n approvedWithList: \"The agent's key now also holds these permissions, on top of its role. It picks them up on its next call.\",\n approvedNoList: \"The agent picks up the permissions you approved on its next call. You can close this page.\",\n claimedWithList: \"The agent's key holds these permissions now. If that was not you, remove them from the key in your agent sessions.\",\n claimedNoList: \"The agent has the permissions you approved. If that was not you, remove them from the key in your agent sessions.\",\n denied: \"The agent was refused these permissions and its key is unchanged. It has to ask again to get them.\",\n expiredFallback: \"Nothing was granted. Ask the agent to start a new request.\",\n approveBody:\n \"Approving adds the permissions you leave checked to this key, on top of its role, for as long as the key lives. If the code does not match, or you did not ask for this, deny it.\",\n emptyTitle: \"Nothing you can grant\",\n emptyDescription: \"You do not hold any of the requested permissions, so you can't approve this request. You can still deny it.\",\n otherCategory: \"Other\",\n legend: \"Permissions requested\",\n legendDescription: \"Uncheck any you do not want to grant. Approving grants only the checked ones.\",\n },\n roleKeyPicker: {\n label: \"Role\",\n description: \"The key can do what this role can, never more than you can.\",\n unavailable: (permissionLabels) => `Holds permissions you don't have: ${permissionLabels.join(\", \")}.`,\n },\n apiKeysPanel: {\n title: \"API keys\",\n createKey: \"Create key\",\n emptyTitle: \"No API keys yet\",\n emptyDescription: \"Create one to let a script or an agent act as you, with the access of the role you pick.\",\n dialogTitle: \"Create API key\",\n dialogDescription: \"You'll only see the full key once, immediately after creating it — store it somewhere safe.\",\n cancel: \"Cancel\",\n create: \"Create\",\n failedTitle: \"Couldn't create the key\",\n failedMessage: \"Couldn't create the key. Try again.\",\n nameLabel: \"Name\",\n nameDescription: \"What this key is for — e.g. \\\"CI deploy script\\\".\",\n namePlaceholder: \"e.g. CI deploy script\",\n expiresLabel: \"Expires in (days)\",\n expiresDescription: \"Leave blank for a key that never expires.\",\n expiresPlaceholder: \"Never\",\n revealedTitle: \"API key created\",\n revealedDescription: \"Copy this now — you won't be able to see it again.\",\n done: \"Done\",\n revealedLabel: \"Your new key\",\n copyKey: \"Copy key\",\n },\n apiKeysTable: {\n columnKey: \"Key\",\n columnStartedBy: \"Started by\",\n columnRole: \"Role\",\n columnLastUsed: \"Last used\",\n columnExpires: \"Expires\",\n never: \"Never\",\n created: (age) => `Created ${age}`,\n roleOf: (keyName) => `Role of ${keyName}`,\n roleNotAssignable: \"This role is not one you can assign here.\",\n revoke: (keyName) => `Revoke ${keyName}`,\n revoking: \"Revoking…\",\n revokeTitle: (keyName) => `Revoke \"${keyName}\"?`,\n revokeDescription: \"Anything using this key will immediately lose access. This cannot be undone.\",\n revokeConfirm: \"Revoke key\",\n grantsOf: (keyName) => `Permissions added to ${keyName}`,\n removeGrant: (permissionLabel, keyName) => `Remove ${permissionLabel} from ${keyName}`,\n updating: \"Updating…\",\n removeGrantTitle: (permissionLabel) => `Remove ${permissionLabel} from this key?`,\n removeGrantDescription: \"The agent loses it on its next call; the key and its role are unchanged.\",\n removeGrantConfirm: \"Remove permission\",\n granted: (age, reason) => (reason ? `Granted ${age}: ${reason}` : `Granted ${age}`),\n },\n agentKeysList: {\n emptyTitle: \"No agent sessions\",\n emptyDescription: \"Claude Code sessions, workers and dispatches that act as you appear here once you approve their access.\",\n },\n devTools: {\n trigger: \"Dev tools\",\n triggerLabel: \"Developer tools\",\n viewAs: \"View as\",\n viewAsLabel: \"View the app as a role\",\n actualRole: \"Your actual role\",\n unknownRole: \"an unknown role\",\n viewingAs: (role, emphasis) => createElement(Fragment, null, \"Viewing as \", emphasis(role), \". Screens and permissions reflect that role, not your own.\"),\n resetToActual: \"Reset to actual\",\n dataSource: \"Data source\",\n dataSources: { simulated: \"Simulated\", live: \"Live\" },\n liveNotConfigured:\n \"No live backend is configured in this demo — stores keep answering with simulated data. A consuming app wires its own fetcher per store to make this real.\",\n networkSpeed: \"Network speed\",\n networkSpeeds: { instant: \"Instant\", fast: \"Fast\", typical: \"Typical\", flaky: \"Flaky\" },\n regenerate: \"Regenerate demo data\",\n regenerateTitle: \"Regenerate demo data?\",\n regenerateDescription:\n \"Every user, team, role and permission reverts to its seed. The use-case ledger is untouched — this never erases product history.\",\n regenerateConfirm: \"Regenerate\",\n openLedger: \"Open Use Case Ledger\",\n },\n invitationsList: {\n columnInvitee: \"Invitee\",\n columnRole: \"Role\",\n columnStatus: \"Status\",\n columnSent: \"Sent\",\n invitedBy: (name) => `Invited by ${name}`,\n status: { pending: \"Pending\", accepted: \"Accepted\", revoked: \"Revoked\", expired: \"Expired\" },\n complaint: \"Complaint\",\n bounced: \"Bounced\",\n deliveryFailed: \"Delivery failed\",\n working: \"Working…\",\n copyLink: (email) => `Copy invite link for ${email}`,\n resend: (email) => `Resend invitation to ${email}`,\n revoke: (email) => `Revoke invitation to ${email}`,\n revokeTitle: (email) => `Revoke invitation to ${email}?`,\n revokeDescription: \"They will no longer be able to accept this invitation.\",\n revokeConfirm: \"Revoke invitation\",\n emptyTitle: \"No invitations yet\",\n emptyDescription: \"Invitations you send will show up here.\",\n },\n inviteMembersDialog: {\n title: \"Invite members\",\n description: \"Each address gets its own invitation email with the role you pick below.\",\n cancel: \"Cancel\",\n send: (count) => plural(count, { zero: \"Send invitation\", one: \"Send invitation\", other: \"Send invitations\" }),\n emailsLabel: \"Email addresses\",\n emailsDescription: \"Press Enter or comma after each one.\",\n emailPlaceholder: \"name@example.com\",\n removeEmail: (email) => `Remove ${email}`,\n invalidEmail: (typed) => `\"${typed}\" doesn't look like an email address`,\n roleLabel: \"Role\",\n },\n membersPanel: {\n columnMember: \"Member\",\n columnRole: \"Role\",\n columnJoined: \"Joined\",\n roleFor: (name) => `Role for ${name}`,\n removing: \"Removing…\",\n remove: (name) => `Remove ${name}`,\n removeTitle: (name) => `Remove ${name}?`,\n removeDescription: (name) =>\n `${name} will lose access to this team immediately, and every one of their active sessions and API tokens will be revoked.`,\n removeConfirm: \"Remove member\",\n emptyTitle: \"No members yet\",\n emptyDescription: \"Invite someone to get this team started.\",\n },\n stagedForm: {\n save: \"Save changes\",\n discard: \"Discard changes\",\n imageNote: (kind, saveLabel, removed) =>\n removed ? `Not saved yet — click ${saveLabel} to remove the ${kind}.` : `Not saved yet — click ${saveLabel} to keep this ${kind}.`,\n },\n profileForm: {\n saved: \"Profile saved.\",\n failedTitle: \"Couldn't save your profile\",\n failedMessage: \"Couldn't save your profile. Try again.\",\n avatar: \"Avatar\",\n name: \"Name\",\n username: \"Username\",\n email: \"Email\",\n },\n teamSettingsForm: {\n saved: \"Team settings saved.\",\n failedTitle: \"Couldn't save the team\",\n failedMessage: \"Couldn't save the team. Try again.\",\n readOnlyTitle: \"Read-only\",\n readOnlyBody: \"You don't have permission to change team settings.\",\n logo: \"Logo\",\n teamName: \"Team name\",\n },\n profilePage: {\n title: \"Profile\",\n rolesHeading: \"Your roles & permissions\",\n viewingAs: (viewing, actual, emphasis) =>\n createElement(\n Fragment,\n null,\n \"You are currently viewing as \",\n emphasis(viewing),\n \". What is listed below is that role's access, not your normal \",\n emphasis(actual),\n \" access.\",\n ),\n holdsRole: (role, team, emphasis) => createElement(Fragment, null, \"You hold the \", emphasis(role), team === undefined ? \" role.\" : ` role on ${team}.`),\n noPermissions: \"This role does not grant any permissions.\",\n noRole: \"No role is assigned for this team.\",\n name: \"Name\",\n email: \"Email\",\n },\n changePasswordForm: {\n failedTitle: \"Couldn't change your password\",\n failedMessage: \"Could not change your password. Try again.\",\n current: \"Current password\",\n next: \"New password\",\n confirmPassword: \"Confirm new password\",\n mismatch: \"Doesn't match the new password above.\",\n submit: \"Change password\",\n setFailedTitle: \"Couldn't set your password\",\n setFailedMessage: \"Could not set your password. Try again.\",\n setSubmit: \"Set password\",\n },\n dangerZone: {\n title: \"Danger zone\",\n },\n sessionsList: {\n columnSession: \"Session\",\n columnBrowser: \"Browser\",\n thisBrowser: \"This browser\",\n copyBrowserId: (shownId) => `Copy browser id ${shownId}`,\n columnLastUsed: \"Last used\",\n columnCreated: \"Created\",\n columnExpires: \"Expires\",\n current: \"Current\",\n never: \"Never\",\n thisSession: \"This session\",\n revoke: (name) => `Revoke ${name}`,\n revoking: \"Revoking…\",\n revokeTitle: (name) => `Revoke \"${name}\"?`,\n revokeDescription: \"That device will be signed out immediately and will need to sign in again.\",\n revokeConfirm: \"Revoke session\",\n emptyTitle: \"No active sessions\",\n },\n teamSwitcher: {\n currentTeam: \"Current team\",\n switchFrom: (currentTeamName) => `Switch team, currently ${currentTeamName}`,\n switchTeam: \"Switch team\",\n },\n accountMenu: {\n triggerLabel: (userName) => `Account menu for ${userName}`,\n profile: \"Profile\",\n roles: \"Roles & Permissions\",\n yourAccess: \"Your access\",\n hasRole: (role, emphasis) => createElement(Fragment, null, \"You have the \", emphasis(role), \" role.\"),\n noRole: \"No role is assigned for this team.\",\n switchTeam: \"Switch team\",\n signOut: \"Sign out\",\n },\n rolePermissionMatrix: {\n caption: \"Which permissions each role has\",\n permission: \"Permission\",\n otherCategory: \"Other\",\n locked: (roleLabel) => `${roleLabel} is locked and can't be edited`,\n cell: (roleLabel, permissionLabel, granted) => `${roleLabel} ${granted ? \"includes\" : \"does not include\"} ${permissionLabel}`,\n },\n toggleMatrix: {\n cell: (columnLabel, rowLabel, on) => `${columnLabel}: ${rowLabel} is ${on ? \"on\" : \"off\"}`,\n unavailable: \"Not available\",\n setColumn: (columnLabel) => `Set every switch in ${columnLabel}`,\n otherGroup: \"Other\",\n busy: \"Saving\",\n },\n rolesPermissionsPage: {\n title: \"Roles & Permissions\",\n subtitleEditable: \"What each role can do. Toggle a permission directly in the matrix, or manage roles below.\",\n subtitleReadOnly: \"What each role can do. Contact an administrator to change a role's access.\",\n newRole: \"New role\",\n manageRoles: \"Manage roles\",\n working: \"Working…\",\n reset: (roleLabel) => `Reset ${roleLabel} to its seeded defaults`,\n edit: (roleLabel) => `Edit ${roleLabel}`,\n delete: (roleLabel) => `Delete ${roleLabel}`,\n deleteTitle: (roleLabel) => `Delete ${roleLabel}?`,\n deleteDescription: \"Anyone still holding this role must be moved to a different one first.\",\n deleteConfirm: \"Delete role\",\n },\n roleEditorDialog: {\n createTitle: \"New role\",\n editTitle: \"Edit role\",\n createDescription: \"A custom role starts with no permissions granted — set them afterward in the matrix, or clone an existing role's set below.\",\n editDescription: \"Renaming a role doesn't change who has it or what it grants. Edit permissions in the matrix.\",\n cancel: \"Cancel\",\n create: \"Create role\",\n save: \"Save\",\n label: \"Label\",\n labelPlaceholder: \"e.g. QA Reviewer\",\n description: \"Description\",\n descriptionHint: \"Shown to whoever picks this role — what it's for.\",\n cloneLabel: \"Clone permissions from\",\n cloneDescription: \"Optional — starts the new role's permission set as a copy of another role's. You can still change it afterward.\",\n cloneNone: \"None — start with no permissions\",\n },\n};\n\n"],"names":["rbacStrings","role","kind","typedCode","roleLabel","isDefault","when","by","permissionLabels","age","keyName","permissionLabel","reason","emphasis","createElement","Fragment","name","email","count","plural","typed","saveLabel","removed","viewing","actual","team","shownId","currentTeamName","userName","granted","columnLabel","rowLabel","on"],"mappings":";;AAkmBO,MAAMA,IAA2B;AAAA,EACtC,UAAU;AAAA,IACR,OAAO,EAAE,SAAS,WAAW,UAAU,YAAY,QAAQ,UAAU,SAAS,WAAW,SAAS,UAAA;AAAA,IAClG,eAAe,EAAE,UAAU,YAAY,SAAS,mBAAmB,QAAQ,UAAU,SAAS,uBAAA;AAAA,IAC9F,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,eAAe,EAAE,SAAS,4CAA4C,MAAM,wCAAA;AAAA,IAC5E,aAAa,EAAE,SAAS,gCAAgC,MAAM,4BAAA;AAAA,IAC9D,MAAM;AAAA,IACN,SAAS;AAAA,IACT,uBAAuB;AAAA,IACvB,WAAW;AAAA,IACX,SAAS;AAAA,IACT,kBAAkB;AAAA,EAAA;AAAA,EAEpB,eAAe;AAAA,IACb,OAAO;AAAA,IACP,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAU,CAACC,MAAS,sCAAsCA,IAAO,aAAaA,CAAI,UAAU,EAAE;AAAA,IAC9F,SAAS,CAACA,MACR,4BAA4BA,IAAO,aAAaA,CAAI,UAAU,EAAE;AAAA,IAClE,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,aAAa,CAACC,GAAMC,MAQX,GAPM;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA;AAAA,MAER,SAAS;AAAA,IAAA,EACTD,CAAI,CAEQ,IADDC,IAAY,0CAA0C,mEAC7C;AAAA,IAExB,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,UAAU,CAACC,GAAWC,MACpB,+DACEA,IAAY,GAAGD,CAAS,sCAAsC,+BAA+BA,CAAS,sBACxG;AAAA,IACF,SAAS;AAAA,IACT,aAAa,CAACE,GAAMC,MAAO,uBAAuBD,CAAI,GAAGC,IAAK,OAAOA,CAAE,KAAK,EAAE;AAAA,IAC9E,WAAW;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,qBAAqB;AAAA,EAAA;AAAA,EAEvB,mBAAmB;AAAA,IACjB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,KAAK;AAAA,IACL,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,aACE;AAAA,IACF,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,mBAAmB;AAAA,EAAA;AAAA,EAErB,eAAe;AAAA,IACb,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa,CAACC,MAAqB,qCAAqCA,EAAiB,KAAK,IAAI,CAAC;AAAA,EAAA;AAAA,EAErG,cAAc;AAAA,IACZ,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf,qBAAqB;AAAA,IACrB,MAAM;AAAA,IACN,eAAe;AAAA,IACf,SAAS;AAAA,EAAA;AAAA,EAEX,cAAc;AAAA,IACZ,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,OAAO;AAAA,IACP,SAAS,CAACC,MAAQ,WAAWA,CAAG;AAAA,IAChC,QAAQ,CAACC,MAAY,WAAWA,CAAO;AAAA,IACvC,mBAAmB;AAAA,IACnB,QAAQ,CAACA,MAAY,UAAUA,CAAO;AAAA,IACtC,UAAU;AAAA,IACV,aAAa,CAACA,MAAY,WAAWA,CAAO;AAAA,IAC5C,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,UAAU,CAACA,MAAY,wBAAwBA,CAAO;AAAA,IACtD,aAAa,CAACC,GAAiBD,MAAY,UAAUC,CAAe,SAASD,CAAO;AAAA,IACpF,UAAU;AAAA,IACV,kBAAkB,CAACC,MAAoB,UAAUA,CAAe;AAAA,IAChE,wBAAwB;AAAA,IACxB,oBAAoB;AAAA,IACpB,SAAS,CAACF,GAAKG,MAAYA,IAAS,WAAWH,CAAG,KAAKG,CAAM,KAAK,WAAWH,CAAG;AAAA,EAAA;AAAA,EAElF,eAAe;AAAA,IACb,YAAY;AAAA,IACZ,kBAAkB;AAAA,EAAA;AAAA,EAEpB,UAAU;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,WAAW,CAACR,GAAMY,MAAaC,EAAcC,GAAU,MAAM,eAAeF,EAASZ,CAAI,GAAG,4DAA4D;AAAA,IACxJ,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,aAAa,EAAE,WAAW,aAAa,MAAM,OAAA;AAAA,IAC7C,mBACE;AAAA,IACF,cAAc;AAAA,IACd,eAAe,EAAE,SAAS,WAAW,MAAM,QAAQ,SAAS,WAAW,OAAO,QAAA;AAAA,IAC9E,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,uBACE;AAAA,IACF,mBAAmB;AAAA,IACnB,YAAY;AAAA,EAAA;AAAA,EAEd,iBAAiB;AAAA,IACf,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,WAAW,CAACe,MAAS,cAAcA,CAAI;AAAA,IACvC,QAAQ,EAAE,SAAS,WAAW,UAAU,YAAY,SAAS,WAAW,SAAS,UAAA;AAAA,IACjF,WAAW;AAAA,IACX,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,UAAU,CAACC,MAAU,wBAAwBA,CAAK;AAAA,IAClD,QAAQ,CAACA,MAAU,wBAAwBA,CAAK;AAAA,IAChD,QAAQ,CAACA,MAAU,wBAAwBA,CAAK;AAAA,IAChD,aAAa,CAACA,MAAU,wBAAwBA,CAAK;AAAA,IACrD,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,kBAAkB;AAAA,EAAA;AAAA,EAEpB,qBAAqB;AAAA,IACnB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,MAAM,CAACC,MAAUC,EAAOD,GAAO,EAAE,MAAM,mBAAmB,KAAK,mBAAmB,OAAO,mBAAA,CAAoB;AAAA,IAC7G,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa,CAACD,MAAU,UAAUA,CAAK;AAAA,IACvC,cAAc,CAACG,MAAU,IAAIA,CAAK;AAAA,IAClC,WAAW;AAAA,EAAA;AAAA,EAEb,cAAc;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,SAAS,CAACJ,MAAS,YAAYA,CAAI;AAAA,IACnC,UAAU;AAAA,IACV,QAAQ,CAACA,MAAS,UAAUA,CAAI;AAAA,IAChC,aAAa,CAACA,MAAS,UAAUA,CAAI;AAAA,IACrC,mBAAmB,CAACA,MAClB,GAAGA,CAAI;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,kBAAkB;AAAA,EAAA;AAAA,EAEpB,YAAY;AAAA,IACV,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW,CAACd,GAAMmB,GAAWC,MAC3BA,IAAU,yBAAyBD,CAAS,kBAAkBnB,CAAI,MAAM,yBAAyBmB,CAAS,iBAAiBnB,CAAI;AAAA,EAAA;AAAA,EAEnI,aAAa;AAAA,IACX,OAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO;AAAA,EAAA;AAAA,EAET,kBAAkB;AAAA,IAChB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAe;AAAA,IACf,eAAe;AAAA,IACf,cAAc;AAAA,IACd,MAAM;AAAA,IACN,UAAU;AAAA,EAAA;AAAA,EAEZ,aAAa;AAAA,IACX,OAAO;AAAA,IACP,cAAc;AAAA,IACd,WAAW,CAACqB,GAASC,GAAQX,MAC3BC;AAAA,MACEC;AAAA,MACA;AAAA,MACA;AAAA,MACAF,EAASU,CAAO;AAAA,MAChB;AAAA,MACAV,EAASW,CAAM;AAAA,MACf;AAAA,IAAA;AAAA,IAEJ,WAAW,CAACvB,GAAMwB,GAAMZ,MAAaC,EAAcC,GAAU,MAAM,iBAAiBF,EAASZ,CAAI,GAAGwB,MAAS,SAAY,WAAW,YAAYA,CAAI,GAAG;AAAA,IACvJ,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,oBAAoB;AAAA,IAClB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS;AAAA,IACT,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,WAAW;AAAA,EAAA;AAAA,EAEb,YAAY;AAAA,IACV,OAAO;AAAA,EAAA;AAAA,EAET,cAAc;AAAA,IACZ,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,eAAe,CAACC,MAAY,mBAAmBA,CAAO;AAAA,IACtD,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ,CAACV,MAAS,UAAUA,CAAI;AAAA,IAChC,UAAU;AAAA,IACV,aAAa,CAACA,MAAS,WAAWA,CAAI;AAAA,IACtC,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,YAAY;AAAA,EAAA;AAAA,EAEd,cAAc;AAAA,IACZ,aAAa;AAAA,IACb,YAAY,CAACW,MAAoB,0BAA0BA,CAAe;AAAA,IAC1E,YAAY;AAAA,EAAA;AAAA,EAEd,aAAa;AAAA,IACX,cAAc,CAACC,MAAa,oBAAoBA,CAAQ;AAAA,IACxD,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,SAAS,CAAC3B,GAAMY,MAAaC,EAAcC,GAAU,MAAM,iBAAiBF,EAASZ,CAAI,GAAG,QAAQ;AAAA,IACpG,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAS;AAAA,EAAA;AAAA,EAEX,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,QAAQ,CAACG,MAAc,GAAGA,CAAS;AAAA,IACnC,MAAM,CAACA,GAAWO,GAAiBkB,MAAY,GAAGzB,CAAS,IAAIyB,IAAU,aAAa,kBAAkB,IAAIlB,CAAe;AAAA,EAAA;AAAA,EAE7H,cAAc;AAAA,IACZ,MAAM,CAACmB,GAAaC,GAAUC,MAAO,GAAGF,CAAW,KAAKC,CAAQ,OAAOC,IAAK,OAAO,KAAK;AAAA,IACxF,aAAa;AAAA,IACb,WAAW,CAACF,MAAgB,uBAAuBA,CAAW;AAAA,IAC9D,YAAY;AAAA,IACZ,MAAM;AAAA,EAAA;AAAA,EAER,sBAAsB;AAAA,IACpB,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO,CAAC1B,MAAc,SAASA,CAAS;AAAA,IACxC,MAAM,CAACA,MAAc,QAAQA,CAAS;AAAA,IACtC,QAAQ,CAACA,MAAc,UAAUA,CAAS;AAAA,IAC1C,aAAa,CAACA,MAAc,UAAUA,CAAS;AAAA,IAC/C,mBAAmB;AAAA,IACnB,eAAe;AAAA,EAAA;AAAA,EAEjB,kBAAkB;AAAA,IAChB,aAAa;AAAA,IACb,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,WAAW;AAAA,EAAA;AAEf;"}
|
|
1
|
+
{"version":3,"file":"rbac.js","sources":["../../../../src/lib/i18n/areas/rbac.ts"],"sourcesContent":["import { plural } from \"../plural\";\nimport { createElement, Fragment, type ReactNode } from \"react\";\nimport type { Emphasis } from \"../emphasis\";\n\n/* DX-4740 — built-in strings of the RBAC components (`components/rbac`). Members are keyed by\n component; a function leaf carries an argument so the whole sentence is the translator's. */\n/** The kinds of requester `AccessRequestPanel` names; the panel's `AccessRequestKind` is this same union. */\nexport type AccessRequestKind = \"session\" | \"worker\" | \"machine\";\n\nexport interface RbacStrings {\n /** The pieces `AccessRequestPanel` and `PermissionRequestPanel` share (`approvalPanelParts.tsx`). */\n approval: {\n /** The badge in the request header, by request state. */\n state: { pending: string; approved: string; denied: string; expired: string; claimed: string };\n /** The title of the readout for a settled request, by state. */\n terminalTitle: { approved: string; claimed: string; denied: string; expired: string };\n /** Title of the callout that shows the confirm code to compare. */\n confirmCodeTitle: string;\n /** Line under the shown confirm code. */\n confirmCodeCompare: string;\n /** Label of the field the approver types the confirm code into. */\n confirmCodeLabel: string;\n /** Help text under the confirm code field. */\n confirmCodeEntryHint: string;\n /** Error under the confirm code field when what was typed is wrong. */\n confirmCodeMismatch: string;\n /** Fallback error text when an approve / deny call rejects without a message, by action. */\n failedMessage: { approve: string; deny: string };\n /** Title of the error callout when an approve / deny call rejects, by action. */\n failedTitle: { approve: string; deny: string };\n /** The Deny button. */\n deny: string;\n /** The Approve button. */\n approve: string;\n /** Last line of the Expired readout when the consumer gave a note. */\n expiredNothingGranted: string;\n /** Term of the fact row naming when the request was made. */\n requested: string;\n /** Term of the fact row naming when a pending request expires. */\n expires: string;\n /** Title of the warning callout above a pending request's decision. */\n approveOnlyTitle: string;\n };\n /** `AccessRequestPanel`. */\n accessRequest: {\n /** Heading of the panel. */\n title: string;\n /** Fact row \"Kind\" value for a request from an agent session. */\n kindSession: string;\n /** Fact row \"Kind\" value for a request from a worker. */\n kindWorker: string;\n /** DX-5809 / DXUI-15: fact row \"Kind\" value for a request from a dev machine's unattended maintenance. */\n kindMachine: string;\n /** DXUI-15: the grant a machine request gets in place of a role picker: fixed, read-only access to cards. */\n machineGrant: string;\n /** DXUI-15: title of the callout that shows the machine grant. */\n machineGrantTitle: string;\n /** DXUI-102: heading of the read-only role block for a session request that names its role. */\n fixedRoleTitle: string;\n /** DXUI-102: body of the \"Approve only if you started this\" callout for a request that names its role; `typedCode` as for `approveBody`. */\n approveBodyFixedRole: (typedCode: boolean) => string;\n /** DXUI-102: line under that heading. */\n fixedRoleHint: string;\n /** Term of the fact row naming the kind of requester. */\n kind: string;\n /** Term of the fact row naming a worker requester. */\n worker: string;\n /** Term of the fact row naming a session requester. */\n session: string;\n /** Term of the fact row naming the repository. */\n repository: string;\n /** Term of the fact row naming the machine. */\n machine: string;\n /** Term of the fact row showing the requester's address. */\n address: string;\n /** Term of the fact row showing the requester's client version. */\n clientVersion: string;\n /** Readout for an approved request; `role` is the granted role's label, when known. */\n approved: (role: string | undefined) => string;\n /** Readout for a claimed request; `role` is the granted role's label, when known. */\n claimed: (role: string | undefined) => string;\n /** Readout for a denied request. */\n denied: string;\n /** Readout for an expired request when the consumer gave no note. */\n expiredFallback: string;\n /** Body of the \"Approve only if you started this\" callout. */\n approveBody: (kind: AccessRequestKind, typedCode: boolean) => string;\n /** Title of the callout shown when no role can be granted. */\n noRoleTitle: string;\n /** Body of the callout shown when no role can be granted. */\n noRoleBody: string;\n /** Description under the role picker; `isDefault` is true when the consumer's default role was preselected. */\n roleHint: (roleLabel: string, isDefault: boolean) => string;\n /** DX-4856: the header badge and readout title once the key this request minted was revoked. */\n revoked: string;\n /** DX-4856: readout body for a revoked key; `when` is the formatted instant, `by` the revoker's name when a person did it. */\n revokedBody: (when: string, by: string | undefined) => string;\n /** DX-4856: label of the button that starts revoking the key. */\n revokeKey: string;\n /** DX-4856: title of the confirmation dialog. */\n revokeTitle: string;\n /** DX-4856: body of the confirmation dialog. */\n revokeBody: string;\n /** DX-4856: the dialog's dismiss button. */\n revokeCancel: string;\n /** DX-4856: title of the error shown when the revoke failed. */\n revokeFailedTitle: string;\n /** DX-4856: message of that error when the rejection carried none. */\n revokeFailedMessage: string;\n };\n /** `PermissionRequestPanel`. */\n permissionRequest: {\n /** Heading of the panel. */\n title: string;\n /** Note under a requested permission the approver does not hold. */\n notHeld: string;\n /** Term of the fact row naming the key that is asking. */\n key: string;\n /** Caption above the agent's stated reason. */\n reasonGiven: string;\n /** Readout for an approved request that lists what was granted. */\n approvedWithList: string;\n /** Readout for an approved request with no list of what was granted. */\n approvedNoList: string;\n /** Readout for a claimed request that lists what was granted. */\n claimedWithList: string;\n /** Readout for a claimed request with no list of what was granted. */\n claimedNoList: string;\n /** Readout for a denied request. */\n denied: string;\n /** Readout for an expired request when the consumer gave no note. */\n expiredFallback: string;\n /** Body of the \"Approve only if you started this\" callout. */\n approveBody: string;\n /** Title of the callout shown when the approver holds none of the requested permissions. */\n emptyTitle: string;\n /** Body of the callout shown when the approver holds none of the requested permissions. */\n emptyDescription: string;\n /** Section heading for requested permissions that carry no category, when others do. */\n otherCategory: string;\n /** Legend of the list of requested permissions. */\n legend: string;\n /** Description under the legend of the list of requested permissions. */\n legendDescription: string;\n };\n /** `RoleKeyPicker`. */\n roleKeyPicker: {\n /** Default heading of the picker. */\n label: string;\n /** Default line under the heading. */\n description: string;\n /** Why a role cannot be chosen, naming the permissions the person lacks. */\n unavailable: (permissionLabels: string[]) => string;\n };\n /** `ApiKeysPanel`. */\n apiKeysPanel: {\n /** Heading of the panel. */\n title: string;\n /** The button that opens the create dialog. */\n createKey: string;\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n /** Title of the create dialog. */\n dialogTitle: string;\n /** Description of the create dialog. */\n dialogDescription: string;\n /** The create dialog's cancel button. */\n cancel: string;\n /** The create dialog's submit button. */\n create: string;\n /** Title of the error callout when creating fails. */\n failedTitle: string;\n /** Fallback error text when creating rejects without a message. */\n failedMessage: string;\n /** Label of the key name field. */\n nameLabel: string;\n /** Description of the key name field. */\n nameDescription: string;\n /** Placeholder of the key name field. */\n namePlaceholder: string;\n /** Label of the expiry days field. */\n expiresLabel: string;\n /** Description of the expiry days field. */\n expiresDescription: string;\n /** Placeholder of the expiry days field. */\n expiresPlaceholder: string;\n /** Title of the dialog that shows the new key once. */\n revealedTitle: string;\n /** Description of the dialog that shows the new key once. */\n revealedDescription: string;\n /** The button that closes the reveal dialog. */\n done: string;\n /** Label of the field showing the new key. */\n revealedLabel: string;\n /** Label of the button that copies the new key. */\n copyKey: string;\n };\n /** `ApiKeysTable` (also `AgentKeysList`). */\n apiKeysTable: {\n /** Column header: the key's name. */\n columnKey: string;\n /** Column header: who started or authorized the key's session (`AgentKeysList` `renderStartedBy`, DX-6801). */\n columnStartedBy: string;\n /** Column header: the key's role. */\n columnRole: string;\n /** Column header: when the key was last used. */\n columnLastUsed: string;\n /** Column header: when the key expires. */\n columnExpires: string;\n /** Cell text for a key never used or with no expiry. */\n never: string;\n /** Under a key's name: how long ago it was created; `age` is the formatted age. */\n created: (age: string) => string;\n /** Accessible name of a key's role selector. */\n roleOf: (keyName: string) => string;\n /** Refusal on a role the owner cannot assign. */\n roleNotAssignable: string;\n /** Accessible name of the revoke key button. */\n revoke: (keyName: string) => string;\n /** Tooltip on the revoke button while a revoke runs. */\n revoking: string;\n /** Title of the revoke key confirmation. */\n revokeTitle: (keyName: string) => string;\n /** Description of the revoke key confirmation. */\n revokeDescription: string;\n /** Confirm button of the revoke key confirmation. */\n revokeConfirm: string;\n /** Accessible name of the list of permissions added to a key. */\n grantsOf: (keyName: string) => string;\n /** Accessible name of the button that removes a granted permission. */\n removeGrant: (permissionLabel: string, keyName: string) => string;\n /** Tooltip on the remove-grant button while an update runs. */\n updating: string;\n /** Title of the remove-grant confirmation. */\n removeGrantTitle: (permissionLabel: string) => string;\n /** Description of the remove-grant confirmation. */\n removeGrantDescription: string;\n /** Confirm button of the remove-grant confirmation. */\n removeGrantConfirm: string;\n /** Line under a granted permission; `age` is the formatted age, `reason` the agent's reason when given. */\n granted: (age: string, reason: string | undefined) => string;\n };\n /** `AgentKeysList`. */\n agentKeysList: {\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n };\n /** `DevToolsPopover`. */\n devTools: {\n /** Visible label of the trigger button (hidden below the sm breakpoint). */\n trigger: string;\n /** Accessible name of the trigger button. */\n triggerLabel: string;\n /** Heading of the \"view as a role\" section. */\n viewAs: string;\n /** Accessible name of the role select. */\n viewAsLabel: string;\n /** Placeholder of the role select while no role is impersonated. */\n actualRole: string;\n /** Name used for the impersonated role when it cannot be found. */\n unknownRole: string;\n /** The impersonation notice; `emphasis` wraps the role's name in the caller's emphasis markup. */\n viewingAs: (role: string, emphasis: Emphasis) => ReactNode;\n /** The button that stops impersonating. */\n resetToActual: string;\n /** Heading and accessible name of the data source section. */\n dataSource: string;\n /** Label of each data source option. */\n dataSources: { simulated: string; live: string };\n /** Note shown when the data source is set to live. */\n liveNotConfigured: string;\n /** Heading and accessible name of the network speed section. */\n networkSpeed: string;\n /** Label of each network speed option. */\n networkSpeeds: { instant: string; fast: string; typical: string; flaky: string };\n /** The button that opens the regenerate confirmation. */\n regenerate: string;\n /** Title of the regenerate confirmation. */\n regenerateTitle: string;\n /** Description of the regenerate confirmation. */\n regenerateDescription: string;\n /** Confirm button of the regenerate confirmation. */\n regenerateConfirm: string;\n /** The button that opens the use-case ledger. */\n openLedger: string;\n };\n /** `InvitationsList`. */\n invitationsList: {\n /** Column header: who was invited. */\n columnInvitee: string;\n /** Column header: the invited role. */\n columnRole: string;\n /** Column header: the invitation's status. */\n columnStatus: string;\n /** Column header: how long ago the invitation was sent. */\n columnSent: string;\n /** Under the invitee's address: who sent the invitation. */\n invitedBy: (name: string) => string;\n /** Status badge by invitation status. */\n status: { pending: string; accepted: string; revoked: string; expired: string };\n /** Badge shown when the recipient complained about the email. */\n complaint: string;\n /** Badge shown when the email bounced. */\n bounced: string;\n /** Badge shown when sending the email failed or was suppressed. */\n deliveryFailed: string;\n /** Tooltip on a row's action buttons while that row is busy. */\n working: string;\n /** Accessible name of the copy-invite-link button. */\n copyLink: (email: string) => string;\n /** Accessible name of the resend button. */\n resend: (email: string) => string;\n /** Accessible name of the revoke button. */\n revoke: (email: string) => string;\n /** Title of the revoke confirmation. */\n revokeTitle: (email: string) => string;\n /** Description of the revoke confirmation. */\n revokeDescription: string;\n /** Confirm button of the revoke confirmation. */\n revokeConfirm: string;\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n };\n /** `InviteMembersDialog`. */\n inviteMembersDialog: {\n /** Title of the dialog. */\n title: string;\n /** Description of the dialog. */\n description: string;\n /** The cancel button. */\n cancel: string;\n /** The submit button; `count` is how many addresses will be invited. */\n send: (count: number) => string;\n /** Label of the email addresses field. */\n emailsLabel: string;\n /** Description of the email addresses field. */\n emailsDescription: string;\n /** Placeholder of the email input while no address has been added. */\n emailPlaceholder: string;\n /** Accessible name of the button that removes an added address. */\n removeEmail: (email: string) => string;\n /** Error under the field when what was typed is not an email address. */\n invalidEmail: (typed: string) => string;\n /** Label of the role select. */\n roleLabel: string;\n };\n /** `MembersPanel`. */\n membersPanel: {\n /** Column header: the member. */\n columnMember: string;\n /** Column header: the member's role. */\n columnRole: string;\n /** Column header: how long ago the member joined. */\n columnJoined: string;\n /** Accessible name of a member's role select. */\n roleFor: (name: string) => string;\n /** Tooltip on the remove button while a removal runs. */\n removing: string;\n /** Accessible name of the remove button. */\n remove: (name: string) => string;\n /** Title of the remove confirmation. */\n removeTitle: (name: string) => string;\n /** Description of the remove confirmation. */\n removeDescription: (name: string) => string;\n /** Confirm button of the remove confirmation. */\n removeConfirm: string;\n /** Title of the empty state. */\n emptyTitle: string;\n /** Description of the empty state. */\n emptyDescription: string;\n };\n /** The save / discard row and staged-image note `ProfileForm` and `TeamSettingsForm` share. */\n stagedForm: {\n /** Default Save button text. */\n save: string;\n /** Default Discard button text. */\n discard: string;\n /** The note under a staged image; `kind` says which image, `saveLabel` is the Save button's text. */\n imageNote: (kind: \"avatar\" | \"logo\", saveLabel: string, removed: boolean) => string;\n };\n /** `ProfileForm`. */\n profileForm: {\n /** Callout shown after a successful save. */\n saved: string;\n /** Title of the error callout when saving fails. */\n failedTitle: string;\n /** Fallback error text when saving rejects without a message. */\n failedMessage: string;\n /** Label of the avatar field. */\n avatar: string;\n /** Label of the name field. */\n name: string;\n /** Label of the username field. */\n username: string;\n /** Label of the email field. */\n email: string;\n };\n /** `TeamSettingsForm`. */\n teamSettingsForm: {\n /** Callout shown after a successful save. */\n saved: string;\n /** Title of the error callout when saving fails. */\n failedTitle: string;\n /** Fallback error text when saving rejects without a message. */\n failedMessage: string;\n /** Title of the callout shown to a viewer who cannot edit. */\n readOnlyTitle: string;\n /** Body of the callout shown to a viewer who cannot edit. */\n readOnlyBody: string;\n /** Label of the logo field. */\n logo: string;\n /** Label of the team name field. */\n teamName: string;\n };\n /** `ProfilePage`. */\n profilePage: {\n /** The page heading. */\n title: string;\n /** Heading of the roles and permissions section. */\n rolesHeading: string;\n /** Notice while impersonating; `viewing` and `actual` are the two role names, each wrapped by `emphasis` (the caller's emphasis markup). */\n viewingAs: (viewing: string, actual: string, emphasis: Emphasis) => ReactNode;\n /** Sentence naming the person's role, wrapped by `emphasis`; `team` is the current team's name when there is one. */\n holdsRole: (role: string, team: string | undefined, emphasis: Emphasis) => ReactNode;\n /** Shown when the role grants no permissions. */\n noPermissions: string;\n /** Shown when no role is assigned for the team. */\n noRole: string;\n /** Label of the read-only identity's name field. */\n name: string;\n /** Label of the read-only identity's email field. */\n email: string;\n };\n /** `ChangePasswordForm`. */\n changePasswordForm: {\n /** Title of the error callout when the change fails. */\n failedTitle: string;\n /** Fallback error text when the change rejects without a message. */\n failedMessage: string;\n /** Label of the current password field. */\n current: string;\n /** Label of the new password field. */\n next: string;\n /** Label of the confirm new password field. */\n confirmPassword: string;\n /** Error under the confirm field when it differs from the new password. */\n mismatch: string;\n /** Default submit button text. */\n submit: string;\n /** Set-password mode (no current password yet): title of the error callout when it fails. */\n setFailedTitle: string;\n /** Set-password mode: fallback error text when it rejects without a message. */\n setFailedMessage: string;\n /** Set-password mode: default submit button text. */\n setSubmit: string;\n };\n /** `DangerZone`. */\n dangerZone: {\n /** Default heading of the section. */\n title: string;\n };\n /** `SessionsList`. */\n sessionsList: {\n /** Column header: the session. */\n columnSession: string;\n /** Column header: the browser the session was made in (DX-5247). */\n columnBrowser: string;\n /** Badge on a row made in the browser this screen is running in (DX-5247). */\n thisBrowser: string;\n /** Accessible name of the button that copies a browser id; receives the shown id (DX-5247). */\n copyBrowserId: (shownId: string) => string;\n /** Column header: when the session was last used. */\n columnLastUsed: string;\n /** Column header: when the session was created. */\n columnCreated: string;\n /** Column header: when the session expires. */\n columnExpires: string;\n /** Badge beside the session this screen is running in. */\n current: string;\n /** Cell text for a session with no expiry. */\n never: string;\n /** Replaces the revoke control on the current session. */\n thisSession: string;\n /** Accessible name of the revoke button. */\n revoke: (name: string) => string;\n /** Tooltip on the revoke button while a revoke runs. */\n revoking: string;\n /** Title of the revoke confirmation. */\n revokeTitle: (name: string) => string;\n /** Description of the revoke confirmation. */\n revokeDescription: string;\n /** Confirm button of the revoke confirmation. */\n revokeConfirm: string;\n /** Title of the empty state. */\n emptyTitle: string;\n };\n /** `TeamSwitcher`. */\n teamSwitcher: {\n /** Accessible name of the team shown when there is nothing to switch to. */\n currentTeam: string;\n /** Accessible name of the trigger that opens the team list. */\n switchFrom: (currentTeamName: string) => string;\n /** Heading of the team list. */\n switchTeam: string;\n };\n /** `AccountMenu`. */\n accountMenu: {\n /** Accessible name of the avatar button that opens the menu. */\n triggerLabel: (userName: string) => string;\n /** Menu item that opens the profile. */\n profile: string;\n /** Menu item that opens roles and permissions. */\n roles: string;\n /** Heading of the access section. */\n yourAccess: string;\n /** Sentence naming the person's role; `emphasis` wraps the role's name in the caller's emphasis markup. */\n hasRole: (role: string, emphasis: Emphasis) => ReactNode;\n /** Shown when no role is assigned for the team. */\n noRole: string;\n /** Heading of the team list. */\n switchTeam: string;\n /** Menu item that signs out. */\n signOut: string;\n };\n /** `RolePermissionMatrix`. */\n rolePermissionMatrix: {\n /** Screen-reader caption of the matrix. */\n caption: string;\n /** Header of the permission column. */\n permission: string;\n /** Section heading for permissions that carry no category, when others do. */\n otherCategory: string;\n /** Accessible name of the lock icon on a role column that cannot be edited. */\n locked: (roleLabel: string) => string;\n /** The sentence a screen reader gets for a cell, saying whether the role holds the permission. */\n cell: (roleLabel: string, permissionLabel: string, granted: boolean) => string;\n };\n /** `ToggleMatrix` (DX-4963), the grid `RolePermissionMatrix` is built on. */\n toggleMatrix: {\n /** The sentence a screen reader gets for a cell when the consumer gives none, saying whether the column has the row switched on. */\n cell: (columnLabel: string, rowLabel: string, on: boolean) => string;\n /** The muted badge in a cell that cannot be switched; the reason is printed under it. */\n unavailable: string;\n /** Accessible name of the checkbox in a column header that sets every switch in the column. */\n setColumn: (columnLabel: string) => string;\n /** Heading for rows with no group, when other rows have one. */\n otherGroup: string;\n /** Accessible name of the spinner in a cell that is being saved. */\n busy: string;\n };\n /** `RolesPermissionsPage`. */\n rolesPermissionsPage: {\n /** The page heading. */\n title: string;\n /** Line under the heading when roles can be edited. */\n subtitleEditable: string;\n /** Line under the heading when roles are read-only. */\n subtitleReadOnly: string;\n /** The button that opens the new role dialog. */\n newRole: string;\n /** Heading of the list of manageable roles. */\n manageRoles: string;\n /** Tooltip on a row's buttons while that role is busy. */\n working: string;\n /** Accessible name of the reset-to-defaults button. */\n reset: (roleLabel: string) => string;\n /** Accessible name of the edit button. */\n edit: (roleLabel: string) => string;\n /** Accessible name of the delete button. */\n delete: (roleLabel: string) => string;\n /** Title of the delete confirmation. */\n deleteTitle: (roleLabel: string) => string;\n /** Description of the delete confirmation. */\n deleteDescription: string;\n /** Confirm button of the delete confirmation. */\n deleteConfirm: string;\n };\n /** `RoleEditorDialog`. */\n roleEditorDialog: {\n /** Title when creating a role. */\n createTitle: string;\n /** Title when editing a role. */\n editTitle: string;\n /** Description when creating a role. */\n createDescription: string;\n /** Description when editing a role. */\n editDescription: string;\n /** The cancel button. */\n cancel: string;\n /** The submit button when creating. */\n create: string;\n /** The submit button when editing. */\n save: string;\n /** Label of the role label field. */\n label: string;\n /** Placeholder of the role label field. */\n labelPlaceholder: string;\n /** Label of the description field. */\n description: string;\n /** Help text under the description field. */\n descriptionHint: string;\n /** Label of the clone-from select. */\n cloneLabel: string;\n /** Description of the clone-from select. */\n cloneDescription: string;\n /** The clone-from option that clones nothing. */\n cloneNone: string;\n };\n}\n\nexport const rbacStrings: RbacStrings = {\n approval: {\n state: { pending: \"Pending\", approved: \"Approved\", denied: \"Denied\", expired: \"Expired\", claimed: \"Claimed\" },\n terminalTitle: { approved: \"Approved\", claimed: \"Already claimed\", denied: \"Denied\", expired: \"This request expired\" },\n confirmCodeTitle: \"Confirm code\",\n confirmCodeCompare: \"Check that this matches the code shown where the request was made.\",\n confirmCodeLabel: \"Confirm code\",\n confirmCodeEntryHint: \"Type the code shown where this request was made. Approve opens once it matches.\",\n confirmCodeMismatch: \"That code does not match this request.\",\n failedMessage: { approve: \"Couldn't approve the request. Try again.\", deny: \"Couldn't deny the request. Try again.\" },\n failedTitle: { approve: \"Couldn't approve the request\", deny: \"Couldn't deny the request\" },\n deny: \"Deny\",\n approve: \"Approve\",\n expiredNothingGranted: \"Nothing was granted, so there is nothing for you to approve or deny.\",\n requested: \"Requested\",\n expires: \"Expires\",\n approveOnlyTitle: \"Approve only if you started this\",\n },\n accessRequest: {\n title: \"Access request\",\n kindSession: \"Agent session\",\n kindWorker: \"Worker\",\n kindMachine: \"Machine\",\n machineGrantTitle: \"Read access to cards, and permission to record test runs\",\n machineGrant: \"This request cannot be given any other permission, so there is no role to choose.\",\n fixedRoleTitle: \"Role requested\",\n approveBodyFixedRole: (typedCode) =>\n `Approving lets this session act as you with the role it requested, for as long as it keeps being used. ${\n typedCode ? \"If you did not ask for this, deny it.\" : \"If the code does not match, or you did not ask for this, deny it.\"\n }`,\n fixedRoleHint: \"The request names this role. Approve it as it is, or deny the request. It cannot be changed here.\",\n kind: \"Kind\",\n worker: \"Worker\",\n session: \"Session\",\n repository: \"Repository\",\n machine: \"Machine\",\n address: \"Address\",\n clientVersion: \"Client version\",\n approved: (role) => `The requester is picking up its key${role ? ` with the ${role} role` : \"\"}. You can close this page.`,\n claimed: (role) =>\n `The requester has its key${role ? ` with the ${role} role` : \"\"}. If that was not you, revoke the key from your API keys.`,\n denied: \"The requester was refused and holds no key. It has to ask again to get access.\",\n expiredFallback: \"Nothing was granted. Ask the requester to start a new request.\",\n approveBody: (kind, typedCode) => {\n const lead = {\n session: \"Approving lets this session act as you with the role you pick, for as long as it keeps being used.\",\n worker: \"Approving lets this worker act as you with the role you pick, for as long as it keeps being used.\",\n // DX-5809: danxbot issues a machine key that lapses after 7 days without use; this copy states that lifetime.\n machine: \"Approving lets this machine read your cards. Its key stays valid while the machine keeps using it and lapses after 7 days unused.\",\n }[kind];\n const deny = typedCode ? \"If you did not ask for this, deny it.\" : \"If the code does not match, or you did not ask for this, deny it.\";\n return `${lead} ${deny}`;\n },\n noRoleTitle: \"No role available\",\n noRoleBody: \"Every role holds a permission you don't have, so you can't approve this request. You can still deny it.\",\n roleHint: (roleLabel, isDefault) =>\n `The key can do what this role can, never more than you can. ${\n isDefault ? `${roleLabel}, the default, is chosen for you.` : `The narrowest allowed role, ${roleLabel}, is chosen for you.`\n }`,\n revoked: \"Revoked\",\n revokedBody: (when, by) => `The key was revoked ${when}${by ? ` by ${by}` : \"\"}. The requester can no longer act with it and has to ask again.`,\n revokeKey: \"Revoke key\",\n revokeTitle: \"Revoke this key?\",\n revokeBody: \"The requester stops acting as you the moment the key is revoked, and has to ask for access again. This cannot be undone.\",\n revokeCancel: \"Cancel\",\n revokeFailedTitle: \"Couldn't revoke the key\",\n revokeFailedMessage: \"Couldn't revoke the key. Try again.\",\n },\n permissionRequest: {\n title: \"Permission request\",\n notHeld: \"You do not hold this permission\",\n key: \"Key\",\n reasonGiven: \"Reason given\",\n approvedWithList: \"The agent's key now also holds these permissions, on top of its role. It picks them up on its next call.\",\n approvedNoList: \"The agent picks up the permissions you approved on its next call. You can close this page.\",\n claimedWithList: \"The agent's key holds these permissions now. If that was not you, remove them from the key in your agent sessions.\",\n claimedNoList: \"The agent has the permissions you approved. If that was not you, remove them from the key in your agent sessions.\",\n denied: \"The agent was refused these permissions and its key is unchanged. It has to ask again to get them.\",\n expiredFallback: \"Nothing was granted. Ask the agent to start a new request.\",\n approveBody:\n \"Approving adds the permissions you leave checked to this key, on top of its role, for as long as the key lives. If the code does not match, or you did not ask for this, deny it.\",\n emptyTitle: \"Nothing you can grant\",\n emptyDescription: \"You do not hold any of the requested permissions, so you can't approve this request. You can still deny it.\",\n otherCategory: \"Other\",\n legend: \"Permissions requested\",\n legendDescription: \"Uncheck any you do not want to grant. Approving grants only the checked ones.\",\n },\n roleKeyPicker: {\n label: \"Role\",\n description: \"The key can do what this role can, never more than you can.\",\n unavailable: (permissionLabels) => `Holds permissions you don't have: ${permissionLabels.join(\", \")}.`,\n },\n apiKeysPanel: {\n title: \"API keys\",\n createKey: \"Create key\",\n emptyTitle: \"No API keys yet\",\n emptyDescription: \"Create one to let a script or an agent act as you, with the access of the role you pick.\",\n dialogTitle: \"Create API key\",\n dialogDescription: \"You'll only see the full key once, immediately after creating it — store it somewhere safe.\",\n cancel: \"Cancel\",\n create: \"Create\",\n failedTitle: \"Couldn't create the key\",\n failedMessage: \"Couldn't create the key. Try again.\",\n nameLabel: \"Name\",\n nameDescription: \"What this key is for — e.g. \\\"CI deploy script\\\".\",\n namePlaceholder: \"e.g. CI deploy script\",\n expiresLabel: \"Expires in (days)\",\n expiresDescription: \"Leave blank for a key that never expires.\",\n expiresPlaceholder: \"Never\",\n revealedTitle: \"API key created\",\n revealedDescription: \"Copy this now — you won't be able to see it again.\",\n done: \"Done\",\n revealedLabel: \"Your new key\",\n copyKey: \"Copy key\",\n },\n apiKeysTable: {\n columnKey: \"Key\",\n columnStartedBy: \"Started by\",\n columnRole: \"Role\",\n columnLastUsed: \"Last used\",\n columnExpires: \"Expires\",\n never: \"Never\",\n created: (age) => `Created ${age}`,\n roleOf: (keyName) => `Role of ${keyName}`,\n roleNotAssignable: \"This role is not one you can assign here.\",\n revoke: (keyName) => `Revoke ${keyName}`,\n revoking: \"Revoking…\",\n revokeTitle: (keyName) => `Revoke \"${keyName}\"?`,\n revokeDescription: \"Anything using this key will immediately lose access. This cannot be undone.\",\n revokeConfirm: \"Revoke key\",\n grantsOf: (keyName) => `Permissions added to ${keyName}`,\n removeGrant: (permissionLabel, keyName) => `Remove ${permissionLabel} from ${keyName}`,\n updating: \"Updating…\",\n removeGrantTitle: (permissionLabel) => `Remove ${permissionLabel} from this key?`,\n removeGrantDescription: \"The agent loses it on its next call; the key and its role are unchanged.\",\n removeGrantConfirm: \"Remove permission\",\n granted: (age, reason) => (reason ? `Granted ${age}: ${reason}` : `Granted ${age}`),\n },\n agentKeysList: {\n emptyTitle: \"No agent sessions\",\n emptyDescription: \"Claude Code sessions, workers and dispatches that act as you appear here once you approve their access.\",\n },\n devTools: {\n trigger: \"Dev tools\",\n triggerLabel: \"Developer tools\",\n viewAs: \"View as\",\n viewAsLabel: \"View the app as a role\",\n actualRole: \"Your actual role\",\n unknownRole: \"an unknown role\",\n viewingAs: (role, emphasis) => createElement(Fragment, null, \"Viewing as \", emphasis(role), \". Screens and permissions reflect that role, not your own.\"),\n resetToActual: \"Reset to actual\",\n dataSource: \"Data source\",\n dataSources: { simulated: \"Simulated\", live: \"Live\" },\n liveNotConfigured:\n \"No live backend is configured in this demo — stores keep answering with simulated data. A consuming app wires its own fetcher per store to make this real.\",\n networkSpeed: \"Network speed\",\n networkSpeeds: { instant: \"Instant\", fast: \"Fast\", typical: \"Typical\", flaky: \"Flaky\" },\n regenerate: \"Regenerate demo data\",\n regenerateTitle: \"Regenerate demo data?\",\n regenerateDescription:\n \"Every user, team, role and permission reverts to its seed. The use-case ledger is untouched — this never erases product history.\",\n regenerateConfirm: \"Regenerate\",\n openLedger: \"Open Use Case Ledger\",\n },\n invitationsList: {\n columnInvitee: \"Invitee\",\n columnRole: \"Role\",\n columnStatus: \"Status\",\n columnSent: \"Sent\",\n invitedBy: (name) => `Invited by ${name}`,\n status: { pending: \"Pending\", accepted: \"Accepted\", revoked: \"Revoked\", expired: \"Expired\" },\n complaint: \"Complaint\",\n bounced: \"Bounced\",\n deliveryFailed: \"Delivery failed\",\n working: \"Working…\",\n copyLink: (email) => `Copy invite link for ${email}`,\n resend: (email) => `Resend invitation to ${email}`,\n revoke: (email) => `Revoke invitation to ${email}`,\n revokeTitle: (email) => `Revoke invitation to ${email}?`,\n revokeDescription: \"They will no longer be able to accept this invitation.\",\n revokeConfirm: \"Revoke invitation\",\n emptyTitle: \"No invitations yet\",\n emptyDescription: \"Invitations you send will show up here.\",\n },\n inviteMembersDialog: {\n title: \"Invite members\",\n description: \"Each address gets its own invitation email with the role you pick below.\",\n cancel: \"Cancel\",\n send: (count) => plural(count, { zero: \"Send invitation\", one: \"Send invitation\", other: \"Send invitations\" }),\n emailsLabel: \"Email addresses\",\n emailsDescription: \"Press Enter or comma after each one.\",\n emailPlaceholder: \"name@example.com\",\n removeEmail: (email) => `Remove ${email}`,\n invalidEmail: (typed) => `\"${typed}\" doesn't look like an email address`,\n roleLabel: \"Role\",\n },\n membersPanel: {\n columnMember: \"Member\",\n columnRole: \"Role\",\n columnJoined: \"Joined\",\n roleFor: (name) => `Role for ${name}`,\n removing: \"Removing…\",\n remove: (name) => `Remove ${name}`,\n removeTitle: (name) => `Remove ${name}?`,\n removeDescription: (name) =>\n `${name} will lose access to this team immediately, and every one of their active sessions and API tokens will be revoked.`,\n removeConfirm: \"Remove member\",\n emptyTitle: \"No members yet\",\n emptyDescription: \"Invite someone to get this team started.\",\n },\n stagedForm: {\n save: \"Save changes\",\n discard: \"Discard changes\",\n imageNote: (kind, saveLabel, removed) =>\n removed ? `Not saved yet — click ${saveLabel} to remove the ${kind}.` : `Not saved yet — click ${saveLabel} to keep this ${kind}.`,\n },\n profileForm: {\n saved: \"Profile saved.\",\n failedTitle: \"Couldn't save your profile\",\n failedMessage: \"Couldn't save your profile. Try again.\",\n avatar: \"Avatar\",\n name: \"Name\",\n username: \"Username\",\n email: \"Email\",\n },\n teamSettingsForm: {\n saved: \"Team settings saved.\",\n failedTitle: \"Couldn't save the team\",\n failedMessage: \"Couldn't save the team. Try again.\",\n readOnlyTitle: \"Read-only\",\n readOnlyBody: \"You don't have permission to change team settings.\",\n logo: \"Logo\",\n teamName: \"Team name\",\n },\n profilePage: {\n title: \"Profile\",\n rolesHeading: \"Your roles & permissions\",\n viewingAs: (viewing, actual, emphasis) =>\n createElement(\n Fragment,\n null,\n \"You are currently viewing as \",\n emphasis(viewing),\n \". What is listed below is that role's access, not your normal \",\n emphasis(actual),\n \" access.\",\n ),\n holdsRole: (role, team, emphasis) => createElement(Fragment, null, \"You hold the \", emphasis(role), team === undefined ? \" role.\" : ` role on ${team}.`),\n noPermissions: \"This role does not grant any permissions.\",\n noRole: \"No role is assigned for this team.\",\n name: \"Name\",\n email: \"Email\",\n },\n changePasswordForm: {\n failedTitle: \"Couldn't change your password\",\n failedMessage: \"Could not change your password. Try again.\",\n current: \"Current password\",\n next: \"New password\",\n confirmPassword: \"Confirm new password\",\n mismatch: \"Doesn't match the new password above.\",\n submit: \"Change password\",\n setFailedTitle: \"Couldn't set your password\",\n setFailedMessage: \"Could not set your password. Try again.\",\n setSubmit: \"Set password\",\n },\n dangerZone: {\n title: \"Danger zone\",\n },\n sessionsList: {\n columnSession: \"Session\",\n columnBrowser: \"Browser\",\n thisBrowser: \"This browser\",\n copyBrowserId: (shownId) => `Copy browser id ${shownId}`,\n columnLastUsed: \"Last used\",\n columnCreated: \"Created\",\n columnExpires: \"Expires\",\n current: \"Current\",\n never: \"Never\",\n thisSession: \"This session\",\n revoke: (name) => `Revoke ${name}`,\n revoking: \"Revoking…\",\n revokeTitle: (name) => `Revoke \"${name}\"?`,\n revokeDescription: \"That device will be signed out immediately and will need to sign in again.\",\n revokeConfirm: \"Revoke session\",\n emptyTitle: \"No active sessions\",\n },\n teamSwitcher: {\n currentTeam: \"Current team\",\n switchFrom: (currentTeamName) => `Switch team, currently ${currentTeamName}`,\n switchTeam: \"Switch team\",\n },\n accountMenu: {\n triggerLabel: (userName) => `Account menu for ${userName}`,\n profile: \"Profile\",\n roles: \"Roles & Permissions\",\n yourAccess: \"Your access\",\n hasRole: (role, emphasis) => createElement(Fragment, null, \"You have the \", emphasis(role), \" role.\"),\n noRole: \"No role is assigned for this team.\",\n switchTeam: \"Switch team\",\n signOut: \"Sign out\",\n },\n rolePermissionMatrix: {\n caption: \"Which permissions each role has\",\n permission: \"Permission\",\n otherCategory: \"Other\",\n locked: (roleLabel) => `${roleLabel} is locked and can't be edited`,\n cell: (roleLabel, permissionLabel, granted) => `${roleLabel} ${granted ? \"includes\" : \"does not include\"} ${permissionLabel}`,\n },\n toggleMatrix: {\n cell: (columnLabel, rowLabel, on) => `${columnLabel}: ${rowLabel} is ${on ? \"on\" : \"off\"}`,\n unavailable: \"Not available\",\n setColumn: (columnLabel) => `Set every switch in ${columnLabel}`,\n otherGroup: \"Other\",\n busy: \"Saving\",\n },\n rolesPermissionsPage: {\n title: \"Roles & Permissions\",\n subtitleEditable: \"What each role can do. Toggle a permission directly in the matrix, or manage roles below.\",\n subtitleReadOnly: \"What each role can do. Contact an administrator to change a role's access.\",\n newRole: \"New role\",\n manageRoles: \"Manage roles\",\n working: \"Working…\",\n reset: (roleLabel) => `Reset ${roleLabel} to its seeded defaults`,\n edit: (roleLabel) => `Edit ${roleLabel}`,\n delete: (roleLabel) => `Delete ${roleLabel}`,\n deleteTitle: (roleLabel) => `Delete ${roleLabel}?`,\n deleteDescription: \"Anyone still holding this role must be moved to a different one first.\",\n deleteConfirm: \"Delete role\",\n },\n roleEditorDialog: {\n createTitle: \"New role\",\n editTitle: \"Edit role\",\n createDescription: \"A custom role starts with no permissions granted — set them afterward in the matrix, or clone an existing role's set below.\",\n editDescription: \"Renaming a role doesn't change who has it or what it grants. Edit permissions in the matrix.\",\n cancel: \"Cancel\",\n create: \"Create role\",\n save: \"Save\",\n label: \"Label\",\n labelPlaceholder: \"e.g. QA Reviewer\",\n description: \"Description\",\n descriptionHint: \"Shown to whoever picks this role — what it's for.\",\n cloneLabel: \"Clone permissions from\",\n cloneDescription: \"Optional — starts the new role's permission set as a copy of another role's. You can still change it afterward.\",\n cloneNone: \"None — start with no permissions\",\n },\n};\n\n"],"names":["rbacStrings","typedCode","role","kind","roleLabel","isDefault","when","by","permissionLabels","age","keyName","permissionLabel","reason","emphasis","createElement","Fragment","name","email","count","plural","typed","saveLabel","removed","viewing","actual","team","shownId","currentTeamName","userName","granted","columnLabel","rowLabel","on"],"mappings":";;AAwmBO,MAAMA,IAA2B;AAAA,EACtC,UAAU;AAAA,IACR,OAAO,EAAE,SAAS,WAAW,UAAU,YAAY,QAAQ,UAAU,SAAS,WAAW,SAAS,UAAA;AAAA,IAClG,eAAe,EAAE,UAAU,YAAY,SAAS,mBAAmB,QAAQ,UAAU,SAAS,uBAAA;AAAA,IAC9F,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,eAAe,EAAE,SAAS,4CAA4C,MAAM,wCAAA;AAAA,IAC5E,aAAa,EAAE,SAAS,gCAAgC,MAAM,4BAAA;AAAA,IAC9D,MAAM;AAAA,IACN,SAAS;AAAA,IACT,uBAAuB;AAAA,IACvB,WAAW;AAAA,IACX,SAAS;AAAA,IACT,kBAAkB;AAAA,EAAA;AAAA,EAEpB,eAAe;AAAA,IACb,OAAO;AAAA,IACP,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,sBAAsB,CAACC,MACrB,0GACEA,IAAY,0CAA0C,mEACxD;AAAA,IACF,eAAe;AAAA,IACf,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAU,CAACC,MAAS,sCAAsCA,IAAO,aAAaA,CAAI,UAAU,EAAE;AAAA,IAC9F,SAAS,CAACA,MACR,4BAA4BA,IAAO,aAAaA,CAAI,UAAU,EAAE;AAAA,IAClE,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,aAAa,CAACC,GAAMF,MAQX,GAPM;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA;AAAA,MAER,SAAS;AAAA,IAAA,EACTE,CAAI,CAEQ,IADDF,IAAY,0CAA0C,mEAC7C;AAAA,IAExB,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,UAAU,CAACG,GAAWC,MACpB,+DACEA,IAAY,GAAGD,CAAS,sCAAsC,+BAA+BA,CAAS,sBACxG;AAAA,IACF,SAAS;AAAA,IACT,aAAa,CAACE,GAAMC,MAAO,uBAAuBD,CAAI,GAAGC,IAAK,OAAOA,CAAE,KAAK,EAAE;AAAA,IAC9E,WAAW;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,qBAAqB;AAAA,EAAA;AAAA,EAEvB,mBAAmB;AAAA,IACjB,OAAO;AAAA,IACP,SAAS;AAAA,IACT,KAAK;AAAA,IACL,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,aACE;AAAA,IACF,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,mBAAmB;AAAA,EAAA;AAAA,EAErB,eAAe;AAAA,IACb,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa,CAACC,MAAqB,qCAAqCA,EAAiB,KAAK,IAAI,CAAC;AAAA,EAAA;AAAA,EAErG,cAAc;AAAA,IACZ,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf,qBAAqB;AAAA,IACrB,MAAM;AAAA,IACN,eAAe;AAAA,IACf,SAAS;AAAA,EAAA;AAAA,EAEX,cAAc;AAAA,IACZ,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,OAAO;AAAA,IACP,SAAS,CAACC,MAAQ,WAAWA,CAAG;AAAA,IAChC,QAAQ,CAACC,MAAY,WAAWA,CAAO;AAAA,IACvC,mBAAmB;AAAA,IACnB,QAAQ,CAACA,MAAY,UAAUA,CAAO;AAAA,IACtC,UAAU;AAAA,IACV,aAAa,CAACA,MAAY,WAAWA,CAAO;AAAA,IAC5C,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,UAAU,CAACA,MAAY,wBAAwBA,CAAO;AAAA,IACtD,aAAa,CAACC,GAAiBD,MAAY,UAAUC,CAAe,SAASD,CAAO;AAAA,IACpF,UAAU;AAAA,IACV,kBAAkB,CAACC,MAAoB,UAAUA,CAAe;AAAA,IAChE,wBAAwB;AAAA,IACxB,oBAAoB;AAAA,IACpB,SAAS,CAACF,GAAKG,MAAYA,IAAS,WAAWH,CAAG,KAAKG,CAAM,KAAK,WAAWH,CAAG;AAAA,EAAA;AAAA,EAElF,eAAe;AAAA,IACb,YAAY;AAAA,IACZ,kBAAkB;AAAA,EAAA;AAAA,EAEpB,UAAU;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,WAAW,CAACP,GAAMW,MAAaC,EAAcC,GAAU,MAAM,eAAeF,EAASX,CAAI,GAAG,4DAA4D;AAAA,IACxJ,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,aAAa,EAAE,WAAW,aAAa,MAAM,OAAA;AAAA,IAC7C,mBACE;AAAA,IACF,cAAc;AAAA,IACd,eAAe,EAAE,SAAS,WAAW,MAAM,QAAQ,SAAS,WAAW,OAAO,QAAA;AAAA,IAC9E,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,uBACE;AAAA,IACF,mBAAmB;AAAA,IACnB,YAAY;AAAA,EAAA;AAAA,EAEd,iBAAiB;AAAA,IACf,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,WAAW,CAACc,MAAS,cAAcA,CAAI;AAAA,IACvC,QAAQ,EAAE,SAAS,WAAW,UAAU,YAAY,SAAS,WAAW,SAAS,UAAA;AAAA,IACjF,WAAW;AAAA,IACX,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,UAAU,CAACC,MAAU,wBAAwBA,CAAK;AAAA,IAClD,QAAQ,CAACA,MAAU,wBAAwBA,CAAK;AAAA,IAChD,QAAQ,CAACA,MAAU,wBAAwBA,CAAK;AAAA,IAChD,aAAa,CAACA,MAAU,wBAAwBA,CAAK;AAAA,IACrD,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,kBAAkB;AAAA,EAAA;AAAA,EAEpB,qBAAqB;AAAA,IACnB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,MAAM,CAACC,MAAUC,EAAOD,GAAO,EAAE,MAAM,mBAAmB,KAAK,mBAAmB,OAAO,mBAAA,CAAoB;AAAA,IAC7G,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa,CAACD,MAAU,UAAUA,CAAK;AAAA,IACvC,cAAc,CAACG,MAAU,IAAIA,CAAK;AAAA,IAClC,WAAW;AAAA,EAAA;AAAA,EAEb,cAAc;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,SAAS,CAACJ,MAAS,YAAYA,CAAI;AAAA,IACnC,UAAU;AAAA,IACV,QAAQ,CAACA,MAAS,UAAUA,CAAI;AAAA,IAChC,aAAa,CAACA,MAAS,UAAUA,CAAI;AAAA,IACrC,mBAAmB,CAACA,MAClB,GAAGA,CAAI;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,kBAAkB;AAAA,EAAA;AAAA,EAEpB,YAAY;AAAA,IACV,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW,CAACb,GAAMkB,GAAWC,MAC3BA,IAAU,yBAAyBD,CAAS,kBAAkBlB,CAAI,MAAM,yBAAyBkB,CAAS,iBAAiBlB,CAAI;AAAA,EAAA;AAAA,EAEnI,aAAa;AAAA,IACX,OAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO;AAAA,EAAA;AAAA,EAET,kBAAkB;AAAA,IAChB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAe;AAAA,IACf,eAAe;AAAA,IACf,cAAc;AAAA,IACd,MAAM;AAAA,IACN,UAAU;AAAA,EAAA;AAAA,EAEZ,aAAa;AAAA,IACX,OAAO;AAAA,IACP,cAAc;AAAA,IACd,WAAW,CAACoB,GAASC,GAAQX,MAC3BC;AAAA,MACEC;AAAA,MACA;AAAA,MACA;AAAA,MACAF,EAASU,CAAO;AAAA,MAChB;AAAA,MACAV,EAASW,CAAM;AAAA,MACf;AAAA,IAAA;AAAA,IAEJ,WAAW,CAACtB,GAAMuB,GAAMZ,MAAaC,EAAcC,GAAU,MAAM,iBAAiBF,EAASX,CAAI,GAAGuB,MAAS,SAAY,WAAW,YAAYA,CAAI,GAAG;AAAA,IACvJ,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;AAAA,EAET,oBAAoB;AAAA,IAClB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS;AAAA,IACT,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,WAAW;AAAA,EAAA;AAAA,EAEb,YAAY;AAAA,IACV,OAAO;AAAA,EAAA;AAAA,EAET,cAAc;AAAA,IACZ,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,eAAe,CAACC,MAAY,mBAAmBA,CAAO;AAAA,IACtD,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ,CAACV,MAAS,UAAUA,CAAI;AAAA,IAChC,UAAU;AAAA,IACV,aAAa,CAACA,MAAS,WAAWA,CAAI;AAAA,IACtC,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,YAAY;AAAA,EAAA;AAAA,EAEd,cAAc;AAAA,IACZ,aAAa;AAAA,IACb,YAAY,CAACW,MAAoB,0BAA0BA,CAAe;AAAA,IAC1E,YAAY;AAAA,EAAA;AAAA,EAEd,aAAa;AAAA,IACX,cAAc,CAACC,MAAa,oBAAoBA,CAAQ;AAAA,IACxD,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,SAAS,CAAC1B,GAAMW,MAAaC,EAAcC,GAAU,MAAM,iBAAiBF,EAASX,CAAI,GAAG,QAAQ;AAAA,IACpG,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAS;AAAA,EAAA;AAAA,EAEX,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,QAAQ,CAACE,MAAc,GAAGA,CAAS;AAAA,IACnC,MAAM,CAACA,GAAWO,GAAiBkB,MAAY,GAAGzB,CAAS,IAAIyB,IAAU,aAAa,kBAAkB,IAAIlB,CAAe;AAAA,EAAA;AAAA,EAE7H,cAAc;AAAA,IACZ,MAAM,CAACmB,GAAaC,GAAUC,MAAO,GAAGF,CAAW,KAAKC,CAAQ,OAAOC,IAAK,OAAO,KAAK;AAAA,IACxF,aAAa;AAAA,IACb,WAAW,CAACF,MAAgB,uBAAuBA,CAAW;AAAA,IAC9D,YAAY;AAAA,IACZ,MAAM;AAAA,EAAA;AAAA,EAER,sBAAsB;AAAA,IACpB,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO,CAAC1B,MAAc,SAASA,CAAS;AAAA,IACxC,MAAM,CAACA,MAAc,QAAQA,CAAS;AAAA,IACtC,QAAQ,CAACA,MAAc,UAAUA,CAAS;AAAA,IAC1C,aAAa,CAACA,MAAc,UAAUA,CAAS;AAAA,IAC/C,mBAAmB;AAAA,IACnB,eAAe;AAAA,EAAA;AAAA,EAEjB,kBAAkB;AAAA,IAChB,aAAa;AAAA,IACb,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,WAAW;AAAA,EAAA;AAEf;"}
|
|
@@ -88,5 +88,22 @@ export interface MachineAccessRequestPanelProps extends AccessRequestPanelCommon
|
|
|
88
88
|
defaultRoleId?: string;
|
|
89
89
|
onApprove: () => Promise<void>;
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
/**
|
|
92
|
+
* DXUI-102: a session request that itself names the role it wants. The approver grants that role or denies the request,
|
|
93
|
+
* so there is no picker: the role is shown read-only with what it grants, and the role props are never read.
|
|
94
|
+
*/
|
|
95
|
+
export interface FixedRoleSessionAccessRequestPanelProps extends AccessRequestPanelCommonProps {
|
|
96
|
+
request: AccessRequest & {
|
|
97
|
+
kind: "session";
|
|
98
|
+
};
|
|
99
|
+
/** The role the request names. */
|
|
100
|
+
fixedRole: Role;
|
|
101
|
+
/** The permission catalog, used to name what `fixedRole` grants. */
|
|
102
|
+
permissions: Permission[];
|
|
103
|
+
roles?: Role[];
|
|
104
|
+
ownPermissionKeys?: string[];
|
|
105
|
+
defaultRoleId?: string;
|
|
106
|
+
onApprove: () => Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
export type AccessRequestPanelProps = RoleAccessRequestPanelProps | MachineAccessRequestPanelProps | FixedRoleSessionAccessRequestPanelProps;
|
|
92
109
|
export declare function AccessRequestPanel(props: AccessRequestPanelProps): import("react").JSX.Element;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -187,7 +187,7 @@ export { cellLabel, eventLabel, formatDateRange, longDate, monthTitle, timeOfDay
|
|
|
187
187
|
export { initialFocusDay, isInMonth, nextDayForKey, useGridNavigation, type GridNavigation, type GridNavigationOptions, } from "./components/calendar/use-grid-navigation";
|
|
188
188
|
export { AmbiguousTimeError, addDays, addDuration, addMonths, atMidnight, atTime, comparePlainDate, dayFraction, dayLengthMs, dayOfWeek, daysBetween, daysInMonth, endOfMonth, hoursInDay, instantAtFraction, instantToPlainDate, instantToPlainDateTime, isSameDate, isoDateString, isoDateTimeString, monthGridDays, nextDay, offsetAt, parsePlainDate, plainDateTimeToInstant, relativeAge, startOfDay, startOfMonth, startOfWeek, weekDays, type CalendarDuration, type Disambiguation, type Instant, type PlainDate, type PlainDateTime, type TimeZone, } from "./lib/time";
|
|
189
189
|
export { allDayBandSegment, dayKey, daySlots, isAllDay, packBand, packLanes, snapFractionToInstant, timeSegments, timedBandSegment, type AllDayEvent, type BandInput, type BandOptions, type BandPlacement, type BandResult, type BandSegment, type CalendarEvent, type CalendarEventId, type CalendarView, type DaySlot, type DragKind, type EventDraft, type EventPalette, type LaneInput, type LaneOptions, type LanePlacement, type PaletteEntry, type PaletteKey, type TimeSegment, type TimedEvent, type VisibleRange, } from "./lib/calendar";
|
|
190
|
-
export { RBACProvider, useRBAC, Can, useHasPermission, AccountMenu, AccountMenuSection, TeamSwitcher, DevToolsPopover, DevToolsPanel, DEV_TOOLS_ICON, RolePermissionMatrix, RoleEditorDialog, ProfileForm, ProfilePage, RolesPermissionsPage, MembersPanel, ChangePasswordForm, SessionsList, ApiKeysPanel, AgentKeysList, AccessRequestPanel, PermissionRequestPanel, RoleKeyPicker, isRoleSelectable, leastPrivilegeRoleId, InvitationsList, InviteMembersDialog, Brand, TeamSettingsForm, DangerZone, type RBACProviderProps, type RBACHookResult, type CanProps, type AccountMenuProps, type AccountMenuAction, type TeamSwitcherProps, type DevToolsPopoverProps, type DevToolsPanelProps, type RolePermissionMatrixProps, type RoleEditorDialogProps, type RoleEditorDialogSubmitInput, type ProfileFormProps, type ProfileFormAccount, type ProfileFormSaveInput, type ProfilePageProps, type RolesPermissionsPageProps, type MembersPanelProps, type MembersPanelMember, type ChangePasswordFormProps, type SessionsListProps, type Session, type ApiKeysPanelProps, type AgentKeysListProps, type ApiKey, type KeyGrant, type KeyRoleEditor, type AccessRequestPanelProps, type RoleAccessRequestPanelProps, type MachineAccessRequestPanelProps, type AccessRequest, type AccessRequestKind, type IssuedKey, type AccessRequestState, type ExpiredNote, type PermissionRequestPanelProps, type PermissionRequest, type RoleKeyPickerProps, type InvitationsListProps, type InvitationsListItem, type InvitationStatus, type InviteMembersDialogProps, type Permission, type Role, type User, type Team, type TeamMembership, type BrandProps, type TeamSettingsFormProps, type TeamSettingsFormTeam, type TeamSettingsFormSaveInput, type DangerZoneProps, } from "./components/rbac";
|
|
190
|
+
export { RBACProvider, useRBAC, Can, useHasPermission, AccountMenu, AccountMenuSection, TeamSwitcher, DevToolsPopover, DevToolsPanel, DEV_TOOLS_ICON, RolePermissionMatrix, RoleEditorDialog, ProfileForm, ProfilePage, RolesPermissionsPage, MembersPanel, ChangePasswordForm, SessionsList, ApiKeysPanel, AgentKeysList, AccessRequestPanel, PermissionRequestPanel, RoleKeyPicker, isRoleSelectable, leastPrivilegeRoleId, InvitationsList, InviteMembersDialog, Brand, TeamSettingsForm, DangerZone, type RBACProviderProps, type RBACHookResult, type CanProps, type AccountMenuProps, type AccountMenuAction, type TeamSwitcherProps, type DevToolsPopoverProps, type DevToolsPanelProps, type RolePermissionMatrixProps, type RoleEditorDialogProps, type RoleEditorDialogSubmitInput, type ProfileFormProps, type ProfileFormAccount, type ProfileFormSaveInput, type ProfilePageProps, type RolesPermissionsPageProps, type MembersPanelProps, type MembersPanelMember, type ChangePasswordFormProps, type SessionsListProps, type Session, type ApiKeysPanelProps, type AgentKeysListProps, type ApiKey, type KeyGrant, type KeyRoleEditor, type AccessRequestPanelProps, type RoleAccessRequestPanelProps, type MachineAccessRequestPanelProps, type FixedRoleSessionAccessRequestPanelProps, type AccessRequest, type AccessRequestKind, type IssuedKey, type AccessRequestState, type ExpiredNote, type PermissionRequestPanelProps, type PermissionRequest, type RoleKeyPickerProps, type InvitationsListProps, type InvitationsListItem, type InvitationStatus, type InviteMembersDialogProps, type Permission, type Role, type User, type Team, type TeamMembership, type BrandProps, type TeamSettingsFormProps, type TeamSettingsFormTeam, type TeamSettingsFormSaveInput, type DangerZoneProps, } from "./components/rbac";
|
|
191
191
|
export { AuthLayout, AcceptInvitationCard, SignupCard, SignInProviders, TermsAcceptance, LoginForm, ForgotPasswordForm, ResetPasswordForm, type AuthLayoutProps, type AcceptInvitationCardProps, type SignupCardProps, type SignupInitialValues, type AcceptInvitationInitialValues, type SignInProvidersProps, type ProviderSelection, type SignInProvider, type SignInProviderId, type VerifiedIdentity, type ProviderContinuation, type TermsAcceptanceProps, type LoginFormProps, type ForgotPasswordFormProps, type ResetPasswordFormProps, } from "./components/auth";
|
|
192
192
|
export { UseCaseCard, RoadmapItemCard, RoadmapSwimlaneBoard, UseCaseLedgerPage, RoadmapPage, PhaseManager, TrackManager, deriveRoadmapItemStatus, isFullyBuilt, isUnbuilt, trackIds, trackProgress, toneForIndex, CATEGORY_TONES, type Domain, type Phase, type Track, type RoadmapItem, type RoadmapItemStatus, type UseCase, type UseCaseStatus, type UseCaseDecision, type UseCaseCardProps, type RoadmapItemCardProps, type RoadmapSwimlaneBoardProps, type UseCaseLedgerPageProps, type RoadmapPageProps, type PhaseManagerProps, type TrackManagerProps, } from "./components/roadmap";
|
|
193
193
|
export { OrderedEntityManager, type OrderedEntity, type OrderedEntityManagerProps, type OrderedEntityRowStatus, } from "./components/OrderedEntityManager";
|
|
@@ -67,6 +67,12 @@ export interface RbacStrings {
|
|
|
67
67
|
machineGrant: string;
|
|
68
68
|
/** DXUI-15: title of the callout that shows the machine grant. */
|
|
69
69
|
machineGrantTitle: string;
|
|
70
|
+
/** DXUI-102: heading of the read-only role block for a session request that names its role. */
|
|
71
|
+
fixedRoleTitle: string;
|
|
72
|
+
/** DXUI-102: body of the "Approve only if you started this" callout for a request that names its role; `typedCode` as for `approveBody`. */
|
|
73
|
+
approveBodyFixedRole: (typedCode: boolean) => string;
|
|
74
|
+
/** DXUI-102: line under that heading. */
|
|
75
|
+
fixedRoleHint: string;
|
|
70
76
|
/** Term of the fact row naming the kind of requester. */
|
|
71
77
|
kind: string;
|
|
72
78
|
/** Term of the fact row naming a worker requester. */
|