@parallelworks/ui 0.19.0 → 0.19.1

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 (217) hide show
  1. package/dist/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
  2. package/dist/ai/adapter/mock/index.js +2 -80
  3. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  4. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  5. package/dist/ai/adapter/openai/errors.js +37 -0
  6. package/dist/ai/adapter/openai/index.js +5 -333
  7. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  8. package/dist/ai/adapter/openai/responses.js +108 -0
  9. package/dist/ai/adapter/openai/sse.js +112 -0
  10. package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
  11. package/dist/ai/agent/classifier.js +12 -0
  12. package/dist/ai/agent/diff.js +223 -0
  13. package/dist/ai/agent/diffHighlight.js +101 -0
  14. package/dist/ai/agent/permissions.js +29 -0
  15. package/dist/ai/agent/toolfmt.js +383 -0
  16. package/dist/ai/agent/transcript.js +127 -0
  17. package/dist/ai/components/AllocationSelector.js +56 -0
  18. package/dist/ai/components/AttachmentManager.js +144 -0
  19. package/dist/ai/components/AttachmentUpload.js +179 -0
  20. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  21. package/dist/ai/components/BranchNavigator.js +57 -0
  22. package/dist/ai/components/ChatEmptyState.js +171 -0
  23. package/dist/ai/components/ChatInput.js +265 -0
  24. package/dist/ai/components/ChatLayout.js +15 -0
  25. package/dist/ai/components/ChatMessage.js +338 -0
  26. package/dist/ai/components/ChatMessageList.js +301 -0
  27. package/dist/ai/components/ChatSidebar.js +345 -0
  28. package/dist/ai/components/ChatThread.js +198 -0
  29. package/dist/ai/components/ComposerChrome.js +50 -0
  30. package/dist/ai/components/ComposerFrame.js +33 -0
  31. package/dist/ai/components/DragOverlay.js +20 -0
  32. package/dist/ai/components/ModelSelector.js +343 -0
  33. package/dist/ai/components/ShareDialog.js +260 -0
  34. package/dist/ai/components/SlashMenu.js +91 -0
  35. package/dist/ai/components/agent/ActivityLine.js +151 -0
  36. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  37. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  38. package/dist/ai/components/attachmentKeys.js +10 -0
  39. package/dist/ai/core/ChatProvider.js +848 -0
  40. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  41. package/dist/ai/core/chatReducer.js +223 -0
  42. package/dist/ai/core/config.js +45 -0
  43. package/dist/ai/core/events.js +4 -0
  44. package/dist/ai/core/exportConversation.js +42 -0
  45. package/dist/ai/core/greeting.js +38 -0
  46. package/dist/ai/core/parts.js +84 -0
  47. package/dist/ai/core/useDragDrop.js +36 -0
  48. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  49. package/dist/ai/core/useSSEStream.js +98 -0
  50. package/dist/ai/index.js +43 -6644
  51. package/dist/ai/strings.js +175 -0
  52. package/dist/ai/ui/Avatar.js +35 -0
  53. package/dist/ai/ui/Dropdown.js +110 -0
  54. package/dist/ai/ui/Markdown.js +79 -0
  55. package/dist/ai/ui/Notice.js +77 -0
  56. package/dist/ai/ui/codeBreaks.js +36 -0
  57. package/dist/ai/ui/prose.js +13 -0
  58. package/dist/ai/ui/sidebar.js +148 -0
  59. package/dist/ai/utils.js +23 -0
  60. package/dist/components/AddMenu.js +46 -0
  61. package/dist/components/Avatar.js +46 -0
  62. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  63. package/dist/components/Breadcrumbs.js +83 -0
  64. package/dist/components/Button.js +83 -0
  65. package/dist/components/Callout.js +23 -0
  66. package/dist/components/Card.js +31 -0
  67. package/dist/components/CollapsiblePanel.js +77 -0
  68. package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
  69. package/dist/components/CopyToClipboard.js +81 -0
  70. package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
  71. package/dist/components/DescriptionList.js +42 -0
  72. package/dist/components/Dropdown.js +349 -0
  73. package/dist/components/EmptyState.js +27 -0
  74. package/dist/components/Filter.js +32 -0
  75. package/dist/components/FilterPill.js +13 -0
  76. package/dist/components/IconButton.js +34 -0
  77. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  78. package/dist/components/Input.js +88 -0
  79. package/dist/components/LetterBadge.js +13 -0
  80. package/dist/components/Listbox.js +123 -0
  81. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  82. package/dist/components/Markdown.js +15 -0
  83. package/dist/components/MultiSelect.js +171 -0
  84. package/dist/components/Overview.js +39 -0
  85. package/dist/components/PageHeader.js +194 -0
  86. package/dist/components/Pagination.js +35 -0
  87. package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +1 -1
  88. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  89. package/dist/components/SectionHeader.js +11 -0
  90. package/dist/components/SettingModeOption.js +30 -0
  91. package/dist/components/SettingRow.js +35 -0
  92. package/dist/components/SettingsCard.js +31 -0
  93. package/dist/components/SettingsGroup.js +17 -0
  94. package/dist/components/Sort.js +42 -0
  95. package/dist/components/StatusBadge.js +63 -0
  96. package/dist/components/SwitchToggle.js +59 -0
  97. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  98. package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
  99. package/dist/components/Toggle.js +20 -0
  100. package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
  101. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  102. package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
  103. package/dist/components/ghostButton.js +7 -0
  104. package/dist/components/inputClasses.js +4 -0
  105. package/dist/components/keys.js +27 -0
  106. package/dist/components/relativeTime.js +32 -0
  107. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  108. package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
  109. package/dist/editor/Editor.js +13 -0
  110. package/dist/editor/EditorField.js +53 -0
  111. package/dist/editor/FormCodePanel.js +173 -0
  112. package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +4 -2
  113. package/dist/editor/index.js +6 -1
  114. package/dist/editor/themes.js +91 -0
  115. package/dist/editor/workers.js +29 -0
  116. package/dist/editor/yaml.js +15 -0
  117. package/dist/file-explorer/FileExplorer.js +1402 -0
  118. package/dist/file-explorer/FileExplorerContext.js +370 -0
  119. package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  120. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  121. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  122. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  123. package/dist/file-explorer/FilePreview/index.js +266 -0
  124. package/dist/file-explorer/FilePreview/parse.js +63 -0
  125. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  126. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  127. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  128. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  129. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  130. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  131. package/dist/file-explorer/FileRow.js +165 -0
  132. package/dist/file-explorer/FileRowsWindow.js +92 -0
  133. package/dist/file-explorer/FileTable.js +172 -0
  134. package/dist/file-explorer/FileTableHeaders.js +49 -0
  135. package/dist/file-explorer/LoadMoreRow.js +46 -0
  136. package/dist/file-explorer/TreeView.js +376 -0
  137. package/dist/file-explorer/helpers.js +537 -0
  138. package/dist/file-explorer/index.js +7 -5671
  139. package/dist/file-explorer/lib/batch.js +39 -0
  140. package/dist/file-explorer/lib/errors.js +9 -0
  141. package/dist/file-explorer/lib/paging.js +124 -0
  142. package/dist/file-explorer/lib/utils.js +322 -0
  143. package/dist/file-explorer/toasts.js +400 -0
  144. package/dist/file-explorer/treeRows.js +73 -0
  145. package/dist/file-explorer/useNearEnd.js +27 -0
  146. package/dist/form/FieldWrapper.js +54 -0
  147. package/dist/form/Fields/BooleanField.js +51 -0
  148. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  149. package/dist/form/Fields/ColorField.js +33 -0
  150. package/dist/form/Fields/DropdownField.js +49 -0
  151. package/dist/form/Fields/DurationField.js +130 -0
  152. package/dist/form/Fields/LabelField.js +19 -0
  153. package/dist/form/Fields/MultiDropdownField.js +40 -0
  154. package/dist/form/Fields/NumberField.js +51 -0
  155. package/dist/form/Fields/ObjectField.js +54 -0
  156. package/dist/form/Fields/RadioField.js +49 -0
  157. package/dist/form/Fields/RangeField.js +58 -0
  158. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  159. package/dist/form/Fields/StepField.js +6 -0
  160. package/dist/form/Fields/StringField.js +37 -0
  161. package/dist/form/Fields/TextAreaField.js +31 -0
  162. package/dist/form/Fields/durationValidity.js +11 -0
  163. package/dist/form/Form.js +643 -0
  164. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  165. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  166. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  167. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  168. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  169. package/dist/form/Wizard/WizardContainer.js +138 -0
  170. package/dist/form/Wizard/WizardNavigation.js +92 -0
  171. package/dist/form/Wizard/WizardStepContent.js +35 -0
  172. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  173. package/dist/form/Wizard/useWizardState.js +118 -0
  174. package/dist/form/Wizard/utils.js +34 -0
  175. package/dist/form/fieldContext.js +26 -0
  176. package/dist/form/fieldRegistry.js +50 -0
  177. package/dist/form/index.js +17 -2321
  178. package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
  179. package/dist/form/useParsedOpts.js +62 -0
  180. package/dist/form/usePrevious.js +11 -0
  181. package/dist/form/utils/checkShowIfObject.js +14 -0
  182. package/dist/form/utils/duration.js +69 -0
  183. package/dist/form/utils/getParentValue.js +23 -0
  184. package/dist/form/utils/getPlaceholder.js +9 -0
  185. package/dist/form/utils/getValueUsingPath.js +23 -0
  186. package/dist/form/utils/secondaryField.js +22 -0
  187. package/dist/graph/AnnotationBanner.js +141 -0
  188. package/dist/graph/Collapse.js +41 -0
  189. package/dist/graph/DependencyGraph.js +1398 -0
  190. package/dist/graph/JobSummary.js +104 -0
  191. package/dist/graph/MatrixGroup.js +107 -0
  192. package/dist/graph/Reveal.js +57 -0
  193. package/dist/graph/TreeView.js +711 -0
  194. package/dist/graph/index.js +1 -2519
  195. package/dist/graph/types.js +6 -0
  196. package/dist/index.js +46 -599
  197. package/dist/list/ActionToolbar.js +184 -0
  198. package/dist/list/HoverCard.js +73 -0
  199. package/dist/list/ListPage.js +145 -0
  200. package/dist/list/ListPager.js +59 -0
  201. package/dist/list/ListTable.js +163 -0
  202. package/dist/list/ListViewControls.js +372 -0
  203. package/dist/list/RowContextMenu.js +350 -0
  204. package/dist/list/UserHoverCard.js +117 -0
  205. package/dist/list/index.js +11 -2
  206. package/dist/list/listSearch.js +137 -0
  207. package/dist/list/listView.js +210 -0
  208. package/dist/list/textEntry.js +10 -0
  209. package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
  210. package/dist/logviewer/index.js +2 -1
  211. package/dist/logviewer/segments.js +80 -0
  212. package/package.json +1 -1
  213. package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
  214. package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
  215. package/dist/chunks/editor-Dk1rbV75.js +0 -361
  216. package/dist/chunks/list-CJm875m7.js +0 -1418
  217. /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
