@parallelworks/ui 0.76.0 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/README.md +30 -5
  2. package/dist/access/AccessDrawer.d.ts +28 -7
  3. package/dist/access/AccessDrawer.js +216 -35
  4. package/dist/access/AccessList.d.ts +19 -1
  5. package/dist/access/AccessList.js +220 -9
  6. package/dist/access/GrantView.d.ts +3 -1
  7. package/dist/access/GrantView.js +17 -4
  8. package/dist/access/PrincipalPicker.js +5 -5
  9. package/dist/access/focus.js +1 -1
  10. package/dist/access/index.d.ts +2 -2
  11. package/dist/access/index.js +2 -2
  12. package/dist/access/strings.d.ts +18 -0
  13. package/dist/access/strings.js +20 -2
  14. package/dist/access/types.d.ts +26 -0
  15. package/dist/ai/adapter/types.d.ts +1 -0
  16. package/dist/ai/components/AllocationSelector.js +1 -1
  17. package/dist/ai/components/AttachmentManager.js +5 -5
  18. package/dist/ai/components/AttachmentUpload.js +2 -2
  19. package/dist/ai/components/BranchNavigator.js +1 -1
  20. package/dist/ai/components/ChatActivity.d.ts +2 -0
  21. package/dist/ai/components/ChatActivity.js +31 -0
  22. package/dist/ai/components/ChatEmptyState.js +3 -3
  23. package/dist/ai/components/ChatInput.js +3 -5
  24. package/dist/ai/components/ChatLayout.js +1 -1
  25. package/dist/ai/components/ChatMessage.js +1 -1
  26. package/dist/ai/components/ChatMessageList.js +2 -2
  27. package/dist/ai/components/ChatSidebar.js +3 -3
  28. package/dist/ai/components/ChatThread.js +4 -4
  29. package/dist/ai/components/ComposerAddMenu.js +9 -20
  30. package/dist/ai/components/ModelSelector.js +3 -3
  31. package/dist/ai/components/PastedText.js +5 -5
  32. package/dist/ai/components/SessionView.js +5 -2
  33. package/dist/ai/components/ShareDialog.js +3 -3
  34. package/dist/ai/components/SlashMenu.d.ts +31 -4
  35. package/dist/ai/components/SlashMenu.js +36 -63
  36. package/dist/ai/components/agent/ActivityLine.js +1 -1
  37. package/dist/ai/components/agent/AgentMessageParts.d.ts +1 -1
  38. package/dist/ai/components/agent/AgentMessageParts.js +44 -18
  39. package/dist/ai/components/conversationActions.js +3 -3
  40. package/dist/ai/core/ChatProvider.js +11 -2
  41. package/dist/ai/core/config.d.ts +10 -1
  42. package/dist/ai/core/config.js +1 -1
  43. package/dist/ai/index.d.ts +1 -1
  44. package/dist/ai/strings.d.ts +2 -0
  45. package/dist/ai/strings.js +2 -1
  46. package/dist/ai/types.d.ts +3 -0
  47. package/dist/ai/ui/ConversationSidebar.js +3 -3
  48. package/dist/ai/ui/sidebar.js +3 -3
  49. package/dist/assets/yaml.worker-DOBV2lND.js +884 -0
  50. package/dist/components/ActionMenu.d.ts +38 -9
  51. package/dist/components/ActionMenu.js +48 -22
  52. package/dist/components/Avatar.d.ts +66 -6
  53. package/dist/components/Avatar.js +130 -18
  54. package/dist/components/Breadcrumbs.d.ts +4 -0
  55. package/dist/components/Breadcrumbs.js +26 -10
  56. package/dist/components/Button.d.ts +3 -2
  57. package/dist/components/Button.js +11 -1
  58. package/dist/components/Callout.d.ts +3 -2
  59. package/dist/components/Callout.js +3 -2
  60. package/dist/components/Card.d.ts +33 -9
  61. package/dist/components/Card.js +24 -8
  62. package/dist/components/Checkbox.d.ts +3 -1
  63. package/dist/components/Checkbox.js +4 -2
  64. package/dist/components/ColorInput.js +1 -1
  65. package/dist/components/Combobox.d.ts +23 -0
  66. package/dist/components/Combobox.js +252 -86
  67. package/dist/components/ConfirmModal.d.ts +26 -2
  68. package/dist/components/ConfirmModal.js +81 -15
  69. package/dist/components/ContextMenu.d.ts +29 -2
  70. package/dist/components/ContextMenu.js +60 -8
  71. package/dist/components/CopyButton.d.ts +21 -8
  72. package/dist/components/CopyButton.js +29 -9
  73. package/dist/components/CreateModal.d.ts +16 -4
  74. package/dist/components/CreateModal.js +27 -16
  75. package/dist/components/DatePicker.d.ts +31 -1
  76. package/dist/components/DatePicker.js +178 -47
  77. package/dist/components/DescriptionList.d.ts +13 -3
  78. package/dist/components/DescriptionList.js +43 -11
  79. package/dist/components/Disclosure.d.ts +10 -2
  80. package/dist/components/Disclosure.js +18 -7
  81. package/dist/components/Drawer.js +5 -5
  82. package/dist/components/EmptyState.d.ts +12 -4
  83. package/dist/components/EmptyState.js +18 -10
  84. package/dist/components/ErrorPage.d.ts +40 -0
  85. package/dist/components/ErrorPage.js +101 -0
  86. package/dist/components/ExternalLink.d.ts +4 -1
  87. package/dist/components/ExternalLink.js +4 -5
  88. package/dist/components/Field.d.ts +21 -6
  89. package/dist/components/Field.js +32 -16
  90. package/dist/components/FileButton.d.ts +19 -0
  91. package/dist/components/FileButton.js +32 -0
  92. package/dist/components/HoverCard.d.ts +26 -6
  93. package/dist/components/HoverCard.js +11 -5
  94. package/dist/components/IconButton.js +4 -2
  95. package/dist/components/InfoTip.js +3 -3
  96. package/dist/components/Input.d.ts +33 -3
  97. package/dist/components/Input.js +149 -14
  98. package/dist/components/Kbd.d.ts +40 -0
  99. package/dist/components/Kbd.js +168 -0
  100. package/dist/components/Listbox.d.ts +103 -0
  101. package/dist/components/Listbox.js +190 -0
  102. package/dist/components/Loader.d.ts +8 -2
  103. package/dist/components/Loader.js +16 -1
  104. package/dist/components/Markdown.js +1 -1
  105. package/dist/components/MarkdownImpl.js +1 -1
  106. package/dist/components/Menu.d.ts +20 -2
  107. package/dist/components/Menu.js +48 -19
  108. package/dist/components/MenuEntries.d.ts +38 -2
  109. package/dist/components/MenuEntries.js +266 -39
  110. package/dist/components/Meter.d.ts +50 -11
  111. package/dist/components/Meter.js +71 -21
  112. package/dist/components/Modal.d.ts +9 -3
  113. package/dist/components/Modal.js +68 -29
  114. package/dist/components/OneTimeCodeInput.js +1 -1
  115. package/dist/components/PageHeader.js +111 -7
  116. package/dist/components/PageHeaderAction.d.ts +8 -3
  117. package/dist/components/PageHeaderAction.js +122 -34
  118. package/dist/components/Pagination.d.ts +13 -1
  119. package/dist/components/Pagination.js +90 -19
  120. package/dist/components/Popover.d.ts +13 -2
  121. package/dist/components/Popover.js +20 -21
  122. package/dist/components/Provider.d.ts +140 -3
  123. package/dist/components/Provider.js +142 -12
  124. package/dist/components/RefreshButton.d.ts +13 -6
  125. package/dist/components/RefreshButton.js +17 -9
  126. package/dist/components/RunStatusIcon.d.ts +16 -7
  127. package/dist/components/RunStatusIcon.js +21 -8
  128. package/dist/components/Section.d.ts +11 -4
  129. package/dist/components/Section.js +33 -22
  130. package/dist/components/SegmentedControl.d.ts +16 -3
  131. package/dist/components/SegmentedControl.js +7 -3
  132. package/dist/components/Select.d.ts +19 -3
  133. package/dist/components/Select.js +114 -68
  134. package/dist/components/SelectionCopy.d.ts +10 -0
  135. package/dist/components/SelectionCopy.js +105 -0
  136. package/dist/components/SettingModeOption.js +1 -1
  137. package/dist/components/SettingsCard.js +1 -1
  138. package/dist/components/Skeleton.js +1 -1
  139. package/dist/components/StatusBadge.d.ts +55 -10
  140. package/dist/components/StatusBadge.js +91 -15
  141. package/dist/components/StickyBar.js +1 -1
  142. package/dist/components/Table.d.ts +22 -4
  143. package/dist/components/Table.js +46 -24
  144. package/dist/components/Tabs.d.ts +9 -4
  145. package/dist/components/Tabs.js +9 -4
  146. package/dist/components/Tag.d.ts +49 -0
  147. package/dist/components/Tag.js +199 -0
  148. package/dist/components/ThemeEditor.js +1 -1
  149. package/dist/components/Toast.js +1 -1
  150. package/dist/components/ToggleGroup.d.ts +4 -1
  151. package/dist/components/ToggleGroup.js +30 -13
  152. package/dist/components/Tooltip.d.ts +9 -3
  153. package/dist/components/Tooltip.js +55 -39
  154. package/dist/components/buttonClasses.d.ts +5 -2
  155. package/dist/components/buttonClasses.js +11 -10
  156. package/dist/components/chart.d.ts +69 -0
  157. package/dist/components/chart.js +145 -0
  158. package/dist/components/comboboxItems.d.ts +7 -1
  159. package/dist/components/comboboxItems.js +6 -2
  160. package/dist/components/dismiss.d.ts +5 -1
  161. package/dist/components/dismiss.js +6 -2
  162. package/dist/components/floating.d.ts +4 -4
  163. package/dist/components/floating.js +5 -5
  164. package/dist/components/headerActionsFit.d.ts +37 -0
  165. package/dist/components/headerActionsFit.js +81 -0
  166. package/dist/components/pageHeaderStore.d.ts +3 -0
  167. package/dist/components/pageHeaderStore.js +3 -0
  168. package/dist/components/pathBreaks.js +2 -2
  169. package/dist/components/popupContainer.d.ts +17 -0
  170. package/dist/components/popupContainer.js +69 -0
  171. package/dist/components/relativeTime.d.ts +21 -10
  172. package/dist/components/relativeTime.js +50 -22
  173. package/dist/components/segmented.d.ts +18 -4
  174. package/dist/components/segmented.js +48 -6
  175. package/dist/components/typedDate.d.ts +5 -0
  176. package/dist/components/typedDate.js +50 -0
  177. package/dist/components/useClosingValue.d.ts +4 -0
  178. package/dist/components/useClosingValue.js +12 -0
  179. package/dist/components/useCopy.d.ts +6 -0
  180. package/dist/components/useCopy.js +3 -3
  181. package/dist/components/useNarrow.d.ts +2 -0
  182. package/dist/components/useNarrow.js +16 -0
  183. package/dist/editor/Editor.js +1 -1
  184. package/dist/editor/FormCodePanel.js +1 -1
  185. package/dist/editor/Monaco.js +1 -1
  186. package/dist/editor/workers.js +1 -1
  187. package/dist/file-explorer/FileExplorer.js +16 -15
  188. package/dist/file-explorer/FileExplorerContext.js +2 -2
  189. package/dist/file-explorer/FilePreview/Viewer.js +3 -3
  190. package/dist/file-explorer/FilePreview/index.js +2 -2
  191. package/dist/file-explorer/FileRowsWindow.js +3 -3
  192. package/dist/file-explorer/FileTable.js +1 -1
  193. package/dist/file-explorer/LoadMoreRow.js +1 -1
  194. package/dist/file-explorer/TreeView.js +5 -5
  195. package/dist/file-explorer/helpers.js +2 -2
  196. package/dist/file-explorer/toasts.js +2 -2
  197. package/dist/form/Fields/CheckboxGroupField.js +1 -1
  198. package/dist/form/Fields/DropdownField.js +1 -1
  199. package/dist/form/Fields/DurationField.js +2 -2
  200. package/dist/form/Fields/MultiDropdownField.js +1 -1
  201. package/dist/form/Fields/NumberField.js +1 -1
  202. package/dist/form/Fields/ObjectField.js +1 -1
  203. package/dist/form/Fields/RangeField.js +1 -1
  204. package/dist/form/Fields/StringField.js +1 -1
  205. package/dist/form/Form.js +3 -3
  206. package/dist/form/FormLayout.js +1 -1
  207. package/dist/form/Wizard/WizardContainer.js +1 -1
  208. package/dist/form/Wizard/WizardNavigation.js +1 -1
  209. package/dist/form/Wizard/WizardStepContent.js +1 -1
  210. package/dist/form/fieldRegistry.js +1 -1
  211. package/dist/form/formEditing.js +1 -1
  212. package/dist/format.d.ts +17 -7
  213. package/dist/format.js +39 -16
  214. package/dist/graph/AnnotationBanner.js +2 -2
  215. package/dist/graph/Connectors.js +5 -5
  216. package/dist/graph/DependencyGraph.js +10 -9
  217. package/dist/graph/GraphEditor.js +4 -4
  218. package/dist/graph/GraphEditorDialogs.js +13 -12
  219. package/dist/graph/GraphNode.js +1 -1
  220. package/dist/graph/InputDialog.js +5 -5
  221. package/dist/graph/InputsEditor.js +7 -7
  222. package/dist/graph/MatrixGroup.js +2 -2
  223. package/dist/graph/ProblemsButton.js +3 -3
  224. package/dist/graph/Reveal.js +1 -1
  225. package/dist/graph/RunWarningsList.js +1 -1
  226. package/dist/graph/ShortcutsButton.js +25 -8
  227. package/dist/graph/StepSummaries.js +1 -1
  228. package/dist/graph/TreeView.js +2 -2
  229. package/dist/graph/WorkflowSettingsDialog.js +3 -3
  230. package/dist/graph/editorFields.js +3 -3
  231. package/dist/graph/editorPrimitives.js +1 -1
  232. package/dist/graph/editorRows.js +5 -5
  233. package/dist/graph/fieldProblems.js +2 -2
  234. package/dist/graph/inputRefs.js +7 -6
  235. package/dist/graph/stepWith.js +2 -2
  236. package/dist/index.d.ts +30 -21
  237. package/dist/index.js +20 -12
  238. package/dist/list/ActionToolbar.d.ts +4 -0
  239. package/dist/list/ActionToolbar.js +35 -12
  240. package/dist/list/ListFilterBar.d.ts +42 -0
  241. package/dist/list/ListFilterBar.js +789 -0
  242. package/dist/list/ListPage.d.ts +42 -4
  243. package/dist/list/ListPage.js +56 -22
  244. package/dist/list/ListTable.d.ts +27 -3
  245. package/dist/list/ListTable.js +48 -23
  246. package/dist/list/ListToolbar.d.ts +31 -0
  247. package/dist/list/ListToolbar.js +43 -0
  248. package/dist/list/ListViewControls.d.ts +8 -4
  249. package/dist/list/ListViewControls.js +22 -14
  250. package/dist/list/UserHoverCard.d.ts +8 -2
  251. package/dist/list/UserHoverCard.js +26 -13
  252. package/dist/list/filterModel.d.ts +122 -0
  253. package/dist/list/filterModel.js +308 -0
  254. package/dist/list/index.d.ts +6 -2
  255. package/dist/list/index.js +6 -2
  256. package/dist/list/listSearch.d.ts +1 -1
  257. package/dist/list/listSearch.js +8 -4
  258. package/dist/list/listView.d.ts +24 -2
  259. package/dist/list/listView.js +47 -45
  260. package/dist/list/rowMenu.d.ts +10 -5
  261. package/dist/list/rowMenu.js +17 -7
  262. package/dist/list/useListFilters.d.ts +68 -0
  263. package/dist/list/useListFilters.js +252 -0
  264. package/dist/logviewer/LogViewer.js +4 -4
  265. package/dist/styles/theme.css +94 -0
  266. package/dist/styles.css +1 -1
  267. package/package.json +11 -11
  268. package/dist/assets/yaml.worker-k9AdOqzf.js +0 -1441
  269. package/dist/components/fullscreen.d.ts +0 -4
  270. package/dist/components/fullscreen.js +0 -18
