@parallelworks/ui 0.19.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
  2. package/dist/ai/adapter/mock/index.js +2 -80
  3. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  4. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  5. package/dist/ai/adapter/openai/errors.js +37 -0
  6. package/dist/ai/adapter/openai/index.js +5 -333
  7. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  8. package/dist/ai/adapter/openai/responses.js +108 -0
  9. package/dist/ai/adapter/openai/sse.js +112 -0
  10. package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
  11. package/dist/ai/agent/classifier.js +12 -0
  12. package/dist/ai/agent/diff.js +223 -0
  13. package/dist/ai/agent/diffHighlight.js +101 -0
  14. package/dist/ai/agent/permissions.js +29 -0
  15. package/dist/ai/agent/toolfmt.js +383 -0
  16. package/dist/ai/agent/transcript.js +127 -0
  17. package/dist/ai/components/AllocationSelector.js +56 -0
  18. package/dist/ai/components/AttachmentManager.js +144 -0
  19. package/dist/ai/components/AttachmentUpload.js +179 -0
  20. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  21. package/dist/ai/components/BranchNavigator.js +57 -0
  22. package/dist/ai/components/ChatEmptyState.js +171 -0
  23. package/dist/ai/components/ChatInput.js +265 -0
  24. package/dist/ai/components/ChatLayout.js +15 -0
  25. package/dist/ai/components/ChatMessage.js +338 -0
  26. package/dist/ai/components/ChatMessageList.js +301 -0
  27. package/dist/ai/components/ChatSidebar.js +345 -0
  28. package/dist/ai/components/ChatThread.js +198 -0
  29. package/dist/ai/components/ComposerChrome.js +50 -0
  30. package/dist/ai/components/ComposerFrame.js +33 -0
  31. package/dist/ai/components/DragOverlay.js +20 -0
  32. package/dist/ai/components/ModelSelector.js +343 -0
  33. package/dist/ai/components/ShareDialog.js +260 -0
  34. package/dist/ai/components/SlashMenu.js +91 -0
  35. package/dist/ai/components/agent/ActivityLine.js +151 -0
  36. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  37. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  38. package/dist/ai/components/attachmentKeys.js +10 -0
  39. package/dist/ai/core/ChatProvider.js +848 -0
  40. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  41. package/dist/ai/core/chatReducer.js +223 -0
  42. package/dist/ai/core/config.js +45 -0
  43. package/dist/ai/core/events.js +4 -0
  44. package/dist/ai/core/exportConversation.js +42 -0
  45. package/dist/ai/core/greeting.js +38 -0
  46. package/dist/ai/core/parts.js +84 -0
  47. package/dist/ai/core/useDragDrop.js +36 -0
  48. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  49. package/dist/ai/core/useSSEStream.js +98 -0
  50. package/dist/ai/index.js +43 -6644
  51. package/dist/ai/strings.js +175 -0
  52. package/dist/ai/ui/Avatar.js +35 -0
  53. package/dist/ai/ui/Dropdown.js +110 -0
  54. package/dist/ai/ui/Markdown.js +79 -0
  55. package/dist/ai/ui/Notice.js +77 -0
  56. package/dist/ai/ui/codeBreaks.js +36 -0
  57. package/dist/ai/ui/prose.js +13 -0
  58. package/dist/ai/ui/sidebar.js +148 -0
  59. package/dist/ai/utils.js +23 -0
  60. package/dist/components/AddMenu.js +46 -0
  61. package/dist/components/Avatar.js +46 -0
  62. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  63. package/dist/components/Breadcrumbs.js +83 -0
  64. package/dist/components/Button.js +83 -0
  65. package/dist/components/Callout.js +23 -0
  66. package/dist/components/Card.js +31 -0
  67. package/dist/components/CollapsiblePanel.js +77 -0
  68. package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
  69. package/dist/components/CopyToClipboard.js +81 -0
  70. package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
  71. package/dist/components/DescriptionList.js +42 -0
  72. package/dist/components/Dropdown.js +349 -0
  73. package/dist/components/EmptyState.js +27 -0
  74. package/dist/components/Filter.js +32 -0
  75. package/dist/components/FilterPill.js +13 -0
  76. package/dist/components/IconButton.js +34 -0
  77. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  78. package/dist/components/Input.js +88 -0
  79. package/dist/components/LetterBadge.js +13 -0
  80. package/dist/components/Listbox.js +123 -0
  81. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  82. package/dist/components/Markdown.js +15 -0
  83. package/dist/components/MultiSelect.js +171 -0
  84. package/dist/components/Overview.js +39 -0
  85. package/dist/components/PageHeader.js +194 -0
  86. package/dist/components/Pagination.js +35 -0
  87. package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +1 -1
  88. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  89. package/dist/components/SectionHeader.js +11 -0
  90. package/dist/components/SettingModeOption.js +30 -0
  91. package/dist/components/SettingRow.js +35 -0
  92. package/dist/components/SettingsCard.js +31 -0
  93. package/dist/components/SettingsGroup.js +17 -0
  94. package/dist/components/Sort.js +42 -0
  95. package/dist/components/StatusBadge.js +63 -0
  96. package/dist/components/SwitchToggle.js +59 -0
  97. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  98. package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
  99. package/dist/components/Toggle.js +20 -0
  100. package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
  101. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  102. package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
  103. package/dist/components/ghostButton.js +7 -0
  104. package/dist/components/inputClasses.js +4 -0
  105. package/dist/components/keys.js +27 -0
  106. package/dist/components/relativeTime.js +32 -0
  107. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  108. package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
  109. package/dist/editor/Editor.js +13 -0
  110. package/dist/editor/EditorField.js +53 -0
  111. package/dist/editor/FormCodePanel.js +173 -0
  112. package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +4 -2
  113. package/dist/editor/index.js +6 -1
  114. package/dist/editor/themes.js +91 -0
  115. package/dist/editor/workers.js +29 -0
  116. package/dist/editor/yaml.js +15 -0
  117. package/dist/file-explorer/FileExplorer.js +1402 -0
  118. package/dist/file-explorer/FileExplorerContext.js +370 -0
  119. package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  120. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  121. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  122. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  123. package/dist/file-explorer/FilePreview/index.js +266 -0
  124. package/dist/file-explorer/FilePreview/parse.js +63 -0
  125. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  126. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  127. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  128. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  129. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  130. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  131. package/dist/file-explorer/FileRow.js +165 -0
  132. package/dist/file-explorer/FileRowsWindow.js +92 -0
  133. package/dist/file-explorer/FileTable.js +172 -0
  134. package/dist/file-explorer/FileTableHeaders.js +49 -0
  135. package/dist/file-explorer/LoadMoreRow.js +46 -0
  136. package/dist/file-explorer/TreeView.js +376 -0
  137. package/dist/file-explorer/helpers.js +537 -0
  138. package/dist/file-explorer/index.js +7 -5671
  139. package/dist/file-explorer/lib/batch.js +39 -0
  140. package/dist/file-explorer/lib/errors.js +9 -0
  141. package/dist/file-explorer/lib/paging.js +124 -0
  142. package/dist/file-explorer/lib/utils.js +322 -0
  143. package/dist/file-explorer/toasts.js +400 -0
  144. package/dist/file-explorer/treeRows.js +73 -0
  145. package/dist/file-explorer/useNearEnd.js +27 -0
  146. package/dist/form/FieldWrapper.js +54 -0
  147. package/dist/form/Fields/BooleanField.js +51 -0
  148. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  149. package/dist/form/Fields/ColorField.js +33 -0
  150. package/dist/form/Fields/DropdownField.js +49 -0
  151. package/dist/form/Fields/DurationField.js +130 -0
  152. package/dist/form/Fields/LabelField.js +19 -0
  153. package/dist/form/Fields/MultiDropdownField.js +40 -0
  154. package/dist/form/Fields/NumberField.js +51 -0
  155. package/dist/form/Fields/ObjectField.js +54 -0
  156. package/dist/form/Fields/RadioField.js +49 -0
  157. package/dist/form/Fields/RangeField.js +58 -0
  158. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  159. package/dist/form/Fields/StepField.js +6 -0
  160. package/dist/form/Fields/StringField.js +37 -0
  161. package/dist/form/Fields/TextAreaField.js +31 -0
  162. package/dist/form/Fields/durationValidity.js +11 -0
  163. package/dist/form/Form.js +643 -0
  164. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  165. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  166. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  167. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  168. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  169. package/dist/form/Wizard/WizardContainer.js +138 -0
  170. package/dist/form/Wizard/WizardNavigation.js +92 -0
  171. package/dist/form/Wizard/WizardStepContent.js +35 -0
  172. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  173. package/dist/form/Wizard/useWizardState.js +118 -0
  174. package/dist/form/Wizard/utils.js +34 -0
  175. package/dist/form/fieldContext.js +26 -0
  176. package/dist/form/fieldRegistry.js +50 -0
  177. package/dist/form/index.js +17 -2321
  178. package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
  179. package/dist/form/useParsedOpts.js +62 -0
  180. package/dist/form/usePrevious.js +11 -0
  181. package/dist/form/utils/checkShowIfObject.js +14 -0
  182. package/dist/form/utils/duration.js +69 -0
  183. package/dist/form/utils/getParentValue.js +23 -0
  184. package/dist/form/utils/getPlaceholder.js +9 -0
  185. package/dist/form/utils/getValueUsingPath.js +23 -0
  186. package/dist/form/utils/secondaryField.js +22 -0
  187. package/dist/graph/AnnotationBanner.js +141 -0
  188. package/dist/graph/Collapse.js +41 -0
  189. package/dist/graph/DependencyGraph.js +1398 -0
  190. package/dist/graph/JobSummary.js +104 -0
  191. package/dist/graph/MatrixGroup.js +107 -0
  192. package/dist/graph/Reveal.js +57 -0
  193. package/dist/graph/TreeView.js +711 -0
  194. package/dist/graph/index.js +1 -2519
  195. package/dist/graph/types.js +6 -0
  196. package/dist/index.js +46 -599
  197. package/dist/list/ActionToolbar.js +184 -0
  198. package/dist/list/HoverCard.js +73 -0
  199. package/dist/list/ListPage.js +145 -0
  200. package/dist/list/ListPager.js +59 -0
  201. package/dist/list/ListTable.js +163 -0
  202. package/dist/list/ListViewControls.js +372 -0
  203. package/dist/list/RowContextMenu.js +350 -0
  204. package/dist/list/UserHoverCard.js +117 -0
  205. package/dist/list/index.js +11 -2
  206. package/dist/list/listSearch.js +137 -0
  207. package/dist/list/listView.js +210 -0
  208. package/dist/list/textEntry.js +10 -0
  209. package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
  210. package/dist/logviewer/index.js +2 -1
  211. package/dist/logviewer/segments.js +80 -0
  212. package/package.json +1 -1
  213. package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
  214. package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
  215. package/dist/chunks/editor-Dk1rbV75.js +0 -361
  216. package/dist/chunks/list-CJm875m7.js +0 -1418
  217. /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
