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