@@ -1,15 +1,18 @@
1
1
  import { cx } from "../cx.js";
2
- import { AddIcon, ChevronRightIcon, LockIcon, OrganizationIcon, TrashIcon } from "../icons.js";
2
+ import { AddIcon, ChevronRightIcon, KeyIcon, LockIcon, OrganizationIcon, TrashIcon } from "../icons.js";
3
3
  import { Loader } from "../components/Loader.js";
4
+ import { menuDivider } from "../components/MenuEntries.js";
5
+ import { Avatar } from "../components/Avatar.js";
4
6
  import { Button } from "../components/Button.js";
5
7
  import { IconButton } from "../components/IconButton.js";
6
8
  import { Callout } from "../components/Callout.js";
7
9
  import { collapsePanelClassName } from "../components/Disclosure.js";
10
+ import { Select } from "../components/Select.js";
8
11
  import { StatusBadge } from "../components/StatusBadge.js";
9
12
  import { alsoHas, firstOfEach, isOwner, key, overlapOf, removalOf } from "./model.js";
10
13
  import { PrincipalTile } from "./PrincipalPicker.js";
11
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
14
  import { useEffect, useId, useRef } from "react";
15
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
13
16
  import { Collapsible } from "@base-ui/react/collapsible";
14
17
  //#region src/access/AccessList.tsx