@@ -0,0 +1,266 @@
1
+ import { useStrings } from "../../components/Provider.js";
2
+ import { ChevronLeftIcon, ChevronRightIcon, CloseIcon, DownloadFileIcon, FileIcon, LinkIcon, ZoomInIcon, ZoomOutIcon } from "../../icons.js";
3
+ import { formatFileSize } from "../lib/utils.js";
4
+ import { getPreviewKind } from "./previewType.js";
5
+ import { StreamedBadge } from "./StreamedBadge.js";
6
+ import { usePresignedUrl } from "./usePresignedUrl.js";
7
+ import { FilePreviewViewer } from "./Viewer.js";
8
+ import cx from "classnames";
9
+ import { useCallback, useEffect, useState } from "react";
10
+ import { useLocalStorage } from "usehooks-ts";
11
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
+ import { createPortal } from "react-dom";
13
+ //#region src/file-explorer/FilePreview/index.tsx
14
+ /** Document views run their own chrome and text to the edge of the stage, which
15
+ * full-window bars would float on top of; they get the bars in flow instead. */
16
+ function isDocumentView(kind) {
17
+ return kind === "code" || kind === "csv" || kind === "notebook";
18
+ }
19
+ function FilePreview({ open, node, siblings, storage, getPresignedUrl, onNavigate, onClose, onDownload, onCopyUri, showSecurityIndicator = true }) {
20
+ const t = useStrings().fileExplorer;
21
+ const [style, setStyle] = useLocalStorage("fileExplorer.previewStyle", "quicklook");
22
+ const [zoom, setZoom] = useState(100);
23
+ const { url, loading: urlLoading, error: urlError } = usePresignedUrl(open ? node : null, getPresignedUrl, {
24
+ enabled: open,
25
+ linkErrorMessage: t.preview.linkError
26
+ });
27
+ const isOverlay = style === "overlay";
28
+ const index = node ? siblings.findIndex((s) => s.path === node.path) : -1;
29
+ const hasPrev = index > 0;
30
+ const hasNext = index > -1 && index < siblings.length - 1;
31
+ const goPrev = useCallback(() => {
32
+ const prev = index > 0 ? siblings[index - 1] : void 0;
33
+ if (prev) onNavigate(prev);
34
+ }, [
35
+ index,
36
+ siblings,
37
+ onNavigate
38
+ ]);
39
+ const goNext = useCallback(() => {
40
+ const next = index > -1 ? siblings[index + 1] : void 0;
41
+ if (next) onNavigate(next);
42
+ }, [
43
+ index,
44
+ siblings,
45
+ onNavigate
46
+ ]);
47
+ useEffect(() => {
48
+ setZoom(100);
49
+ }, [node]);
50
+ useEffect(() => {
51
+ if (!open) return;
52
+ const onKeyDown = (e) => {
53
+ if (e.key === "Escape") onClose();
54
+ else if (e.key === "ArrowRight") goNext();
55
+ else if (e.key === "ArrowLeft") goPrev();
56
+ };
57
+ document.addEventListener("keydown", onKeyDown);
58
+ return () => document.removeEventListener("keydown", onKeyDown);
59
+ }, [
60
+ open,
61
+ onClose,
62
+ goNext,
63
+ goPrev
64
+ ]);
65
+ if (!open || !node) return null;
66
+ const kind = getPreviewKind(node);
67
+ const showZoom = kind === "image";
68
+ const floatingChrome = isOverlay && !isDocumentView(kind);
69
+ const topBar = /* @__PURE__ */ jsxs("div", {
70
+ className: cx("flex items-center justify-between gap-3 px-4 py-3", floatingChrome ? "absolute inset-x-0 top-0 z-10 bg-linear-to-b from-black/80 to-transparent text-white" : "shrink-0 border-b theme-border"),
71
+ children: [/* @__PURE__ */ jsxs("div", {
72
+ className: "flex min-w-0 items-center gap-2.5",
73
+ children: [
74
+ /* @__PURE__ */ jsx(FileIcon, { className: cx("h-4 w-4 shrink-0", !floatingChrome && "theme-muted-text") }),
75
+ /* @__PURE__ */ jsx("span", {
76
+ className: "truncate font-semibold",
77
+ children: node.name
78
+ }),
79
+ showSecurityIndicator && url && /* @__PURE__ */ jsx(StreamedBadge, {})
80
+ ]
81
+ }), /* @__PURE__ */ jsxs("div", {
82
+ className: "flex shrink-0 items-center gap-1.5",
83
+ children: [
84
+ /* @__PURE__ */ jsxs("div", {
85
+ className: cx("mr-1 flex items-center rounded-lg p-0.5", floatingChrome ? "bg-white/10" : "theme-muted-panel"),
86
+ children: [/* @__PURE__ */ jsx(SegButton, {
87
+ active: !isOverlay,
88
+ overlayChrome: floatingChrome,
89
+ onClick: () => setStyle("quicklook"),
90
+ children: t.preview.quickLook
91
+ }), /* @__PURE__ */ jsx(SegButton, {
92
+ active: isOverlay,
93
+ overlayChrome: floatingChrome,
94
+ onClick: () => setStyle("overlay"),
95
+ children: t.preview.fullWindow
96
+ })]
97
+ }),
98
+ /* @__PURE__ */ jsx(ChromeButton, {
99
+ overlay: floatingChrome,
100
+ label: t.preview.copyUri,
101
+ onClick: () => onCopyUri(node),
102
+ children: /* @__PURE__ */ jsx(LinkIcon, { className: "h-4 w-4" })
103
+ }),
104
+ /* @__PURE__ */ jsx(ChromeButton, {
105
+ overlay: floatingChrome,
106
+ label: t.preview.download,
107
+ onClick: () => onDownload(node),
108
+ children: /* @__PURE__ */ jsx(DownloadFileIcon, { className: "h-4 w-4" })
109
+ }),
110
+ /* @__PURE__ */ jsx(ChromeButton, {
111
+ overlay: floatingChrome,
112
+ label: t.preview.close,
113
+ onClick: onClose,
114
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: "h-4 w-4" })
115
+ })
116
+ ]
117
+ })]
118
+ });
119
+ const footer = /* @__PURE__ */ jsxs("div", {
120
+ className: cx("flex items-center justify-between gap-4 px-4 py-2.5", floatingChrome ? "absolute inset-x-0 bottom-0 z-10 bg-linear-to-t from-black/80 to-transparent text-white" : "shrink-0 border-t theme-border"),
121
+ children: [/* @__PURE__ */ jsxs("span", {
122
+ className: cx("text-xs", !floatingChrome && "theme-muted-text"),
123
+ children: [typeof node.size === "number" && formatFileSize(node.size), node.contentType && ` · ${node.contentType}`]
124
+ }), /* @__PURE__ */ jsxs("div", {
125
+ className: "flex items-center gap-3",
126
+ children: [showZoom && /* @__PURE__ */ jsxs("div", {
127
+ className: cx("flex items-center gap-1 rounded-lg p-0.5", floatingChrome ? "bg-white/10" : "theme-muted-panel"),
128
+ children: [
129
+ /* @__PURE__ */ jsx(MiniButton, {
130
+ overlay: floatingChrome,
131
+ label: t.preview.zoomOut,
132
+ onClick: () => setZoom((z) => Math.max(25, z - 25)),
133
+ children: /* @__PURE__ */ jsx(ZoomOutIcon, { className: "h-3.5 w-3.5" })
134
+ }),
135
+ /* @__PURE__ */ jsxs("span", {
136
+ className: "min-w-11 text-center text-xs tabular-nums",
137
+ children: [zoom, "%"]
138
+ }),
139
+ /* @__PURE__ */ jsx(MiniButton, {
140
+ overlay: floatingChrome,
141
+ label: t.preview.zoomIn,
142
+ onClick: () => setZoom((z) => Math.min(400, z + 25)),
143
+ children: /* @__PURE__ */ jsx(ZoomInIcon, { className: "h-3.5 w-3.5" })
144
+ })
145
+ ]
146
+ }), /* @__PURE__ */ jsxs("div", {
147
+ className: "flex items-center gap-1",
148
+ children: [
149
+ /* @__PURE__ */ jsx(MiniButton, {
150
+ overlay: floatingChrome,
151
+ label: t.preview.previousFile,
152
+ disabled: !hasPrev,
153
+ onClick: goPrev,
154
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-4 w-4" })
155
+ }),
156
+ /* @__PURE__ */ jsx("span", {
157
+ className: "min-w-14 text-center text-xs tabular-nums",
158
+ children: index >= 0 ? `${index + 1} / ${siblings.length}` : ""
159
+ }),
160
+ /* @__PURE__ */ jsx(MiniButton, {
161
+ overlay: floatingChrome,
162
+ label: t.preview.nextFile,
163
+ disabled: !hasNext,
164
+ onClick: goNext,
165
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-4 w-4" })
166
+ })
167
+ ]
168
+ })]
169
+ })]
170
+ });
171
+ const stage = /* @__PURE__ */ jsx("div", {
172
+ className: "relative min-h-0 flex-1 overflow-hidden",
173
+ children: /* @__PURE__ */ jsx(FilePreviewViewer, {
174
+ node,
175
+ kind,
176
+ url,
177
+ urlLoading,
178
+ urlError,
179
+ zoom,
180
+ storage,
181
+ onDownload: () => onDownload(node)
182
+ }, node.path)
183
+ });
184
+ return createPortal(/* @__PURE__ */ jsxs("div", {
185
+ role: "none",
186
+ className: "fixed inset-0 z-9995 flex items-center justify-center",
187
+ style: {
188
+ backgroundColor: isOverlay ? "rgba(1,4,9,.94)" : "rgba(1,4,9,.62)",
189
+ backdropFilter: isOverlay ? void 0 : "blur(3px)",
190
+ WebkitBackdropFilter: isOverlay ? void 0 : "blur(3px)"
191
+ },
192
+ onClick: (e) => {
193
+ if (e.target === e.currentTarget) onClose();
194
+ },
195
+ children: [isOverlay && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(EdgeButton, {
196
+ side: "left",
197
+ label: t.preview.previousFile,
198
+ disabled: !hasPrev,
199
+ onClick: goPrev
200
+ }), /* @__PURE__ */ jsx(EdgeButton, {
201
+ side: "right",
202
+ label: t.preview.nextFile,
203
+ disabled: !hasNext,
204
+ onClick: goNext
205
+ })] }), /* @__PURE__ */ jsxs("div", {
206
+ role: "dialog",
207
+ "aria-modal": "true",
208
+ "aria-label": node.name,
209
+ className: cx("relative flex flex-col", isOverlay ? "h-screen w-screen" : "overflow-hidden rounded-2xl border theme-border shadow-2xl", floatingChrome ? "bg-transparent" : "bg-(--theme-panel-bg)"),
210
+ style: isOverlay ? void 0 : {
211
+ width: "min(1120px, 94vw)",
212
+ height: "min(780px, 90vh)"
213
+ },
214
+ children: [
215
+ topBar,
216
+ stage,
217
+ footer
218
+ ]
219
+ })]
220
+ }), document.body);
221
+ }
222
+ function SegButton({ active, overlayChrome, onClick, children }) {
223
+ return /* @__PURE__ */ jsx("button", {
224
+ type: "button",
225
+ onClick,
226
+ className: cx("cursor-pointer whitespace-nowrap rounded-md px-2.5 py-1 text-[11.5px] font-medium transition-colors", active ? "bg-(--theme-element) text-(--theme-element-text)" : overlayChrome ? "text-white/70 hover:text-white" : "theme-muted-text hover:theme-text"),
227
+ children
228
+ });
229
+ }
230
+ function ChromeButton({ overlay, label, onClick, children }) {
231
+ return /* @__PURE__ */ jsx("button", {
232
+ type: "button",
233
+ "aria-label": label,
234
+ title: label,
235
+ onClick,
236
+ className: cx("flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg transition-colors", overlay ? "text-white/90 hover:bg-white/15" : "theme-muted-text hover:theme-hover hover:theme-text"),
237
+ children
238
+ });
239
+ }
240
+ function MiniButton({ overlay, label, onClick, disabled, children }) {
241
+ return /* @__PURE__ */ jsx("button", {
242
+ type: "button",
243
+ "aria-label": label,
244
+ title: label,
245
+ onClick,
246
+ disabled,
247
+ className: cx("flex h-6 w-7 items-center justify-center rounded-md transition-colors", disabled ? "cursor-not-allowed opacity-40" : cx("cursor-pointer", overlay ? "hover:bg-white/15" : "hover:theme-hover")),
248
+ children
249
+ });
250
+ }
251
+ function EdgeButton({ side, label, disabled, onClick }) {
252
+ return /* @__PURE__ */ jsx("button", {
253
+ type: "button",
254
+ "aria-label": label,
255
+ disabled,
256
+ onClick: (e) => {
257
+ e.stopPropagation();
258
+ onClick();
259
+ },
260
+ className: cx("absolute top-1/2 z-20 flex h-13 w-13 -translate-y-1/2 items-center justify-center rounded-full text-white backdrop-blur", side === "left" ? "left-5" : "right-5", disabled ? "cursor-not-allowed opacity-30" : "cursor-pointer hover:bg-white/20"),
261
+ style: { backgroundColor: "rgba(22,27,34,.7)" },
262
+ children: side === "left" ? /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-6 w-6" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-6 w-6" })
263
+ });
264
+ }
265
+ //#endregion
266
+ export { FilePreview };
@@ -0,0 +1,63 @@
1
+ //#region src/file-explorer/FilePreview/parse.ts
2
+ /** Parse CSV/TSV, honoring quoted fields (embedded delimiter/newline/escaped quote);
3
+ * `maxRows` stops early so a big file isn't walked in full for a preview. */
4
+ function parseDelimited(text, delimiter, maxRows) {
5
+ const rows = [];
6
+ let row = [];
7
+ let field = "";
8
+ let inQuotes = false;
9
+ for (let i = 0; i < text.length; i++) {
10
+ const char = text[i];
11
+ if (inQuotes) {
12
+ if (char === "\"") {
13
+ if (text[i + 1] === "\"") {
14
+ field += "\"";
15
+ i++;
16
+ } else inQuotes = false;
17
+ } else field += char;
18
+ continue;
19
+ }
20
+ if (char === "\"") inQuotes = true;
21
+ else if (char === delimiter) {
22
+ row.push(field);
23
+ field = "";
24
+ } else if (char === "\n" || char === "\r") {
25
+ if (char === "\r" && text[i + 1] === "\n") i++;
26
+ row.push(field);
27
+ rows.push(row);
28
+ row = [];
29
+ field = "";
30
+ if (maxRows !== void 0 && rows.length >= maxRows) break;
31
+ } else field += char;
32
+ }
33
+ if (field.length > 0 || row.length > 0) {
34
+ row.push(field);
35
+ rows.push(row);
36
+ }
37
+ while (rows.length > 0) {
38
+ const last = rows[rows.length - 1];
39
+ if (last && last.length === 1 && last[0] === "") rows.pop();
40
+ else break;
41
+ }
42
+ return rows;
43
+ }
44
+ function parseNotebook(text) {
45
+ try {
46
+ const parsed = JSON.parse(text);
47
+ if (!parsed || !Array.isArray(parsed.cells)) return null;
48
+ return parsed;
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+ /** nbformat `source`/`text` is a string or an array of lines; normalize to one string. */
54
+ function joinSource(source) {
55
+ if (Array.isArray(source)) return source.map((s) => typeof s === "string" ? s : "").join("");
56
+ return typeof source === "string" ? source : "";
57
+ }
58
+ var ANSI_ESCAPE = /\x1b\[[0-9;]*m/g;
59
+ function stripAnsi(text) {
60
+ return text.replace(ANSI_ESCAPE, "");
61
+ }
62
+ //#endregion
63
+ export { joinSource, parseDelimited, parseNotebook, stripAnsi };
@@ -0,0 +1,98 @@
1
+ import { CorsError } from "../lib/errors.js";
2
+ //#region src/file-explorer/FilePreview/previewCache.ts
3
+ var MAX_ENTRIES = 2;
4
+ var urlCache = /* @__PURE__ */ new Map();
5
+ var contentCache = /* @__PURE__ */ new Map();
6
+ function trim(cache, onEvict) {
7
+ while (cache.size > MAX_ENTRIES) {
8
+ const oldest = cache.keys().next().value;
9
+ if (oldest === void 0) return;
10
+ const evicted = cache.get(oldest);
11
+ cache.delete(oldest);
12
+ if (evicted !== void 0) onEvict(evicted);
13
+ }
14
+ }
15
+ function disposeContent(record) {
16
+ record.controller.abort();
17
+ if (record.value !== void 0) record.dispose?.(record.value);
18
+ }
19
+ function moveToNewest(cache, path, record) {
20
+ cache.delete(path);
21
+ cache.set(path, record);
22
+ }
23
+ /** Request a presigned URL for `path` once and remember the result; a failed or
24
+ * empty result is not cached so a later mount retries. */
25
+ function loadPreviewUrl(path, loader) {
26
+ const existing = urlCache.get(path);
27
+ if (existing) {
28
+ moveToNewest(urlCache, path, existing);
29
+ return existing;
30
+ }
31
+ const record = { promise: loader() };
32
+ record.promise.then((value) => {
33
+ if (value[0] && !value[1]) record.value = value;
34
+ else if (urlCache.get(path) === record) urlCache.delete(path);
35
+ }).catch(() => {
36
+ if (urlCache.get(path) === record) urlCache.delete(path);
37
+ });
38
+ urlCache.set(path, record);
39
+ trim(urlCache, () => {});
40
+ return record;
41
+ }
42
+ /** Fetch the object for `path` once and remember it; `dispose` frees the value
43
+ * (e.g. revokes a blob URL) when the entry is evicted. A rejected fetch is not
44
+ * cached so a later mount retries. */
45
+ function loadPreviewContent(path, loader, dispose) {
46
+ const existing = contentCache.get(path);
47
+ if (existing) {
48
+ moveToNewest(contentCache, path, existing);
49
+ return existing;
50
+ }
51
+ const controller = new AbortController();
52
+ const record = {
53
+ promise: loader(controller.signal),
54
+ controller,
55
+ dispose
56
+ };
57
+ record.promise.then((value) => {
58
+ record.value = value;
59
+ }).catch(() => {
60
+ if (contentCache.get(path) === record) contentCache.delete(path);
61
+ });
62
+ contentCache.set(path, record);
63
+ trim(contentCache, disposeContent);
64
+ return record;
65
+ }
66
+ /** Fetch a preview object over its signed URL; a 401/403 means the URL is stale
67
+ * or unauthorized, so drop it from the cache and let the next mount fetch a fresh
68
+ * one instead of replaying the dead one. */
69
+ async function fetchPreviewObject(path, url, signal, headers) {
70
+ let response;
71
+ try {
72
+ response = await fetch(url, {
73
+ signal,
74
+ ...headers ? { headers } : {}
75
+ });
76
+ } catch (error) {
77
+ if (error instanceof TypeError) throw new CorsError();
78
+ throw error;
79
+ }
80
+ if (!response.ok) {
81
+ if (response.status === 401 || response.status === 403) urlCache.delete(path);
82
+ throw new Error(`Failed to load file (${response.status})`);
83
+ }
84
+ return response;
85
+ }
86
+ function peekPreviewUrl(path) {
87
+ return urlCache.get(path)?.value;
88
+ }
89
+ function peekPreviewContent(path) {
90
+ return contentCache.get(path)?.value;
91
+ }
92
+ function clearPreviewCache() {
93
+ for (const record of contentCache.values()) disposeContent(record);
94
+ contentCache.clear();
95
+ urlCache.clear();
96
+ }
97
+ //#endregion
98
+ export { clearPreviewCache, fetchPreviewObject, loadPreviewContent, loadPreviewUrl, peekPreviewContent, peekPreviewUrl };
@@ -0,0 +1,151 @@
1
+ import { getFileExtension } from "../lib/utils.js";
2
+ //#region src/file-explorer/FilePreview/previewType.ts
3
+ /** Short-lived so the link doesn't linger; an hour covers a viewing session. */
4
+ var PREVIEW_URL_EXPIRES_IN = 3600;
5
+ /** Cap text pulled into the tab; media streams through native elements uncapped. */
6
+ var CODE_PREVIEW_MAX_BYTES = 10485760;
7
+ var TABULAR_PREVIEW_MAX_BYTES = 20971520;
8
+ /** A line cap bounds what a text preview holds and renders; the byte cap above cuts
9
+ * short whatever the line cap hasn't, and refuses outright only content with no line
10
+ * break to cut on. Well under Monaco's 20MB and 300K-line thresholds, past which it
11
+ * stops tokenizing and highlighting dies. */
12
+ var CODE_PREVIEW_MAX_LINES = 5e3;
13
+ /** Fetched into a blob URL to render inline regardless of served content type; falls back to download above this. */
14
+ var PDF_PREVIEW_MAX_BYTES = 52428800;
15
+ var IMAGE_EXT = /* @__PURE__ */ new Set([
16
+ "png",
17
+ "jpg",
18
+ "jpeg",
19
+ "gif",
20
+ "webp",
21
+ "bmp",
22
+ "ico",
23
+ "avif",
24
+ "svg"
25
+ ]);
26
+ var VIDEO_EXT = /* @__PURE__ */ new Set([
27
+ "mp4",
28
+ "mov",
29
+ "webm",
30
+ "m4v",
31
+ "ogv"
32
+ ]);
33
+ var AUDIO_EXT = /* @__PURE__ */ new Set([
34
+ "mp3",
35
+ "wav",
36
+ "ogg",
37
+ "oga",
38
+ "flac",
39
+ "m4a",
40
+ "aac"
41
+ ]);
42
+ var ARCHIVE_EXT = /* @__PURE__ */ new Set([
43
+ "zip",
44
+ "tar",
45
+ "gz",
46
+ "tgz",
47
+ "bz2",
48
+ "xz",
49
+ "7z",
50
+ "rar"
51
+ ]);
52
+ var LANGUAGE_BY_EXT = {
53
+ py: "python",
54
+ ipy: "python",
55
+ js: "javascript",
56
+ jsx: "javascript",
57
+ ts: "typescript",
58
+ tsx: "typescript",
59
+ go: "go",
60
+ rs: "rust",
61
+ java: "java",
62
+ c: "c",
63
+ h: "c",
64
+ cpp: "cpp",
65
+ cc: "cpp",
66
+ hpp: "cpp",
67
+ cs: "csharp",
68
+ rb: "ruby",
69
+ php: "php",
70
+ swift: "swift",
71
+ kt: "kotlin",
72
+ scala: "scala",
73
+ r: "r",
74
+ jl: "julia",
75
+ sh: "shell",
76
+ bash: "shell",
77
+ zsh: "shell",
78
+ fish: "shell",
79
+ ps1: "powershell",
80
+ sql: "sql",
81
+ json: "json",
82
+ jsonl: "json",
83
+ yaml: "yaml",
84
+ yml: "yaml",
85
+ toml: "ini",
86
+ ini: "ini",
87
+ cfg: "ini",
88
+ conf: "ini",
89
+ env: "ini",
90
+ xml: "xml",
91
+ html: "html",
92
+ htm: "html",
93
+ css: "css",
94
+ scss: "scss",
95
+ md: "markdown",
96
+ markdown: "markdown",
97
+ tex: "plaintext",
98
+ txt: "plaintext",
99
+ log: "plaintext",
100
+ gitignore: "plaintext"
101
+ };
102
+ var LANGUAGE_BY_FILENAME = {
103
+ dockerfile: "dockerfile",
104
+ makefile: "plaintext"
105
+ };
106
+ function getMonacoLanguage(node) {
107
+ const ext = getFileExtension(node.name);
108
+ if (ext && LANGUAGE_BY_EXT[ext]) return LANGUAGE_BY_EXT[ext];
109
+ return LANGUAGE_BY_FILENAME[node.name.toLowerCase()] ?? "plaintext";
110
+ }
111
+ function isCodeFile(node) {
112
+ const ext = getFileExtension(node.name);
113
+ return ext !== null && ext in LANGUAGE_BY_EXT || node.name.toLowerCase() in LANGUAGE_BY_FILENAME;
114
+ }
115
+ function kindFromContentType(ct) {
116
+ if (ct === "application/pdf") return "pdf";
117
+ if (ct === "application/x-ipynb+json") return "notebook";
118
+ if (ct === "text/csv") return "csv";
119
+ if (ct.startsWith("image/")) return "image";
120
+ if (ct.startsWith("video/")) return "video";
121
+ if (ct.startsWith("audio/")) return "audio";
122
+ if (ct.startsWith("text/") || ct === "application/json" || ct === "application/xml") return "code";
123
+ return null;
124
+ }
125
+ function kindFromExtension(ext) {
126
+ if (ext === "pdf") return "pdf";
127
+ if (ext === "ipynb") return "notebook";
128
+ if (ext === "csv" || ext === "tsv") return "csv";
129
+ if (IMAGE_EXT.has(ext)) return "image";
130
+ if (VIDEO_EXT.has(ext)) return "video";
131
+ if (AUDIO_EXT.has(ext)) return "audio";
132
+ if (ARCHIVE_EXT.has(ext)) return "archive";
133
+ if (ext in LANGUAGE_BY_EXT) return "code";
134
+ return null;
135
+ }
136
+ /** Content type wins when present; extension is the fallback. */
137
+ function getPreviewKind(node) {
138
+ if (node.type !== "file") return "unsupported";
139
+ const ct = (node.contentType ?? "").split(";")[0]?.toLowerCase().trim() ?? "";
140
+ const ext = getFileExtension(node.name);
141
+ const ctKind = kindFromContentType(ct);
142
+ const extKind = ext !== null ? kindFromExtension(ext) : null;
143
+ if (ctKind === "code" && (extKind === "csv" || extKind === "notebook")) return extKind;
144
+ return ctKind ?? extKind ?? (isCodeFile(node) ? "code" : "unsupported");
145
+ }
146
+ function canPreview(node) {
147
+ const kind = getPreviewKind(node);
148
+ return kind !== "unsupported" && kind !== "archive";
149
+ }
150
+ //#endregion
151
+ export { CODE_PREVIEW_MAX_BYTES, CODE_PREVIEW_MAX_LINES, PDF_PREVIEW_MAX_BYTES, PREVIEW_URL_EXPIRES_IN, TABULAR_PREVIEW_MAX_BYTES, canPreview, getFileExtension, getMonacoLanguage, getPreviewKind };