@50arms/ui 35.1.0 → 35.2.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.
@@ -1,20 +1,20 @@
1
1
  import { jsx as t } from "react/jsx-runtime";
2
- import { Icon as f } from "../Icon.js";
3
- import { TableEmptyState as l } from "../Table.js";
4
- import { ApiKeysTable as g } from "./ApiKeysTable.js";
5
- import { useUiStrings as y } from "../../lib/i18n/provider.js";
6
- function A({ keys: e, onRevoke: r, busyId: o, roleEditor: m, onRevokeGrant: n, renderName: s, renderStatus: p, emptyState: a, className: c }) {
7
- const i = y().agentKeysList;
8
- return e.length === 0 ? a ?? /* @__PURE__ */ t(
9
- l,
2
+ import { Icon as l } from "../Icon.js";
3
+ import { TableEmptyState as g } from "../Table.js";
4
+ import { ApiKeysTable as y } from "./ApiKeysTable.js";
5
+ import { useUiStrings as u } from "../../lib/i18n/provider.js";
6
+ function L({ keys: e, onRevoke: r, busyId: o, roleEditor: m, onRevokeGrant: n, renderName: s, renderStatus: p, renderStartedBy: a, emptyState: c, className: f }) {
7
+ const i = u().agentKeysList;
8
+ return e.length === 0 ? c ?? /* @__PURE__ */ t(
9
+ g,
10
10
  {
11
- icon: /* @__PURE__ */ t(f, { name: "bot", size: "lg", className: "text-tertiary" }),
11
+ icon: /* @__PURE__ */ t(l, { name: "bot", size: "lg", className: "text-tertiary" }),
12
12
  title: i.emptyTitle,
13
13
  description: i.emptyDescription
14
14
  }
15
- ) : /* @__PURE__ */ t(g, { keys: e, onRevoke: r, busyId: o, roleEditor: m, onRevokeGrant: n, renderName: s, renderStatus: p, className: c });
15
+ ) : /* @__PURE__ */ t(y, { keys: e, onRevoke: r, busyId: o, roleEditor: m, onRevokeGrant: n, renderName: s, renderStatus: p, renderStartedBy: a, className: f });
16
16
  }
17
17
  export {
18
- A as AgentKeysList
18
+ L as AgentKeysList
19
19
  };
20
20
  //# sourceMappingURL=AgentKeysList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentKeysList.js","sources":["../../../src/components/rbac/AgentKeysList.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { TableEmptyState } from \"../Table\";\nimport { useUiStrings } from \"../../lib/i18n\";\nimport { ApiKeysTable, type ApiKey, type KeyRoleEditor } from \"./ApiKeysTable\";\n\n/* ----------------------------------------------------------------------------\n AGENT KEYS LIST (DX-4425)\n\n THE KEYS A WORKER OR AN AGENT SESSION MINTED ON A PERSON'S BEHALF, ALONE. They\n were a second group inside `ApiKeysPanel`, which made a page that wanted only\n the agent list render a \"Create key\" button and a personal-keys heading it did\n not own. A person never creates one of these here (an approved access request\n or a dispatch mints it), so this list has no create flow: rows, a confirmed\n revoke, and an empty state. It shares its table with `ApiKeysPanel`\n (`ApiKeysTable`), so the two never disagree about a column.\n\n `roleEditor` (DX-4427) turns each role badge into an in-place picker, so an\n agent's permissions can be raised or lowered without revoking it: a revoke is\n terminal (the agent is told to stop), a role change is not.\n\n A KEY SHOWS THE PERMISSIONS ADDED TO IT (DX-4433). A key's `grants` are what\n approved permission requests (`PermissionRequestPanel`) added on top of its\n role. `onRevokeGrant` makes each removable behind its own confirm, without\n touching the key or its role.\n\n A ROW CAN LINK AND SHOW A LIVE STATUS (DX-4487): `renderName` replaces the\n name text (a router link to what the key belongs to) and `renderStatus` adds\n a line under it (a worker's readiness), both given the row.\n\n PRESENTATIONAL ONLY: `onRevoke` and `onRevokeGrant` (each after its confirm\n dialog) and `roleEditor.onChange` are the side effects.\n ---------------------------------------------------------------------------- */\n\nexport interface AgentKeysListProps {\n /** The keys agents hold, already scoped to the person. */\n keys: ApiKey[];\n onRevoke: (id: number) => Promise<void>;\n /** The id of a key currently mid-revoke, mid-role-change or mid-grant-removal. Disables just that row's controls. */\n busyId?: number | null;\n /** Makes each key's role editable in place. Omit for a read-only role badge. */\n roleEditor?: KeyRoleEditor;\n /** Makes each key's grant chips removable (DX-4433). Omit and keys that carry grants show them read-only. */\n onRevokeGrant?: (keyId: number, grantId: number) => Promise<void>;\n /** Replaces a key's name text, e.g. with a link to the worker the key belongs to (DX-4487). Return `null` to keep the plain name. */\n renderName?: (apiKey: ApiKey) => ReactNode;\n /** One line under a key's name, e.g. the worker's readiness badge (DX-4487). Return `null` for a key with none. */\n renderStatus?: (apiKey: ApiKey) => ReactNode;\n emptyState?: ReactNode;\n className?: string;\n}\n\nexport function AgentKeysList({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, emptyState, className }: AgentKeysListProps) {\n const strings = useUiStrings().agentKeysList;\n if (keys.length === 0) {\n return (\n emptyState ?? (\n <TableEmptyState\n icon={<Icon name=\"bot\" size=\"lg\" className=\"text-tertiary\" />}\n title={strings.emptyTitle}\n description={strings.emptyDescription}\n />\n )\n );\n }\n return <ApiKeysTable keys={keys} onRevoke={onRevoke} busyId={busyId} roleEditor={roleEditor} onRevokeGrant={onRevokeGrant} renderName={renderName} renderStatus={renderStatus} className={className} />;\n}\n"],"names":["AgentKeysList","keys","onRevoke","busyId","roleEditor","onRevokeGrant","renderName","renderStatus","emptyState","className","strings","useUiStrings","jsx","TableEmptyState","Icon","ApiKeysTable"],"mappings":";;;;;AAoDO,SAASA,EAAc,EAAE,MAAAC,GAAM,UAAAC,GAAU,QAAAC,GAAQ,YAAAC,GAAY,eAAAC,GAAe,YAAAC,GAAY,cAAAC,GAAc,YAAAC,GAAY,WAAAC,EAAA,GAAiC;AACxJ,QAAMC,IAAUC,IAAe;AAC/B,SAAIV,EAAK,WAAW,IAEhBO,KACE,gBAAAI;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,wBAAOC,GAAA,EAAK,MAAK,OAAM,MAAK,MAAK,WAAU,iBAAgB;AAAA,MAC3D,OAAOJ,EAAQ;AAAA,MACf,aAAaA,EAAQ;AAAA,IAAA;AAAA,EAAA,IAKtB,gBAAAE,EAACG,KAAa,MAAAd,GAAY,UAAAC,GAAoB,QAAAC,GAAgB,YAAAC,GAAwB,eAAAC,GAA8B,YAAAC,GAAwB,cAAAC,GAA4B,WAAAE,EAAA,CAAsB;AACvM;"}
1
+ {"version":3,"file":"AgentKeysList.js","sources":["../../../src/components/rbac/AgentKeysList.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { TableEmptyState } from \"../Table\";\nimport { useUiStrings } from \"../../lib/i18n\";\nimport { ApiKeysTable, type ApiKey, type KeyRoleEditor } from \"./ApiKeysTable\";\n\n/* ----------------------------------------------------------------------------\n AGENT KEYS LIST (DX-4425)\n\n THE KEYS A WORKER OR AN AGENT SESSION MINTED ON A PERSON'S BEHALF, ALONE. They\n were a second group inside `ApiKeysPanel`, which made a page that wanted only\n the agent list render a \"Create key\" button and a personal-keys heading it did\n not own. A person never creates one of these here (an approved access request\n or a dispatch mints it), so this list has no create flow: rows, a confirmed\n revoke, and an empty state. It shares its table with `ApiKeysPanel`\n (`ApiKeysTable`), so the two never disagree about a column.\n\n `roleEditor` (DX-4427) turns each role badge into an in-place picker, so an\n agent's permissions can be raised or lowered without revoking it: a revoke is\n terminal (the agent is told to stop), a role change is not.\n\n A KEY SHOWS THE PERMISSIONS ADDED TO IT (DX-4433). A key's `grants` are what\n approved permission requests (`PermissionRequestPanel`) added on top of its\n role. `onRevokeGrant` makes each removable behind its own confirm, without\n touching the key or its role.\n\n A ROW CAN LINK AND SHOW A LIVE STATUS (DX-4487): `renderName` replaces the\n name text (a router link to what the key belongs to) and `renderStatus` adds\n a line under it (a worker's readiness), both given the row.\n\n A ROW CAN SAY WHO STARTED IT (DX-6801): `renderStartedBy` adds a \"Started\n by\" column right after the name (the person who approved the key, or the\n agent session that started it), given the row.\n\n PRESENTATIONAL ONLY: `onRevoke` and `onRevokeGrant` (each after its confirm\n dialog) and `roleEditor.onChange` are the side effects.\n ---------------------------------------------------------------------------- */\n\nexport interface AgentKeysListProps {\n /** The keys agents hold, already scoped to the person. */\n keys: ApiKey[];\n onRevoke: (id: number) => Promise<void>;\n /** The id of a key currently mid-revoke, mid-role-change or mid-grant-removal. Disables just that row's controls. */\n busyId?: number | null;\n /** Makes each key's role editable in place. Omit for a read-only role badge. */\n roleEditor?: KeyRoleEditor;\n /** Makes each key's grant chips removable (DX-4433). Omit and keys that carry grants show them read-only. */\n onRevokeGrant?: (keyId: number, grantId: number) => Promise<void>;\n /** Replaces a key's name text, e.g. with a link to the worker the key belongs to (DX-4487). Return `null` to keep the plain name. */\n renderName?: (apiKey: ApiKey) => ReactNode;\n /** One line under a key's name, e.g. the worker's readiness badge (DX-4487). Return `null` for a key with none. */\n renderStatus?: (apiKey: ApiKey) => ReactNode;\n /** Adds a \"Started by\" column right after the name: who started or authorized the key's session (DX-6801). Omit for no such column. */\n renderStartedBy?: (apiKey: ApiKey) => ReactNode;\n emptyState?: ReactNode;\n className?: string;\n}\n\nexport function AgentKeysList({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, renderStartedBy, emptyState, className }: AgentKeysListProps) {\n const strings = useUiStrings().agentKeysList;\n if (keys.length === 0) {\n return (\n emptyState ?? (\n <TableEmptyState\n icon={<Icon name=\"bot\" size=\"lg\" className=\"text-tertiary\" />}\n title={strings.emptyTitle}\n description={strings.emptyDescription}\n />\n )\n );\n }\n return <ApiKeysTable keys={keys} onRevoke={onRevoke} busyId={busyId} roleEditor={roleEditor} onRevokeGrant={onRevokeGrant} renderName={renderName} renderStatus={renderStatus} renderStartedBy={renderStartedBy} className={className} />;\n}\n"],"names":["AgentKeysList","keys","onRevoke","busyId","roleEditor","onRevokeGrant","renderName","renderStatus","renderStartedBy","emptyState","className","strings","useUiStrings","jsx","TableEmptyState","Icon","ApiKeysTable"],"mappings":";;;;;AA0DO,SAASA,EAAc,EAAE,MAAAC,GAAM,UAAAC,GAAU,QAAAC,GAAQ,YAAAC,GAAY,eAAAC,GAAe,YAAAC,GAAY,cAAAC,GAAc,iBAAAC,GAAiB,YAAAC,GAAY,WAAAC,EAAA,GAAiC;AACzK,QAAMC,IAAUC,IAAe;AAC/B,SAAIX,EAAK,WAAW,IAEhBQ,KACE,gBAAAI;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,wBAAOC,GAAA,EAAK,MAAK,OAAM,MAAK,MAAK,WAAU,iBAAgB;AAAA,MAC3D,OAAOJ,EAAQ;AAAA,MACf,aAAaA,EAAQ;AAAA,IAAA;AAAA,EAAA,IAKtB,gBAAAE,EAACG,GAAA,EAAa,MAAAf,GAAY,UAAAC,GAAoB,QAAAC,GAAgB,YAAAC,GAAwB,eAAAC,GAA8B,YAAAC,GAAwB,cAAAC,GAA4B,iBAAAC,GAAkC,WAAAE,EAAA,CAAsB;AACzO;"}
@@ -2,14 +2,14 @@ import { jsx as l, jsxs as f } from "react/jsx-runtime";
2
2
  import { useState as u } from "react";
3
3
  import { AlertDialog as g } from "../Dialog.js";
4
4
  import { Badge as v } from "../Badge.js";
5
- import { DataTable as h, CellStack as C } from "../Table.js";
6
- import { Icon as p } from "../Icon.js";
7
- import { IconButton as b } from "../IconButton.js";
8
- import { StatusSelect as A } from "../StatusSelect.js";
9
- import { roleUnavailableReason as T } from "./RoleKeyPicker.js";
10
- import { DateTimeText as k } from "../DateTimeText.js";
11
- import { RelativeTime as N, useRelativeText as x } from "../RelativeTime.js";
12
- import { EndedLine as R, IdleLine as L } from "./EndedLine.js";
5
+ import { DataTable as C, CellStack as A } from "../Table.js";
6
+ import { Icon as b } from "../Icon.js";
7
+ import { IconButton as p } from "../IconButton.js";
8
+ import { StatusSelect as T } from "../StatusSelect.js";
9
+ import { roleUnavailableReason as k } from "./RoleKeyPicker.js";
10
+ import { DateTimeText as N } from "../DateTimeText.js";
11
+ import { RelativeTime as R, useRelativeText as x } from "../RelativeTime.js";
12
+ import { EndedLine as S, IdleLine as L } from "./EndedLine.js";
13
13
  import { useUiStrings as m } from "../../lib/i18n/provider.js";
14
14
  function O({
15
15
  apiKey: e,
@@ -19,15 +19,15 @@ function O({
19
19
  const { apiKeysTable: i, roleKeyPicker: a } = m();
20
20
  if (r === void 0 || e.roleId === void 0 || e.ended !== void 0)
21
21
  return /* @__PURE__ */ l(v, { tone: "neutral", children: e.roleLabel });
22
- const t = new Set(r.ownPermissionKeys), n = (typeof r.roles == "function" ? r.roles(e) : r.roles).map((s) => {
23
- const c = T(s, t, r.permissions, a.unavailable);
24
- return { value: s.id, label: s.label, tone: "neutral", ...c === null ? {} : { refusal: c } };
22
+ const d = new Set(r.ownPermissionKeys), t = (typeof r.roles == "function" ? r.roles(e) : r.roles).map((s) => {
23
+ const n = k(s, d, r.permissions, a.unavailable);
24
+ return { value: s.id, label: s.label, tone: "neutral", ...n === null ? {} : { refusal: n } };
25
25
  });
26
- return n.some((s) => s.value === e.roleId) || n.unshift({ value: e.roleId, label: e.roleLabel, tone: "neutral", refusal: i.roleNotAssignable }), /* @__PURE__ */ l(
27
- A,
26
+ return t.some((s) => s.value === e.roleId) || t.unshift({ value: e.roleId, label: e.roleLabel, tone: "neutral", refusal: i.roleNotAssignable }), /* @__PURE__ */ l(
27
+ T,
28
28
  {
29
29
  value: e.roleId,
30
- options: n,
30
+ options: t,
31
31
  "aria-label": i.roleOf(e.name),
32
32
  disabled: o,
33
33
  onValueChange: (s) => {
@@ -36,21 +36,21 @@ function O({
36
36
  }
37
37
  );
38
38
  }
39
- function S({
39
+ function U({
40
40
  apiKey: e,
41
41
  busy: o,
42
42
  onRevoke: r
43
43
  }) {
44
- const i = m().apiKeysTable, [a, t] = u(!1);
44
+ const i = m().apiKeysTable, [a, d] = u(!1);
45
45
  return /* @__PURE__ */ l(
46
46
  g,
47
47
  {
48
48
  open: a,
49
- onOpenChange: t,
49
+ onOpenChange: d,
50
50
  trigger: /* @__PURE__ */ l(
51
- b,
51
+ p,
52
52
  {
53
- icon: /* @__PURE__ */ l(p, { name: "trash-2", size: "sm" }),
53
+ icon: /* @__PURE__ */ l(b, { name: "trash-2", size: "sm" }),
54
54
  label: i.revoke(e.name),
55
55
  tone: "danger",
56
56
  size: "sm",
@@ -63,30 +63,30 @@ function S({
63
63
  destructive: !0,
64
64
  loading: o,
65
65
  onConfirm: () => {
66
- r(e.id), t(!1);
66
+ r(e.id), d(!1);
67
67
  }
68
68
  }
69
69
  );
70
70
  }
71
- function U({
71
+ function I({
72
72
  apiKey: e,
73
73
  grant: o,
74
74
  busy: r,
75
75
  onRevokeGrant: i
76
76
  }) {
77
- const a = m().apiKeysTable, t = x(o.grantedAt), [d, n] = u(!1);
77
+ const a = m().apiKeysTable, d = x(o.grantedAt), [c, t] = u(!1);
78
78
  return /* @__PURE__ */ f("li", { className: "flex min-w-0 flex-col gap-0.5", children: [
79
79
  /* @__PURE__ */ f("div", { className: "flex min-w-0 items-center gap-1", children: [
80
80
  /* @__PURE__ */ l(v, { tone: "accent", size: "sm", children: `+ ${o.label}` }),
81
81
  i && /* @__PURE__ */ l(
82
82
  g,
83
83
  {
84
- open: d,
85
- onOpenChange: n,
84
+ open: c,
85
+ onOpenChange: t,
86
86
  trigger: /* @__PURE__ */ l(
87
- b,
87
+ p,
88
88
  {
89
- icon: /* @__PURE__ */ l(p, { name: "x", size: "xs" }),
89
+ icon: /* @__PURE__ */ l(b, { name: "x", size: "xs" }),
90
90
  label: a.removeGrant(o.label, e.name),
91
91
  tone: "danger",
92
92
  size: "sm",
@@ -99,38 +99,40 @@ function U({
99
99
  destructive: !0,
100
100
  loading: r,
101
101
  onConfirm: () => {
102
- i(e.id, o.id), n(!1);
102
+ i(e.id, o.id), t(!1);
103
103
  }
104
104
  }
105
105
  )
106
106
  ] }),
107
- /* @__PURE__ */ l("span", { className: "text-xs break-words text-tertiary", children: a.granted(t, o.reason || void 0) })
107
+ /* @__PURE__ */ l("span", { className: "text-xs break-words text-tertiary", children: a.granted(d, o.reason || void 0) })
108
108
  ] });
109
109
  }
110
- function I({
110
+ function z({
111
111
  apiKey: e,
112
112
  busy: o,
113
113
  onRevokeGrant: r,
114
114
  renderName: i,
115
115
  renderStatus: a
116
116
  }) {
117
- const t = m().apiKeysTable, d = x(e.createdAt), n = e.grants ?? [], s = a?.(e);
117
+ const d = m().apiKeysTable, c = x(e.createdAt), t = e.grants ?? [], s = a?.(e);
118
118
  return /* @__PURE__ */ f("div", { className: "flex min-w-0 flex-col gap-2", children: [
119
- /* @__PURE__ */ l(C, { primary: i?.(e) ?? e.name, secondary: t.created(d) }),
120
- e.ended && /* @__PURE__ */ l(R, { ended: e.ended }),
119
+ /* @__PURE__ */ l(A, { primary: i?.(e) ?? e.name, secondary: d.created(c) }),
120
+ e.ended && /* @__PURE__ */ l(S, { ended: e.ended }),
121
121
  e.idle && /* @__PURE__ */ l(L, { idle: e.idle }),
122
122
  s,
123
- n.length > 0 && /* @__PURE__ */ l("ul", { "aria-label": t.grantsOf(e.name), className: "flex min-w-0 flex-col gap-1.5", children: n.map((c) => /* @__PURE__ */ l(U, { apiKey: e, grant: c, busy: o, onRevokeGrant: e.ended === void 0 ? r : void 0 }, c.id)) })
123
+ t.length > 0 && /* @__PURE__ */ l("ul", { "aria-label": d.grantsOf(e.name), className: "flex min-w-0 flex-col gap-1.5", children: t.map((n) => /* @__PURE__ */ l(I, { apiKey: e, grant: n, busy: o, onRevokeGrant: e.ended === void 0 ? r : void 0 }, n.id)) })
124
124
  ] });
125
125
  }
126
- function z(e, o, r, i, a, t, d) {
126
+ function D(e, o, r, i, a, d, c, t) {
127
+ const s = t === void 0 ? [] : [{ id: "startedBy", header: e.columnStartedBy, enableSorting: !1, cell: ({ row: n }) => t(n.original) }];
127
128
  return [
128
129
  {
129
130
  id: "key",
130
131
  header: e.columnKey,
131
132
  accessorFn: (n) => n.name,
132
- cell: ({ row: n }) => /* @__PURE__ */ l(I, { apiKey: n.original, busy: o === n.original.id, onRevokeGrant: a, renderName: t, renderStatus: d })
133
+ cell: ({ row: n }) => /* @__PURE__ */ l(z, { apiKey: n.original, busy: o === n.original.id, onRevokeGrant: a, renderName: d, renderStatus: c })
133
134
  },
135
+ ...s,
134
136
  {
135
137
  id: "role",
136
138
  header: e.columnRole,
@@ -141,27 +143,27 @@ function z(e, o, r, i, a, t, d) {
141
143
  id: "lastUsed",
142
144
  header: e.columnLastUsed,
143
145
  accessorFn: (n) => n.lastUsedAt ?? "",
144
- cell: ({ row: n }) => /* @__PURE__ */ l("span", { className: "text-secondary", children: n.original.lastUsedAt ? /* @__PURE__ */ l(N, { at: n.original.lastUsedAt }) : e.never })
146
+ cell: ({ row: n }) => /* @__PURE__ */ l("span", { className: "text-secondary", children: n.original.lastUsedAt ? /* @__PURE__ */ l(R, { at: n.original.lastUsedAt }) : e.never })
145
147
  },
146
148
  {
147
149
  id: "expires",
148
150
  header: e.columnExpires,
149
151
  accessorFn: (n) => n.expiresAt ?? "",
150
- cell: ({ row: n }) => /* @__PURE__ */ l("span", { className: "text-secondary", children: n.original.expiresAt ? /* @__PURE__ */ l(k, { at: n.original.expiresAt }) : e.never })
152
+ cell: ({ row: n }) => /* @__PURE__ */ l("span", { className: "text-secondary", children: n.original.expiresAt ? /* @__PURE__ */ l(N, { at: n.original.expiresAt }) : e.never })
151
153
  },
152
154
  {
153
155
  id: "actions",
154
156
  header: "",
155
157
  enableSorting: !1,
156
- cell: ({ row: n }) => /* @__PURE__ */ l("div", { className: "flex justify-end", children: n.original.ended === void 0 && /* @__PURE__ */ l(S, { apiKey: n.original, busy: o === n.original.id, onRevoke: r }) })
158
+ cell: ({ row: n }) => /* @__PURE__ */ l("div", { className: "flex justify-end", children: n.original.ended === void 0 && /* @__PURE__ */ l(U, { apiKey: n.original, busy: o === n.original.id, onRevoke: r }) })
157
159
  }
158
160
  ];
159
161
  }
160
- function M({ keys: e, onRevoke: o, busyId: r, roleEditor: i, onRevokeGrant: a, renderName: t, renderStatus: d, className: n }) {
161
- const s = m().apiKeysTable;
162
- return /* @__PURE__ */ l(h, { columns: z(s, r, o, i, a, t, d), data: e, getRowId: (c) => String(c.id), className: n });
162
+ function Q({ keys: e, onRevoke: o, busyId: r, roleEditor: i, onRevokeGrant: a, renderName: d, renderStatus: c, renderStartedBy: t, className: s }) {
163
+ const n = m().apiKeysTable;
164
+ return /* @__PURE__ */ l(C, { columns: D(n, r, o, i, a, d, c, t), data: e, getRowId: (h) => String(h.id), className: s });
163
165
  }
164
166
  export {
165
- M as ApiKeysTable
167
+ Q as ApiKeysTable
166
168
  };
167
169
  //# sourceMappingURL=ApiKeysTable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApiKeysTable.js","sources":["../../../src/components/rbac/ApiKeysTable.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport type { ColumnDef } from \"@tanstack/react-table\";\nimport { AlertDialog } from \"../Dialog\";\nimport { Badge } from \"../Badge\";\nimport { CellStack, DataTable } from \"../Table\";\nimport { Icon } from \"../Icon\";\nimport { IconButton } from \"../IconButton\";\nimport { StatusSelect, type StatusOption } from \"../StatusSelect\";\nimport { roleUnavailableReason } from \"./RoleKeyPicker\";\nimport type { Permission, Role } from \"./types\";\nimport { DateTimeText } from \"../DateTimeText\";\nimport { RelativeTime, useRelativeText } from \"../RelativeTime\";\nimport { useUiStrings } from \"../../lib/i18n\";\nimport type { UiStrings } from \"../../lib/i18n\";\nimport { EndedLine, IdleLine, type EndedState, type IdleState } from \"./EndedLine\";\n\n/* ----------------------------------------------------------------------------\n API KEYS TABLE (DX-4425)\n\n THE ONE ROW SHAPE EVERY KEY LIST SHARES. `ApiKeysPanel` (the keys a person\n made for themselves) and `AgentKeysList` (the keys a worker or an agent\n session minted on their behalf) list the same credential: a name, the role it\n acts with, when it was last used, when it expires, and a confirmed revoke.\n Both render this table so a column change lands once. It is not exported from\n the package: a consumer reaches it through the two components that frame it.\n\n PRESENTATIONAL ONLY, like `SessionsList`: `onRevoke` fires only after the\n `AlertDialog` confirms.\n\n THE ROLE CELL EDITS IN PLACE (DX-4427) when the consumer passes `roleEditor`:\n the role badge IS the control (`StatusSelect`), so raising or lowering a live\n key's permissions needs no dialog and no revoke. A role the owner may not\n grant is listed with the reason (`roleUnavailableReason`, the same rule\n `RoleKeyPicker` applies when a key is issued). A key with no `roleId`, or no\n `roleEditor`, keeps the read-only badge.\n\n A KEY'S GRANTS SIT UNDER ITS NAME (DX-4433). An agent can ask its owner for a\n permission its role lacks (`PermissionRequestPanel`); an approval adds it to\n that one key on top of its role. Each grant shows as a \"+ Label\" chip with\n when it was granted and why, as text rather than a tooltip so a phone reads it\n too. With `onRevokeGrant` each chip carries its own remove control behind a\n confirm: dropping a grant is not revoking the key, and the role is untouched.\n Without the handler the chips are read-only, and a key with no grants renders\n exactly as before.\n\n A ROW CAN LINK AND CARRY A LIVE STATUS (DX-4487). `renderName` replaces the\n name text (a consumer renders its router's link, so the library stays\n router-agnostic) and `renderStatus` adds one line under the name (a readiness\n badge for a worker's key). Both are given the row; either may return `null`\n for a key that has neither, and omitting them renders exactly as before.\n ---------------------------------------------------------------------------- */\n\nexport interface ApiKey {\n id: number;\n name: string;\n /** The label of the role this key acts with. A label, not an id: a key can carry a role of a team other than the one whose\n * `roles` the create dialog offers, and only the consumer's server can name that one. */\n roleLabel: string;\n /** The id of that role, matching a `Role.id` in `roleEditor.roles`. Needed only for a key whose role is editable. */\n roleId?: string;\n /** ISO instant. */\n createdAt: string;\n /** ISO instant, or `null`/omitted if it has never been used. */\n lastUsedAt?: string | null;\n /** ISO instant, or `null`/omitted for a key with no expiry. */\n expiresAt?: string | null;\n /** Permissions added to this key on top of its role (DX-4433). Omit, or leave empty, for a key that holds only its role. */\n grants?: KeyGrant[];\n /** DX-5246: set on a key that has ended (revoked, expired or retired): the consumer's own words for how it ended (`label`) and the ISO instant it did (`at`). An ended row shows them under its name and offers no revoke, role change or grant removal. */\n ended?: EndedState;\n /** DX-5246: set on a key that still works but nobody is using (its session gone quiet, a script that stopped): the consumer's own words (`label`) and the ISO instant it was last in use (`at`). An idle row shows them under its name and keeps its revoke, role change and grant removal. */\n idle?: IdleState;\n}\n\n/** One permission an approved request added to a key, on top of its role. */\nexport interface KeyGrant {\n id: number;\n /** The permission key granted. Compared for equality only. */\n permissionKey: string;\n /** The permission's label, as shown on the chip and in the confirm. */\n label: string;\n /** ISO instant. */\n grantedAt: string;\n /** The reason the agent gave when it asked. Plain text. */\n reason?: string;\n}\n\n/** Makes a key's role editable in place. `roles` are the roles the owner may pick from: one list for every key, or a function\n * of the key when the keys do not share one (DX-4431: an agent session takes agent roles, a worker a human role that can manage workers). */\nexport interface KeyRoleEditor {\n roles: Role[] | ((apiKey: ApiKey) => Role[]);\n /** The permission catalog, used to name the permissions that make a role unavailable. */\n permissions: Permission[];\n /** What the owner holds. A role holding anything outside this set is listed but cannot be chosen. */\n ownPermissionKeys: string[];\n /** Fired when a different role is picked. The consumer saves it and refreshes `keys`. */\n onChange: (id: number, roleId: string) => Promise<void>;\n}\n\nfunction RoleCell({\n apiKey,\n busy,\n editor,\n}: {\n apiKey: ApiKey;\n busy: boolean;\n editor: KeyRoleEditor | undefined;\n}) {\n const { apiKeysTable: strings, roleKeyPicker } = useUiStrings();\n if (editor === undefined || apiKey.roleId === undefined || apiKey.ended !== undefined) {\n return <Badge tone=\"neutral\">{apiKey.roleLabel}</Badge>;\n }\n const own = new Set(editor.ownPermissionKeys);\n const roles = typeof editor.roles === \"function\" ? editor.roles(apiKey) : editor.roles;\n const options: StatusOption[] = roles.map((role) => {\n const refusal = roleUnavailableReason(role, own, editor.permissions, roleKeyPicker.unavailable);\n return { value: role.id, label: role.label, tone: \"neutral\", ...(refusal === null ? {} : { refusal }) };\n });\n // A key can carry a role outside the offered set (another team's); it is shown, never silently swapped for a listed one.\n if (!options.some((o) => o.value === apiKey.roleId)) {\n options.unshift({ value: apiKey.roleId, label: apiKey.roleLabel, tone: \"neutral\", refusal: strings.roleNotAssignable });\n }\n return (\n <StatusSelect\n value={apiKey.roleId}\n options={options}\n aria-label={strings.roleOf(apiKey.name)}\n disabled={busy}\n onValueChange={(roleId) => {\n if (roleId !== apiKey.roleId) void editor.onChange(apiKey.id, roleId);\n }}\n />\n );\n}\n\nfunction RevokeCell({\n apiKey,\n busy,\n onRevoke,\n}: {\n apiKey: ApiKey;\n busy: boolean;\n onRevoke: (id: number) => Promise<void>;\n}) {\n const strings = useUiStrings().apiKeysTable;\n const [confirmOpen, setConfirmOpen] = useState(false);\n\n return (\n <AlertDialog\n open={confirmOpen}\n onOpenChange={setConfirmOpen}\n trigger={\n <IconButton\n icon={<Icon name=\"trash-2\" size=\"sm\" />}\n label={strings.revoke(apiKey.name)}\n tone=\"danger\"\n size=\"sm\"\n disabledReason={busy ? strings.revoking : undefined}\n />\n }\n title={strings.revokeTitle(apiKey.name)}\n description={strings.revokeDescription}\n confirmLabel={strings.revokeConfirm}\n destructive\n loading={busy}\n onConfirm={() => {\n void onRevoke(apiKey.id);\n setConfirmOpen(false);\n }}\n />\n );\n}\n\nfunction GrantChip({\n apiKey,\n grant,\n busy,\n onRevokeGrant,\n}: {\n apiKey: ApiKey;\n grant: KeyGrant;\n busy: boolean;\n onRevokeGrant: ((keyId: number, grantId: number) => Promise<void>) | undefined;\n}) {\n const strings = useUiStrings().apiKeysTable;\n const grantedAge = useRelativeText(grant.grantedAt);\n const [confirmOpen, setConfirmOpen] = useState(false);\n return (\n <li className=\"flex min-w-0 flex-col gap-0.5\">\n <div className=\"flex min-w-0 items-center gap-1\">\n <Badge tone=\"accent\" size=\"sm\">{`+ ${grant.label}`}</Badge>\n {onRevokeGrant && (\n <AlertDialog\n open={confirmOpen}\n onOpenChange={setConfirmOpen}\n trigger={\n <IconButton\n icon={<Icon name=\"x\" size=\"xs\" />}\n label={strings.removeGrant(grant.label, apiKey.name)}\n tone=\"danger\"\n size=\"sm\"\n disabledReason={busy ? strings.updating : undefined}\n />\n }\n title={strings.removeGrantTitle(grant.label)}\n description={strings.removeGrantDescription}\n confirmLabel={strings.removeGrantConfirm}\n destructive\n loading={busy}\n onConfirm={() => {\n void onRevokeGrant(apiKey.id, grant.id);\n setConfirmOpen(false);\n }}\n />\n )}\n </div>\n <span className=\"text-xs break-words text-tertiary\">\n {strings.granted(grantedAge, grant.reason || undefined)}\n </span>\n </li>\n );\n}\n\nfunction KeyCell({\n apiKey,\n busy,\n onRevokeGrant,\n renderName,\n renderStatus,\n}: {\n apiKey: ApiKey;\n busy: boolean;\n onRevokeGrant: ((keyId: number, grantId: number) => Promise<void>) | undefined;\n renderName: ((apiKey: ApiKey) => ReactNode) | undefined;\n renderStatus: ((apiKey: ApiKey) => ReactNode) | undefined;\n}) {\n const strings = useUiStrings().apiKeysTable;\n const createdAge = useRelativeText(apiKey.createdAt);\n const grants = apiKey.grants ?? [];\n const status = renderStatus?.(apiKey);\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <CellStack primary={renderName?.(apiKey) ?? apiKey.name} secondary={strings.created(createdAge)} />\n {apiKey.ended && <EndedLine ended={apiKey.ended} />}\n {apiKey.idle && <IdleLine idle={apiKey.idle} />}\n {status}\n {grants.length > 0 && (\n <ul aria-label={strings.grantsOf(apiKey.name)} className=\"flex min-w-0 flex-col gap-1.5\">\n {grants.map((grant) => (\n <GrantChip key={grant.id} apiKey={apiKey} grant={grant} busy={busy} onRevokeGrant={apiKey.ended === undefined ? onRevokeGrant : undefined} />\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction buildColumns(\n strings: UiStrings[\"apiKeysTable\"],\n busyId: number | null | undefined,\n onRevoke: (id: number) => Promise<void>,\n roleEditor: KeyRoleEditor | undefined,\n onRevokeGrant: ((keyId: number, grantId: number) => Promise<void>) | undefined,\n renderName: ((apiKey: ApiKey) => ReactNode) | undefined,\n renderStatus: ((apiKey: ApiKey) => ReactNode) | undefined,\n): ColumnDef<ApiKey, unknown>[] {\n return [\n {\n id: \"key\",\n header: strings.columnKey,\n accessorFn: (k) => k.name,\n cell: ({ row }) => <KeyCell apiKey={row.original} busy={busyId === row.original.id} onRevokeGrant={onRevokeGrant} renderName={renderName} renderStatus={renderStatus} />,\n },\n {\n id: \"role\",\n header: strings.columnRole,\n accessorFn: (k) => k.roleLabel,\n cell: ({ row }) => <RoleCell apiKey={row.original} busy={busyId === row.original.id} editor={roleEditor} />,\n },\n {\n id: \"lastUsed\",\n header: strings.columnLastUsed,\n accessorFn: (k) => k.lastUsedAt ?? \"\",\n cell: ({ row }) => (\n <span className=\"text-secondary\">\n {row.original.lastUsedAt ? <RelativeTime at={row.original.lastUsedAt} /> : strings.never}\n </span>\n ),\n },\n {\n id: \"expires\",\n header: strings.columnExpires,\n accessorFn: (k) => k.expiresAt ?? \"\",\n cell: ({ row }) => (\n <span className=\"text-secondary\">\n {row.original.expiresAt ? <DateTimeText at={row.original.expiresAt} /> : strings.never}\n </span>\n ),\n },\n {\n id: \"actions\",\n header: \"\",\n enableSorting: false,\n cell: ({ row }) => (\n <div className=\"flex justify-end\">\n {row.original.ended === undefined && <RevokeCell apiKey={row.original} busy={busyId === row.original.id} onRevoke={onRevoke} />}\n </div>\n ),\n },\n ];\n}\n\nexport interface ApiKeysTableProps {\n keys: ApiKey[];\n onRevoke: (id: number) => Promise<void>;\n /** The id of a key currently mid-revoke, mid-role-change or mid-grant-removal. Disables just that row's controls. */\n busyId?: number | null;\n /** Makes each key's role editable in place (DX-4427). Omit for a read-only role badge. */\n roleEditor?: KeyRoleEditor;\n /** Makes each grant's chip removable (DX-4433). Fired only after the confirm dialog. Omit for read-only grant chips. */\n onRevokeGrant?: (keyId: number, grantId: number) => Promise<void>;\n /** Replaces a key's name text, e.g. with a link to what the key belongs to (DX-4487). Return `null` to keep the plain name. */\n renderName?: (apiKey: ApiKey) => ReactNode;\n /** One line under a key's name, e.g. a live status badge (DX-4487). Return `null` for a key with none. */\n renderStatus?: (apiKey: ApiKey) => ReactNode;\n className?: string;\n}\n\nexport function ApiKeysTable({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, className }: ApiKeysTableProps) {\n const strings = useUiStrings().apiKeysTable;\n return <DataTable columns={buildColumns(strings, busyId, onRevoke, roleEditor, onRevokeGrant, renderName, renderStatus)} data={keys} getRowId={(k) => String(k.id)} className={className} />;\n}\n"],"names":["RoleCell","apiKey","busy","editor","strings","roleKeyPicker","useUiStrings","jsx","Badge","own","options","role","refusal","roleUnavailableReason","o","StatusSelect","roleId","RevokeCell","onRevoke","confirmOpen","setConfirmOpen","useState","AlertDialog","IconButton","Icon","GrantChip","grant","onRevokeGrant","grantedAge","useRelativeText","jsxs","KeyCell","renderName","renderStatus","createdAge","grants","status","CellStack","EndedLine","IdleLine","buildColumns","busyId","roleEditor","k","row","RelativeTime","DateTimeText","ApiKeysTable","keys","className","DataTable"],"mappings":"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"}
1
+ {"version":3,"file":"ApiKeysTable.js","sources":["../../../src/components/rbac/ApiKeysTable.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport type { ColumnDef } from \"@tanstack/react-table\";\nimport { AlertDialog } from \"../Dialog\";\nimport { Badge } from \"../Badge\";\nimport { CellStack, DataTable } from \"../Table\";\nimport { Icon } from \"../Icon\";\nimport { IconButton } from \"../IconButton\";\nimport { StatusSelect, type StatusOption } from \"../StatusSelect\";\nimport { roleUnavailableReason } from \"./RoleKeyPicker\";\nimport type { Permission, Role } from \"./types\";\nimport { DateTimeText } from \"../DateTimeText\";\nimport { RelativeTime, useRelativeText } from \"../RelativeTime\";\nimport { useUiStrings } from \"../../lib/i18n\";\nimport type { UiStrings } from \"../../lib/i18n\";\nimport { EndedLine, IdleLine, type EndedState, type IdleState } from \"./EndedLine\";\n\n/* ----------------------------------------------------------------------------\n API KEYS TABLE (DX-4425)\n\n THE ONE ROW SHAPE EVERY KEY LIST SHARES. `ApiKeysPanel` (the keys a person\n made for themselves) and `AgentKeysList` (the keys a worker or an agent\n session minted on their behalf) list the same credential: a name, the role it\n acts with, when it was last used, when it expires, and a confirmed revoke.\n Both render this table so a column change lands once. It is not exported from\n the package: a consumer reaches it through the two components that frame it.\n\n PRESENTATIONAL ONLY, like `SessionsList`: `onRevoke` fires only after the\n `AlertDialog` confirms.\n\n THE ROLE CELL EDITS IN PLACE (DX-4427) when the consumer passes `roleEditor`:\n the role badge IS the control (`StatusSelect`), so raising or lowering a live\n key's permissions needs no dialog and no revoke. A role the owner may not\n grant is listed with the reason (`roleUnavailableReason`, the same rule\n `RoleKeyPicker` applies when a key is issued). A key with no `roleId`, or no\n `roleEditor`, keeps the read-only badge.\n\n A KEY'S GRANTS SIT UNDER ITS NAME (DX-4433). An agent can ask its owner for a\n permission its role lacks (`PermissionRequestPanel`); an approval adds it to\n that one key on top of its role. Each grant shows as a \"+ Label\" chip with\n when it was granted and why, as text rather than a tooltip so a phone reads it\n too. With `onRevokeGrant` each chip carries its own remove control behind a\n confirm: dropping a grant is not revoking the key, and the role is untouched.\n Without the handler the chips are read-only, and a key with no grants renders\n exactly as before.\n\n A ROW CAN LINK AND CARRY A LIVE STATUS (DX-4487). `renderName` replaces the\n name text (a consumer renders its router's link, so the library stays\n router-agnostic) and `renderStatus` adds one line under the name (a readiness\n badge for a worker's key). Both are given the row; either may return `null`\n for a key that has neither, and omitting them renders exactly as before.\n\n A ROW CAN SAY WHO STARTED IT (DX-6801). `renderStartedBy` adds a \"Started by\"\n column right after the key's name: the consumer draws who started or\n authorized the key's session (a person, or the agent session that started\n it), so the library stays free of the consumer's identity shapes. Omitting it\n renders no such column.\n ---------------------------------------------------------------------------- */\n\nexport interface ApiKey {\n id: number;\n name: string;\n /** The label of the role this key acts with. A label, not an id: a key can carry a role of a team other than the one whose\n * `roles` the create dialog offers, and only the consumer's server can name that one. */\n roleLabel: string;\n /** The id of that role, matching a `Role.id` in `roleEditor.roles`. Needed only for a key whose role is editable. */\n roleId?: string;\n /** ISO instant. */\n createdAt: string;\n /** ISO instant, or `null`/omitted if it has never been used. */\n lastUsedAt?: string | null;\n /** ISO instant, or `null`/omitted for a key with no expiry. */\n expiresAt?: string | null;\n /** Permissions added to this key on top of its role (DX-4433). Omit, or leave empty, for a key that holds only its role. */\n grants?: KeyGrant[];\n /** DX-5246: set on a key that has ended (revoked, expired or retired): the consumer's own words for how it ended (`label`) and the ISO instant it did (`at`). An ended row shows them under its name and offers no revoke, role change or grant removal. */\n ended?: EndedState;\n /** DX-5246: set on a key that still works but nobody is using (its session gone quiet, a script that stopped): the consumer's own words (`label`) and the ISO instant it was last in use (`at`). An idle row shows them under its name and keeps its revoke, role change and grant removal. */\n idle?: IdleState;\n}\n\n/** One permission an approved request added to a key, on top of its role. */\nexport interface KeyGrant {\n id: number;\n /** The permission key granted. Compared for equality only. */\n permissionKey: string;\n /** The permission's label, as shown on the chip and in the confirm. */\n label: string;\n /** ISO instant. */\n grantedAt: string;\n /** The reason the agent gave when it asked. Plain text. */\n reason?: string;\n}\n\n/** Makes a key's role editable in place. `roles` are the roles the owner may pick from: one list for every key, or a function\n * of the key when the keys do not share one (DX-4431: an agent session takes agent roles, a worker a human role that can manage workers). */\nexport interface KeyRoleEditor {\n roles: Role[] | ((apiKey: ApiKey) => Role[]);\n /** The permission catalog, used to name the permissions that make a role unavailable. */\n permissions: Permission[];\n /** What the owner holds. A role holding anything outside this set is listed but cannot be chosen. */\n ownPermissionKeys: string[];\n /** Fired when a different role is picked. The consumer saves it and refreshes `keys`. */\n onChange: (id: number, roleId: string) => Promise<void>;\n}\n\nfunction RoleCell({\n apiKey,\n busy,\n editor,\n}: {\n apiKey: ApiKey;\n busy: boolean;\n editor: KeyRoleEditor | undefined;\n}) {\n const { apiKeysTable: strings, roleKeyPicker } = useUiStrings();\n if (editor === undefined || apiKey.roleId === undefined || apiKey.ended !== undefined) {\n return <Badge tone=\"neutral\">{apiKey.roleLabel}</Badge>;\n }\n const own = new Set(editor.ownPermissionKeys);\n const roles = typeof editor.roles === \"function\" ? editor.roles(apiKey) : editor.roles;\n const options: StatusOption[] = roles.map((role) => {\n const refusal = roleUnavailableReason(role, own, editor.permissions, roleKeyPicker.unavailable);\n return { value: role.id, label: role.label, tone: \"neutral\", ...(refusal === null ? {} : { refusal }) };\n });\n // A key can carry a role outside the offered set (another team's); it is shown, never silently swapped for a listed one.\n if (!options.some((o) => o.value === apiKey.roleId)) {\n options.unshift({ value: apiKey.roleId, label: apiKey.roleLabel, tone: \"neutral\", refusal: strings.roleNotAssignable });\n }\n return (\n <StatusSelect\n value={apiKey.roleId}\n options={options}\n aria-label={strings.roleOf(apiKey.name)}\n disabled={busy}\n onValueChange={(roleId) => {\n if (roleId !== apiKey.roleId) void editor.onChange(apiKey.id, roleId);\n }}\n />\n );\n}\n\nfunction RevokeCell({\n apiKey,\n busy,\n onRevoke,\n}: {\n apiKey: ApiKey;\n busy: boolean;\n onRevoke: (id: number) => Promise<void>;\n}) {\n const strings = useUiStrings().apiKeysTable;\n const [confirmOpen, setConfirmOpen] = useState(false);\n\n return (\n <AlertDialog\n open={confirmOpen}\n onOpenChange={setConfirmOpen}\n trigger={\n <IconButton\n icon={<Icon name=\"trash-2\" size=\"sm\" />}\n label={strings.revoke(apiKey.name)}\n tone=\"danger\"\n size=\"sm\"\n disabledReason={busy ? strings.revoking : undefined}\n />\n }\n title={strings.revokeTitle(apiKey.name)}\n description={strings.revokeDescription}\n confirmLabel={strings.revokeConfirm}\n destructive\n loading={busy}\n onConfirm={() => {\n void onRevoke(apiKey.id);\n setConfirmOpen(false);\n }}\n />\n );\n}\n\nfunction GrantChip({\n apiKey,\n grant,\n busy,\n onRevokeGrant,\n}: {\n apiKey: ApiKey;\n grant: KeyGrant;\n busy: boolean;\n onRevokeGrant: ((keyId: number, grantId: number) => Promise<void>) | undefined;\n}) {\n const strings = useUiStrings().apiKeysTable;\n const grantedAge = useRelativeText(grant.grantedAt);\n const [confirmOpen, setConfirmOpen] = useState(false);\n return (\n <li className=\"flex min-w-0 flex-col gap-0.5\">\n <div className=\"flex min-w-0 items-center gap-1\">\n <Badge tone=\"accent\" size=\"sm\">{`+ ${grant.label}`}</Badge>\n {onRevokeGrant && (\n <AlertDialog\n open={confirmOpen}\n onOpenChange={setConfirmOpen}\n trigger={\n <IconButton\n icon={<Icon name=\"x\" size=\"xs\" />}\n label={strings.removeGrant(grant.label, apiKey.name)}\n tone=\"danger\"\n size=\"sm\"\n disabledReason={busy ? strings.updating : undefined}\n />\n }\n title={strings.removeGrantTitle(grant.label)}\n description={strings.removeGrantDescription}\n confirmLabel={strings.removeGrantConfirm}\n destructive\n loading={busy}\n onConfirm={() => {\n void onRevokeGrant(apiKey.id, grant.id);\n setConfirmOpen(false);\n }}\n />\n )}\n </div>\n <span className=\"text-xs break-words text-tertiary\">\n {strings.granted(grantedAge, grant.reason || undefined)}\n </span>\n </li>\n );\n}\n\nfunction KeyCell({\n apiKey,\n busy,\n onRevokeGrant,\n renderName,\n renderStatus,\n}: {\n apiKey: ApiKey;\n busy: boolean;\n onRevokeGrant: ((keyId: number, grantId: number) => Promise<void>) | undefined;\n renderName: ((apiKey: ApiKey) => ReactNode) | undefined;\n renderStatus: ((apiKey: ApiKey) => ReactNode) | undefined;\n}) {\n const strings = useUiStrings().apiKeysTable;\n const createdAge = useRelativeText(apiKey.createdAt);\n const grants = apiKey.grants ?? [];\n const status = renderStatus?.(apiKey);\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <CellStack primary={renderName?.(apiKey) ?? apiKey.name} secondary={strings.created(createdAge)} />\n {apiKey.ended && <EndedLine ended={apiKey.ended} />}\n {apiKey.idle && <IdleLine idle={apiKey.idle} />}\n {status}\n {grants.length > 0 && (\n <ul aria-label={strings.grantsOf(apiKey.name)} className=\"flex min-w-0 flex-col gap-1.5\">\n {grants.map((grant) => (\n <GrantChip key={grant.id} apiKey={apiKey} grant={grant} busy={busy} onRevokeGrant={apiKey.ended === undefined ? onRevokeGrant : undefined} />\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction buildColumns(\n strings: UiStrings[\"apiKeysTable\"],\n busyId: number | null | undefined,\n onRevoke: (id: number) => Promise<void>,\n roleEditor: KeyRoleEditor | undefined,\n onRevokeGrant: ((keyId: number, grantId: number) => Promise<void>) | undefined,\n renderName: ((apiKey: ApiKey) => ReactNode) | undefined,\n renderStatus: ((apiKey: ApiKey) => ReactNode) | undefined,\n renderStartedBy: ((apiKey: ApiKey) => ReactNode) | undefined,\n): ColumnDef<ApiKey, unknown>[] {\n const startedBy: ColumnDef<ApiKey, unknown>[] =\n renderStartedBy === undefined ? [] : [{ id: \"startedBy\", header: strings.columnStartedBy, enableSorting: false, cell: ({ row }) => renderStartedBy(row.original) }];\n return [\n {\n id: \"key\",\n header: strings.columnKey,\n accessorFn: (k) => k.name,\n cell: ({ row }) => <KeyCell apiKey={row.original} busy={busyId === row.original.id} onRevokeGrant={onRevokeGrant} renderName={renderName} renderStatus={renderStatus} />,\n },\n ...startedBy,\n {\n id: \"role\",\n header: strings.columnRole,\n accessorFn: (k) => k.roleLabel,\n cell: ({ row }) => <RoleCell apiKey={row.original} busy={busyId === row.original.id} editor={roleEditor} />,\n },\n {\n id: \"lastUsed\",\n header: strings.columnLastUsed,\n accessorFn: (k) => k.lastUsedAt ?? \"\",\n cell: ({ row }) => (\n <span className=\"text-secondary\">\n {row.original.lastUsedAt ? <RelativeTime at={row.original.lastUsedAt} /> : strings.never}\n </span>\n ),\n },\n {\n id: \"expires\",\n header: strings.columnExpires,\n accessorFn: (k) => k.expiresAt ?? \"\",\n cell: ({ row }) => (\n <span className=\"text-secondary\">\n {row.original.expiresAt ? <DateTimeText at={row.original.expiresAt} /> : strings.never}\n </span>\n ),\n },\n {\n id: \"actions\",\n header: \"\",\n enableSorting: false,\n cell: ({ row }) => (\n <div className=\"flex justify-end\">\n {row.original.ended === undefined && <RevokeCell apiKey={row.original} busy={busyId === row.original.id} onRevoke={onRevoke} />}\n </div>\n ),\n },\n ];\n}\n\nexport interface ApiKeysTableProps {\n keys: ApiKey[];\n onRevoke: (id: number) => Promise<void>;\n /** The id of a key currently mid-revoke, mid-role-change or mid-grant-removal. Disables just that row's controls. */\n busyId?: number | null;\n /** Makes each key's role editable in place (DX-4427). Omit for a read-only role badge. */\n roleEditor?: KeyRoleEditor;\n /** Makes each grant's chip removable (DX-4433). Fired only after the confirm dialog. Omit for read-only grant chips. */\n onRevokeGrant?: (keyId: number, grantId: number) => Promise<void>;\n /** Replaces a key's name text, e.g. with a link to what the key belongs to (DX-4487). Return `null` to keep the plain name. */\n renderName?: (apiKey: ApiKey) => ReactNode;\n /** One line under a key's name, e.g. a live status badge (DX-4487). Return `null` for a key with none. */\n renderStatus?: (apiKey: ApiKey) => ReactNode;\n /** Adds a \"Started by\" column right after the key's name, drawn per row (DX-6801). Omit for no such column. */\n renderStartedBy?: (apiKey: ApiKey) => ReactNode;\n className?: string;\n}\n\nexport function ApiKeysTable({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, renderStartedBy, className }: ApiKeysTableProps) {\n const strings = useUiStrings().apiKeysTable;\n return <DataTable columns={buildColumns(strings, busyId, onRevoke, roleEditor, onRevokeGrant, renderName, renderStatus, renderStartedBy)} data={keys} getRowId={(k) => String(k.id)} className={className} />;\n}\n"],"names":["RoleCell","apiKey","busy","editor","strings","roleKeyPicker","useUiStrings","jsx","Badge","own","options","role","refusal","roleUnavailableReason","o","StatusSelect","roleId","RevokeCell","onRevoke","confirmOpen","setConfirmOpen","useState","AlertDialog","IconButton","Icon","GrantChip","grant","onRevokeGrant","grantedAge","useRelativeText","jsxs","KeyCell","renderName","renderStatus","createdAge","grants","status","CellStack","EndedLine","IdleLine","buildColumns","busyId","roleEditor","renderStartedBy","startedBy","row","k","RelativeTime","DateTimeText","ApiKeysTable","keys","className","DataTable"],"mappings":"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"}
@@ -102,6 +102,7 @@ const d = {
102
102
  },
103
103
  apiKeysTable: {
104
104
  columnKey: "Key",
105
+ columnStartedBy: "Started by",
105
106
  columnRole: "Role",
106
107
  columnLastUsed: "Last used",
107
108
  columnExpires: "Expires",
@@ -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: 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 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":"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"}
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":"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"}
@@ -14,7 +14,9 @@ export interface AgentKeysListProps {
14
14
  renderName?: (apiKey: ApiKey) => ReactNode;
15
15
  /** One line under a key's name, e.g. the worker's readiness badge (DX-4487). Return `null` for a key with none. */
16
16
  renderStatus?: (apiKey: ApiKey) => ReactNode;
17
+ /** Adds a "Started by" column right after the name: who started or authorized the key's session (DX-6801). Omit for no such column. */
18
+ renderStartedBy?: (apiKey: ApiKey) => ReactNode;
17
19
  emptyState?: ReactNode;
18
20
  className?: string;
19
21
  }
20
- export declare function AgentKeysList({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, emptyState, className }: AgentKeysListProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined>;
22
+ export declare function AgentKeysList({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, renderStartedBy, emptyState, className }: AgentKeysListProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined>;
@@ -58,6 +58,8 @@ export interface ApiKeysTableProps {
58
58
  renderName?: (apiKey: ApiKey) => ReactNode;
59
59
  /** One line under a key's name, e.g. a live status badge (DX-4487). Return `null` for a key with none. */
60
60
  renderStatus?: (apiKey: ApiKey) => ReactNode;
61
+ /** Adds a "Started by" column right after the key's name, drawn per row (DX-6801). Omit for no such column. */
62
+ renderStartedBy?: (apiKey: ApiKey) => ReactNode;
61
63
  className?: string;
62
64
  }
63
- export declare function ApiKeysTable({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, className }: ApiKeysTableProps): import("react").JSX.Element;
65
+ export declare function ApiKeysTable({ keys, onRevoke, busyId, roleEditor, onRevokeGrant, renderName, renderStatus, renderStartedBy, className }: ApiKeysTableProps): import("react").JSX.Element;
@@ -207,6 +207,8 @@ export interface RbacStrings {
207
207
  apiKeysTable: {
208
208
  /** Column header: the key's name. */
209
209
  columnKey: string;
210
+ /** Column header: who started or authorized the key's session (`AgentKeysList` `renderStartedBy`, DX-6801). */
211
+ columnStartedBy: string;
210
212
  /** Column header: the key's role. */
211
213
  columnRole: string;
212
214
  /** Column header: when the key was last used. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@50arms/ui",
3
- "version": "35.1.0",
3
+ "version": "35.2.0",
4
4
  "type": "module",
5
5
  "description": "50 Arms — a domain-agnostic React design system with motion as a first-class primitive.",
6
6
  "license": "MIT",