15
18
  /** The id the owner's section has among the roles' sections. */
@@ -20,6 +23,21 @@ var aboutOf = (principal, t) => principal.kind === "user" ? principal.detail : p
20
23
  /** Where a role someone has elsewhere comes from, as "through" reads it. */
21
24
  var sourceOf = (holding) => holding.through?.name ?? holding.from ?? "";
22
25
  /** Stands where a remove button would, on a row that can't be removed here. */
26
+ /** A role named where a row's role select would sit, so read-only rows line up with
27
+ * editable ones: the select's width, border and padding, without the box. */
28
+ function RoleText({ children }) {
29
+ return /* @__PURE__ */ jsx("span", {
30
+ className: "w-36 shrink-0 wrap-anywhere border border-transparent px-2 text-xs text-(--theme-muted-text-color)",
31
+ children
32
+ });
33
+ }
34
+ /** Holds the remove button's place on a row that has none. */
35
+ function NoAction() {
36
+ return /* @__PURE__ */ jsx("span", {
37
+ "aria-hidden": "true",
38
+ className: "size-7 shrink-0"
39
+ });
40
+ }
23
41
  function Locked() {
24
42
  return /* @__PURE__ */ jsx("span", {
25
43
  className: "flex size-7 items-center justify-center text-(--theme-muted-text-color)",
@@ -30,12 +48,13 @@ function Locked() {
30
48
  });
31
49
  }
32
50
  /** A role or principal whose rows fold under it. */
33
- function Section({ id, open, onOpenChange, disabled, lead, title, description, aside, narrowAside, notice, children }) {
51
+ function Section({ id, open, onOpenChange, disabled, lead, title, description, aside, narrowAside, notice, onContextMenu, children }) {
34
52
  return /* @__PURE__ */ jsxs(Collapsible.Root, {
35
53
  open: open && !disabled,
36
54
  onOpenChange,
37
55
  disabled,
38
56
  className: "border-b border-(--theme-border)",
57
+ onContextMenu,
39
58
  children: [
40
59
  /* @__PURE__ */ jsxs(Collapsible.Trigger, {
41
60
  id,
@@ -87,9 +106,10 @@ function Section({ id, open, onOpenChange, disabled, lead, title, description, a
87
106
  });
88
107
  }
89
108
  /** A line under a section: a principal under a role, or a role under a principal. */
90
- function Row({ lead, title, meta, action, muted }) {
109
+ function Row({ lead, title, meta, action, muted, onContextMenu }) {
91
110
  return /* @__PURE__ */ jsxs("div", {
92
111
  className: "flex items-center gap-3 py-1.5 ps-11 pe-4 @min-[30rem]/access:ps-11",
112
+ onContextMenu,
93
113
  children: [
94
114
  lead,
95
115
  /* @__PURE__ */ jsxs("div", {
@@ -173,7 +193,7 @@ function RemoveConfirm({ model, removal, saving, onCancel, onConfirm, t }) {
173
193
  children: impact.owner ? /* @__PURE__ */ jsx("p", {
174
194
  className: "m-0 text-(--theme-muted-text-color)",
175
195
  children: t.ownerLosesNothing
176
- }) : impact.lost.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
196
+ }) : impact.lost.length > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
177
197
  /* @__PURE__ */ jsx("p", {
178
198
  className: "m-0 text-(--theme-muted-text-color)",
179
199
  children: t.losesIntro(principal.kind, principal.memberCount)
@@ -277,7 +297,7 @@ function ByRole({ model, shown, order, expanded, onExpandedChange, filtering, ac
277
297
  notice: failure,
278
298
  title: role.name,
279
299
  description: role.description,
280
- aside: /* @__PURE__ */ jsxs(Fragment, { children: [everyoneTag, count] }),
300
+ aside: /* @__PURE__ */ jsxs(Fragment$1, { children: [everyoneTag, count] }),
281
301
  narrowAside: everyoneTag && !count ? /* @__PURE__ */ jsx("span", {
282
302
  className: "mt-1 inline-flex",
283
303
  children: everyoneTag
@@ -310,6 +330,11 @@ function ByRole({ model, shown, order, expanded, onExpandedChange, filtering, ac
310
330
  const hint = overlapHint(overlapOf(model, principalId, role), t);
311
331
  const label = t.removeRole(principalLabel(principal, t), role.name);
312
332
  return /* @__PURE__ */ jsx(Row, {
333
+ onContextMenu: rowMenu(actions, () => rowEntries(model, principal, actions, t, {
334
+ principalId,
335
+ roleIds: [roleId],
336
+ all: false
337
+ })),
313
338
  lead,
314
339
  title: principalLabel(principal, t),
315
340
  meta: [aboutOf(principal, t), hint].filter(Boolean).join(" · "),
@@ -349,7 +374,7 @@ function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions,
349
374
  const room = owner ? 1 : 2;
350
375
  const badges = badgeRoles.length <= room ? badgeRoles : badgeRoles.slice(0, room - 1);
351
376
  const hidden = badgeRoles.slice(badges.length);
352
- const roleBadges = /* @__PURE__ */ jsxs(Fragment, { children: [
377
+ const roleBadges = /* @__PURE__ */ jsxs(Fragment$1, { children: [
353
378
  owner && /* @__PURE__ */ jsx(StatusBadge, {
354
379
  size: "md",
355
380
  variant: "info",
@@ -378,6 +403,11 @@ function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions,
378
403
  principal,
379
404
  className: "hidden @min-[30rem]/access:flex"
380
405
  }),
406
+ onContextMenu: held.length > 0 ? rowMenu(actions, () => rowEntries(model, principal, actions, t, {
407
+ principalId,
408
+ roleIds: held.map((role) => role.id),
409
+ all: true
410
+ })) : void 0,
381
411
  notice: failure,
382
412
  title: principalLabel(principal, t),
383
413
  description: everyone ? t.everyoneJoinLater : aboutOf(principal, t),
@@ -393,7 +423,7 @@ function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions,
393
423
  onCancel: actions.onCancelRemove,
394
424
  onConfirm: () => actions.removal && actions.onRemove(actions.removal),
395
425
  t
396
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [
426
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
397
427
  owner && /* @__PURE__ */ jsx(Row, {
398
428
  title: /* @__PURE__ */ jsx("span", {
399
429
  className: "font-medium",
@@ -482,5 +512,186 @@ function RoleRow({ model, principal, role, actions, t }) {
482
512
  })
483
513
  });
484
514
  }
515
+ /** A row's right-click menu, which repeats what its buttons do; none while read-only. */
516
+ function rowMenu(actions, entries) {
517
+ if (actions.readOnly) return;
518
+ return (e) => {
519
+ e.stopPropagation();
520
+ actions.openMenu(e, entries());
521
+ };
522
+ }
523
+ /** A principal's row menu: its role, where each holds one, more roles otherwise, then removal. */
524
+ function rowEntries(model, principal, actions, t, removal) {
525
+ const held = new Set((model.held.get(principal.id) ?? []).map((role) => role.id));
526
+ const lead = actions.singleRole ? [{
527
+ label: t.roleMenu,
528
+ icon: /* @__PURE__ */ jsx(KeyIcon, {}),
529
+ items: model.grantable.map((role) => ({
530
+ label: role.name,
531
+ description: role.description,
532
+ checked: held.has(role.id),
533
+ onClick: () => {
534
+ if (!held.has(role.id) || held.size > 1) actions.onChangeRole(principal.id, role.id);
535
+ }
536
+ }))
537
+ }] : isOwner(model, principal.id) ? [] : [{
538
+ label: t.grantMoreRoles,
539
+ icon: /* @__PURE__ */ jsx(AddIcon, {}),
540
+ onClick: () => actions.onGrantMore(principal.id)
541
+ }];
542
+ return [
543
+ ...lead,
544
+ ...lead.length > 0 ? [menuDivider] : [],
545
+ {
546
+ label: removal.all || actions.singleRole ? t.removeAccess : t.confirmRemove(removal.roleIds.map((id) => model.roleById.get(id)?.name ?? id)),
547
+ icon: /* @__PURE__ */ jsx(TrashIcon, {}),
548
+ destructive: true,
549
+ onClick: () => actions.onAskRemove(removal)
550
+ }
551
+ ];
552
+ }
553
+ /** A reason someone has access that no grant here changes, locked ahead of the grants. */
554
+ function RuleRow({ rule, roleName, lead, t }) {
555
+ const people = rule.people ?? [];
556
+ const shown = people.slice(0, 4);
557
+ const more = people.length - shown.length;
558
+ const icon = rule.icon ?? /* @__PURE__ */ jsx(LockIcon, {});
559
+ return /* @__PURE__ */ jsxs("div", {
560
+ className: "flex items-center gap-3 border-b border-(--theme-border) px-4 py-2.5",
561
+ children: [
562
+ lead === "chevron" ? /* @__PURE__ */ jsx("span", {
563
+ "aria-hidden": "true",
564
+ className: "flex size-4 shrink-0 items-center justify-center text-(--theme-muted-text-color) [&_svg]:size-4",
565
+ children: icon
566
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [lead === "both" && /* @__PURE__ */ jsx("span", {
567
+ "aria-hidden": "true",
568
+ className: "size-4 shrink-0"
569
+ }), /* @__PURE__ */ jsx("span", {
570
+ "aria-hidden": "true",
571
+ className: "hidden size-8 shrink-0 items-center justify-center rounded-md bg-(--theme-muted-panel-bg) text-(--theme-muted-text-color) @min-[30rem]/access:flex [&_svg]:size-4",
572
+ children: icon
573
+ })] }),
574
+ /* @__PURE__ */ jsxs("span", {
575
+ className: "flex min-w-0 flex-1 flex-col",
576
+ children: [/* @__PURE__ */ jsx("span", {
577
+ className: "text-sm font-medium wrap-anywhere",
578
+ children: rule.title
579
+ }), rule.detail && /* @__PURE__ */ jsx("span", {
580
+ className: "text-xs wrap-anywhere text-(--theme-muted-text-color)",
581
+ children: rule.detail
582
+ })]
583
+ }),
584
+ shown.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
585
+ className: "sr-only",
586
+ children: t.ruleMembers(shown.map((person) => person.name), more)
587
+ }), /* @__PURE__ */ jsxs("span", {
588
+ "aria-hidden": "true",
589
+ className: "hidden shrink-0 items-center gap-1 @min-[30rem]/access:flex",
590
+ children: [shown.map((person, index) => /* @__PURE__ */ jsx(Avatar, {
591
+ name: person.name,
592
+ src: person.avatarUrl,
593
+ size: "md",
594
+ decorative: true
595
+ }, `${person.name}-${index.toString()}`)), more > 0 && /* @__PURE__ */ jsx("span", {
596
+ className: "inline-flex size-7 items-center justify-center rounded-full bg-(--theme-muted-panel-bg) text-[11px] font-medium tabular-nums text-(--theme-muted-text-color)",
597
+ children: t.moreMembers(more)
598
+ })]
599
+ })] }),
600
+ roleName && (lead === "tile" ? /* @__PURE__ */ jsx(RoleText, { children: roleName }) : /* @__PURE__ */ jsx("span", {
601
+ className: "shrink-0 text-xs text-(--theme-muted-text-color)",
602
+ children: roleName
603
+ })),
604
+ /* @__PURE__ */ jsx(Locked, {})
605
+ ]
606
+ });
607
+ }
608
+ /** Person and group one by one where each holds one role: a flat row each, its role picked
609
+ * from a list on the row. */
610
+ function ByPrincipalSingle({ model, order, actions, t, sectionId }) {
611
+ return order.map((principalId) => {
612
+ const principal = model.principalById.get(principalId);
613
+ if (!principal) return null;
614
+ const owner = isOwner(model, principalId);
615
+ const held = model.held.get(principalId) ?? [];
616
+ const inheritedRoles = (model.inherited.get(principalId) ?? []).map((holding) => holding.role);
617
+ const role = held[0];
618
+ const name = principalLabel(principal, t);
619
+ const failure = actions.failure?.principalId === principalId ? actions.failure.node : void 0;
620
+ const removal = {
621
+ principalId,
622
+ roleIds: held.map((r) => r.id),
623
+ all: held.length > 1
624
+ };
625
+ if (actions.removal?.principalId === principalId) return /* @__PURE__ */ jsx("div", {
626
+ className: "border-b border-(--theme-border)",
627
+ children: /* @__PURE__ */ jsx(RemoveConfirm, {
628
+ model,
629
+ removal: actions.removal,
630
+ saving: actions.saving.size > 0,
631
+ onCancel: actions.onCancelRemove,
632
+ onConfirm: () => actions.removal && actions.onRemove(actions.removal),
633
+ t
634
+ })
635
+ }, principalId);
636
+ const saving = held.some((r) => actions.saving.has(key({
637
+ principalId,
638
+ roleId: r.id
639
+ })));
640
+ const options = [...model.grantable, ...role && !model.grantable.includes(role) ? [role] : []].map((r) => ({
641
+ value: r.id,
642
+ label: r.name
643
+ }));
644
+ const control = owner ? /* @__PURE__ */ jsx(StatusBadge, {
645
+ size: "md",
646
+ variant: "info",
647
+ children: t.owner
648
+ }) : !role ? /* @__PURE__ */ jsx(RoleText, { children: inheritedRoles.map((r) => r.name).join(", ") }) : actions.readOnly ? /* @__PURE__ */ jsx(RoleText, { children: role.name }) : /* @__PURE__ */ jsx(Select, {
649
+ size: "sm",
650
+ "aria-label": t.roleFor(name),
651
+ items: options,
652
+ value: role.id,
653
+ disabled: saving,
654
+ onValueChange: (next) => {
655
+ if (next !== null && (next !== role.id || held.length > 1)) actions.onChangeRole(principalId, next);
656
+ },
657
+ className: "w-36 shrink-0"
658
+ });
659
+ return /* @__PURE__ */ jsxs("div", {
660
+ id: sectionId(principalId),
661
+ tabIndex: -1,
662
+ className: "border-b border-(--theme-border) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--theme-focus)",
663
+ onContextMenu: role && !owner ? rowMenu(actions, () => rowEntries(model, principal, actions, t, removal)) : void 0,
664
+ children: [/* @__PURE__ */ jsxs("div", {
665
+ className: "flex items-center gap-3 px-4 py-2.5",
666
+ children: [
667
+ /* @__PURE__ */ jsx(PrincipalTile, {
668
+ principal,
669
+ className: "hidden @min-[30rem]/access:flex"
670
+ }),
671
+ /* @__PURE__ */ jsxs("span", {
672
+ className: "flex min-w-0 flex-1 flex-col",
673
+ children: [/* @__PURE__ */ jsx("span", {
674
+ className: "text-sm font-medium wrap-anywhere",
675
+ children: name
676
+ }), aboutOf(principal, t) && /* @__PURE__ */ jsx("span", {
677
+ className: "text-xs wrap-anywhere text-(--theme-muted-text-color)",
678
+ children: aboutOf(principal, t)
679
+ })]
680
+ }),
681
+ control,
682
+ owner || !role ? /* @__PURE__ */ jsx(Locked, {}) : actions.readOnly ? /* @__PURE__ */ jsx(NoAction, {}) : /* @__PURE__ */ jsx(RemoveButton, {
683
+ label: t.removeRole(name, role.name),
684
+ saving,
685
+ removal,
686
+ onAsk: actions.onAskRemove
687
+ })
688
+ ]
689
+ }), failure && /* @__PURE__ */ jsx("div", {
690
+ className: "px-4 pb-3",
691
+ children: failure
692
+ })]
693
+ }, principalId);
694
+ });
695
+ }
485
696
  //#endregion
486
- export { ByPrincipal, ByRole, OWNER_SECTION, RemoveConfirm, principalLabel, removeKey };
697
+ export { ByPrincipal, ByPrincipalSingle, ByRole, OWNER_SECTION, RemoveConfirm, RuleRow, principalLabel, removeKey };
@@ -8,7 +8,7 @@ export interface GrantSelection {
8
8
  roleIds: string[];
9
9
  }
10
10
  /** The grant form's body and footer, which the drawer lays out in its own body and footer. */
11
- export declare function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, t, }: {
11
+ export declare function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, singleRole, t, }: {
12
12
  model: AccessModel;
13
13
  selection: GrantSelection;
14
14
  onSelectionChange: (next: GrantSelection) => void;
@@ -29,6 +29,8 @@ export declare function useGrantView({ model, selection, onSelectionChange, reso
29
29
  focusLater: (find: () => HTMLElement | null | undefined) => void;
30
30
  /** The drawer's body, above its footer, which the open list fills. */
31
31
  boundary: Element | null;
32
+ /** One role each: the form picks one, and granting it takes the role each already holds. */
33
+ singleRole?: boolean;
32
34
  t: AccessStrings;
33
35
  }): {
34
36
  body: ReactNode;
@@ -4,11 +4,11 @@ import { Combobox } from "../components/Combobox.js";
4
4
  import { StatusBadge } from "../components/StatusBadge.js";
5
5
  import { covers, grantPlan, isOwner } from "./model.js";
6
6
  import { PrincipalPicker } from "./PrincipalPicker.js";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { useId, useRef, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/access/GrantView.tsx
10
10
  /** The grant form's body and footer, which the drawer lays out in its own body and footer. */
11
- function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, t }) {
11
+ function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, singleRole = false, t }) {
12
12
  const uid = useId();
13
13
  const [confirming, setConfirming] = useState(false);
14
14
  const keepButton = useRef(null);
@@ -61,9 +61,13 @@ function useGrantView({ model, selection, onSelectionChange, resourceName, descr
61
61
  };
62
62
  const grant = () => {
63
63
  setConfirming(false);
64
+ const revoke = singleRole ? [...new Set(plan.grant.map((granted) => granted.principalId))].flatMap((principalId) => (model.held.get(principalId) ?? []).filter((held) => !roleIds.includes(held.id)).map((held) => ({
65
+ principalId,
66
+ roleId: held.id
67
+ }))) : [];
64
68
  onGrant({
65
69
  grant: plan.grant,
66
- revoke: []
70
+ revoke
67
71
  });
68
72
  };
69
73
  const statusId = `${uid}status`;
@@ -98,7 +102,16 @@ function useGrantView({ model, selection, onSelectionChange, resourceName, descr
98
102
  htmlFor: `${uid}roles`,
99
103
  className: "mb-1.5 block text-sm font-medium",
100
104
  children: t.rolesLabel
101
- }), /* @__PURE__ */ jsx(Combobox, {
105
+ }), singleRole ? /* @__PURE__ */ jsx(Combobox, {
106
+ id: `${uid}roles`,
107
+ items: roleItems,
108
+ value: roleIds[0] ?? null,
109
+ onValueChange: (next) => onSelectionChange({
110
+ principalIds,
111
+ roleIds: next === null ? [] : [next]
112
+ }),
113
+ placeholder: t.searchRoles
114
+ }) : /* @__PURE__ */ jsx(Combobox, {
102
115
  multiple: true,
103
116
  id: `${uid}roles`,
104
117
  items: roleItems,
@@ -9,8 +9,8 @@ import { Combobox } from "../components/Combobox.js";
9
9
  import { useRelativeTime } from "../components/relativeTime.js";
10
10
  import { StatusBadge } from "../components/StatusBadge.js";
11
11
  import { covers, isOwner } from "./model.js";
12
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
12
  import { useEffect, useMemo, useState } from "react";
13
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
14
14
  //#region src/access/PrincipalPicker.tsx
15
15
  /** Waits this long on a highlighted group before asking for its details, so arrowing past
16
16
  * groups doesn't ask for each one. */
@@ -124,7 +124,7 @@ function PrincipalPicker({ model, value, onValueChange, granting, describeGroup,
124
124
  return principal?.kind === "everyone" ? t.everyoneInOrganization : principal?.name ?? principalId;
125
125
  };
126
126
  const highlightedPrincipal = highlighted === void 0 ? void 0 : seen.get(highlighted);
127
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Combobox, {
127
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Combobox, {
128
128
  multiple: true,
129
129
  id,
130
130
  "aria-describedby": describedBy,
@@ -261,7 +261,7 @@ function Updated({ value, t }) {
261
261
  });
262
262
  }
263
263
  function DetailsLine({ details, t }) {
264
- return /* @__PURE__ */ jsx(Fragment, { children: [details.source === "synced" && t.syncedShort, memberLine(details, 2, t)].filter(Boolean).join(" · ") });
264
+ return /* @__PURE__ */ jsx(Fragment$1, { children: [details.source === "synced" && t.syncedShort, memberLine(details, 2, t)].filter(Boolean).join(" · ") });
265
265
  }
266
266
  /** What the highlighted one holds here, and what granting the picked roles would change. */
267
267
  function OnResource({ principalId, model, granting, t }) {
@@ -383,7 +383,7 @@ function GroupDetailsPane({ group, state, model, granting, t }) {
383
383
  className: "rounded-full"
384
384
  })
385
385
  ]
386
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [
386
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
387
387
  state.failed && /* @__PURE__ */ jsx("p", {
388
388
  className: "m-0 text-xs text-(--theme-error-text)",
389
389
  children: t.detailsFailed
@@ -394,7 +394,7 @@ function GroupDetailsPane({ group, state, model, granting, t }) {
394
394
  }),
395
395
  count !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
396
396
  /* @__PURE__ */ jsx(PaneHeading, { children: everyone ? t.people(count) : t.members(count) }),
397
- details && details.members.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Faces, {
397
+ details && details.members.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Faces, {
398
398
  details,
399
399
  t
400
400
  }), /* @__PURE__ */ jsx("p", {
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useRef } from "react";
5
5
  * later, which would undo wherever focus is sent next; parked, nothing is lost and it doesn't. */
6
6
  function holdFocus() {
7
7
  const active = document.activeElement;
8
- const dialog = active instanceof HTMLElement ? active.closest("[role=\"dialog\"]") : null;
8
+ const dialog = active instanceof HTMLElement ? active.closest("[role=\"dialog\"], [data-access-panel]") : null;
9
9
  if (dialog && dialog !== active) dialog.focus({ preventScroll: true });
10
10
  }
11
11
  /** Returns a function that sends focus to what `find` returns once the change it goes with
@@ -1,3 +1,3 @@
1
- export { type AccessArrangement, AccessDrawer, type AccessDrawerProps } from './AccessDrawer.js';
1
+ export { type AccessArrangement, AccessDrawer, type AccessDrawerProps, type AccessEditorProps, AccessPanel, type AccessPanelProps, } from './AccessDrawer.js';
2
2
  export { ACCESS_STRINGS, type AccessStrings, type AccessText, useAccessStrings, } from './strings.js';
3
- export type { AccessChange, AccessGrant, AccessGroupDetails, AccessInheritedGrant, AccessMember, AccessPermission, AccessPrincipal, AccessRole, } from './types.js';
3
+ export type { AccessChange, AccessGrant, AccessGroupDetails, AccessInheritedGrant, AccessMember, AccessPermission, AccessPrincipal, AccessRole, AccessRule, AccessVisibility, } from './types.js';
@@ -1,3 +1,3 @@
1
1
  import { ACCESS_STRINGS, useAccessStrings } from "./strings.js";
2
- import { AccessDrawer } from "./AccessDrawer.js";
3
- export { ACCESS_STRINGS, AccessDrawer, useAccessStrings };
2
+ import { AccessDrawer, AccessPanel } from "./AccessDrawer.js";
3
+ export { ACCESS_STRINGS, AccessDrawer, AccessPanel, useAccessStrings };
@@ -76,6 +76,24 @@ export declare const ACCESS_STRINGS: {
76
76
  readOnly: string;
77
77
  /** After `readOnly` when the host gives no reason. */
78
78
  readOnlyReason: string;
79
+ /** Names the switch between open to everyone and only those listed. */
80
+ visibility: string;
81
+ /** The switch's choice that limits it to the people and groups listed. */
82
+ restrictedLabel: string;
83
+ /** The toast after the switch saves; `choice` is the label now chosen. */
84
+ visibilityChanged: (choice: string) => string;
85
+ visibilityFailed: (choice: string) => string;
86
+ /** Names the role picker on a row where each person or group holds one role. */
87
+ roleFor: (principal: string) => string;
88
+ /** A row menu's submenu of roles. */
89
+ roleMenu: string;
90
+ /** A row menu's action that takes every role the row holds here. */
91
+ removeAccess: string;
92
+ /** The toast after a row's one role is swapped for another. */
93
+ roleChanged: (principal: string, role: string) => string;
94
+ roleChangeFailed: (principal: string, role: string) => string;
95
+ /** Read with a rule's faces: the first few by name, and how many more. */
96
+ ruleMembers: (names: readonly string[], more: number) => string;
79
97
  emptyTitle: string;
80
98
  emptyDescription: (resource: string) => string;
81
99
  noMatches: string;
@@ -1,6 +1,6 @@
1
1
  import { useStrings } from "../components/Provider.js";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
2
  import { useMemo } from "react";
3
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/access/strings.tsx
5
5
  var plural = new Intl.PluralRules("en");
6
6
  var list = new Intl.ListFormat("en", { type: "conjunction" });
@@ -101,6 +101,24 @@ var ACCESS_STRINGS = {
101
101
  readOnly: "View only.",
102
102
  /** After `readOnly` when the host gives no reason. */
103
103
  readOnlyReason: "Only people who manage access can make changes.",
104
+ /** Names the switch between open to everyone and only those listed. */
105
+ visibility: "Who can see it",
106
+ /** The switch's choice that limits it to the people and groups listed. */
107
+ restrictedLabel: "Only people with access",
108
+ /** The toast after the switch saves; `choice` is the label now chosen. */
109
+ visibilityChanged: (choice) => `Changed to ${choice}`,
110
+ visibilityFailed: (choice) => `Couldn’t change to ${choice}`,
111
+ /** Names the role picker on a row where each person or group holds one role. */
112
+ roleFor: (principal) => `Role for ${principal}`,
113
+ /** A row menu's submenu of roles. */
114
+ roleMenu: "Role",
115
+ /** A row menu's action that takes every role the row holds here. */
116
+ removeAccess: "Remove access",
117
+ /** The toast after a row's one role is swapped for another. */
118
+ roleChanged: (principal, role) => `Changed ${principal} to ${role}`,
119
+ roleChangeFailed: (principal, role) => `Couldn’t change ${principal} to ${role}`,
120
+ /** Read with a rule's faces: the first few by name, and how many more. */
121
+ ruleMembers: (names, more) => more > 0 ? `Includes ${and([...names, `${more.toLocaleString()} more`])}` : `Includes ${and(names)}`,
104
122
  emptyTitle: "No access granted",
105
123
  emptyDescription: (resource) => `Grant a role to a person or group to give them access to ${resource}.`,
106
124
  noMatches: "No matches",
@@ -132,7 +150,7 @@ var ACCESS_STRINGS = {
132
150
  alreadyCovered: (roles) => `Included in ${and(roles)}`,
133
151
  everyoneHasIt: "Already granted to Everyone",
134
152
  /** The footer's account of what pressing Grant does. */
135
- grantSummary: (principals, roles) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("strong", {
153
+ grantSummary: (principals, roles) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("strong", {
136
154
  className: "font-medium text-(--theme-app)",
137
155
  children: and(roles)
138
156
  }), ` for ${and(principals)}`] }),
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from 'react';
1
2
  import type { TimeValue } from '../format.js';
2
3
  /** A named set of permissions. People and groups are granted roles, never permissions one by
3
4
  * one. */
@@ -72,3 +73,28 @@ export interface AccessGroupDetails {
72
73
  /** When its membership last changed. */
73
74
  updatedAt?: TimeValue;
74
75
  }
76
+ /** A reason someone has access that no grant here changes, such as "Workspace admins always
77
+ * have access". It shows, locked, ahead of the grants. */
78
+ export interface AccessRule {
79
+ id: string;
80
+ /** In the leading column, in place of a section's chevron. */
81
+ icon?: ReactNode;
82
+ title: string;
83
+ /** A line under the title, such as who sets it. */
84
+ detail?: string | undefined;
85
+ /** A few of the people it covers, shown as overlapping faces: four, then how many more. */
86
+ people?: readonly AccessMember[] | undefined;
87
+ /** The role it gives, when it gives everyone it covers the same one. */
88
+ roleId?: string | undefined;
89
+ }
90
+ /** Whether a resource is open to everyone who can see what it is in, or only to those listed. */
91
+ export interface AccessVisibility {
92
+ restricted: boolean;
93
+ /** Saves the switch, as `onChange` saves a grant: until the promise settles the switch shows
94
+ * it is saving, and when it rejects the panel says nothing changed and offers to retry. */
95
+ onChange: (restricted: boolean) => void | Promise<unknown>;
96
+ /** The open choice, which names what it is open to: "Everyone in the workspace". */
97
+ openLabel: string;
98
+ /** The restricted choice; defaults to the strings' "Only people with access". */
99
+ restrictedLabel?: string | undefined;
100
+ }
@@ -28,6 +28,7 @@ export interface ToolApprovalAnswer {
28
28
  toolCallId: string;
29
29
  allowed: boolean;
30
30
  feedback?: string;
31
+ tool?: string;
31
32
  }
32
33
  export interface StreamHandlers {
33
34
  onContent: (content: string) => void;
@@ -4,8 +4,8 @@ import { useChatConfig } from "../core/config.js";
4
4
  import { useChat } from "../core/ChatProvider.js";
5
5
  import { chipClassName } from "../ui/chip.js";
6
6
  import { isOrgModel } from "../utils.js";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { useEffect } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  import useSWR from "swr";
10
10
  //#region src/ai/components/AllocationSelector.tsx
11
11
  var dollars = new Intl.NumberFormat(void 0, {
@@ -1,18 +1,18 @@
1
1
  import { cx } from "../../cx.js";
2
+ import { EmptyState } from "../../components/EmptyState.js";
2
3
  import { DownloadIcon, FileIcon, TrashIcon } from "../../icons.js";
3
4
  import { safeUrl } from "../../safeUrl.js";
4
5
  import { Loader } from "../../components/Loader.js";
5
6
  import { toast } from "../../components/Toast.js";
6
7
  import { Tooltip } from "../../components/Tooltip.js";
7
8
  import { useStrings } from "../../components/Provider.js";
8
- import { EmptyState } from "../../components/EmptyState.js";
9
9
  import { formatBytes } from "../../format.js";
10
10
  import { RelativeTime } from "../../components/relativeTime.js";
11
11
  import { useChatConfig } from "../core/config.js";
12
12
  import { useChat } from "../core/ChatProvider.js";
13
13
  import { attachmentsPageKey } from "./attachmentKeys.js";
14
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
14
  import { useCallback, useMemo, useState } from "react";
15
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
16
  import useSWRInfinite from "swr/infinite";
17
17
  //#region src/ai/components/AttachmentManager.tsx
18
18
  function AttachmentManager() {
@@ -64,7 +64,7 @@ function AttachmentManager() {
64
64
  }) : attachments.length === 0 ? /* @__PURE__ */ jsx(EmptyState, {
65
65
  variant: "bare",
66
66
  title: t.empty
67
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
67
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
68
68
  className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4",
69
69
  children: attachments.map((att) => {
70
70
  const downloadUrl = safeUrl(attachmentsAdapter.downloadUrl(att.id));
@@ -72,7 +72,7 @@ function AttachmentManager() {
72
72
  const isDeleting = deleting === att.id;
73
73
  const thumbnail = thumbnails[att.id];
74
74
  const showThumbnail = att.contentType?.startsWith("image/") && thumbnail !== "broken";
75
- const preview = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(FileIcon, {
75
+ const preview = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FileIcon, {
76
76
  "aria-hidden": "true",
77
77
  className: "w-8 h-8 theme-muted-text"
78
78
  }), showThumbnail && /* @__PURE__ */ jsx("img", {
@@ -104,7 +104,7 @@ function AttachmentManager() {
104
104
  children: name
105
105
  }), /* @__PURE__ */ jsxs("p", {
106
106
  className: "truncate theme-muted-text",
107
- children: [att.size ? formatBytes(att.size) : "", att.uploadedAt && /* @__PURE__ */ jsxs(Fragment, { children: [att.size ? " · " : "", /* @__PURE__ */ jsx(RelativeTime, { value: att.uploadedAt })] })]
107
+ children: [att.size ? formatBytes(att.size) : "", att.uploadedAt && /* @__PURE__ */ jsxs(Fragment$1, { children: [att.size ? " · " : "", /* @__PURE__ */ jsx(RelativeTime, { value: att.uploadedAt })] })]
108
108
  })]
109
109
  }), /* @__PURE__ */ jsxs("div", {
110
110
  className: "flex items-center gap-0.5 flex-shrink-0",
@@ -6,8 +6,8 @@ import { formatBytes } from "../../format.js";
6
6
  import { useChatConfig } from "../core/config.js";
7
7
  import { useChat } from "../core/ChatProvider.js";
8
8
  import { ATTACHMENTS_INFINITE_KEY } from "./attachmentKeys.js";
9
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
9
  import { useCallback, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { mutate } from "swr";
12
12
  //#region src/ai/components/AttachmentUpload.tsx
13
13
  var DEFAULT_MAX_FILE_SIZE = 26214400;
@@ -118,7 +118,7 @@ function AttachmentUpload({ conversationId, attachments, onAttachmentsChange, di
118
118
  const handleClick = () => {
119
119
  fileInputRef.current?.click();
120
120
  };
121
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("input", {
121
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("input", {
122
122
  ref: fileInputRef,
123
123
  type: "file",
124
124
  multiple: true,
@@ -1,8 +1,8 @@
1
1
  import { ChevronLeftIcon, ChevronRightIcon } from "../../icons.js";
2
2
  import { IconButton } from "../../components/IconButton.js";
3
3
  import { useChatConfig } from "../core/config.js";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
4
  import { useMemo } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/ai/components/BranchNavigator.tsx
7
7
  function findSiblings(messages, messageId) {
8
8
  const message = messages.find((m) => m.id === messageId);
@@ -0,0 +1,2 @@
1
+ /** An agent session's working line for the provider's reply, naming its current step. */
2
+ export default function ChatActivity(): import("react").JSX.Element | null;