@parallelworks/ui 0.18.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 (349) hide show
  1. package/README.md +86 -6
  2. package/dist/ai/adapter/memoryStore.d.ts +8 -0
  3. package/dist/ai/adapter/memoryStore.js +152 -0
  4. package/dist/ai/adapter/mock/index.d.ts +2 -0
  5. package/dist/ai/adapter/mock/index.js +3 -0
  6. package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
  7. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  8. package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
  9. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  10. package/dist/ai/adapter/openai/errors.d.ts +3 -0
  11. package/dist/ai/adapter/openai/errors.js +37 -0
  12. package/dist/ai/adapter/openai/index.d.ts +6 -0
  13. package/dist/ai/adapter/openai/index.js +6 -0
  14. package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
  15. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  16. package/dist/ai/adapter/openai/responses.d.ts +4 -0
  17. package/dist/ai/adapter/openai/responses.js +108 -0
  18. package/dist/ai/adapter/openai/sse.d.ts +24 -0
  19. package/dist/ai/adapter/openai/sse.js +112 -0
  20. package/dist/ai/adapter/openai/wire.d.ts +40 -0
  21. package/dist/ai/adapter/types.d.ts +131 -0
  22. package/dist/ai/adapter/types.js +11 -0
  23. package/dist/ai/agent/classifier.d.ts +2 -0
  24. package/dist/ai/agent/classifier.js +12 -0
  25. package/dist/ai/agent/diff.d.ts +35 -0
  26. package/dist/ai/agent/diff.js +223 -0
  27. package/dist/ai/agent/diffHighlight.d.ts +6 -0
  28. package/dist/ai/agent/diffHighlight.js +101 -0
  29. package/dist/ai/agent/index.d.ts +6 -0
  30. package/dist/ai/agent/permissions.d.ts +11 -0
  31. package/dist/ai/agent/permissions.js +29 -0
  32. package/dist/ai/agent/toolfmt.d.ts +18 -0
  33. package/dist/ai/agent/toolfmt.js +383 -0
  34. package/dist/ai/agent/transcript.d.ts +38 -0
  35. package/dist/ai/agent/transcript.js +127 -0
  36. package/dist/ai/ai.css +325 -0
  37. package/dist/ai/components/AllocationSelector.d.ts +4 -0
  38. package/dist/ai/components/AllocationSelector.js +56 -0
  39. package/dist/ai/components/AttachmentManager.d.ts +1 -0
  40. package/dist/ai/components/AttachmentManager.js +144 -0
  41. package/dist/ai/components/AttachmentUpload.d.ts +24 -0
  42. package/dist/ai/components/AttachmentUpload.js +179 -0
  43. package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
  44. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  45. package/dist/ai/components/BranchNavigator.d.ts +8 -0
  46. package/dist/ai/components/BranchNavigator.js +57 -0
  47. package/dist/ai/components/ChatEmptyState.d.ts +3 -0
  48. package/dist/ai/components/ChatEmptyState.js +171 -0
  49. package/dist/ai/components/ChatInput.d.ts +45 -0
  50. package/dist/ai/components/ChatInput.js +265 -0
  51. package/dist/ai/components/ChatLayout.d.ts +5 -0
  52. package/dist/ai/components/ChatLayout.js +15 -0
  53. package/dist/ai/components/ChatMessage.d.ts +24 -0
  54. package/dist/ai/components/ChatMessage.js +338 -0
  55. package/dist/ai/components/ChatMessageList.d.ts +35 -0
  56. package/dist/ai/components/ChatMessageList.js +301 -0
  57. package/dist/ai/components/ChatSidebar.d.ts +5 -0
  58. package/dist/ai/components/ChatSidebar.js +345 -0
  59. package/dist/ai/components/ChatThread.d.ts +3 -0
  60. package/dist/ai/components/ChatThread.js +198 -0
  61. package/dist/ai/components/ComposerChrome.d.ts +18 -0
  62. package/dist/ai/components/ComposerChrome.js +50 -0
  63. package/dist/ai/components/ComposerFrame.d.ts +16 -0
  64. package/dist/ai/components/ComposerFrame.js +33 -0
  65. package/dist/ai/components/DragOverlay.d.ts +5 -0
  66. package/dist/ai/components/DragOverlay.js +20 -0
  67. package/dist/ai/components/ModelSelector.d.ts +6 -0
  68. package/dist/ai/components/ModelSelector.js +343 -0
  69. package/dist/ai/components/ShareDialog.d.ts +11 -0
  70. package/dist/ai/components/ShareDialog.js +260 -0
  71. package/dist/ai/components/SlashMenu.d.ts +28 -0
  72. package/dist/ai/components/SlashMenu.js +91 -0
  73. package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
  74. package/dist/ai/components/agent/ActivityLine.js +151 -0
  75. package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
  76. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  77. package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
  78. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  79. package/dist/ai/components/attachmentKeys.d.ts +4 -0
  80. package/dist/ai/components/attachmentKeys.js +10 -0
  81. package/dist/ai/core/ChatProvider.d.ts +66 -0
  82. package/dist/ai/core/ChatProvider.js +848 -0
  83. package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
  84. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  85. package/dist/ai/core/chatReducer.d.ts +114 -0
  86. package/dist/ai/core/chatReducer.js +223 -0
  87. package/dist/ai/core/config.d.ts +47 -0
  88. package/dist/ai/core/config.js +45 -0
  89. package/dist/ai/core/events.d.ts +1 -0
  90. package/dist/ai/core/events.js +4 -0
  91. package/dist/ai/core/exportConversation.d.ts +4 -0
  92. package/dist/ai/core/exportConversation.js +42 -0
  93. package/dist/ai/core/greeting.d.ts +3 -0
  94. package/dist/ai/core/greeting.js +38 -0
  95. package/dist/ai/core/parts.d.ts +11 -0
  96. package/dist/ai/core/parts.js +84 -0
  97. package/dist/ai/core/useDragDrop.d.ts +14 -0
  98. package/dist/ai/core/useDragDrop.js +36 -0
  99. package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
  100. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  101. package/dist/ai/core/useSSEStream.d.ts +34 -0
  102. package/dist/ai/core/useSSEStream.js +98 -0
  103. package/dist/ai/index.d.ts +40 -0
  104. package/dist/ai/index.js +44 -0
  105. package/dist/ai/strings.d.ts +167 -0
  106. package/dist/ai/strings.js +175 -0
  107. package/dist/ai/types.d.ts +236 -0
  108. package/dist/ai/ui/Avatar.d.ts +8 -0
  109. package/dist/ai/ui/Avatar.js +35 -0
  110. package/dist/ai/ui/Dropdown.d.ts +31 -0
  111. package/dist/ai/ui/Dropdown.js +110 -0
  112. package/dist/ai/ui/Markdown.d.ts +8 -0
  113. package/dist/ai/ui/Markdown.js +79 -0
  114. package/dist/ai/ui/Notice.d.ts +21 -0
  115. package/dist/ai/ui/Notice.js +77 -0
  116. package/dist/ai/ui/buttons.d.ts +1 -0
  117. package/dist/ai/ui/codeBreaks.d.ts +16 -0
  118. package/dist/ai/ui/codeBreaks.js +36 -0
  119. package/dist/ai/ui/prose.d.ts +1 -0
  120. package/dist/ai/ui/prose.js +13 -0
  121. package/dist/ai/ui/sidebar.d.ts +81 -0
  122. package/dist/ai/ui/sidebar.js +148 -0
  123. package/dist/ai/utils.d.ts +4 -0
  124. package/dist/ai/utils.js +23 -0
  125. package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
  126. package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
  127. package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
  128. package/dist/components/AddMenu.js +46 -0
  129. package/dist/components/Avatar.d.ts +1 -1
  130. package/dist/components/Avatar.js +46 -0
  131. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  132. package/dist/components/Breadcrumbs.d.ts +1 -1
  133. package/dist/components/Breadcrumbs.js +83 -0
  134. package/dist/components/Button.js +83 -0
  135. package/dist/components/Callout.js +23 -0
  136. package/dist/components/Card.js +31 -0
  137. package/dist/components/CollapsiblePanel.js +77 -0
  138. package/dist/components/ConfirmModal.js +74 -0
  139. package/dist/components/CopyToClipboard.js +81 -0
  140. package/dist/{chunks/CreateModal-BY6DLmur.js → components/CreateModal.js} +10 -189
  141. package/dist/components/DescriptionList.js +42 -0
  142. package/dist/components/Dropdown.d.ts +1 -1
  143. package/dist/components/Dropdown.js +349 -0
  144. package/dist/components/EmptyState.d.ts +1 -1
  145. package/dist/components/EmptyState.js +27 -0
  146. package/dist/components/Filter.js +32 -0
  147. package/dist/components/FilterPill.js +13 -0
  148. package/dist/components/IconButton.js +34 -0
  149. package/dist/components/Indicator.d.ts +2 -2
  150. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  151. package/dist/components/Input.d.ts +1 -1
  152. package/dist/components/Input.js +88 -0
  153. package/dist/components/LetterBadge.d.ts +1 -1
  154. package/dist/components/LetterBadge.js +13 -0
  155. package/dist/components/Listbox.js +123 -0
  156. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  157. package/dist/components/Markdown.js +15 -0
  158. package/dist/components/MarkdownImpl.d.ts +1 -1
  159. package/dist/components/MultiSelect.js +171 -0
  160. package/dist/components/Overview.js +39 -0
  161. package/dist/components/PageHeader.js +194 -0
  162. package/dist/components/Pagination.js +35 -0
  163. package/dist/components/Provider.d.ts +16 -65
  164. package/dist/{chunks/Provider-Ghua9PkN.js → components/Provider.js} +54 -20
  165. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  166. package/dist/components/SectionHeader.js +11 -0
  167. package/dist/components/SettingModeOption.js +30 -0
  168. package/dist/components/SettingRow.d.ts +1 -1
  169. package/dist/components/SettingRow.js +35 -0
  170. package/dist/components/SettingsCard.js +31 -0
  171. package/dist/components/SettingsGroup.d.ts +1 -1
  172. package/dist/components/SettingsGroup.js +17 -0
  173. package/dist/components/Sort.js +42 -0
  174. package/dist/components/StatusBadge.js +63 -0
  175. package/dist/components/SwitchToggle.js +59 -0
  176. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  177. package/dist/{chunks/Table-4OHjdKdO.js → components/Table.js} +7 -5
  178. package/dist/components/Toggle.js +20 -0
  179. package/dist/{chunks/Tooltip-Crxo_eU_.js → components/Tooltip.js} +6 -4
  180. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  181. package/dist/components/focus.d.ts +2 -0
  182. package/dist/components/focus.js +7 -0
  183. package/dist/components/ghostButton.js +7 -0
  184. package/dist/components/inputClasses.js +4 -0
  185. package/dist/components/keys.d.ts +12 -0
  186. package/dist/components/keys.js +27 -0
  187. package/dist/components/relativeTime.js +32 -0
  188. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  189. package/dist/duration.d.ts +3 -0
  190. package/dist/duration.js +17 -0
  191. package/dist/editor/Editor.js +13 -0
  192. package/dist/editor/EditorField.js +53 -0
  193. package/dist/editor/FormCodePanel.js +173 -0
  194. package/dist/editor/Monaco.d.ts +1 -20
  195. package/dist/editor/Monaco.js +112 -0
  196. package/dist/editor/index.d.ts +2 -1
  197. package/dist/editor/index.js +7 -2
  198. package/dist/editor/themes.js +91 -0
  199. package/dist/editor/workers.js +29 -0
  200. package/dist/editor/yaml.d.ts +5 -0
  201. package/dist/editor/yaml.js +15 -0
  202. package/dist/engine.d.ts +98 -0
  203. package/dist/file-explorer/FileExplorer.d.ts +11 -2
  204. package/dist/file-explorer/FileExplorer.js +1402 -0
  205. package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
  206. package/dist/file-explorer/FileExplorerContext.js +370 -0
  207. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
  208. package/dist/{chunks/CodePreviewEditor-4lx3kE-w.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  209. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  210. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  211. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  212. package/dist/file-explorer/FilePreview/index.js +266 -0
  213. package/dist/file-explorer/FilePreview/parse.js +63 -0
  214. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  215. package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
  216. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  217. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  218. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  219. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  220. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  221. package/dist/file-explorer/FileRow.d.ts +1 -1
  222. package/dist/file-explorer/FileRow.js +165 -0
  223. package/dist/file-explorer/FileRowsWindow.js +92 -0
  224. package/dist/file-explorer/FileTable.js +172 -0
  225. package/dist/file-explorer/FileTableHeaders.js +49 -0
  226. package/dist/file-explorer/LoadMoreRow.js +46 -0
  227. package/dist/file-explorer/TreeView.js +376 -0
  228. package/dist/file-explorer/helpers.d.ts +4 -4
  229. package/dist/file-explorer/helpers.js +537 -0
  230. package/dist/file-explorer/index.d.ts +3 -3
  231. package/dist/file-explorer/index.js +7 -5705
  232. package/dist/file-explorer/lib/batch.js +39 -0
  233. package/dist/file-explorer/lib/errors.js +9 -0
  234. package/dist/file-explorer/lib/paging.js +124 -0
  235. package/dist/file-explorer/lib/types.d.ts +6 -1
  236. package/dist/file-explorer/lib/utils.d.ts +1 -3
  237. package/dist/file-explorer/lib/utils.js +322 -0
  238. package/dist/file-explorer/toasts.js +400 -0
  239. package/dist/file-explorer/treeRows.js +73 -0
  240. package/dist/file-explorer/useNearEnd.d.ts +1 -1
  241. package/dist/file-explorer/useNearEnd.js +27 -0
  242. package/dist/form/FieldWrapper.d.ts +2 -2
  243. package/dist/form/FieldWrapper.js +54 -0
  244. package/dist/form/Fields/BooleanField.js +51 -0
  245. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  246. package/dist/form/Fields/ColorField.js +33 -0
  247. package/dist/form/Fields/DropdownField.js +49 -0
  248. package/dist/form/Fields/DurationField.js +130 -0
  249. package/dist/form/Fields/LabelField.js +19 -0
  250. package/dist/form/Fields/MultiDropdownField.js +40 -0
  251. package/dist/form/Fields/NumberField.js +51 -0
  252. package/dist/form/Fields/ObjectField.js +54 -0
  253. package/dist/form/Fields/RadioField.js +49 -0
  254. package/dist/form/Fields/RangeField.js +58 -0
  255. package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
  256. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  257. package/dist/form/Fields/StepField.js +6 -0
  258. package/dist/form/Fields/StringField.js +37 -0
  259. package/dist/form/Fields/TextAreaField.js +31 -0
  260. package/dist/form/Fields/durationValidity.js +11 -0
  261. package/dist/form/Form.d.ts +4 -21
  262. package/dist/form/Form.js +643 -0
  263. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  264. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  265. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  266. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  267. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  268. package/dist/form/Wizard/WizardContainer.js +138 -0
  269. package/dist/form/Wizard/WizardNavigation.js +92 -0
  270. package/dist/form/Wizard/WizardStepContent.js +35 -0
  271. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  272. package/dist/form/Wizard/useWizardState.js +118 -0
  273. package/dist/form/Wizard/utils.js +34 -0
  274. package/dist/form/fieldContext.js +26 -0
  275. package/dist/form/fieldRegistry.js +50 -0
  276. package/dist/form/index.d.ts +11 -12
  277. package/dist/form/index.js +18 -2445
  278. package/dist/form/lib.d.ts +6 -1
  279. package/dist/{chunks/FieldWrapper-Bef01EWO.js → form/lib.js} +5 -104
  280. package/dist/form/types/fieldComponentTypes.d.ts +3 -2
  281. package/dist/form/types/fieldTypes.d.ts +6 -20
  282. package/dist/form/useParsedOpts.d.ts +1 -1
  283. package/dist/form/useParsedOpts.js +62 -0
  284. package/dist/form/usePrevious.js +11 -0
  285. package/dist/form/utils/checkShowIfObject.js +14 -0
  286. package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
  287. package/dist/form/utils/duration.js +69 -0
  288. package/dist/form/utils/getParentValue.js +23 -0
  289. package/dist/form/utils/getPlaceholder.js +9 -0
  290. package/dist/form/utils/getValueUsingPath.js +23 -0
  291. package/dist/form/utils/secondaryField.js +22 -0
  292. package/dist/graph/AnnotationBanner.js +141 -0
  293. package/dist/graph/Collapse.js +41 -0
  294. package/dist/{workflow/index.js → graph/DependencyGraph.js} +76 -1163
  295. package/dist/graph/JobSummary.js +104 -0
  296. package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
  297. package/dist/graph/MatrixGroup.js +107 -0
  298. package/dist/graph/Reveal.js +57 -0
  299. package/dist/graph/TreeView.js +711 -0
  300. package/dist/{workflow → graph}/index.d.ts +1 -1
  301. package/dist/graph/index.js +2 -0
  302. package/dist/{workflow → graph}/types.d.ts +3 -3
  303. package/dist/graph/types.js +6 -0
  304. package/dist/icons.d.ts +20 -21
  305. package/dist/index.d.ts +38 -40
  306. package/dist/index.js +47 -599
  307. package/dist/list/ActionToolbar.js +184 -0
  308. package/dist/list/HoverCard.js +73 -0
  309. package/dist/list/ListPage.js +145 -0
  310. package/dist/list/ListPager.js +59 -0
  311. package/dist/list/ListTable.d.ts +1 -1
  312. package/dist/list/ListTable.js +163 -0
  313. package/dist/list/ListViewControls.d.ts +2 -2
  314. package/dist/list/ListViewControls.js +372 -0
  315. package/dist/list/RowContextMenu.js +350 -0
  316. package/dist/list/UserHoverCard.js +117 -0
  317. package/dist/list/index.d.ts +9 -9
  318. package/dist/list/index.js +11 -2
  319. package/dist/list/listSearch.js +137 -0
  320. package/dist/list/listView.js +210 -0
  321. package/dist/list/textEntry.js +10 -0
  322. package/dist/logviewer/LogViewer.d.ts +1 -1
  323. package/dist/logviewer/LogViewer.js +750 -0
  324. package/dist/logviewer/index.d.ts +1 -0
  325. package/dist/logviewer/index.js +3 -742
  326. package/dist/logviewer/segments.d.ts +9 -0
  327. package/dist/logviewer/segments.js +80 -0
  328. package/dist/styles/fonts.css +4 -4
  329. package/dist/styles/theme.css +6 -4
  330. package/dist/styles.css +1 -1
  331. package/dist/theme/index.js +2 -2
  332. package/package.json +38 -14
  333. package/LICENSE +0 -202
  334. package/dist/chunks/Monaco-C1POOdVv.js +0 -1046
  335. package/dist/chunks/PageHeader-l49p1nM9.js +0 -690
  336. package/dist/chunks/SwitchToggle-CHPP8uZQ.js +0 -755
  337. package/dist/chunks/editor-9_uVtUyy.js +0 -347
  338. package/dist/chunks/list-qrojZZNv.js +0 -1411
  339. package/dist/editor/usesGitlab.d.ts +0 -97
  340. package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
  341. package/dist/form/types/workflow-schema.d.ts +0 -1145
  342. package/dist/form/utils/pwResolver.d.ts +0 -18
  343. package/dist/{chunks/MarkdownImpl-Bq4QhrtA.js → components/MarkdownImpl.js} +1 -1
  344. /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
  345. /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
  346. /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
  347. /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
  348. /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
  349. /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
@@ -0,0 +1,750 @@
1
+ import { useNotify, useOptionalWorkflowEngine, useStrings } from "../components/Provider.js";
2
+ import { ArrowDownIcon, ArrowUpIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ClockIcon, CopyIcon, DownloadIcon, ExpandIcon, ShrinkIcon, XIcon } from "../icons.js";
3
+ import { TooltipInfo } from "../components/Tooltip.js";
4
+ import { highlightSegments, parseAnsiSegments, plainSegments } from "./segments.js";
5
+ import cx from "classnames";
6
+ import { Fragment, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ import { DateTime } from "luxon";
9
+ //#region src/logviewer/LogViewer.tsx
10
+ function LogSegments({ segments }) {
11
+ return segments.map((segment, i) => segment.highlighted ? /* @__PURE__ */ jsx("mark", {
12
+ className: cx("search-highlight", segment.className),
13
+ children: segment.content
14
+ }, i) : segment.className ? /* @__PURE__ */ jsx("span", {
15
+ className: segment.className,
16
+ children: segment.content
17
+ }, i) : /* @__PURE__ */ jsx(Fragment, { children: segment.content }, i));
18
+ }
19
+ var LogLine = memo(function LogLine({ index, segments, lineNumbers, isSelected, lineHeight, onLineClick, searchTerm, command, groupDepth = 0, isGroupCollapsed, onGroupToggle, annotationLabels }) {
20
+ const displaySegments = useMemo(() => highlightSegments(command?.message ? plainSegments(command.message) : segments, searchTerm), [
21
+ segments,
22
+ searchTerm,
23
+ command
24
+ ]);
25
+ const annotationLabel = useMemo(() => {
26
+ if (command?.type === "error") return /* @__PURE__ */ jsx("span", {
27
+ className: "text-red-500 font-semibold mr-1",
28
+ children: annotationLabels.error
29
+ });
30
+ if (command?.type === "warning") return /* @__PURE__ */ jsx("span", {
31
+ className: "text-yellow-500 font-semibold mr-1",
32
+ children: annotationLabels.warning
33
+ });
34
+ if (command?.type === "notice") return /* @__PURE__ */ jsx("span", {
35
+ className: "text-blue-500 font-semibold mr-1",
36
+ children: annotationLabels.notice
37
+ });
38
+ return null;
39
+ }, [command?.type, annotationLabels]);
40
+ const groupToggle = command?.type === "group" && onGroupToggle ? () => {
41
+ if (window.getSelection()?.isCollapsed === false) return;
42
+ onGroupToggle(index);
43
+ } : null;
44
+ const groupToggleProps = groupToggle ? {
45
+ role: "button",
46
+ tabIndex: 0,
47
+ "aria-expanded": !isGroupCollapsed,
48
+ onClick: groupToggle,
49
+ onKeyDown: (e) => {
50
+ if (e.target !== e.currentTarget) return;
51
+ if (e.key === "Enter" || e.key === " ") {
52
+ e.preventDefault();
53
+ groupToggle();
54
+ }
55
+ }
56
+ } : void 0;
57
+ return /* @__PURE__ */ jsxs("div", {
58
+ "data-line-number": index + 1,
59
+ ...groupToggleProps,
60
+ className: cx("flex items-start text-sm font-mono group", isSelected ? "bg-(--theme-link)/15" : "hover:bg-(--theme-hover)", "text-(--theme-app)", command?.type === "error" && "bg-red-500/10", command?.type === "warning" && "bg-yellow-500/10", command?.type === "notice" && "bg-blue-500/10", command?.type === "debug" && "opacity-60", command?.type === "group" && "bg-(--theme-hover) cursor-pointer"),
61
+ style: {
62
+ minHeight: `${lineHeight}px`,
63
+ lineHeight: `${lineHeight}px`,
64
+ paddingLeft: groupDepth > 0 ? `${groupDepth * 16}px` : void 0
65
+ },
66
+ children: [lineNumbers && /* @__PURE__ */ jsx("button", {
67
+ type: "button",
68
+ onClick: (e) => {
69
+ e.stopPropagation();
70
+ onLineClick(index + 1, e);
71
+ },
72
+ className: cx("inline-flex items-center justify-end w-14 pr-3 shrink-0 cursor-pointer select-none", "hover:underline hover:text-(--theme-link) transition-colors", "text-(--theme-muted-text-color)", isSelected && "text-(--theme-link)"),
73
+ children: index + 1
74
+ }), /* @__PURE__ */ jsxs("pre", {
75
+ className: cx("grow text-left whitespace-pre m-0 py-0.5 pr-2 flex items-center", lineNumbers && "pl-2 border-l border-(--theme-border)", command?.type === "error" && "border-l-red-500 border-l-2", command?.type === "warning" && "border-l-yellow-500 border-l-2", command?.type === "notice" && "border-l-blue-500 border-l-2", command?.type === "group" && "font-bold"),
76
+ children: [
77
+ command?.type === "group" && /* @__PURE__ */ jsx("span", {
78
+ className: "mr-1 shrink-0 inline-flex items-center",
79
+ children: isGroupCollapsed ? /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "w-3 h-3" })
80
+ }),
81
+ annotationLabel,
82
+ /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(LogSegments, { segments: displaySegments }) })
83
+ ]
84
+ })]
85
+ });
86
+ });
87
+ function validateTimeRange(from, to) {
88
+ if (from === "" && to === "") return "";
89
+ const fromTime = from === "" ? null : DateTime.fromISO(from);
90
+ const toTime = to === "" ? null : DateTime.fromISO(to);
91
+ if (fromTime && !fromTime.isValid) return "invalidStartTime";
92
+ if (toTime && !toTime.isValid) return "invalidEndTime";
93
+ if (fromTime && toTime && toTime <= fromTime) return "endBeforeStart";
94
+ if (toTime && toTime > DateTime.now()) return "endInFuture";
95
+ return "";
96
+ }
97
+ var TopPaginationBanner = memo(function TopPaginationBanner({ endOfLog, loadingTop, onLoadOlder }) {
98
+ const { logviewer: t } = useStrings();
99
+ const baseCx = cx("flex items-center justify-center gap-2 h-7 text-xs font-mono select-none", "text-[var(--theme-muted-text-color)]", "border-b border-[var(--theme-border)]");
100
+ if (endOfLog) return /* @__PURE__ */ jsx("div", {
101
+ className: cx(baseCx, "opacity-70"),
102
+ children: t.beginningOfLog
103
+ });
104
+ if (loadingTop) return /* @__PURE__ */ jsxs("div", {
105
+ className: baseCx,
106
+ children: [/* @__PURE__ */ jsx("span", {
107
+ className: "w-3 h-3 rounded-full border-2 border-current border-t-transparent animate-spin",
108
+ "aria-hidden": true
109
+ }), /* @__PURE__ */ jsx("span", { children: t.loadingOlderEntries })]
110
+ });
111
+ return /* @__PURE__ */ jsx("button", {
112
+ type: "button",
113
+ onClick: onLoadOlder,
114
+ className: cx(baseCx, "w-full hover:text-[var(--theme-app)] hover:bg-[var(--theme-hover)] transition-colors"),
115
+ children: t.loadOlderEntries
116
+ });
117
+ });
118
+ function LogViewer({ log, height = "unset", width, roundedBottom = false, lineNumbers = true, additionalLeftBarComponents = null, additionalRightBarComponents = null, additionalBottomLeftBarComponents = null, additionalBottomRightBarComponents = null, hideExpand = false, inline = false, contentClassName, enableWorkflowCommands: workflowCommandsRequested = false, onReachTop, loadingTop = false, endOfLog = false, prependedSignal = 0, enableTimeRangeFilter = false, onTimeRangeChange, initialTimeRangeFrom = "", initialTimeRangeTo = "" }) {
119
+ const engine = useOptionalWorkflowEngine(workflowCommandsRequested);
120
+ const enableWorkflowCommands = workflowCommandsRequested && engine !== void 0;
121
+ const notify = useNotify();
122
+ const { common: tCommon, logviewer: t } = useStrings();
123
+ const annotationLabels = useMemo(() => ({
124
+ error: t.error,
125
+ warning: t.warning,
126
+ notice: t.notice
127
+ }), [t]);
128
+ const [fullscreen, setFullscreen] = useState(false);
129
+ const [follow, _setFollow] = useState(true);
130
+ const followRef = useRef(true);
131
+ const updateFollow = useCallback((value) => {
132
+ followRef.current = value;
133
+ _setFollow(value);
134
+ }, []);
135
+ const [logUrl, setLogUrl] = useState("");
136
+ const [fullParsedLog, setFullParsedLog] = useState([]);
137
+ const [processedLines, setProcessedLines] = useState([]);
138
+ const [rawLines, setRawLines] = useState([]);
139
+ const [showDebug, setShowDebug] = useState(false);
140
+ const [collapsedGroups, setCollapsedGroups] = useState(/* @__PURE__ */ new Set());
141
+ const [filter, setFilter] = useState("");
142
+ const [timeRangeFrom, setTimeRangeFrom] = useState(initialTimeRangeFrom);
143
+ const [timeRangeTo, setTimeRangeTo] = useState(initialTimeRangeTo);
144
+ const [timeRangeOpen, setTimeRangeOpen] = useState(false);
145
+ const timeRangePopoverRef = useRef(null);
146
+ const timeRangeError = validateTimeRange(timeRangeFrom, timeRangeTo);
147
+ useEffect(() => {
148
+ setTimeRangeFrom(initialTimeRangeFrom);
149
+ }, [initialTimeRangeFrom]);
150
+ useEffect(() => {
151
+ setTimeRangeTo(initialTimeRangeTo);
152
+ }, [initialTimeRangeTo]);
153
+ const [visibleStart, setVisibleStart] = useState(0);
154
+ const [visibleEnd, setVisibleEnd] = useState(0);
155
+ const [selectedLines, setSelectedLines] = useState(/* @__PURE__ */ new Set());
156
+ const [lastClickedLine, setLastClickedLine] = useState(null);
157
+ const [copied, setCopied] = useState(false);
158
+ const [highlightCopyPosition, setHighlightCopyPosition] = useState(null);
159
+ const [highlightedText, setHighlightedText] = useState("");
160
+ const logContainerRef = useRef(null);
161
+ const ansiCache = useRef({});
162
+ const scrollAnimationRef = useRef(null);
163
+ const prevLogLengthRef = useRef(0);
164
+ const userScrollUpRef = useRef(false);
165
+ const reachTopFiredRef = useRef(false);
166
+ const prevScrollHeightRef = useRef(0);
167
+ const prevPrependedSignalRef = useRef(prependedSignal);
168
+ const pendingPrependRef = useRef(false);
169
+ const LINE_HEIGHT = 20;
170
+ const OVERSCAN = 20;
171
+ const handleLineClick = useCallback((lineNum, e) => {
172
+ e.preventDefault();
173
+ updateFollow(false);
174
+ if (e.shiftKey && lastClickedLine !== null) {
175
+ const start = Math.min(lastClickedLine, lineNum);
176
+ const end = Math.max(lastClickedLine, lineNum);
177
+ const newSelected = /* @__PURE__ */ new Set();
178
+ for (let i = start; i <= end; i++) newSelected.add(i);
179
+ setSelectedLines(newSelected);
180
+ } else if (selectedLines.has(lineNum) && selectedLines.size === 1) setSelectedLines(/* @__PURE__ */ new Set());
181
+ else {
182
+ setSelectedLines(/* @__PURE__ */ new Set([lineNum]));
183
+ setLastClickedLine(lineNum);
184
+ }
185
+ }, [
186
+ lastClickedLine,
187
+ selectedLines,
188
+ updateFollow
189
+ ]);
190
+ const copyAllLogs = useCallback(async () => {
191
+ const text = rawLines.join("\n");
192
+ try {
193
+ await navigator.clipboard.writeText(text);
194
+ setCopied(true);
195
+ setTimeout(() => setCopied(false), 2e3);
196
+ } catch (_err) {
197
+ notify.error("Failed to copy logs to clipboard");
198
+ }
199
+ }, [rawLines, notify]);
200
+ const handleTextMouseUp = useCallback((e) => {
201
+ const selectedText = window.getSelection()?.toString().trim();
202
+ if (selectedText && selectedText.length > 0) {
203
+ setHighlightCopyPosition({
204
+ x: e.clientX,
205
+ y: e.clientY
206
+ });
207
+ setHighlightedText(selectedText);
208
+ } else {
209
+ setHighlightCopyPosition(null);
210
+ setHighlightedText("");
211
+ }
212
+ }, []);
213
+ const copyHighlightedText = useCallback(async () => {
214
+ if (!highlightedText) return;
215
+ try {
216
+ await navigator.clipboard.writeText(highlightedText);
217
+ notify.success("Text copied to clipboard");
218
+ window.getSelection()?.removeAllRanges();
219
+ setHighlightCopyPosition(null);
220
+ setHighlightedText("");
221
+ } catch (_err) {
222
+ notify.error("Failed to copy text to clipboard");
223
+ }
224
+ }, [highlightedText, notify]);
225
+ useEffect(() => {
226
+ const handleClickOutside = (e) => {
227
+ if (e.target.closest("[data-highlight-copy-button]")) return;
228
+ setTimeout(() => {
229
+ setHighlightCopyPosition(null);
230
+ setHighlightedText("");
231
+ }, 100);
232
+ };
233
+ const handleKeyDown = (e) => {
234
+ if (e.key === "Escape") {
235
+ setHighlightCopyPosition(null);
236
+ setHighlightedText("");
237
+ }
238
+ };
239
+ if (highlightCopyPosition) {
240
+ document.addEventListener("mousedown", handleClickOutside);
241
+ document.addEventListener("keydown", handleKeyDown);
242
+ }
243
+ return () => {
244
+ document.removeEventListener("mousedown", handleClickOutside);
245
+ document.removeEventListener("keydown", handleKeyDown);
246
+ };
247
+ }, [highlightCopyPosition]);
248
+ useEffect(() => {
249
+ if (!timeRangeOpen) return;
250
+ const handleClickOutside = (e) => {
251
+ const target = e.target;
252
+ if (timeRangePopoverRef.current?.contains(target)) return;
253
+ if (target.closest("[data-time-range-trigger]")) return;
254
+ setTimeRangeOpen(false);
255
+ };
256
+ const handleKey = (e) => {
257
+ if (e.key === "Escape") setTimeRangeOpen(false);
258
+ };
259
+ document.addEventListener("mousedown", handleClickOutside);
260
+ document.addEventListener("keydown", handleKey);
261
+ return () => {
262
+ document.removeEventListener("mousedown", handleClickOutside);
263
+ document.removeEventListener("keydown", handleKey);
264
+ };
265
+ }, [timeRangeOpen]);
266
+ const copySelectedLines = useCallback(async () => {
267
+ if (selectedLines.size === 0) return;
268
+ const text = Array.from(selectedLines).sort((a, b) => a - b).map((ln) => rawLines[ln - 1] || "").join("\n");
269
+ try {
270
+ await navigator.clipboard.writeText(text);
271
+ setCopied(true);
272
+ setTimeout(() => setCopied(false), 2e3);
273
+ } catch (_err) {
274
+ notify.error("Failed to copy selected logs to clipboard");
275
+ }
276
+ }, [
277
+ selectedLines,
278
+ rawLines,
279
+ notify
280
+ ]);
281
+ const handleGroupToggle = useCallback((lineIndex) => {
282
+ setCollapsedGroups((prev) => {
283
+ const next = new Set(prev);
284
+ if (next.has(lineIndex)) next.delete(lineIndex);
285
+ else next.add(lineIndex);
286
+ return next;
287
+ });
288
+ }, []);
289
+ const parsedLog = useMemo(() => {
290
+ let filtered = enableWorkflowCommands ? processedLines : fullParsedLog;
291
+ if (enableWorkflowCommands) filtered = filtered.filter((item) => {
292
+ if (item.command?.type === "endgroup") return false;
293
+ if (!showDebug && item.command?.type === "debug") return false;
294
+ if (item.groupId !== void 0 && item.command?.type !== "group" && collapsedGroups.has(item.groupId)) return false;
295
+ return true;
296
+ });
297
+ if (filter !== "") {
298
+ const normalizedFilter = filter.toLowerCase();
299
+ filtered = filtered.filter((item) => {
300
+ const command = enableWorkflowCommands ? item.command : void 0;
301
+ return (command?.message ? command.message : item.segments.map((segment) => segment.content).join("")).toLowerCase().includes(normalizedFilter);
302
+ });
303
+ }
304
+ return filtered;
305
+ }, [
306
+ fullParsedLog,
307
+ processedLines,
308
+ filter,
309
+ enableWorkflowCommands,
310
+ showDebug,
311
+ collapsedGroups
312
+ ]);
313
+ const smoothScrollToBottom = useCallback(() => {
314
+ if (!logContainerRef.current) return;
315
+ if (scrollAnimationRef.current) {
316
+ cancelAnimationFrame(scrollAnimationRef.current);
317
+ scrollAnimationRef.current = null;
318
+ }
319
+ const container = logContainerRef.current;
320
+ const targetScroll = container.scrollHeight - container.clientHeight;
321
+ const currentScroll = container.scrollTop;
322
+ const distance = targetScroll - currentScroll;
323
+ if (Math.abs(distance) < 5) {
324
+ container.scrollTop = targetScroll;
325
+ return;
326
+ }
327
+ const startTime = performance.now();
328
+ const duration = 150;
329
+ const animate = (currentTime) => {
330
+ const elapsed = currentTime - startTime;
331
+ const progress = Math.min(elapsed / duration, 1);
332
+ const eased = 1 - (1 - progress) ** 3;
333
+ container.scrollTop = currentScroll + distance * eased;
334
+ if (progress < 1) scrollAnimationRef.current = requestAnimationFrame(animate);
335
+ else scrollAnimationRef.current = null;
336
+ };
337
+ scrollAnimationRef.current = requestAnimationFrame(animate);
338
+ }, []);
339
+ const scrollLogViewer = useCallback((location, ref) => {
340
+ if (!ref?.current) return;
341
+ if (location === "top") ref.current.scroll({
342
+ top: 0,
343
+ left: 0,
344
+ behavior: "smooth"
345
+ });
346
+ else smoothScrollToBottom();
347
+ }, [smoothScrollToBottom]);
348
+ useEffect(() => {
349
+ const container = logContainerRef.current;
350
+ if (!container || inline) return;
351
+ const onWheel = (e) => {
352
+ if (e.deltaY < 0) userScrollUpRef.current = true;
353
+ if (scrollAnimationRef.current) {
354
+ cancelAnimationFrame(scrollAnimationRef.current);
355
+ scrollAnimationRef.current = null;
356
+ }
357
+ };
358
+ const onTouchStart = () => {
359
+ userScrollUpRef.current = true;
360
+ if (scrollAnimationRef.current) {
361
+ cancelAnimationFrame(scrollAnimationRef.current);
362
+ scrollAnimationRef.current = null;
363
+ }
364
+ };
365
+ container.addEventListener("wheel", onWheel, { passive: true });
366
+ container.addEventListener("touchstart", onTouchStart, { passive: true });
367
+ return () => {
368
+ container.removeEventListener("wheel", onWheel);
369
+ container.removeEventListener("touchstart", onTouchStart);
370
+ };
371
+ }, [inline]);
372
+ const maybeFireReachTop = useCallback((scrollTop) => {
373
+ if (!onReachTop || loadingTop || endOfLog) return;
374
+ if (scrollTop < 50 && !reachTopFiredRef.current) {
375
+ reachTopFiredRef.current = true;
376
+ onReachTop();
377
+ } else if (scrollTop > 100) reachTopFiredRef.current = false;
378
+ }, [
379
+ onReachTop,
380
+ loadingTop,
381
+ endOfLog
382
+ ]);
383
+ const handleLogScroll = (event) => {
384
+ const { scrollTop, clientHeight, scrollHeight } = event.currentTarget;
385
+ const isAnimating = scrollAnimationRef.current !== null;
386
+ const atBottom = scrollHeight - clientHeight - scrollTop < 2;
387
+ if (!isAnimating) {
388
+ if (atBottom && !follow) updateFollow(true);
389
+ else if (userScrollUpRef.current && follow) updateFollow(false);
390
+ userScrollUpRef.current = false;
391
+ }
392
+ maybeFireReachTop(scrollTop);
393
+ if (!followRef.current) {
394
+ const visibleCount = Math.ceil(clientHeight / LINE_HEIGHT) + 40;
395
+ const maxStart = Math.max(0, parsedLog.length - visibleCount);
396
+ const startIndex = Math.min(maxStart, Math.max(0, Math.floor(scrollTop / LINE_HEIGHT) - OVERSCAN));
397
+ setVisibleStart(startIndex);
398
+ setVisibleEnd(startIndex + visibleCount);
399
+ }
400
+ };
401
+ useEffect(() => {
402
+ if (!log) return;
403
+ const lines = (typeof log === "object" ? JSON.stringify(log) : log.toString()).split("\n");
404
+ const cleanedLines = lines[lines.length - 1] === "" ? lines.slice(0, -1) : lines;
405
+ const isAppending = cleanedLines.length > prevLogLengthRef.current;
406
+ prevLogLengthRef.current = cleanedLines.length;
407
+ setRawLines(cleanedLines);
408
+ const processed = cleanedLines.map((line, index) => {
409
+ if (ansiCache.current[line] === void 0) ansiCache.current[line] = parseAnsiSegments(line);
410
+ return {
411
+ index,
412
+ segments: ansiCache.current[line]
413
+ };
414
+ });
415
+ setFullParsedLog(processed);
416
+ if (enableWorkflowCommands && engine) setProcessedLines(engine.processLogLines(processed, cleanedLines));
417
+ if (followRef.current && logContainerRef.current) {
418
+ setVisibleEnd((prev) => Math.max(prev, cleanedLines.length));
419
+ if (isAppending) requestAnimationFrame(() => {
420
+ requestAnimationFrame(() => {
421
+ smoothScrollToBottom();
422
+ });
423
+ });
424
+ }
425
+ const file = new Blob([log], { type: "text/plaintext" });
426
+ const url = URL.createObjectURL(file);
427
+ setLogUrl(url);
428
+ return () => {
429
+ URL.revokeObjectURL(url);
430
+ if (scrollAnimationRef.current) cancelAnimationFrame(scrollAnimationRef.current);
431
+ };
432
+ }, [
433
+ log,
434
+ smoothScrollToBottom,
435
+ enableWorkflowCommands,
436
+ engine
437
+ ]);
438
+ const parsedLogLengthRef = useRef(parsedLog.length);
439
+ parsedLogLengthRef.current = parsedLog.length;
440
+ useEffect(() => {
441
+ if (!logContainerRef.current) return;
442
+ const observer = new ResizeObserver(() => {
443
+ if (!logContainerRef.current) return;
444
+ if (parsedLogLengthRef.current === 0) return;
445
+ const container = logContainerRef.current;
446
+ const clientHeight = container.clientHeight;
447
+ const visibleCount = Math.ceil(clientHeight / LINE_HEIGHT) + 40;
448
+ if (followRef.current) {
449
+ const minStart = Math.max(0, parsedLogLengthRef.current - visibleCount);
450
+ setVisibleStart((prev) => Math.min(prev, minStart));
451
+ setVisibleEnd(parsedLogLengthRef.current);
452
+ requestAnimationFrame(() => {
453
+ requestAnimationFrame(() => {
454
+ smoothScrollToBottom();
455
+ });
456
+ });
457
+ } else {
458
+ const maxStart = Math.max(0, parsedLogLengthRef.current - visibleCount);
459
+ const startIndex = Math.min(maxStart, Math.max(0, Math.floor(container.scrollTop / LINE_HEIGHT) - OVERSCAN));
460
+ setVisibleStart(startIndex);
461
+ setVisibleEnd(startIndex + visibleCount);
462
+ }
463
+ });
464
+ observer.observe(logContainerRef.current);
465
+ return () => observer.disconnect();
466
+ }, [smoothScrollToBottom]);
467
+ useLayoutEffect(() => {
468
+ if (prependedSignal > prevPrependedSignalRef.current) pendingPrependRef.current = true;
469
+ else if (prependedSignal < prevPrependedSignalRef.current) pendingPrependRef.current = false;
470
+ prevPrependedSignalRef.current = prependedSignal;
471
+ if (!pendingPrependRef.current) return;
472
+ const container = logContainerRef.current;
473
+ if (!container) return;
474
+ const delta = container.scrollHeight - prevScrollHeightRef.current;
475
+ if (delta <= 0) return;
476
+ pendingPrependRef.current = false;
477
+ container.scrollTop += delta;
478
+ if (!followRef.current) {
479
+ const visibleCount = Math.ceil(container.clientHeight / LINE_HEIGHT) + 40;
480
+ const maxStart = Math.max(0, parsedLog.length - visibleCount);
481
+ const startIndex = Math.min(maxStart, Math.max(0, Math.floor(container.scrollTop / LINE_HEIGHT) - OVERSCAN));
482
+ setVisibleStart(startIndex);
483
+ setVisibleEnd(startIndex + visibleCount);
484
+ }
485
+ }, [prependedSignal, parsedLog.length]);
486
+ useLayoutEffect(() => {
487
+ if (logContainerRef.current) prevScrollHeightRef.current = logContainerRef.current.scrollHeight;
488
+ });
489
+ const handleFilterChange = (event) => {
490
+ const newFilter = event.target.value;
491
+ setFilter(newFilter);
492
+ updateFollow(false);
493
+ if (logContainerRef.current) {
494
+ const clientHeight = logContainerRef.current.clientHeight;
495
+ const visibleCount = Math.ceil(clientHeight / LINE_HEIGHT) + 40;
496
+ setVisibleStart(0);
497
+ setVisibleEnd(Math.min(parsedLog.length, visibleCount));
498
+ scrollLogViewer("top", logContainerRef);
499
+ } else {
500
+ setVisibleStart(0);
501
+ setVisibleEnd(50);
502
+ }
503
+ };
504
+ const ExpandButtonIcon = fullscreen ? ShrinkIcon : ExpandIcon;
505
+ const expandButtonText = fullscreen ? "Collapse" : "Expand";
506
+ const paddingTop = visibleStart * LINE_HEIGHT;
507
+ const paddingBottom = Math.max(0, parsedLog.length - visibleEnd) * LINE_HEIGHT;
508
+ const visibleLogs = inline ? parsedLog : parsedLog.slice(visibleStart, Math.min(parsedLog.length, visibleEnd));
509
+ return /* @__PURE__ */ jsxs("div", {
510
+ "data-testid": "logviewer-container",
511
+ className: cx("flex flex-col grow", roundedBottom && "rounded-lg"),
512
+ style: !fullscreen ? {
513
+ height,
514
+ width
515
+ } : {
516
+ height: "calc(100% - 50px)",
517
+ width: "100%",
518
+ position: "fixed",
519
+ left: 0,
520
+ top: 50,
521
+ zIndex: 9999
522
+ },
523
+ children: [
524
+ /* @__PURE__ */ jsxs("div", {
525
+ className: cx("flex select-none items-center gap-x-2 p-2", inline ? "bg-[var(--theme-panel-bg)] border-b border-[var(--theme-border)]" : "theme-panel"),
526
+ children: [/* @__PURE__ */ jsxs("div", {
527
+ className: cx("w-full flex flex-row gap-x-2 items-center", hideExpand && "justify-between"),
528
+ children: [
529
+ /* @__PURE__ */ jsxs("div", {
530
+ className: "flex gap-x-2 w-full",
531
+ children: [
532
+ !inline && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
533
+ type: "button",
534
+ className: "btn btn-neutral",
535
+ onClick: () => {
536
+ scrollLogViewer("top", logContainerRef);
537
+ updateFollow(false);
538
+ },
539
+ children: [/* @__PURE__ */ jsx(ArrowUpIcon, {}), /* @__PURE__ */ jsx("span", { children: t.top })]
540
+ }), /* @__PURE__ */ jsxs("button", {
541
+ type: "button",
542
+ className: "btn btn-neutral",
543
+ onClick: () => {
544
+ if (!follow) {
545
+ updateFollow(true);
546
+ setVisibleEnd((prev) => Math.max(prev, parsedLog.length));
547
+ requestAnimationFrame(() => {
548
+ smoothScrollToBottom();
549
+ });
550
+ } else updateFollow(false);
551
+ },
552
+ children: [/* @__PURE__ */ jsx(ArrowDownIcon, {}), /* @__PURE__ */ jsx("span", { children: !follow ? "Follow" : "Following" })]
553
+ })] }),
554
+ selectedLines.size > 0 ? /* @__PURE__ */ jsxs("div", {
555
+ className: "relative flex items-center h-full",
556
+ children: [/* @__PURE__ */ jsxs("button", {
557
+ type: "button",
558
+ className: "btn btn-neutral",
559
+ onClick: copySelectedLines,
560
+ children: [copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-green-500" }) : /* @__PURE__ */ jsx(CopyIcon, {}), /* @__PURE__ */ jsx("span", { children: copied ? tCommon.copied : t.copyLines(selectedLines.size) })]
561
+ }), /* @__PURE__ */ jsx("button", {
562
+ type: "button",
563
+ "aria-label": t.clearSelection,
564
+ className: "absolute -top-1.5 -right-1.5 btn-neutral rounded-full p-1 border transition-colors shadow-sm cursor-pointer z-10",
565
+ onClick: () => setSelectedLines(/* @__PURE__ */ new Set()),
566
+ title: t.clearSelection,
567
+ children: /* @__PURE__ */ jsx(XIcon, { className: "text-[10px]" })
568
+ })]
569
+ }) : /* @__PURE__ */ jsxs("button", {
570
+ type: "button",
571
+ className: "btn btn-neutral",
572
+ onClick: copyAllLogs,
573
+ children: [copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-green-500" }) : /* @__PURE__ */ jsx(CopyIcon, {}), /* @__PURE__ */ jsx("span", { children: copied ? tCommon.copied : t.copyAll })]
574
+ }),
575
+ additionalLeftBarComponents,
576
+ enableWorkflowCommands && /* @__PURE__ */ jsx("button", {
577
+ type: "button",
578
+ className: cx("btn btn-neutral", showDebug && "btn-active"),
579
+ onClick: () => setShowDebug((prev) => !prev),
580
+ children: /* @__PURE__ */ jsx("span", { children: showDebug ? t.hideDebug : t.showDebug })
581
+ }),
582
+ enableTimeRangeFilter && /* @__PURE__ */ jsxs("div", {
583
+ className: "relative",
584
+ children: [/* @__PURE__ */ jsxs("button", {
585
+ type: "button",
586
+ "data-time-range-trigger": true,
587
+ className: "btn btn-neutral",
588
+ onClick: () => setTimeRangeOpen((o) => !o),
589
+ children: [
590
+ /* @__PURE__ */ jsx(ClockIcon, {}),
591
+ /* @__PURE__ */ jsx("span", { children: t.timeRange }),
592
+ (timeRangeFrom !== "" || timeRangeTo !== "") && /* @__PURE__ */ jsx("span", {
593
+ title: t.timeRangeActive,
594
+ className: "ml-1 px-1.5 py-0.5 text-[10px] rounded-full bg-[var(--theme-element)]/15 text-[var(--theme-element)]",
595
+ children: t.timeRangeOn
596
+ })
597
+ ]
598
+ }), timeRangeOpen && /* @__PURE__ */ jsxs("div", {
599
+ ref: timeRangePopoverRef,
600
+ className: cx("absolute top-full left-0 mt-1 z-50 w-80 p-3 rounded-lg shadow-lg", "border border-[var(--theme-border)] bg-[var(--theme-panel-bg)]", "flex flex-col gap-y-3"),
601
+ children: [
602
+ /* @__PURE__ */ jsxs("div", {
603
+ className: "flex items-center gap-x-1.5",
604
+ children: [/* @__PURE__ */ jsx("span", {
605
+ className: "text-xs font-semibold text-[var(--theme-app)]",
606
+ children: t.filterByTimeRange
607
+ }), /* @__PURE__ */ jsx(TooltipInfo, { text: t.timeRangeHelp })]
608
+ }),
609
+ /* @__PURE__ */ jsxs("label", {
610
+ className: "flex flex-col gap-y-1",
611
+ children: [/* @__PURE__ */ jsx("span", {
612
+ className: "text-[11px] uppercase tracking-wide text-[var(--theme-muted-text-color)]",
613
+ children: t.timeRangeFrom
614
+ }), /* @__PURE__ */ jsx("input", {
615
+ type: "datetime-local",
616
+ value: timeRangeFrom,
617
+ onChange: (e) => setTimeRangeFrom(e.target.value),
618
+ className: "rounded-md text-sm h-8 px-2 bg-[var(--theme-input-bg)] text-[var(--theme-input)] border border-[var(--theme-border)]"
619
+ })]
620
+ }),
621
+ /* @__PURE__ */ jsxs("label", {
622
+ className: "flex flex-col gap-y-1",
623
+ children: [/* @__PURE__ */ jsx("span", {
624
+ className: "text-[11px] uppercase tracking-wide text-[var(--theme-muted-text-color)]",
625
+ children: t.timeRangeTo
626
+ }), /* @__PURE__ */ jsx("input", {
627
+ type: "datetime-local",
628
+ value: timeRangeTo,
629
+ onChange: (e) => setTimeRangeTo(e.target.value),
630
+ className: "rounded-md text-sm h-8 px-2 bg-[var(--theme-input-bg)] text-[var(--theme-input)] border border-[var(--theme-border)]"
631
+ })]
632
+ }),
633
+ timeRangeError !== "" && /* @__PURE__ */ jsx("span", {
634
+ className: "text-[11px] text-red-500",
635
+ children: t[timeRangeError]
636
+ }),
637
+ /* @__PURE__ */ jsxs("div", {
638
+ className: "flex gap-x-2",
639
+ children: [/* @__PURE__ */ jsx("button", {
640
+ type: "button",
641
+ disabled: timeRangeError !== "",
642
+ className: "btn btn-primary flex-1 justify-center",
643
+ onClick: () => {
644
+ onTimeRangeChange?.(timeRangeFrom, timeRangeTo);
645
+ setTimeRangeOpen(false);
646
+ },
647
+ children: t.apply
648
+ }), (timeRangeFrom !== "" || timeRangeTo !== "") && /* @__PURE__ */ jsx("button", {
649
+ type: "button",
650
+ className: "btn btn-neutral flex-1 justify-center",
651
+ onClick: () => {
652
+ setTimeRangeFrom("");
653
+ setTimeRangeTo("");
654
+ onTimeRangeChange?.("", "");
655
+ setTimeRangeOpen(false);
656
+ },
657
+ children: t.clear
658
+ })]
659
+ })
660
+ ]
661
+ })]
662
+ })
663
+ ]
664
+ }),
665
+ /* @__PURE__ */ jsx("input", {
666
+ type: "text",
667
+ className: "rounded-md text-sm h-8",
668
+ placeholder: t.filterLogs,
669
+ onChange: handleFilterChange
670
+ }),
671
+ /* @__PURE__ */ jsxs("a", {
672
+ href: logUrl,
673
+ className: cx(!logUrl && "disabled", "btn btn-neutral"),
674
+ download: true,
675
+ children: [/* @__PURE__ */ jsx(DownloadIcon, {}), /* @__PURE__ */ jsx("span", { children: t.download })]
676
+ }),
677
+ /* @__PURE__ */ jsxs("button", {
678
+ type: "button",
679
+ className: cx("btn btn-neutral", hideExpand && "hidden"),
680
+ onClick: () => setFullscreen((prev) => !prev),
681
+ children: [/* @__PURE__ */ jsx(ExpandButtonIcon, {}), /* @__PURE__ */ jsx("span", { children: expandButtonText })]
682
+ })
683
+ ]
684
+ }), additionalRightBarComponents]
685
+ }),
686
+ /* @__PURE__ */ jsxs("div", {
687
+ "data-testid": "logviewer",
688
+ role: "none",
689
+ className: cx(roundedBottom && "rounded-b-lg", "w-full overflow-x-auto", !inline && "h-full grow overflow-y-auto", !inline && "bg-(--theme-muted-panel-bg)", contentClassName),
690
+ style: inline ? void 0 : {
691
+ overflowY: "auto",
692
+ position: "relative",
693
+ overscrollBehavior: "contain"
694
+ },
695
+ ref: logContainerRef,
696
+ onScroll: inline ? void 0 : handleLogScroll,
697
+ onMouseUp: handleTextMouseUp,
698
+ children: [!inline && onReachTop && /* @__PURE__ */ jsx(TopPaginationBanner, {
699
+ endOfLog,
700
+ loadingTop,
701
+ onLoadOlder: onReachTop
702
+ }), /* @__PURE__ */ jsx("div", {
703
+ className: "min-w-max",
704
+ style: inline ? void 0 : {
705
+ paddingTop,
706
+ paddingBottom
707
+ },
708
+ children: visibleLogs.map((item) => /* @__PURE__ */ jsx(LogLine, {
709
+ index: item.index,
710
+ segments: item.segments,
711
+ lineNumbers,
712
+ isSelected: selectedLines.has(item.index + 1),
713
+ lineHeight: LINE_HEIGHT,
714
+ onLineClick: handleLineClick,
715
+ searchTerm: filter,
716
+ command: enableWorkflowCommands ? item.command : void 0,
717
+ groupDepth: enableWorkflowCommands ? item.groupDepth : 0,
718
+ isGroupCollapsed: enableWorkflowCommands && item.command?.type === "group" ? collapsedGroups.has(item.index) : void 0,
719
+ onGroupToggle: enableWorkflowCommands ? handleGroupToggle : void 0,
720
+ annotationLabels
721
+ }, item.index))
722
+ })]
723
+ }),
724
+ highlightCopyPosition && highlightedText && /* @__PURE__ */ jsx("button", {
725
+ type: "button",
726
+ "data-highlight-copy-button": true,
727
+ className: cx("fixed z-[10000] flex items-center gap-1 px-2 py-1.5 text-xs font-medium", "rounded-md shadow-lg border cursor-pointer transition-colors duration-150", "bg-(--theme-panel-bg) border-(--theme-border) hover:bg-(--theme-hover) text-(--theme-app)"),
728
+ style: {
729
+ left: highlightCopyPosition.x,
730
+ top: highlightCopyPosition.y + 8,
731
+ transform: "translateX(-50%)"
732
+ },
733
+ onClick: copyHighlightedText,
734
+ children: copied ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(CheckIcon, { className: "text-green-500 w-3.5 h-3.5" }), /* @__PURE__ */ jsx("span", { children: tCommon.copied })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(CopyIcon, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ jsx("span", { children: tCommon.copy })] })
735
+ }),
736
+ (additionalBottomLeftBarComponents || additionalBottomRightBarComponents) && /* @__PURE__ */ jsxs("div", {
737
+ className: cx("flex theme-panel select-none items-center gap-x-2 p-2"),
738
+ children: [/* @__PURE__ */ jsx("div", {
739
+ className: cx("w-full flex flex-row gap-x-2 items-center", hideExpand && "justify-between"),
740
+ children: /* @__PURE__ */ jsx("div", {
741
+ className: "flex gap-x-2 w-full",
742
+ children: additionalBottomLeftBarComponents
743
+ })
744
+ }), additionalBottomRightBarComponents]
745
+ })
746
+ ]
747
+ });
748
+ }
749
+ //#endregion
750
+ export { LogViewer };