@parallelworks/ui 0.19.1 → 0.21.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.
- package/README.md +1 -1
- package/dist/ai/adapter/openai/createOpenAIStream.js +3 -2
- package/dist/ai/agent/diff.d.ts +0 -1
- package/dist/ai/agent/diff.js +3 -2
- package/dist/ai/agent/toolfmt.js +2 -3
- package/dist/ai/ai.css +5 -0
- package/dist/ai/components/AllocationSelector.js +3 -2
- package/dist/ai/components/AttachmentManager.js +5 -2
- package/dist/ai/components/BranchNavigator.js +4 -2
- package/dist/ai/components/ChatInput.d.ts +2 -5
- package/dist/ai/components/ChatInput.js +10 -7
- package/dist/ai/components/ChatMessage.js +11 -8
- package/dist/ai/components/ChatSidebar.d.ts +0 -1
- package/dist/ai/components/ChatSidebar.js +4 -6
- package/dist/ai/components/ChatThread.js +5 -8
- package/dist/ai/components/ModelSelector.js +3 -2
- package/dist/ai/components/ShareDialog.js +6 -3
- package/dist/ai/components/SlashMenu.d.ts +0 -1
- package/dist/ai/components/agent/ActivityLine.d.ts +0 -1
- package/dist/ai/components/agent/ActivityLine.js +2 -2
- package/dist/ai/components/agent/AgentMessageParts.d.ts +1 -26
- package/dist/ai/components/agent/AgentMessageParts.js +4 -5
- package/dist/ai/core/ChatProvider.d.ts +2 -6
- package/dist/ai/core/ChatProvider.js +42 -67
- package/dist/ai/core/KeyboardShortcutsProvider.js +1 -1
- package/dist/ai/core/chatReducer.d.ts +0 -6
- package/dist/ai/core/chatReducer.js +1 -15
- package/dist/ai/core/config.js +2 -1
- package/dist/ai/core/useKeyboardShortcuts.d.ts +3 -1
- package/dist/ai/core/useKeyboardShortcuts.js +9 -11
- package/dist/ai/core/useSSEStream.d.ts +0 -1
- package/dist/ai/core/useSSEStream.js +5 -17
- package/dist/ai/strings.d.ts +0 -1
- package/dist/ai/strings.js +0 -1
- package/dist/ai/types.d.ts +1 -1
- package/dist/ai/ui/Avatar.d.ts +1 -2
- package/dist/ai/ui/Avatar.js +7 -18
- package/dist/ai/ui/Markdown.d.ts +1 -3
- package/dist/ai/ui/Markdown.js +1 -2
- package/dist/ai/ui/sidebar.d.ts +0 -1
- package/dist/ai/ui/sidebar.js +3 -1
- package/dist/ai/utils.js +1 -1
- package/dist/assets/editor.worker-DfmPPyOL.js +60 -0
- package/dist/assets/json.worker-Dqgjpq9F.js +92 -0
- package/dist/assets/yaml.worker-DLx0whrM.js +1441 -0
- package/dist/components/Avatar.js +4 -2
- package/dist/components/BareModal.js +1 -5
- package/dist/components/Breadcrumbs.js +21 -14
- package/dist/components/CollapsiblePanel.d.ts +1 -3
- package/dist/components/CollapsiblePanel.js +5 -5
- package/dist/components/Dropdown.d.ts +0 -4
- package/dist/components/Dropdown.js +5 -6
- package/dist/components/Listbox.js +14 -18
- package/dist/components/MultiSelect.js +5 -8
- package/dist/components/Pagination.js +1 -1
- package/dist/components/Provider.d.ts +0 -8
- package/dist/components/Provider.js +12 -4
- package/dist/components/SwitchToggle.js +3 -5
- package/dist/components/Table.d.ts +1 -3
- package/dist/components/dropdownUtils.js +5 -6
- package/dist/components/relativeTime.d.ts +0 -7
- package/dist/components/relativeTime.js +1 -1
- package/dist/duration.js +1 -1
- package/dist/editor/Editor.d.ts +1 -1
- package/dist/editor/Editor.js +1 -1
- package/dist/editor/EditorField.d.ts +0 -1
- package/dist/editor/EditorField.js +8 -8
- package/dist/editor/FormCodePanel.js +14 -20
- package/dist/editor/Monaco.js +2 -25
- package/dist/editor/workers.d.ts +5 -0
- package/dist/editor/workers.js +14 -8
- package/dist/editor/yaml.d.ts +9 -1
- package/dist/editor/yaml.worker.d.ts +1 -0
- package/dist/editor/yamlLanguage.d.ts +6 -0
- package/dist/editor/yamlLanguage.js +312 -0
- package/dist/file-explorer/FileExplorer.js +60 -60
- package/dist/file-explorer/FileExplorerContext.d.ts +1 -2
- package/dist/file-explorer/FileExplorerContext.js +92 -125
- package/dist/file-explorer/FilePreview/Inline.d.ts +1 -2
- package/dist/file-explorer/FilePreview/Inline.js +2 -2
- package/dist/file-explorer/FilePreview/Viewer.js +0 -4
- package/dist/file-explorer/FilePreview/index.d.ts +1 -2
- package/dist/file-explorer/FilePreview/index.js +3 -3
- package/dist/file-explorer/FilePreview/parse.d.ts +2 -1
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.d.ts +5 -4
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +23 -36
- package/dist/file-explorer/FilePreview/useObjectText.d.ts +1 -2
- package/dist/file-explorer/FilePreview/useObjectText.js +5 -7
- package/dist/file-explorer/FileRow.js +1 -1
- package/dist/file-explorer/FileRowsWindow.d.ts +5 -12
- package/dist/file-explorer/FileTable.d.ts +2 -6
- package/dist/file-explorer/LoadMoreRow.d.ts +8 -0
- package/dist/file-explorer/TreeView.d.ts +0 -1
- package/dist/file-explorer/TreeView.js +6 -6
- package/dist/file-explorer/helpers.js +2 -4
- package/dist/file-explorer/lib/fileExplorer.d.ts +0 -2
- package/dist/file-explorer/lib/types.d.ts +0 -1
- package/dist/file-explorer/lib/utils.js +15 -20
- package/dist/file-explorer/toasts.js +36 -34
- package/dist/form/Fields/BooleanField.js +5 -4
- package/dist/form/Fields/CheckboxGroupField.js +5 -4
- package/dist/form/Fields/ColorField.js +5 -4
- package/dist/form/Fields/DropdownField.d.ts +0 -1
- package/dist/form/Fields/DropdownField.js +10 -13
- package/dist/form/Fields/DurationField.js +2 -2
- package/dist/form/Fields/LabelField.js +5 -5
- package/dist/form/Fields/MultiDropdownField.d.ts +1 -1
- package/dist/form/Fields/MultiDropdownField.js +8 -11
- package/dist/form/Fields/NumberField.js +6 -5
- package/dist/form/Fields/ObjectField.d.ts +1 -2
- package/dist/form/Fields/ObjectField.js +22 -21
- package/dist/form/Fields/RadioField.js +4 -3
- package/dist/form/Fields/RangeField.js +7 -6
- package/dist/form/Fields/StringField.js +2 -1
- package/dist/form/Fields/TextAreaField.js +2 -1
- package/dist/form/Form.d.ts +7 -8
- package/dist/form/Form.js +52 -78
- package/dist/form/SpecialTypes/DropdownWrapper.d.ts +0 -2
- package/dist/form/SpecialTypes/DropdownWrapper.js +1 -3
- package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +1 -3
- package/dist/form/SpecialTypes/FormikCustomDropdown.js +4 -7
- package/dist/form/SpecialTypes/FormikCustomInput.js +13 -11
- package/dist/form/Wizard/WizardContainer.js +8 -25
- package/dist/form/Wizard/WizardNavigation.d.ts +1 -1
- package/dist/form/Wizard/WizardNavigation.js +5 -6
- package/dist/form/Wizard/WizardStepContent.d.ts +1 -1
- package/dist/form/Wizard/WizardStepContent.js +2 -2
- package/dist/form/Wizard/WizardStepIndicator.js +7 -17
- package/dist/form/Wizard/types.d.ts +4 -46
- package/dist/form/Wizard/useWizardState.d.ts +2 -10
- package/dist/form/Wizard/useWizardState.js +42 -92
- package/dist/form/Wizard/utils.js +6 -11
- package/dist/form/lib.js +28 -54
- package/dist/form/types/fieldTypes.d.ts +4 -5
- package/dist/form/utils/dependentOptions.d.ts +6 -0
- package/dist/form/utils/dependentOptions.js +21 -0
- package/dist/form/utils/getParentValue.d.ts +2 -1
- package/dist/form/utils/getParentValue.js +10 -15
- package/dist/form/utils/getValueUsingPath.js +1 -1
- package/dist/graph/AnnotationBanner.d.ts +1 -1
- package/dist/graph/AnnotationBanner.js +1 -1
- package/dist/graph/Collapse.d.ts +3 -3
- package/dist/graph/Collapse.js +3 -8
- package/dist/graph/DependencyGraph.d.ts +5 -4
- package/dist/graph/DependencyGraph.js +172 -222
- package/dist/graph/JobSummary.d.ts +10 -8
- package/dist/graph/JobSummary.js +13 -13
- package/dist/graph/MatrixGroup.d.ts +5 -17
- package/dist/graph/MatrixGroup.js +11 -22
- package/dist/graph/TreeView.d.ts +1 -3
- package/dist/graph/TreeView.js +104 -491
- package/dist/graph/types.d.ts +3 -2
- package/dist/graph/util.d.ts +5 -0
- package/dist/graph/util.js +18 -0
- package/dist/icons.d.ts +5 -5
- package/dist/icons.js +6 -6
- package/dist/index.d.ts +1 -1
- package/dist/list/ListViewControls.js +17 -35
- package/dist/list/RowContextMenu.js +9 -8
- package/dist/list/UserHoverCard.js +5 -5
- package/dist/logviewer/LogViewer.js +7 -9
- package/dist/logviewer/segments.js +2 -2
- package/dist/safeUrl.d.ts +6 -0
- package/dist/safeUrl.js +22 -0
- package/dist/styles/theme.css +1 -0
- package/dist/styles.css +1 -1
- package/dist/theme/index.js +5 -5
- package/package.json +33 -37
- package/dist/ai/ui/buttons.d.ts +0 -1
- package/dist/assets/editor.worker-BmHUIVG4.js +0 -14807
- package/dist/assets/json.worker-D8bJ92nw.js +0 -22207
- package/dist/assets/yaml.worker-C4gyGAko.js +0 -50201
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { safeUrl } from "../safeUrl.js";
|
|
1
2
|
import { useNotify, useSlots, useStrings } from "../components/Provider.js";
|
|
2
3
|
import { AccessIcon, AlertIcon, AngleDownIcon, ChevronRightIcon, ClipboardIcon, CollapseIcon, DownloadFileIcon, EyeIcon, FileIcon, FileTextIcon, FolderIcon, LinkIcon, RefreshIcon, ShareIcon, TrashIcon, UploadIcon } from "../icons.js";
|
|
3
4
|
import { keyedByContent } from "../components/keys.js";
|
|
@@ -55,6 +56,10 @@ function UriCard({ value }) {
|
|
|
55
56
|
]
|
|
56
57
|
});
|
|
57
58
|
}
|
|
59
|
+
var MAX_UPLOAD_SIZE = 85899345920;
|
|
60
|
+
function isUploadSizeExceeded(size) {
|
|
61
|
+
return size > MAX_UPLOAD_SIZE;
|
|
62
|
+
}
|
|
58
63
|
function isStorageDirectory(node) {
|
|
59
64
|
return node?.type === "directory" && !!node.storageId;
|
|
60
65
|
}
|
|
@@ -67,7 +72,7 @@ function getAncestorDirPaths(path) {
|
|
|
67
72
|
const segments = (isDir ? path.slice(0, -1) : path).split("/").filter(Boolean);
|
|
68
73
|
const dirSegmentCount = isDir ? segments.length : segments.length - 1;
|
|
69
74
|
const ancestors = [];
|
|
70
|
-
for (let i = 1; i <= dirSegmentCount; i++) ancestors.push(segments.slice(0, i).join("/")
|
|
75
|
+
for (let i = 1; i <= dirSegmentCount; i++) ancestors.push(`${segments.slice(0, i).join("/")}/`);
|
|
71
76
|
return ancestors;
|
|
72
77
|
}
|
|
73
78
|
/** The tree's width is the host's when the tree is embedded on its own, and this
|
|
@@ -156,9 +161,10 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
156
161
|
setCheckedItems(/* @__PURE__ */ new Set());
|
|
157
162
|
}
|
|
158
163
|
const selectedNodeChildren = useMemo(() => selectedNode ? getNodeChildren(parentToChildrenMap, selectedNode.path) : [], [parentToChildrenMap, selectedNode]);
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
164
|
+
const findStorage = (storageId) => storages.find((s) => s.id === storageId);
|
|
165
|
+
const storageCanWrite = (storageId) => findStorage(storageId)?.canWrite === true;
|
|
166
|
+
const storageCanUpload = (storageId) => findStorage(storageId)?.canUpload !== false;
|
|
167
|
+
const selectedStorage = findStorage(selectedNode?.storageId);
|
|
162
168
|
const selectedNodeCanWrite = selectedStorage?.canWrite === true;
|
|
163
169
|
const selectedNodeCanUpload = selectedStorage?.canUpload !== false;
|
|
164
170
|
const selectedNodeCanShare = selectedStorage?.canShare !== false;
|
|
@@ -180,10 +186,6 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
180
186
|
useEffect(() => clearPreviewCache, []);
|
|
181
187
|
const { openMenu, contextMenu } = useRowMenu();
|
|
182
188
|
const [sidebarWidth, setSidebarWidth] = useLocalStorage(SIDEBAR_WIDTH_STORAGE_KEY, 300);
|
|
183
|
-
const MAX_UPLOAD_SIZE = 85899345920;
|
|
184
|
-
const isUploadSizeExceeded = (size) => {
|
|
185
|
-
return size > MAX_UPLOAD_SIZE;
|
|
186
|
-
};
|
|
187
189
|
const handleToggleExpand = useCallback((path) => {
|
|
188
190
|
setExpandedPaths((prev) => {
|
|
189
191
|
const next = new Set(prev);
|
|
@@ -195,10 +197,10 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
195
197
|
setExpandedPaths(/* @__PURE__ */ new Set([""]));
|
|
196
198
|
}, []);
|
|
197
199
|
const getStorageProviderAndClient = async (storageId) => {
|
|
198
|
-
const storage =
|
|
200
|
+
const storage = findStorage(storageId);
|
|
199
201
|
if (!storage) {
|
|
200
202
|
notify.error(t.messages.storageUnavailable);
|
|
201
|
-
return;
|
|
203
|
+
return null;
|
|
202
204
|
}
|
|
203
205
|
const { provider, client } = await getProviderAndClient(storage).catch(() => ({
|
|
204
206
|
provider: null,
|
|
@@ -235,7 +237,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
235
237
|
const factory = await getStorageProviderAndClient(node.storageId);
|
|
236
238
|
if (!factory) throw new Error("Failed to connect to storage provider.");
|
|
237
239
|
const { storage, provider, client } = factory;
|
|
238
|
-
if (provider
|
|
240
|
+
if (provider.listDirectoryInput && provider.convertDataToStorageObjects) {
|
|
239
241
|
const dir_path = node.root ? "" : node.relativePath ?? "";
|
|
240
242
|
const input = provider.listDirectoryInput(storage, dir_path, cursor ? { cursor } : {});
|
|
241
243
|
const objects = await client.listDirectory(input);
|
|
@@ -261,7 +263,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
261
263
|
const errorMessage = isCorsError ? error.message || "CORS error" : error instanceof Error ? error.message : "Unknown error";
|
|
262
264
|
if (owns()) {
|
|
263
265
|
setListings((prev) => recordListingError(options?.replace ? clearListingsUnder(prev, node.path) : prev, node.path, errorMessage));
|
|
264
|
-
updateConnectionIssuesMessage((prev) => new Map(prev).set(nodeStorageId, `Failed to load contents for ${node
|
|
266
|
+
updateConnectionIssuesMessage((prev) => new Map(prev).set(nodeStorageId, `Failed to load contents for ${node.displayName || node.name}: ${errorMessage}`));
|
|
265
267
|
if (isCorsError) setHasCorsIssue((prev) => new Map(prev).set(nodeStorageId, true));
|
|
266
268
|
}
|
|
267
269
|
return { corsError: isCorsError };
|
|
@@ -282,7 +284,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
282
284
|
setDetailTab("details");
|
|
283
285
|
}
|
|
284
286
|
setSelectedPath(path);
|
|
285
|
-
if (node.type === "directory" && node
|
|
287
|
+
if (node.type === "directory" && node.storageId && !isListed(listings, path)) await fetchNodeChildren(node);
|
|
286
288
|
};
|
|
287
289
|
useEffect(() => {
|
|
288
290
|
if (!normalizedSelectedPath) return;
|
|
@@ -429,18 +431,21 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
429
431
|
if (selectedNode && selectedNode.type === "directory") return true;
|
|
430
432
|
return false;
|
|
431
433
|
};
|
|
434
|
+
const getFilesToDownload = () => {
|
|
435
|
+
if (checkedItems.size > 0) return Array.from(checkedItems).map((path) => treeMap[path]).filter((node) => node?.type === "file");
|
|
436
|
+
return selectedNode?.type === "file" ? [selectedNode] : [];
|
|
437
|
+
};
|
|
432
438
|
const handleDownload = async () => {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
if (filesToDownload.length === 0) {
|
|
439
|
+
const filesToDownload = getFilesToDownload();
|
|
440
|
+
const firstFile = filesToDownload[0];
|
|
441
|
+
if (!firstFile) {
|
|
437
442
|
notify.error(t.messages.noFilesForDownload);
|
|
438
443
|
return;
|
|
439
444
|
}
|
|
440
|
-
const factory = await getStorageProviderAndClient(
|
|
445
|
+
const factory = await getStorageProviderAndClient(firstFile.storageId);
|
|
441
446
|
if (!factory) return;
|
|
442
447
|
const { provider, client } = factory;
|
|
443
|
-
if (!provider
|
|
448
|
+
if (!provider.getFileInput) {
|
|
444
449
|
notify.error(t.messages.downloadUnsupported);
|
|
445
450
|
return;
|
|
446
451
|
}
|
|
@@ -459,7 +464,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
459
464
|
const factory = await getStorageProviderAndClient(node.storageId);
|
|
460
465
|
if (!factory) return;
|
|
461
466
|
const { provider, client } = factory;
|
|
462
|
-
if (!provider
|
|
467
|
+
if (!provider.getFileInput) {
|
|
463
468
|
notify.error(t.messages.sharingUnsupported);
|
|
464
469
|
return;
|
|
465
470
|
}
|
|
@@ -473,8 +478,10 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
473
478
|
notify.info(t.messages.fileLinkCopied);
|
|
474
479
|
};
|
|
475
480
|
const triggerBrowserDownload = (url, filename) => {
|
|
481
|
+
const href = safeUrl(url);
|
|
482
|
+
if (!href) return;
|
|
476
483
|
const a = document.createElement("a");
|
|
477
|
-
a.href =
|
|
484
|
+
a.href = href;
|
|
478
485
|
a.download = filename;
|
|
479
486
|
document.body.appendChild(a);
|
|
480
487
|
a.click();
|
|
@@ -486,14 +493,14 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
486
493
|
const factory = await getStorageProviderAndClient(node.storageId);
|
|
487
494
|
if (!factory) return [null, /* @__PURE__ */ new Error("Failed to connect to storage provider.")];
|
|
488
495
|
const { provider, client } = factory;
|
|
489
|
-
if (!provider
|
|
496
|
+
if (!provider.getFileInput) return [null, /* @__PURE__ */ new Error("Preview is not supported for this storage.")];
|
|
490
497
|
const input = provider.getFileInput(node.storageName ?? "", node, PREVIEW_URL_EXPIRES_IN, downloadFilename);
|
|
491
498
|
return client.getFile(input);
|
|
492
499
|
};
|
|
493
500
|
const previewSiblings = useMemo(() => previewNode ? getNodeChildren(parentToChildrenMap, getParentPath(previewNode.path)).filter((n) => n.type === "file") : [], [previewNode, parentToChildrenMap]);
|
|
494
501
|
const openPreview = (node) => {
|
|
495
502
|
if (node.type !== "file") return;
|
|
496
|
-
if (onOpenFile?.(node,
|
|
503
|
+
if (onOpenFile?.(node, findStorage(node.storageId))) return;
|
|
497
504
|
setPreviewNode(node);
|
|
498
505
|
setPreviewOpen(true);
|
|
499
506
|
};
|
|
@@ -505,7 +512,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
505
512
|
if (!expandedPaths.has(node.path)) handleToggleExpand(node.path);
|
|
506
513
|
};
|
|
507
514
|
const getNodeUris = (node) => {
|
|
508
|
-
const storage =
|
|
515
|
+
const storage = findStorage(node.storageId);
|
|
509
516
|
if (!storage || !objectUris) return [];
|
|
510
517
|
return objectUris(storage, getObjectKeyFromNode(node));
|
|
511
518
|
};
|
|
@@ -531,7 +538,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
531
538
|
triggerBrowserDownload(presignedUrl, node.name);
|
|
532
539
|
};
|
|
533
540
|
const deleteNode = (node) => {
|
|
534
|
-
if (
|
|
541
|
+
if (findStorage(node.storageId)?.canWrite !== true) {
|
|
535
542
|
notify.error(t.messages.noWriteAccess);
|
|
536
543
|
return;
|
|
537
544
|
}
|
|
@@ -553,7 +560,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
553
560
|
}];
|
|
554
561
|
};
|
|
555
562
|
const buildRowMenu = (node) => {
|
|
556
|
-
const storage =
|
|
563
|
+
const storage = findStorage(node.storageId);
|
|
557
564
|
const nodeCanWrite = storage?.canWrite === true;
|
|
558
565
|
const nodeCanShare = storage?.canShare !== false;
|
|
559
566
|
const isFile = node.type === "file";
|
|
@@ -646,13 +653,10 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
646
653
|
});
|
|
647
654
|
};
|
|
648
655
|
const generateDownloadCommand = () => {
|
|
649
|
-
|
|
650
|
-
if (
|
|
651
|
-
else if (selectedNode && selectedNode.type === "file") filesToDownload = [selectedNode];
|
|
652
|
-
if (filesToDownload.length === 0) return "";
|
|
653
|
-
if (!downloadCommand) return "";
|
|
656
|
+
const filesToDownload = getFilesToDownload();
|
|
657
|
+
if (!downloadCommand || filesToDownload.length === 0) return "";
|
|
654
658
|
const objects = filesToDownload.flatMap((node) => {
|
|
655
|
-
const storage =
|
|
659
|
+
const storage = findStorage(node.storageId);
|
|
656
660
|
return storage ? [{
|
|
657
661
|
storage,
|
|
658
662
|
key: getObjectKeyFromNode(node),
|
|
@@ -694,16 +698,17 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
694
698
|
}
|
|
695
699
|
};
|
|
696
700
|
const handleDelete = async () => {
|
|
697
|
-
|
|
701
|
+
const firstPending = pendingDelete?.[0];
|
|
702
|
+
if (!pendingDelete || !firstPending) {
|
|
698
703
|
notify.error(t.messages.noItemsForDeletion);
|
|
699
704
|
return;
|
|
700
705
|
}
|
|
701
|
-
const parentPath = getParentPath(
|
|
706
|
+
const parentPath = getParentPath(firstPending.path);
|
|
702
707
|
const parentNode = treeMap[parentPath];
|
|
703
|
-
const factory = await getStorageProviderAndClient(
|
|
708
|
+
const factory = await getStorageProviderAndClient(firstPending.storageId);
|
|
704
709
|
if (!factory) return;
|
|
705
710
|
const { storage, provider, client } = factory;
|
|
706
|
-
if (!provider
|
|
711
|
+
if (!provider.deleteFilesInput) {
|
|
707
712
|
notify.error(t.messages.deleteUnsupported);
|
|
708
713
|
return;
|
|
709
714
|
}
|
|
@@ -744,7 +749,6 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
744
749
|
notify.warning(t.messages.waitForCurrentUpload);
|
|
745
750
|
return;
|
|
746
751
|
}
|
|
747
|
-
setWaitForUpload(true);
|
|
748
752
|
const uploadNodes = Array.from(files).map((file) => ({
|
|
749
753
|
name: file.name,
|
|
750
754
|
file,
|
|
@@ -757,7 +761,6 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
757
761
|
totalSize
|
|
758
762
|
});
|
|
759
763
|
setUploadModalOpen(true);
|
|
760
|
-
setWaitForUpload(false);
|
|
761
764
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
762
765
|
if (folderInputRef.current) folderInputRef.current.value = "";
|
|
763
766
|
};
|
|
@@ -771,7 +774,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
771
774
|
return;
|
|
772
775
|
}
|
|
773
776
|
const targetNode = treeMap[pendingUpload.targetPath];
|
|
774
|
-
if (!targetNode
|
|
777
|
+
if (!targetNode?.storageId) {
|
|
775
778
|
notify.error(t.messages.invalidUploadTarget);
|
|
776
779
|
return;
|
|
777
780
|
}
|
|
@@ -783,7 +786,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
783
786
|
const { storage, provider, client } = factory;
|
|
784
787
|
const storageName = storage.bucketName || storage.name;
|
|
785
788
|
const cleanTargetPath = targetNode.root ? "" : removeLeadingAndTrailingSlashes(targetNode.relativePath || "");
|
|
786
|
-
if (!provider
|
|
789
|
+
if (!provider.uploadFileInput) {
|
|
787
790
|
notify.error(t.messages.uploadUnsupported);
|
|
788
791
|
return;
|
|
789
792
|
}
|
|
@@ -810,7 +813,6 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
810
813
|
}
|
|
811
814
|
setUploadModalOpen(false);
|
|
812
815
|
setPendingUpload(null);
|
|
813
|
-
setWaitForUpload(false);
|
|
814
816
|
};
|
|
815
817
|
const validateFolderName = (name) => {
|
|
816
818
|
if (createFolderTarget?.type !== "directory") return null;
|
|
@@ -858,6 +860,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
858
860
|
if (onRefresh) onRefresh();
|
|
859
861
|
return { corsError: false };
|
|
860
862
|
};
|
|
863
|
+
const downloadCommandText = generateDownloadCommand();
|
|
861
864
|
return /* @__PURE__ */ jsxs("div", {
|
|
862
865
|
className: "w-full h-full flex relative",
|
|
863
866
|
children: [
|
|
@@ -1055,22 +1058,19 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
1055
1058
|
className: "text-sm rounded-sm hover:theme-hover cursor-pointer w-full items-center px-2 py-1.5",
|
|
1056
1059
|
onClick: handleDownload,
|
|
1057
1060
|
children: t.chrome.downloadFromBrowser
|
|
1058
|
-
}) }), downloadCommand &&
|
|
1061
|
+
}) }), downloadCommand && downloadCommandText && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MenuSeparator, { className: "my-0.5 h-px theme-border" }), /* @__PURE__ */ jsx(MenuItem, { children: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
1059
1062
|
className: "text-sm w-full text-center pointer-events-none px-2 py-1.5",
|
|
1060
1063
|
children: downloadCommand.label
|
|
1061
|
-
}), (
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
1066
|
-
className: "
|
|
1067
|
-
children:
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
})
|
|
1072
|
-
});
|
|
1073
|
-
})()] }) })] })]
|
|
1064
|
+
}), /* @__PURE__ */ jsx(CopyCodeBlock, {
|
|
1065
|
+
textToCopy: downloadCommandText,
|
|
1066
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1067
|
+
className: "overflow-x-auto text-xs",
|
|
1068
|
+
children: keyedByContent(downloadCommandText.split("\n"), (l) => l).map(({ key, item: line }) => /* @__PURE__ */ jsx("div", {
|
|
1069
|
+
className: "whitespace-nowrap",
|
|
1070
|
+
children: line
|
|
1071
|
+
}, key))
|
|
1072
|
+
})
|
|
1073
|
+
})] }) })] })]
|
|
1074
1074
|
})] }),
|
|
1075
1075
|
/* @__PURE__ */ jsxs("button", {
|
|
1076
1076
|
type: "button",
|
|
@@ -1078,7 +1078,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
1078
1078
|
className: "btn btn-info cursor-pointer flex items-center justify-center",
|
|
1079
1079
|
disabled: !selectedNode.storageId,
|
|
1080
1080
|
onClick: () => setAccessDrawerOpen(true),
|
|
1081
|
-
hidden:
|
|
1081
|
+
hidden: groups.length === 0 || !selectedNodeCanManageAccess,
|
|
1082
1082
|
children: [/* @__PURE__ */ jsx(AccessIcon, { className: "h-4 w-4 mr-2" }), /* @__PURE__ */ jsx("span", {
|
|
1083
1083
|
className: "hidden md:inline",
|
|
1084
1084
|
children: t.chrome.manageAccess
|
|
@@ -1126,7 +1126,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
1126
1126
|
onSelectAll: handleBatchCheckbox
|
|
1127
1127
|
})
|
|
1128
1128
|
}), /* @__PURE__ */ jsx(NoDataAvailablePreview, {
|
|
1129
|
-
selectedStorage:
|
|
1129
|
+
selectedStorage: selectedStorage ?? null,
|
|
1130
1130
|
canWrite: selectedNodeCanWrite,
|
|
1131
1131
|
onRefresh: handleRefresh,
|
|
1132
1132
|
error: hasCorsIssue.get(selectedNode.storageId ?? "") ? new CorsError(connectionIssuesMessage.get(selectedNode.storageId ?? "") || "") : null,
|
|
@@ -1159,7 +1159,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
1159
1159
|
})]
|
|
1160
1160
|
}), effectiveTab === "preview" && previewable ? /* @__PURE__ */ jsx(FilePreviewInline, {
|
|
1161
1161
|
node: selectedNode,
|
|
1162
|
-
storage:
|
|
1162
|
+
storage: selectedStorage ?? null,
|
|
1163
1163
|
getPresignedUrl,
|
|
1164
1164
|
onOpenFull: openPreview,
|
|
1165
1165
|
onDownload: downloadNode,
|
|
@@ -1286,7 +1286,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
1286
1286
|
open: previewOpen,
|
|
1287
1287
|
node: previewNode,
|
|
1288
1288
|
siblings: previewSiblings,
|
|
1289
|
-
storage:
|
|
1289
|
+
storage: findStorage(previewNode?.storageId) ?? null,
|
|
1290
1290
|
getPresignedUrl,
|
|
1291
1291
|
onNavigate: setPreviewNode,
|
|
1292
1292
|
onClose: closePreview,
|
|
@@ -1393,7 +1393,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
1393
1393
|
open: accessDrawerOpen,
|
|
1394
1394
|
setOpen: setAccessDrawerOpen,
|
|
1395
1395
|
groups,
|
|
1396
|
-
storage:
|
|
1396
|
+
storage: selectedStorage
|
|
1397
1397
|
})
|
|
1398
1398
|
]
|
|
1399
1399
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IFileExplorerClient, IFileExplorerProvider } from './lib/fileExplorer.js';
|
|
2
|
-
import type { TreeNode,
|
|
2
|
+
import type { TreeNode, UploadNode, UploadSession } from './lib/types.js';
|
|
3
3
|
interface IFileExplorerContextValue {
|
|
4
4
|
uploadSessionMap: Map<string, UploadSession>;
|
|
5
5
|
uploadQueue: string[];
|
|
@@ -7,7 +7,6 @@ interface IFileExplorerContextValue {
|
|
|
7
7
|
getUploadSessionById: (sessionId: string) => UploadSession | undefined;
|
|
8
8
|
getUploadQueueIndex: (sessionId: string) => number;
|
|
9
9
|
startUploadSession: (sessionId: string) => Promise<void>;
|
|
10
|
-
updateFileUploadProgress?: (sessionId: string, fileKey: string, progress: UploadFileProgress) => void;
|
|
11
10
|
}
|
|
12
11
|
interface IFileExplorerProviderProps {
|
|
13
12
|
children: React.ReactNode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useNotify, useStrings } from "../components/Provider.js";
|
|
2
2
|
import { keyedByContent } from "../components/keys.js";
|
|
3
|
-
import { getUploadSessionETA, removeLeadingSlash } from "./lib/utils.js";
|
|
3
|
+
import { calculateUploadNodesTotalSize, getUploadSessionETA, removeLeadingSlash } from "./lib/utils.js";
|
|
4
4
|
import { UploadSessionToast } from "./toasts.js";
|
|
5
5
|
import { createContext, use, useRef } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -21,37 +21,26 @@ function FileExplorerProvider({ children }) {
|
|
|
21
21
|
const uploadQueueRef = useRef([]);
|
|
22
22
|
const isProcessingRef = useRef(false);
|
|
23
23
|
const uploadSessionIdCounter = useRef(0);
|
|
24
|
-
const uploadSessionIdPrefix = "upload-session";
|
|
25
24
|
const generateUploadSessionId = () => {
|
|
26
|
-
return
|
|
25
|
+
return `upload-session-${Date.now()}-${uploadSessionIdCounter.current++}`;
|
|
27
26
|
};
|
|
28
27
|
const calculateWeightedProgress = (session) => {
|
|
29
28
|
if (!session.progress?.allFiles || session.progress.allFiles.size === 0) return 0;
|
|
30
29
|
let totalWeightedProgress = 0;
|
|
31
30
|
let totalWeight = 0;
|
|
32
31
|
session.progress.allFiles.forEach((fileProgress) => {
|
|
33
|
-
const fileSize = fileProgress.fileSizeBytes
|
|
34
|
-
|
|
35
|
-
totalWeightedProgress += filePercentage / 100 * fileSize;
|
|
32
|
+
const fileSize = fileProgress.fileSizeBytes;
|
|
33
|
+
totalWeightedProgress += (fileProgress.percentage ?? 0) / 100 * fileSize;
|
|
36
34
|
totalWeight += fileSize;
|
|
37
35
|
});
|
|
38
36
|
return totalWeight > 0 ? totalWeightedProgress / totalWeight * 100 : 0;
|
|
39
37
|
};
|
|
40
|
-
const
|
|
41
|
-
if (!session.progress?.allFiles) return {
|
|
42
|
-
loaded: 0,
|
|
43
|
-
total: session.progress?.totalSizeBytes || 0
|
|
44
|
-
};
|
|
38
|
+
const sumLoadedBytes = (session) => {
|
|
45
39
|
let totalLoaded = 0;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
totalLoaded += fileProgress.loadedBytes || 0;
|
|
49
|
-
totalSize += fileProgress.fileSizeBytes || 0;
|
|
40
|
+
session.progress?.allFiles?.forEach((fileProgress) => {
|
|
41
|
+
totalLoaded += fileProgress.loadedBytes ?? 0;
|
|
50
42
|
});
|
|
51
|
-
return
|
|
52
|
-
loaded: totalLoaded,
|
|
53
|
-
total: totalSize
|
|
54
|
-
};
|
|
43
|
+
return totalLoaded;
|
|
55
44
|
};
|
|
56
45
|
const updateFileProgressInUploadSession = (session, relativePath, updates) => {
|
|
57
46
|
if (!session.progress?.allFiles) return;
|
|
@@ -77,10 +66,10 @@ function FileExplorerProvider({ children }) {
|
|
|
77
66
|
progress: {
|
|
78
67
|
completedFiles: 0,
|
|
79
68
|
totalFiles: uploadNodes.length,
|
|
80
|
-
totalSizeBytes: uploadNodes
|
|
69
|
+
totalSizeBytes: calculateUploadNodesTotalSize(uploadNodes),
|
|
81
70
|
allFiles: new Map(uploadNodes.map((file) => [file.relativePath, {
|
|
82
71
|
fileKey: file.relativePath,
|
|
83
|
-
fileSizeBytes: file.file
|
|
72
|
+
fileSizeBytes: file.file.size,
|
|
84
73
|
abortController: new AbortController(),
|
|
85
74
|
status: "pending",
|
|
86
75
|
percentage: 0
|
|
@@ -154,109 +143,90 @@ function FileExplorerProvider({ children }) {
|
|
|
154
143
|
}
|
|
155
144
|
session.status = "uploading";
|
|
156
145
|
isProcessingRef.current = true;
|
|
146
|
+
const progressToast = (shown = session) => /* @__PURE__ */ jsx(UploadSessionToast, {
|
|
147
|
+
session: shown,
|
|
148
|
+
queueLength: uploadQueueRef.current.length,
|
|
149
|
+
onCancel: () => handleSessionCancel(session),
|
|
150
|
+
onCancelFile: (path) => cancelFileInSession(sessionId, path)
|
|
151
|
+
});
|
|
157
152
|
try {
|
|
158
153
|
notify.update(sessionId, {
|
|
159
|
-
render:
|
|
160
|
-
session,
|
|
161
|
-
queueLength: uploadQueueRef.current.length,
|
|
162
|
-
onCancel: () => handleSessionCancel(session),
|
|
163
|
-
onCancelFile: (path) => cancelFileInSession(sessionId, path)
|
|
164
|
-
}),
|
|
154
|
+
render: progressToast(),
|
|
165
155
|
icon: false,
|
|
166
156
|
isLoading: false,
|
|
167
157
|
closeButton: false,
|
|
168
158
|
autoClose: false
|
|
169
159
|
});
|
|
170
160
|
const results = await Promise.allSettled(session.uploadNodes.map(async (node) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
161
|
+
const fileProgress = session.progress?.allFiles?.get(node.relativePath);
|
|
162
|
+
if (!fileProgress) return;
|
|
163
|
+
if (fileProgress.status === "cancelled") throw new Error("Upload cancelled by user");
|
|
164
|
+
updateFileProgressInUploadSession(session, node.relativePath, {
|
|
165
|
+
status: "uploading",
|
|
166
|
+
loadedBytes: 0,
|
|
167
|
+
totalBytes: node.file.size,
|
|
168
|
+
percentage: 0
|
|
169
|
+
});
|
|
170
|
+
const objectPath = session.targetPath ? `${session.targetPath}/${removeLeadingSlash(node.relativePath)}` : removeLeadingSlash(node.relativePath);
|
|
171
|
+
const uploadFileInput = session.provider.uploadFileInput;
|
|
172
|
+
if (!uploadFileInput) {
|
|
173
|
+
updateFileProgressInUploadSession(session, node.relativePath, { status: "failed" });
|
|
174
|
+
throw new Error("Upload is not supported for this storage provider");
|
|
175
|
+
}
|
|
176
|
+
const input = uploadFileInput(session.storageName, objectPath, node.file);
|
|
177
|
+
const onProgress = (progress) => {
|
|
178
|
+
if (session.status === "cancelled" || !session.progress?.allFiles) return;
|
|
179
|
+
const currentFileProgress = session.progress.allFiles.get(node.relativePath);
|
|
180
|
+
if (!currentFileProgress || [
|
|
181
|
+
"failed",
|
|
182
|
+
"cancelled",
|
|
183
|
+
"completed"
|
|
184
|
+
].includes(currentFileProgress.status ?? "")) return;
|
|
178
185
|
updateFileProgressInUploadSession(session, node.relativePath, {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
percentage:
|
|
186
|
+
loadedBytes: progress.loadedBytes,
|
|
187
|
+
totalBytes: progress.totalBytes,
|
|
188
|
+
percentage: progress.percentage,
|
|
189
|
+
status: progress.percentage === 100 ? "completed" : "uploading"
|
|
190
|
+
});
|
|
191
|
+
if (progress.percentage === 100) session.progress.completedFiles += 1;
|
|
192
|
+
const totalLoadedBytes = sumLoadedBytes(session);
|
|
193
|
+
session.progress.overallProgress = calculateWeightedProgress(session);
|
|
194
|
+
session.progress.totalLoadedBytes = totalLoadedBytes;
|
|
195
|
+
const { estimatedSecondsLeft, lastProgressTime, lastProgressBytes, shouldUpdateETA } = getUploadSessionETA(totalLoadedBytes, session.progress.totalSizeBytes, session.progress.lastProgressTime, session.progress.lastProgressBytes);
|
|
196
|
+
session.progress.lastProgressTime = lastProgressTime;
|
|
197
|
+
session.progress.lastProgressBytes = lastProgressBytes;
|
|
198
|
+
if (shouldUpdateETA) session.progress.estimatedSecondsLeft = estimatedSecondsLeft;
|
|
199
|
+
notify.update(sessionId, {
|
|
200
|
+
render: progressToast(),
|
|
201
|
+
icon: false,
|
|
202
|
+
isLoading: false,
|
|
203
|
+
closeButton: false,
|
|
204
|
+
autoClose: false
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
try {
|
|
208
|
+
await session.client.uploadFile(input, onProgress, fileProgress.abortController);
|
|
209
|
+
updateFileProgressInUploadSession(session, node.relativePath, { status: "completed" });
|
|
210
|
+
} catch (error) {
|
|
211
|
+
const errorMessage = error instanceof Error ? error.message : String(error ?? "");
|
|
212
|
+
const isCancelled = errorMessage.toLowerCase().includes("abort") || errorMessage.toLowerCase().includes("cancel");
|
|
213
|
+
updateFileProgressInUploadSession(session, node.relativePath, { status: isCancelled ? "cancelled" : "failed" });
|
|
214
|
+
notify.update(sessionId, {
|
|
215
|
+
render: progressToast({
|
|
216
|
+
...session,
|
|
217
|
+
progress: {
|
|
218
|
+
completedFiles: 0,
|
|
219
|
+
totalFiles: 0,
|
|
220
|
+
totalSizeBytes: 0,
|
|
221
|
+
...session.progress
|
|
222
|
+
}
|
|
223
|
+
}),
|
|
224
|
+
icon: false,
|
|
225
|
+
isLoading: false,
|
|
226
|
+
closeButton: session.status === "failed" || session.status === "cancelled",
|
|
227
|
+
autoClose: false
|
|
183
228
|
});
|
|
184
|
-
|
|
185
|
-
const uploadFileInput = session.provider.uploadFileInput;
|
|
186
|
-
if (!uploadFileInput) return {
|
|
187
|
-
reason: "Upload is not supported for this storage provider",
|
|
188
|
-
status: "rejected"
|
|
189
|
-
};
|
|
190
|
-
const input = uploadFileInput(session.storageName, objectPath, node.file);
|
|
191
|
-
const onProgress = (progress) => {
|
|
192
|
-
if (session.status === "cancelled") return;
|
|
193
|
-
if (session.progress?.allFiles) {
|
|
194
|
-
const currentFileProgress = session.progress.allFiles.get(node.relativePath);
|
|
195
|
-
if (!currentFileProgress) return;
|
|
196
|
-
if ([
|
|
197
|
-
"failed",
|
|
198
|
-
"cancelled",
|
|
199
|
-
"complete"
|
|
200
|
-
].includes(currentFileProgress.status ?? "")) return;
|
|
201
|
-
const wasCompleted = currentFileProgress.percentage === 100;
|
|
202
|
-
updateFileProgressInUploadSession(session, node.relativePath, {
|
|
203
|
-
loadedBytes: progress.loadedBytes,
|
|
204
|
-
totalBytes: progress.totalBytes,
|
|
205
|
-
percentage: progress.percentage,
|
|
206
|
-
status: progress.percentage === 100 ? "completed" : "uploading"
|
|
207
|
-
});
|
|
208
|
-
if (progress.percentage === 100 && !wasCompleted) session.progress.completedFiles += 1;
|
|
209
|
-
const overallProgress = calculateWeightedProgress(session);
|
|
210
|
-
const { loaded: totalLoadedBytes } = calculateOverallLoadedBytes(session);
|
|
211
|
-
session.progress.overallProgress = overallProgress;
|
|
212
|
-
session.progress.totalLoadedBytes = totalLoadedBytes;
|
|
213
|
-
const { estimatedSecondsLeft, lastProgressTime, lastProgressBytes, shouldUpdateETA } = getUploadSessionETA(totalLoadedBytes, session.progress.totalSizeBytes, session.progress.lastProgressTime, session.progress.lastProgressBytes);
|
|
214
|
-
session.progress.lastProgressTime = lastProgressTime;
|
|
215
|
-
session.progress.lastProgressBytes = lastProgressBytes;
|
|
216
|
-
if (shouldUpdateETA) session.progress.estimatedSecondsLeft = estimatedSecondsLeft;
|
|
217
|
-
notify.update(sessionId, {
|
|
218
|
-
render: /* @__PURE__ */ jsx(UploadSessionToast, {
|
|
219
|
-
session,
|
|
220
|
-
queueLength: uploadQueueRef.current.length,
|
|
221
|
-
onCancel: () => handleSessionCancel(session),
|
|
222
|
-
onCancelFile: (path) => cancelFileInSession(sessionId, path)
|
|
223
|
-
}),
|
|
224
|
-
icon: false,
|
|
225
|
-
isLoading: false,
|
|
226
|
-
closeButton: false,
|
|
227
|
-
autoClose: false
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
try {
|
|
232
|
-
await session.client.uploadFile(input, onProgress, fileProgress.abortController);
|
|
233
|
-
updateFileProgressInUploadSession(session, node.relativePath, { status: "completed" });
|
|
234
|
-
} catch (error) {
|
|
235
|
-
const errorMessage = error instanceof Error ? error.message : String(error ?? "");
|
|
236
|
-
const isCancelled = errorMessage.toLowerCase().includes("abort") || errorMessage.toLowerCase().includes("cancel");
|
|
237
|
-
updateFileProgressInUploadSession(session, node.relativePath, { status: isCancelled ? "cancelled" : "failed" });
|
|
238
|
-
notify.update(sessionId, {
|
|
239
|
-
render: /* @__PURE__ */ jsx(UploadSessionToast, {
|
|
240
|
-
session: {
|
|
241
|
-
...session,
|
|
242
|
-
progress: {
|
|
243
|
-
completedFiles: 0,
|
|
244
|
-
totalFiles: 0,
|
|
245
|
-
totalSizeBytes: 0,
|
|
246
|
-
...session.progress
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
queueLength: uploadQueueRef.current.length,
|
|
250
|
-
onCancel: () => handleSessionCancel(session),
|
|
251
|
-
onCancelFile: (path) => cancelFileInSession(sessionId, path)
|
|
252
|
-
}),
|
|
253
|
-
icon: false,
|
|
254
|
-
isLoading: false,
|
|
255
|
-
closeButton: session.status === "failed" || session.status === "cancelled",
|
|
256
|
-
autoClose: false
|
|
257
|
-
});
|
|
258
|
-
throw error;
|
|
259
|
-
}
|
|
229
|
+
throw error;
|
|
260
230
|
}
|
|
261
231
|
}));
|
|
262
232
|
try {
|
|
@@ -266,19 +236,16 @@ function FileExplorerProvider({ children }) {
|
|
|
266
236
|
}
|
|
267
237
|
const failedResults = results.filter((r) => r.status === "rejected");
|
|
268
238
|
const actualFailedResults = failedResults.filter((result) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return !reason.toLowerCase().includes("abort") && !reason.toLowerCase().includes("cancel");
|
|
272
|
-
}
|
|
273
|
-
return false;
|
|
239
|
+
const reason = result.reason?.message || result.reason?.toString() || "";
|
|
240
|
+
return !reason.toLowerCase().includes("abort") && !reason.toLowerCase().includes("cancel");
|
|
274
241
|
});
|
|
275
|
-
const abortedCount = failedResults
|
|
242
|
+
const abortedCount = failedResults.length - actualFailedResults.length;
|
|
276
243
|
const failedFileNames = actualFailedResults.map((result) => {
|
|
277
|
-
const originalIndex = results.
|
|
244
|
+
const originalIndex = results.indexOf(result);
|
|
278
245
|
return session.uploadNodes[originalIndex]?.name || `File #${originalIndex + 1}`;
|
|
279
|
-
})
|
|
280
|
-
const successfulCount = results
|
|
281
|
-
if (actualFailedResults
|
|
246
|
+
});
|
|
247
|
+
const successfulCount = results.length - failedResults.length;
|
|
248
|
+
if (actualFailedResults.length > 0) notify.update(sessionId, {
|
|
282
249
|
render: /* @__PURE__ */ jsxs("div", {
|
|
283
250
|
className: "text-md",
|
|
284
251
|
children: [
|
|
@@ -344,8 +311,8 @@ function FileExplorerProvider({ children }) {
|
|
|
344
311
|
}
|
|
345
312
|
};
|
|
346
313
|
const processNextUploadSessionInQueue = async () => {
|
|
347
|
-
if (isProcessingRef.current || uploadQueueRef.current.length === 0) return;
|
|
348
314
|
const nextSessionId = uploadQueueRef.current[0];
|
|
315
|
+
if (isProcessingRef.current || nextSessionId === void 0) return;
|
|
349
316
|
await startUploadSession(nextSessionId);
|
|
350
317
|
};
|
|
351
318
|
const contextValue = {
|
|
@@ -7,7 +7,6 @@ interface FilePreviewInlineProps {
|
|
|
7
7
|
onDownload: (node: TreeNode) => void;
|
|
8
8
|
/** When false, skip fetching and release any held preview blob. */
|
|
9
9
|
active?: boolean;
|
|
10
|
-
showSecurityIndicator?: boolean;
|
|
11
10
|
}
|
|
12
|
-
export declare function FilePreviewInline({ node, storage, getPresignedUrl, onOpenFull, onDownload, active,
|
|
11
|
+
export declare function FilePreviewInline({ node, storage, getPresignedUrl, onOpenFull, onDownload, active, }: FilePreviewInlineProps): import("react").JSX.Element;
|
|
13
12
|
export {};
|