@@ -0,0 +1,260 @@
1
+ import { ShareIcon, TrashIcon } from "../../icons.js";
2
+ import { ConfirmModal } from "../../components/ConfirmModal.js";
3
+ import Loader from "../../components/Loader.js";
4
+ import { useChatConfig } from "../core/config.js";
5
+ import { useChat } from "../core/ChatProvider.js";
6
+ import Dropdown from "../ui/Dropdown.js";
7
+ import { useCallback, useEffect, useState, useTransition } from "react";
8
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/ai/components/ShareDialog.tsx
10
+ function ShareDialog({ conversationId, isOpen, onClose }) {
11
+ const { strings } = useChatConfig();
12
+ const t = strings.shareConversation;
13
+ const { adapter, notify } = useChat();
14
+ const sharing = adapter.sharing;
15
+ const [permissions, setPermissions] = useState([]);
16
+ const [teams, setTeams] = useState([]);
17
+ const [loading, setLoading] = useState(false);
18
+ const [saving, startSaveTransition] = useTransition();
19
+ const [orgViewAccess, setOrgViewAccess] = useState(false);
20
+ const [orgCollaborateAccess, setOrgCollaborateAccess] = useState(false);
21
+ const [originalPermissions, setOriginalPermissions] = useState([]);
22
+ const [originalOrgCollaborateAccess, setOriginalOrgCollaborateAccess] = useState(false);
23
+ useEffect(() => {
24
+ if (!isOpen || !sharing) return;
25
+ const loadData = async () => {
26
+ setLoading(true);
27
+ try {
28
+ const perms = await sharing.listPermissions(conversationId);
29
+ setPermissions(perms);
30
+ setOriginalPermissions([...perms]);
31
+ const orgPerm = perms.find((p) => p.entireOrganization);
32
+ if (orgPerm) {
33
+ setOrgViewAccess(true);
34
+ setOrgCollaborateAccess(orgPerm.permission === "collaborate");
35
+ setOriginalOrgCollaborateAccess(orgPerm.permission === "collaborate");
36
+ } else {
37
+ setOrgViewAccess(false);
38
+ setOrgCollaborateAccess(false);
39
+ setOriginalOrgCollaborateAccess(false);
40
+ }
41
+ setTeams(await sharing.listGroups());
42
+ } catch (error) {
43
+ console.error("Failed to load sharing data:", error);
44
+ notify.error(t.loadError);
45
+ } finally {
46
+ setLoading(false);
47
+ }
48
+ };
49
+ loadData();
50
+ }, [
51
+ isOpen,
52
+ conversationId,
53
+ sharing,
54
+ notify,
55
+ t.loadError
56
+ ]);
57
+ const handleSave = useCallback(() => {
58
+ if (!sharing) return;
59
+ startSaveTransition(async () => {
60
+ try {
61
+ const hadOrgPerm = originalPermissions.find((p) => p.entireOrganization);
62
+ const wantOrgPerm = orgViewAccess;
63
+ if (wantOrgPerm && !hadOrgPerm) await sharing.addPermission(conversationId, {
64
+ permission: orgCollaborateAccess ? "collaborate" : "view",
65
+ entireOrganization: true
66
+ });
67
+ else if (!wantOrgPerm && hadOrgPerm?.id) await sharing.removePermission(conversationId, hadOrgPerm.id);
68
+ else if (wantOrgPerm && hadOrgPerm?.id && (originalOrgCollaborateAccess !== orgCollaborateAccess || hadOrgPerm.permission === "collaborate" !== orgCollaborateAccess)) await sharing.updatePermission(conversationId, hadOrgPerm.id, orgCollaborateAccess ? "collaborate" : "view");
69
+ const originalTeamPerms = originalPermissions.filter((p) => p.team && !p.entireOrganization);
70
+ const currentTeamPerms = permissions.filter((p) => p.team && !p.entireOrganization);
71
+ for (const perm of currentTeamPerms) {
72
+ const original = originalTeamPerms.find((p) => p.team === perm.team);
73
+ if (!original) await sharing.addPermission(conversationId, {
74
+ permission: perm.permission,
75
+ team: perm.team,
76
+ entireOrganization: false
77
+ });
78
+ else if (original.permission !== perm.permission && original.id) await sharing.updatePermission(conversationId, original.id, perm.permission);
79
+ }
80
+ for (const original of originalTeamPerms) if (!currentTeamPerms.find((p) => p.team === original.team) && original.id) await sharing.removePermission(conversationId, original.id);
81
+ } catch (error) {
82
+ notify.error(error instanceof Error ? error.message : String(error));
83
+ return;
84
+ }
85
+ notify.success(t.saveSuccess);
86
+ onClose();
87
+ });
88
+ }, [
89
+ sharing,
90
+ conversationId,
91
+ permissions,
92
+ originalPermissions,
93
+ orgViewAccess,
94
+ orgCollaborateAccess,
95
+ originalOrgCollaborateAccess,
96
+ onClose,
97
+ notify,
98
+ t.saveSuccess
99
+ ]);
100
+ const handleAddTeam = useCallback((teamId) => {
101
+ if (permissions.some((p) => p.team === teamId)) return;
102
+ const team = teams.find((candidate) => candidate.id === teamId);
103
+ if (team) setPermissions((prev) => [...prev, {
104
+ team: teamId,
105
+ teamName: team.name,
106
+ permission: "view",
107
+ entireOrganization: false
108
+ }]);
109
+ }, [teams, permissions]);
110
+ const handleRemoveTeam = useCallback((teamId) => {
111
+ setPermissions((prev) => prev.filter((p) => p.team !== teamId));
112
+ }, []);
113
+ const handleTeamPermissionChange = useCallback((teamId, permission) => {
114
+ setPermissions((prev) => prev.map((p) => p.team === teamId ? {
115
+ ...p,
116
+ permission
117
+ } : p));
118
+ }, []);
119
+ if (!sharing) return null;
120
+ const teamPermissions = permissions.filter((p) => p.team && !p.entireOrganization);
121
+ const availableTeams = teams.filter((team) => !permissions.some((p) => p.team === team.id));
122
+ return /* @__PURE__ */ jsx(ConfirmModal, {
123
+ open: isOpen,
124
+ onClose,
125
+ align: "center",
126
+ title: t.title,
127
+ confirmLabel: strings.modal.save,
128
+ cancelLabel: strings.modal.cancel,
129
+ onConfirm: handleSave,
130
+ confirmDisabled: saving,
131
+ children: /* @__PURE__ */ jsx("div", {
132
+ className: "space-y-4",
133
+ children: loading ? /* @__PURE__ */ jsx("div", {
134
+ className: "py-4",
135
+ children: /* @__PURE__ */ jsx(Loader, {
136
+ size: 24,
137
+ text: strings.modal.loading
138
+ })
139
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
140
+ /* @__PURE__ */ jsxs("div", {
141
+ className: "border theme-border rounded-lg p-3",
142
+ children: [/* @__PURE__ */ jsx("h3", {
143
+ className: "font-medium text-sm mb-2",
144
+ children: t.orgAccess
145
+ }), /* @__PURE__ */ jsxs("div", {
146
+ className: "space-y-2",
147
+ children: [/* @__PURE__ */ jsxs("label", {
148
+ className: "flex items-center gap-2",
149
+ children: [/* @__PURE__ */ jsx("input", {
150
+ type: "checkbox",
151
+ checked: orgViewAccess,
152
+ onChange: (e) => {
153
+ setOrgViewAccess(e.target.checked);
154
+ if (!e.target.checked) setOrgCollaborateAccess(false);
155
+ },
156
+ className: "rounded"
157
+ }), /* @__PURE__ */ jsx("span", {
158
+ className: "text-sm",
159
+ children: t.orgCanView
160
+ })]
161
+ }), /* @__PURE__ */ jsxs("label", {
162
+ className: "flex items-center gap-2 ml-4",
163
+ children: [/* @__PURE__ */ jsx("input", {
164
+ type: "checkbox",
165
+ checked: orgCollaborateAccess,
166
+ onChange: (e) => setOrgCollaborateAccess(e.target.checked),
167
+ disabled: !orgViewAccess,
168
+ className: "rounded"
169
+ }), /* @__PURE__ */ jsx("span", {
170
+ className: "text-sm",
171
+ children: t.allowCollaboration
172
+ })]
173
+ })]
174
+ })]
175
+ }),
176
+ /* @__PURE__ */ jsxs("div", {
177
+ className: "border theme-border rounded-lg p-3",
178
+ children: [
179
+ /* @__PURE__ */ jsx("h3", {
180
+ className: "font-medium text-sm mb-2",
181
+ children: t.groupAccess
182
+ }),
183
+ teamPermissions.length > 0 ? /* @__PURE__ */ jsx("ul", {
184
+ className: "space-y-2 mb-3 max-h-[200px] overflow-y-auto",
185
+ children: teamPermissions.map((perm) => /* @__PURE__ */ jsxs("li", {
186
+ className: "flex items-center justify-between theme-muted-panel rounded px-2 py-1.5",
187
+ children: [/* @__PURE__ */ jsx("span", {
188
+ className: "text-sm theme-text",
189
+ children: perm.teamName || perm.team
190
+ }), /* @__PURE__ */ jsxs("div", {
191
+ className: "flex items-center gap-2",
192
+ children: [/* @__PURE__ */ jsx(Dropdown, {
193
+ options: [{
194
+ label: t.viewOnly,
195
+ value: "view"
196
+ }, {
197
+ label: t.canCollaborate,
198
+ value: "collaborate"
199
+ }],
200
+ value: perm.permission,
201
+ onChange: (val) => handleTeamPermissionChange(perm.team, val),
202
+ wrapperClassName: "w-40",
203
+ textBoxClassName: "text-xs border theme-border rounded px-2 py-1"
204
+ }), /* @__PURE__ */ jsx("button", {
205
+ type: "button",
206
+ onClick: () => handleRemoveTeam(perm.team),
207
+ className: "p-1 rounded hover:bg-red-500/10",
208
+ title: t.remove,
209
+ children: /* @__PURE__ */ jsx(TrashIcon, { className: "w-3 h-3 text-red-500" })
210
+ })]
211
+ })]
212
+ }, perm.team))
213
+ }) : /* @__PURE__ */ jsx("p", {
214
+ className: "text-sm theme-muted-text mb-3",
215
+ children: t.noGroups
216
+ }),
217
+ availableTeams.length > 0 && /* @__PURE__ */ jsx("div", {
218
+ className: "flex items-center gap-2",
219
+ children: /* @__PURE__ */ jsx(Dropdown, {
220
+ options: availableTeams.map((team) => ({
221
+ label: team.name,
222
+ value: team.id
223
+ })),
224
+ value: "",
225
+ onChange: (val) => handleAddTeam(val),
226
+ placeholder: t.addGroups,
227
+ wrapperClassName: "flex-1",
228
+ textBoxClassName: "text-sm border theme-border rounded px-2 py-1.5 w-full"
229
+ })
230
+ })
231
+ ]
232
+ }),
233
+ /* @__PURE__ */ jsx("p", {
234
+ className: "text-xs theme-muted-text",
235
+ children: t.info
236
+ })
237
+ ] })
238
+ })
239
+ });
240
+ }
241
+ function ShareButton({ conversationId, disabled = false }) {
242
+ const { strings } = useChatConfig();
243
+ const { adapter } = useChat();
244
+ const [isOpen, setIsOpen] = useState(false);
245
+ if (!adapter.sharing) return null;
246
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
247
+ type: "button",
248
+ onClick: () => setIsOpen(true),
249
+ disabled,
250
+ className: "flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] theme-muted-text transition-colors hover:theme-muted-panel hover:theme-text disabled:opacity-50",
251
+ title: strings.shareConversation.shareButton,
252
+ children: [/* @__PURE__ */ jsx(ShareIcon, { className: "h-3 w-3" }), strings.shareConversation.shareButton]
253
+ }), /* @__PURE__ */ jsx(ShareDialog, {
254
+ conversationId,
255
+ isOpen,
256
+ onClose: () => setIsOpen(false)
257
+ })] });
258
+ }
259
+ //#endregion
260
+ export { ShareButton, ShareDialog as default };
@@ -0,0 +1,91 @@
1
+ import cx from "classnames";
2
+ import { useEffect, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/ai/components/SlashMenu.tsx
5
+ var MAX_SHOWN = 8;
6
+ var TYPING_NAME = /^\/([\w:-]*)$/;
7
+ function slashMatches(input, commands) {
8
+ const typed = TYPING_NAME.exec(input);
9
+ if (!typed) return [];
10
+ const query = (typed[1] ?? "").toLowerCase();
11
+ return commands.filter((c) => c.name.toLowerCase().startsWith(query)).slice(0, MAX_SHOWN);
12
+ }
13
+ /** The palette's open state and keys; the caller owns the input. */
14
+ function useSlashMenu(input, config, setInput) {
15
+ const [active, setActive] = useState(0);
16
+ const [dismissed, setDismissed] = useState(false);
17
+ const matches = config ? slashMatches(input, config.commands) : [];
18
+ const exact = matches.length === 1 && `/${matches[0]?.name}` === input;
19
+ const open = matches.length > 0 && !dismissed && !exact;
20
+ const startsCommand = input.startsWith("/");
21
+ const onOpen = config?.onOpen;
22
+ useEffect(() => {
23
+ if (startsCommand) onOpen?.();
24
+ }, [startsCommand, onOpen]);
25
+ const query = TYPING_NAME.exec(input)?.[1] ?? null;
26
+ const [shownQuery, setShownQuery] = useState(query);
27
+ if (query !== shownQuery) {
28
+ setShownQuery(query);
29
+ setActive(0);
30
+ setDismissed(false);
31
+ }
32
+ const choose = (name) => setInput(`/${name} `);
33
+ /** True when the key belonged to the menu. */
34
+ const handleKey = (e) => {
35
+ if (!open) return false;
36
+ switch (e.key) {
37
+ case "ArrowDown":
38
+ setActive((i) => (i + 1) % matches.length);
39
+ break;
40
+ case "ArrowUp":
41
+ setActive((i) => (i - 1 + matches.length) % matches.length);
42
+ break;
43
+ case "Tab":
44
+ case "Enter": {
45
+ if (e.shiftKey) return false;
46
+ const pick = matches[Math.min(active, matches.length - 1)];
47
+ if (!pick) return false;
48
+ choose(pick.name);
49
+ break;
50
+ }
51
+ case "Escape":
52
+ setDismissed(true);
53
+ break;
54
+ default: return false;
55
+ }
56
+ e.preventDefault();
57
+ return true;
58
+ };
59
+ return {
60
+ open,
61
+ matches,
62
+ active,
63
+ choose,
64
+ handleKey
65
+ };
66
+ }
67
+ function SlashMenu({ label, matches, active, onChoose }) {
68
+ return /* @__PURE__ */ jsx("div", {
69
+ role: "listbox",
70
+ "aria-label": label,
71
+ "data-testid": "slash-menu",
72
+ className: "absolute bottom-full left-0 right-0 mb-2 z-20 overflow-hidden rounded-xl border theme-border bg-(--theme-panel-bg) shadow-lg",
73
+ children: matches.map((c, i) => /* @__PURE__ */ jsxs("button", {
74
+ type: "button",
75
+ role: "option",
76
+ "aria-selected": i === active,
77
+ onMouseDown: (e) => e.preventDefault(),
78
+ onClick: () => onChoose(c.name),
79
+ className: cx("flex w-full items-baseline gap-3 px-3 py-1.5 text-left text-sm", i === active ? "theme-hover" : "hover:theme-hover"),
80
+ children: [/* @__PURE__ */ jsxs("span", {
81
+ className: "font-mono theme-text",
82
+ children: ["/", c.name]
83
+ }), c.description && /* @__PURE__ */ jsx("span", {
84
+ className: "truncate text-xs theme-muted-text",
85
+ children: c.description
86
+ })]
87
+ }, c.name))
88
+ });
89
+ }
90
+ //#endregion
91
+ export { SlashMenu, slashMatches, useSlashMenu };
@@ -0,0 +1,151 @@
1
+ import { LoaderIcon, StopSolidIcon } from "../../../icons.js";
2
+ import { useChatConfig } from "../../core/config.js";
3
+ import cx from "classnames";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { DateTime } from "luxon";
7
+ //#region src/ai/components/agent/ActivityLine.tsx
8
+ /** The agent status words: one is picked per turn and held until it ends. */
9
+ var activityWords = [
10
+ "Thinking",
11
+ "Cogitating",
12
+ "Pondering",
13
+ "Percolating",
14
+ "Ruminating",
15
+ "Noodling",
16
+ "Conjuring",
17
+ "Simmering",
18
+ "Marinating",
19
+ "Tinkering",
20
+ "Scheming",
21
+ "Brewing",
22
+ "Wrangling",
23
+ "Finagling",
24
+ "Spelunking",
25
+ "Puttering",
26
+ "Composing",
27
+ "Synthesizing",
28
+ "Deliberating",
29
+ "Mulling",
30
+ "Contemplating",
31
+ "Vibing",
32
+ "Whittling",
33
+ "Concocting",
34
+ "Formulating",
35
+ "Hatching",
36
+ "Herding",
37
+ "Ideating",
38
+ "Manifesting",
39
+ "Moseying",
40
+ "Musing",
41
+ "Percussing",
42
+ "Reticulating",
43
+ "Schlepping",
44
+ "Stewing",
45
+ "Transmuting",
46
+ "Wibbling",
47
+ "Crunching",
48
+ "Forging",
49
+ "Cooking"
50
+ ];
51
+ function randomActivityWord() {
52
+ return activityWords[Math.floor(Math.random() * activityWords.length)];
53
+ }
54
+ /** Elapsed run time the way an agent status line prints it: 45s, 2m13s,
55
+ * 1h2m3s. */
56
+ function formatElapsed(seconds) {
57
+ const total = Math.max(0, Math.floor(seconds));
58
+ const hours = Math.floor(total / 3600);
59
+ const minutes = Math.floor(total % 3600 / 60);
60
+ const rest = total % 60;
61
+ if (hours > 0) return `${hours}h${minutes}m${rest}s`;
62
+ if (minutes > 0) return `${minutes}m${rest}s`;
63
+ return `${rest}s`;
64
+ }
65
+ /** Token counts the way an agent status line prints them: 512, 1.2k, 3.4M. */
66
+ function compactCount(n) {
67
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
68
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
69
+ return String(Math.floor(n));
70
+ }
71
+ function secondsSince(iso) {
72
+ return Math.max(0, DateTime.now().diff(DateTime.fromISO(iso)).as("seconds"));
73
+ }
74
+ /** Seconds since `startedAt`, re-read every second; null when there is no
75
+ * start to count from. */
76
+ function useElapsedSeconds(startedAt) {
77
+ const [elapsed, setElapsed] = useState(() => startedAt ? secondsSince(startedAt) : null);
78
+ useEffect(() => {
79
+ if (!startedAt) {
80
+ setElapsed(null);
81
+ return;
82
+ }
83
+ setElapsed(secondsSince(startedAt));
84
+ const id = setInterval(() => setElapsed(secondsSince(startedAt)), 1e3);
85
+ return () => clearInterval(id);
86
+ }, [startedAt]);
87
+ return elapsed;
88
+ }
89
+ /** A status word held for the whole turn and re-rolled when a new one starts. */
90
+ function useTurnWord(startedAt) {
91
+ const [word, setWord] = useState(randomActivityWord);
92
+ const turn = useRef(startedAt);
93
+ useEffect(() => {
94
+ if (turn.current !== startedAt) {
95
+ turn.current = startedAt;
96
+ setWord(randomActivityWord());
97
+ }
98
+ }, [startedAt]);
99
+ return word;
100
+ }
101
+ /** The terminal's "it's working" line for a running turn: spinner, status
102
+ * word, how long the turn has run, its token counts so far, and a way to
103
+ * stop it. */
104
+ function ActivityLine({ startedAt, inputTokens, outputTokens, onStop, stopping = false, word, testId }) {
105
+ const { strings } = useChatConfig();
106
+ const elapsed = useElapsedSeconds(startedAt);
107
+ const turnWord = useTurnWord(startedAt);
108
+ const meta = [];
109
+ if (elapsed !== null) meta.push(formatElapsed(elapsed));
110
+ if (inputTokens || outputTokens) meta.push(strings.activity.tokens(compactCount(inputTokens ?? 0), compactCount(outputTokens ?? 0)));
111
+ return /* @__PURE__ */ jsxs("div", {
112
+ "data-testid": testId,
113
+ className: "flex min-h-8 items-center gap-2 px-1 text-sm",
114
+ children: [
115
+ /* @__PURE__ */ jsx(LoaderIcon, {
116
+ className: "h-3.5 w-3.5 shrink-0 animate-spin text-(--theme-element) motion-reduce:hidden",
117
+ "aria-hidden": "true"
118
+ }),
119
+ /* @__PURE__ */ jsx("span", {
120
+ className: "hidden shrink-0 leading-none text-(--theme-element) motion-reduce:inline",
121
+ "aria-hidden": "true",
122
+ children: "●"
123
+ }),
124
+ /* @__PURE__ */ jsxs("span", {
125
+ "data-testid": testId ? `${testId}-word` : void 0,
126
+ className: "min-w-0 truncate text-(--theme-element)",
127
+ children: [word ?? turnWord, "…"]
128
+ }),
129
+ meta.length > 0 && /* @__PURE__ */ jsxs("span", {
130
+ "data-testid": testId ? `${testId}-meta` : void 0,
131
+ className: "shrink-0 text-xs tabular-nums theme-muted-text",
132
+ children: [
133
+ "(",
134
+ meta.join(" · "),
135
+ ")"
136
+ ]
137
+ }),
138
+ onStop && /* @__PURE__ */ jsxs("button", {
139
+ type: "button",
140
+ onClick: onStop,
141
+ disabled: stopping,
142
+ "aria-label": strings.input.stopGenerating,
143
+ title: strings.input.stopGenerating,
144
+ className: cx("ml-auto inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-xs theme-muted-text transition-colors", "hover:theme-hover hover:theme-text disabled:cursor-not-allowed disabled:opacity-50"),
145
+ children: [/* @__PURE__ */ jsx(StopSolidIcon, { className: "h-3 w-3" }), strings.activity.stop]
146
+ })
147
+ ]
148
+ });
149
+ }
150
+ //#endregion
151
+ export { activityWords, compactCount, ActivityLine as default, formatElapsed, randomActivityWord };