@parallelworks/ui 0.16.0 → 0.17.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/dist/chunks/{CodePreviewEditor-DuMZMA_k.js → CodePreviewEditor-UAtnpmOV.js} +1 -1
- package/dist/chunks/{CreateModal-B7smkHkv.js → CreateModal-BbV5cTj7.js} +3 -3
- package/dist/chunks/{Monaco-BXDH2jVj.js → Monaco-DVyIpyv4.js} +485 -172
- package/dist/chunks/{PageHeader-CoZWF0pJ.js → PageHeader-MxuOs9cH.js} +1 -1
- package/dist/chunks/{Provider-CbFVFB7O.js → Provider-DHmZ3v9i.js} +28 -2
- package/dist/chunks/{StatusBadge-zvEtK16a.js → StatusBadge-C1Blx_cW.js} +23 -6
- package/dist/chunks/{SwitchToggle-3V836Cn7.js → SwitchToggle-BRQoEwLZ.js} +7 -4
- package/dist/chunks/{Table-CutP1bRt.js → Table-C6JdFFiJ.js} +1 -1
- package/dist/chunks/{editor-Ko3zX22Y.js → editor-mNznodJN.js} +2 -2
- package/dist/chunks/{list-CduoUsMW.js → list-7k0eaI5N.js} +21 -19
- package/dist/components/Button.d.ts +2 -1
- package/dist/components/Provider.d.ts +57 -2
- package/dist/components/SectionHeader.d.ts +3 -1
- package/dist/components/StatusBadge.d.ts +7 -2
- package/dist/components/relativeTime.d.ts +15 -0
- package/dist/editor/index.js +1 -1
- package/dist/editor/usesGitlab.d.ts +97 -0
- package/dist/file-explorer/index.js +253 -253
- package/dist/file-explorer/lib/paging.d.ts +27 -28
- package/dist/file-explorer/lib/types.d.ts +0 -1
- package/dist/file-explorer/lib/utils.d.ts +16 -5
- package/dist/form/index.js +4 -4
- package/dist/form/types/workflow-schema.d.ts +38 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +42 -11
- package/dist/list/ListPage.d.ts +3 -1
- package/dist/list/ListPager.d.ts +3 -1
- package/dist/list/ListTable.d.ts +2 -1
- package/dist/list/index.js +2 -2
- package/dist/list/listView.d.ts +1 -1
- package/dist/logviewer/index.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/workflow/DependencyGraph.d.ts +2 -0
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +3 -2
- package/dist/workflow/types.d.ts +5 -0
- package/package.json +3 -3
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { AccessIcon, AlertIcon, AngleDownIcon, AngleRightIcon, AngleUpIcon, ChevronLeftIcon, ChevronRightIcon, ClipboardIcon, CloseIcon, CloudUploadIcon, CollapseIcon, CustomizeIcon, DiskIcon, DocumentIcon, DownloadFileIcon, ExpandIcon, ExpandVerticalIcon, EyeIcon, FileIcon, FileTextIcon, FolderIcon, FolderOpenIcon, ImageIcon, LinkIcon, LockIcon, MinimizeIcon, MusicIcon, PdfIcon, RefreshIcon, ShareIcon, SpreadsheetIcon, SuccessIcon, TrashIcon, UploadIcon, UserIcon, VideoIcon, ZipIcon, ZoomInIcon, ZoomOutIcon } from "../icons.js";
|
|
2
|
-
import { c as ConfirmModal, f as Markdown, h as Callout, m as CopyToClipboard, n as CreateModal, p as CopyCodeBlock } from "../chunks/CreateModal-
|
|
3
|
-
import {
|
|
2
|
+
import { c as ConfirmModal, f as Markdown, h as Callout, m as CopyToClipboard, n as CreateModal, p as CopyCodeBlock } from "../chunks/CreateModal-BbV5cTj7.js";
|
|
3
|
+
import { i as useNotify, l as useSlots, o as useProvisionCorsRules, u as useStrings } from "../chunks/Provider-DHmZ3v9i.js";
|
|
4
4
|
import { n as TOOLTIP_ID, r as TooltipInfo } from "../chunks/Tooltip-n9w7Tkt1.js";
|
|
5
|
-
import { t as StatusBadge } from "../chunks/StatusBadge-
|
|
5
|
+
import { t as StatusBadge } from "../chunks/StatusBadge-C1Blx_cW.js";
|
|
6
6
|
import { t as Loader } from "../chunks/Loader-BXoXTZGc.js";
|
|
7
|
-
import { _ as useRowMenuActive, d as assembleRowMenu, f as copySubmenu, g as useRowMenu, u as MoreButton } from "../chunks/PageHeader-
|
|
8
|
-
import { n as Table } from "../chunks/Table-
|
|
9
|
-
import { C as ListSkeleton, E as RowSelectCheckbox, O as listTableFixedProps, k as listTableProps, x as ListActionsHeader } from "../chunks/list-
|
|
7
|
+
import { _ as useRowMenuActive, d as assembleRowMenu, f as copySubmenu, g as useRowMenu, u as MoreButton } from "../chunks/PageHeader-MxuOs9cH.js";
|
|
8
|
+
import { n as Table } from "../chunks/Table-C6JdFFiJ.js";
|
|
9
|
+
import { C as ListSkeleton, E as RowSelectCheckbox, O as listTableFixedProps, k as listTableProps, x as ListActionsHeader } from "../chunks/list-7k0eaI5N.js";
|
|
10
10
|
import cx from "classnames";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { Suspense, createContext, lazy, memo, use, useCallback, useEffect, useEffectEvent, useId, useLayoutEffect, useMemo, useRef, useState, useTransition } from "react";
|
|
13
|
+
import { useLocalStorage } from "usehooks-ts";
|
|
13
14
|
import { createPortal } from "react-dom";
|
|
14
15
|
import { Menu, MenuButton, MenuItem, MenuItems, MenuSeparator } from "@headlessui/react";
|
|
15
16
|
import Skeleton from "react-loading-skeleton";
|
|
16
17
|
import { DateTime } from "luxon";
|
|
17
18
|
import { Resizable } from "re-resizable";
|
|
18
|
-
import { useLocalStorage } from "usehooks-ts";
|
|
19
19
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
20
20
|
//#region src/file-explorer/lib/utils.ts
|
|
21
21
|
function formatFileSize(bytes) {
|
|
@@ -38,143 +38,143 @@ function getNodeName(node) {
|
|
|
38
38
|
const parts = removeTrailingSlash(node.path || "").split("/");
|
|
39
39
|
return parts[parts.length - 1] ?? "";
|
|
40
40
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
parentToChildrenMap: {}
|
|
45
|
-
};
|
|
46
|
-
const objects = storage.objects ?? [];
|
|
47
|
-
const cspBucketName = storage.bucketName || storage.name;
|
|
48
|
-
const storagePath = storage.user ? ensureTrailingSlash(`${storage.user}/${storage.name}`) : ensureTrailingSlash(storage.name);
|
|
49
|
-
const treeMap = { [storagePath]: {
|
|
50
|
-
name: storage.name,
|
|
51
|
-
displayName: storage?.displayName,
|
|
52
|
-
path: storagePath,
|
|
53
|
-
relativePath: "",
|
|
54
|
-
type: "directory",
|
|
55
|
-
created: storage.created,
|
|
56
|
-
modified: storage.modified,
|
|
57
|
-
storageId: storage.id,
|
|
58
|
-
storageName: cspBucketName,
|
|
59
|
-
storageNodeIcon: storage.type,
|
|
60
|
-
storageImageUrl: storage.imageUrl,
|
|
61
|
-
storageType: storage.type,
|
|
62
|
-
root: true
|
|
63
|
-
} };
|
|
64
|
-
const directories = objects.filter((obj) => obj.type === "directory");
|
|
65
|
-
const files = objects.filter((obj) => obj.type === "file");
|
|
66
|
-
directories.forEach((dir) => {
|
|
67
|
-
const fullPath = ensureTrailingSlash(`${storagePath}${removeLeadingSlash(removeTrailingSlash(dir.path))}`);
|
|
68
|
-
treeMap[fullPath] = {
|
|
69
|
-
name: getNodeName(dir),
|
|
70
|
-
path: fullPath,
|
|
71
|
-
relativePath: dir?.key || dir.path,
|
|
72
|
-
type: dir.type,
|
|
73
|
-
created: dir?.created,
|
|
74
|
-
modified: dir?.modified,
|
|
75
|
-
storageId: storage.id,
|
|
76
|
-
storageName: cspBucketName
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
files.forEach((file) => {
|
|
80
|
-
const relativeFilePath = removeLeadingSlash(file.path);
|
|
81
|
-
const fullPath = `${storagePath}${relativeFilePath}`;
|
|
82
|
-
treeMap[fullPath] = {
|
|
83
|
-
name: getNodeName(file),
|
|
84
|
-
path: fullPath,
|
|
85
|
-
relativePath: file.key || relativeFilePath,
|
|
86
|
-
type: file.type,
|
|
87
|
-
size: file.size,
|
|
88
|
-
created: file?.created,
|
|
89
|
-
modified: file?.modified,
|
|
90
|
-
contentType: file?.contentType,
|
|
91
|
-
hash: file?.hash,
|
|
92
|
-
storageClass: file?.storageClass,
|
|
93
|
-
storageId: storage.id,
|
|
94
|
-
storageName: cspBucketName
|
|
95
|
-
};
|
|
96
|
-
});
|
|
97
|
-
const parentToChildrenMap = { [storagePath]: [] };
|
|
98
|
-
Object.values(treeMap).forEach((node) => {
|
|
99
|
-
if (node.path === storagePath) return;
|
|
100
|
-
const cleanPath = node.path.endsWith("/") && node.path.length > 1 ? node.path.slice(0, -1) : node.path;
|
|
101
|
-
const lastSlash = cleanPath.lastIndexOf("/");
|
|
102
|
-
const parentPath = lastSlash <= 0 ? storagePath : ensureTrailingSlash(cleanPath.substring(0, lastSlash + 1));
|
|
103
|
-
if (!parentToChildrenMap[parentPath]) parentToChildrenMap[parentPath] = [];
|
|
104
|
-
parentToChildrenMap[parentPath].push(node);
|
|
105
|
-
});
|
|
106
|
-
Object.entries(parentToChildrenMap).forEach(([parentPath, childrenArr]) => {
|
|
107
|
-
if (unsortedParents?.has(parentPath)) return;
|
|
108
|
-
childrenArr.sort((a, b) => {
|
|
109
|
-
if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
|
|
110
|
-
return a.name.localeCompare(b.name);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
41
|
+
function toNode(entry, storage, storagePath, storageName) {
|
|
42
|
+
const relativePath = removeLeadingSlash(entry.path);
|
|
43
|
+
const isDirectory = entry.type === "directory";
|
|
113
44
|
return {
|
|
114
|
-
|
|
115
|
-
|
|
45
|
+
name: getNodeName(entry),
|
|
46
|
+
path: isDirectory ? ensureTrailingSlash(`${storagePath}${removeTrailingSlash(relativePath)}`) : `${storagePath}${relativePath}`,
|
|
47
|
+
relativePath: entry.key || (isDirectory ? entry.path : relativePath),
|
|
48
|
+
type: entry.type,
|
|
49
|
+
size: entry.size,
|
|
50
|
+
created: entry.created,
|
|
51
|
+
modified: entry.modified,
|
|
52
|
+
contentType: entry.contentType,
|
|
53
|
+
hash: entry.hash,
|
|
54
|
+
storageClass: entry.storageClass,
|
|
55
|
+
storageId: storage.id,
|
|
56
|
+
storageName
|
|
116
57
|
};
|
|
117
58
|
}
|
|
118
|
-
function
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
59
|
+
function compareNodes(a, b) {
|
|
60
|
+
if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
|
|
61
|
+
return (a.displayName || a.name).localeCompare(b.displayName || b.name);
|
|
62
|
+
}
|
|
63
|
+
function extendsEntries(next, previous) {
|
|
64
|
+
return next.length >= previous.length && previous.every((entry, i) => next[i] === entry);
|
|
65
|
+
}
|
|
66
|
+
function childrenOf(dir, sorted) {
|
|
67
|
+
if (sorted) {
|
|
68
|
+
dir.sorted ??= [...dir.directories, ...dir.files].sort(compareNodes);
|
|
69
|
+
return dir.sorted;
|
|
127
70
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
71
|
+
dir.unsorted ??= [...dir.directories, ...dir.files];
|
|
72
|
+
return dir.unsorted;
|
|
73
|
+
}
|
|
74
|
+
/** One accumulator per listed directory, so a landed page costs the page and not
|
|
75
|
+
* the tree. One builder per explorer instance. */
|
|
76
|
+
function createTreeBuilder() {
|
|
77
|
+
const directories = /* @__PURE__ */ new Map();
|
|
78
|
+
let last = null;
|
|
79
|
+
function unchanged(storages, options) {
|
|
80
|
+
if (!last || last.storages !== storages || last.options.forceUserHierarchy !== options.forceUserHierarchy || last.options.unsortedParents !== options.unsortedParents) return false;
|
|
81
|
+
const before = last.options.listings;
|
|
82
|
+
if (options.listings.size !== before.size) return false;
|
|
83
|
+
for (const [dirPath, listing] of options.listings) if (before.get(dirPath)?.entries !== listing.entries) return false;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
function nodesFor(dirPath, storage, storagePath, storageName, entries) {
|
|
87
|
+
const cached = directories.get(dirPath);
|
|
88
|
+
const reusable = cached?.storageName === storageName ? cached : void 0;
|
|
89
|
+
if (reusable && reusable.entries === entries) return reusable;
|
|
90
|
+
let dir;
|
|
91
|
+
if (reusable && extendsEntries(entries, reusable.entries)) dir = reusable;
|
|
92
|
+
else {
|
|
93
|
+
dir = {
|
|
94
|
+
entries: [],
|
|
95
|
+
storageName,
|
|
96
|
+
directories: [],
|
|
97
|
+
files: []
|
|
98
|
+
};
|
|
99
|
+
directories.set(dirPath, dir);
|
|
100
|
+
}
|
|
101
|
+
for (let i = dir.entries.length; i < entries.length; i++) {
|
|
102
|
+
const node = toNode(entries[i], storage, storagePath, storageName);
|
|
103
|
+
if (node.path === dirPath) continue;
|
|
104
|
+
if (node.type === "directory") dir.directories.push(node);
|
|
105
|
+
else dir.files.push(node);
|
|
106
|
+
}
|
|
107
|
+
dir.entries = entries;
|
|
108
|
+
dir.unsorted = void 0;
|
|
109
|
+
dir.sorted = void 0;
|
|
110
|
+
return dir;
|
|
111
|
+
}
|
|
112
|
+
function addStorage(storage, storagePath, options, tree) {
|
|
113
|
+
const storageName = storage.bucketName || storage.name;
|
|
114
|
+
const root = {
|
|
115
|
+
name: storage.name,
|
|
116
|
+
displayName: storage.displayName,
|
|
117
|
+
path: storagePath,
|
|
118
|
+
relativePath: "",
|
|
133
119
|
type: "directory",
|
|
134
|
-
|
|
120
|
+
created: storage.created,
|
|
121
|
+
modified: storage.modified,
|
|
122
|
+
storageId: storage.id,
|
|
123
|
+
storageName,
|
|
124
|
+
storageNodeIcon: storage.type,
|
|
125
|
+
storageImageUrl: storage.imageUrl,
|
|
126
|
+
storageType: storage.type,
|
|
127
|
+
root: true
|
|
135
128
|
};
|
|
136
|
-
|
|
137
|
-
for (const
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
path: storageFullPath,
|
|
144
|
-
relativePath: "",
|
|
145
|
-
type: "directory",
|
|
146
|
-
created: storage?.created,
|
|
147
|
-
modified: storage?.modified,
|
|
148
|
-
storageId: storage.id,
|
|
149
|
-
storageName: cspBucketName,
|
|
150
|
-
storageNodeIcon: storage.type,
|
|
151
|
-
storageImageUrl: storage.imageUrl,
|
|
152
|
-
storageType: storage.type,
|
|
153
|
-
root: true
|
|
154
|
-
};
|
|
155
|
-
parentToChildrenMap[userPath].push(treeMap[storageFullPath]);
|
|
156
|
-
if (storage.objects) {
|
|
157
|
-
const { treeMap: storageTree, parentToChildrenMap: storageChildren } = buildTreeFromStorage(storage, options?.unsortedParents);
|
|
158
|
-
Object.assign(treeMap, storageTree);
|
|
159
|
-
for (const [parent, children] of Object.entries(storageChildren)) {
|
|
160
|
-
if (!parentToChildrenMap[parent]) parentToChildrenMap[parent] = [];
|
|
161
|
-
parentToChildrenMap[parent].push(...children);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
129
|
+
tree.treeMap[storagePath] = root;
|
|
130
|
+
for (const [dirPath, listing] of options.listings) {
|
|
131
|
+
if (!dirPath.startsWith(storagePath)) continue;
|
|
132
|
+
const children = childrenOf(nodesFor(dirPath, storage, storagePath, storageName, listing.entries), !options.unsortedParents?.has(dirPath));
|
|
133
|
+
if (children.length === 0) continue;
|
|
134
|
+
for (const node of children) tree.treeMap[node.path] = node;
|
|
135
|
+
tree.parentToChildrenMap[dirPath] = children;
|
|
164
136
|
}
|
|
137
|
+
return root;
|
|
165
138
|
}
|
|
166
|
-
|
|
167
|
-
if (options
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
139
|
+
return (storages, options) => {
|
|
140
|
+
if (last && unchanged(storages, options)) return last.tree;
|
|
141
|
+
const tree = {
|
|
142
|
+
treeMap: {},
|
|
143
|
+
parentToChildrenMap: {},
|
|
144
|
+
rootNodes: []
|
|
145
|
+
};
|
|
146
|
+
if (storages.length === 1 && !options.forceUserHierarchy) {
|
|
147
|
+
const storage = storages[0];
|
|
148
|
+
const storagePath = ensureTrailingSlash(storage.user ? `${storage.user}/${storage.name}` : storage.name);
|
|
149
|
+
tree.rootNodes.push(addStorage(storage, storagePath, options, tree));
|
|
150
|
+
} else {
|
|
151
|
+
const userGroups = {};
|
|
152
|
+
for (const storage of storages) {
|
|
153
|
+
const username = storage.user ?? "";
|
|
154
|
+
if (!userGroups[username]) userGroups[username] = [];
|
|
155
|
+
userGroups[username].push(storage);
|
|
156
|
+
}
|
|
157
|
+
for (const username of Object.keys(userGroups)) {
|
|
158
|
+
const userPath = ensureTrailingSlash(username);
|
|
159
|
+
const userNode = {
|
|
160
|
+
name: username,
|
|
161
|
+
path: userPath,
|
|
162
|
+
type: "directory",
|
|
163
|
+
displayName: username
|
|
164
|
+
};
|
|
165
|
+
tree.treeMap[userPath] = userNode;
|
|
166
|
+
tree.rootNodes.push(userNode);
|
|
167
|
+
const storageRoots = (userGroups[username] ?? []).map((storage) => addStorage(storage, ensureTrailingSlash(`${userPath}${removeLeadingAndTrailingSlashes(storage.name)}`), options, tree));
|
|
168
|
+
tree.parentToChildrenMap[userPath] = storageRoots.sort(compareNodes);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const dirPath of directories.keys()) if (!options.listings.has(dirPath)) directories.delete(dirPath);
|
|
172
|
+
last = {
|
|
173
|
+
storages,
|
|
174
|
+
options,
|
|
175
|
+
tree
|
|
176
|
+
};
|
|
177
|
+
return tree;
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
function getNodeChildren(parentToChildrenMap, parentPath) {
|
|
@@ -277,6 +277,9 @@ function getCspUri(csp, cspBucketName, key) {
|
|
|
277
277
|
if (!scheme) return null;
|
|
278
278
|
return `${scheme}://${cspBucketName}/${key}`;
|
|
279
279
|
}
|
|
280
|
+
function getUriScheme(uri) {
|
|
281
|
+
return uri.match(/^([a-z0-9+.-]+):\/\//i)?.[1] ?? "";
|
|
282
|
+
}
|
|
280
283
|
function removeLeadingSlash(path) {
|
|
281
284
|
return path.replace(/^\/+/, "");
|
|
282
285
|
}
|
|
@@ -1686,46 +1689,60 @@ function beginLoadingMore(listings, path) {
|
|
|
1686
1689
|
const listing = listings.get(path);
|
|
1687
1690
|
if (!listing) return listings;
|
|
1688
1691
|
return new Map(listings).set(path, {
|
|
1689
|
-
...listing
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
+
...listing,
|
|
1693
|
+
loadingMore: true,
|
|
1694
|
+
error: void 0
|
|
1692
1695
|
});
|
|
1693
1696
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
function advanceListing(listings, path, page, expectedPagesLoaded) {
|
|
1697
|
-
if ((listings.get(path)?.pagesLoaded ?? 0) !== expectedPagesLoaded) return listings;
|
|
1697
|
+
function advanceListing(listings, path, page) {
|
|
1698
|
+
const listing = listings.get(path);
|
|
1698
1699
|
return new Map(listings).set(path, {
|
|
1699
|
-
|
|
1700
|
-
pagesLoaded:
|
|
1701
|
-
loadingMore: false
|
|
1700
|
+
cursor: page.cursor,
|
|
1701
|
+
pagesLoaded: (listing?.pagesLoaded ?? 0) + 1,
|
|
1702
|
+
loadingMore: false,
|
|
1703
|
+
entries: [...listing?.entries ?? [], ...page.entries]
|
|
1702
1704
|
});
|
|
1703
1705
|
}
|
|
1704
|
-
/**
|
|
1705
|
-
*
|
|
1706
|
+
/** Subfolders the page no longer names lose their records, or a re-created folder
|
|
1707
|
+
* would show old contents; the rest keep theirs, since a refresh lists them
|
|
1708
|
+
* alongside this one and a parent landing later must not undo a child's page. */
|
|
1709
|
+
function replaceListing(listings, path, page) {
|
|
1710
|
+
const prefix = ensureTrailingSlash(path);
|
|
1711
|
+
const subfolders = new Set(page.entries.filter((entry) => entry.type === "directory").map(getNodeName));
|
|
1712
|
+
const next = new Map(listings);
|
|
1713
|
+
next.delete(path);
|
|
1714
|
+
for (const key of listings.keys()) {
|
|
1715
|
+
if (!key.startsWith(prefix)) continue;
|
|
1716
|
+
if (!subfolders.has(key.slice(prefix.length).split("/")[0] ?? "")) next.delete(key);
|
|
1717
|
+
}
|
|
1718
|
+
return advanceListing(next, path, page);
|
|
1719
|
+
}
|
|
1720
|
+
/** `pagesLoaded` stays put, so a failed first page still reads as unlisted. */
|
|
1706
1721
|
function recordListingError(listings, path, error) {
|
|
1707
1722
|
const listing = listings.get(path);
|
|
1708
1723
|
return new Map(listings).set(path, {
|
|
1709
|
-
|
|
1724
|
+
cursor: listing?.cursor,
|
|
1710
1725
|
pagesLoaded: listing?.pagesLoaded ?? 0,
|
|
1711
1726
|
loadingMore: false,
|
|
1712
|
-
error
|
|
1727
|
+
error,
|
|
1728
|
+
entries: listing?.entries ?? []
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
/** Keeps the cursor and pages, so a retry resumes paging instead of starting over. */
|
|
1732
|
+
function clearListingError(listings, path) {
|
|
1733
|
+
const listing = listings.get(path);
|
|
1734
|
+
if (!listing) return listings;
|
|
1735
|
+
return new Map(listings).set(path, {
|
|
1736
|
+
...listing,
|
|
1737
|
+
error: void 0
|
|
1713
1738
|
});
|
|
1714
1739
|
}
|
|
1715
|
-
/** Slash-terminates the prefix: without it, clearing `logs` would also clear
|
|
1716
|
-
* `logs-archive/`. */
|
|
1717
1740
|
function clearListingsUnder(listings, path) {
|
|
1718
|
-
const prefix = path
|
|
1741
|
+
const prefix = ensureTrailingSlash(path);
|
|
1719
1742
|
const next = new Map(listings);
|
|
1720
1743
|
for (const key of listings.keys()) if (key === path || key.startsWith(prefix)) next.delete(key);
|
|
1721
1744
|
return next;
|
|
1722
1745
|
}
|
|
1723
|
-
/** The same prefix rule for the attempt sets that shadow `listings`. They gate
|
|
1724
|
-
* re-listing, so a path left behind here reads as tried-and-empty forever. */
|
|
1725
|
-
function forgetPathsUnder(paths, path) {
|
|
1726
|
-
const prefix = path.endsWith("/") ? path : `${path}/`;
|
|
1727
|
-
for (const key of [...paths]) if (key === path || key.startsWith(prefix)) paths.delete(key);
|
|
1728
|
-
}
|
|
1729
1746
|
/** Tree paths whose children should keep arrival order, since sorting them would
|
|
1730
1747
|
* reshuffle rows under the user mid-scroll. */
|
|
1731
1748
|
function incompletePaths(listings) {
|
|
@@ -1734,11 +1751,11 @@ function incompletePaths(listings) {
|
|
|
1734
1751
|
return paths;
|
|
1735
1752
|
}
|
|
1736
1753
|
/** What a deep link needs next. Pure so the walk is table-testable. */
|
|
1737
|
-
function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings, inFlight,
|
|
1754
|
+
function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings, inFlight, pagesPulled }) {
|
|
1738
1755
|
for (const path of ancestors) {
|
|
1739
1756
|
if (!isListableDir(path)) continue;
|
|
1740
1757
|
if (inFlight.has(path)) return { kind: "done" };
|
|
1741
|
-
if (!
|
|
1758
|
+
if (!listings.has(path)) return {
|
|
1742
1759
|
kind: "fetch",
|
|
1743
1760
|
path
|
|
1744
1761
|
};
|
|
@@ -1746,20 +1763,23 @@ function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings,
|
|
|
1746
1763
|
if (targetResolved) return { kind: "done" };
|
|
1747
1764
|
const deepest = [...ancestors].reverse().find(isListableDir);
|
|
1748
1765
|
if (!deepest) return { kind: "done" };
|
|
1749
|
-
if (!hasMore(listings, deepest)) return {
|
|
1750
|
-
|
|
1751
|
-
|
|
1766
|
+
if (!hasMore(listings, deepest)) return {
|
|
1767
|
+
kind: "stuck",
|
|
1768
|
+
path: deepest
|
|
1769
|
+
};
|
|
1770
|
+
if (loadMoreError(listings, deepest)) return {
|
|
1771
|
+
kind: "stuck",
|
|
1772
|
+
path: deepest
|
|
1773
|
+
};
|
|
1774
|
+
if (pagesPulled >= 20) return {
|
|
1775
|
+
kind: "stuck",
|
|
1776
|
+
path: deepest
|
|
1777
|
+
};
|
|
1752
1778
|
return isLoadingMore(listings, deepest) ? { kind: "done" } : {
|
|
1753
1779
|
kind: "more",
|
|
1754
1780
|
path: deepest
|
|
1755
1781
|
};
|
|
1756
1782
|
}
|
|
1757
|
-
/** `replace` drops the directory's previous contents first, which is how a refresh
|
|
1758
|
-
* sheds deleted objects rather than re-adding them. */
|
|
1759
|
-
function nextObjects(previous, page, options) {
|
|
1760
|
-
if (!options.replace) return [...previous, ...page];
|
|
1761
|
-
return [...previous.filter((obj) => !(obj.path.startsWith(options.dirPath) && obj.path !== options.dirPath)), ...page];
|
|
1762
|
-
}
|
|
1763
1783
|
//#endregion
|
|
1764
1784
|
//#region src/file-explorer/FilePreview/StreamedBadge.tsx
|
|
1765
1785
|
function StreamedBadge() {
|
|
@@ -2537,7 +2557,7 @@ function useObjectText(url, { enabled, maxBytes, maxLines, knownSize, cacheKey,
|
|
|
2537
2557
|
}
|
|
2538
2558
|
//#endregion
|
|
2539
2559
|
//#region src/file-explorer/FilePreview/Viewer.tsx
|
|
2540
|
-
var CodePreviewEditor = lazy(() => import("../chunks/CodePreviewEditor-
|
|
2560
|
+
var CodePreviewEditor = lazy(() => import("../chunks/CodePreviewEditor-UAtnpmOV.js"));
|
|
2541
2561
|
var PREVIEW_MARKDOWN_CONTROLS = {
|
|
2542
2562
|
table: { fullscreen: false },
|
|
2543
2563
|
mermaid: { fullscreen: false }
|
|
@@ -3873,8 +3893,8 @@ function flattenTreeRows(roots, parentToChildrenMap, expandedPaths, options) {
|
|
|
3873
3893
|
isExpanded
|
|
3874
3894
|
});
|
|
3875
3895
|
if (!isExpanded) return;
|
|
3876
|
-
if (options?.loadingPaths?.has(node.path)) {
|
|
3877
|
-
|
|
3896
|
+
if (options?.loadingPaths?.has(node.path) && children.length === 0) {
|
|
3897
|
+
rows.push(statusRow("skeleton", node, depth + 1));
|
|
3878
3898
|
return;
|
|
3879
3899
|
}
|
|
3880
3900
|
const limit = options?.fileLimits?.get(node.path) ?? 50;
|
|
@@ -4276,7 +4296,7 @@ function useTreePitchAudit(scrollEl, rows, items) {
|
|
|
4276
4296
|
//#region src/file-explorer/FileExplorer.tsx
|
|
4277
4297
|
function UriCard({ value }) {
|
|
4278
4298
|
const t = useStrings().fileExplorer;
|
|
4279
|
-
const scheme = value
|
|
4299
|
+
const scheme = getUriScheme(value);
|
|
4280
4300
|
return /* @__PURE__ */ jsxs(CopyToClipboard, {
|
|
4281
4301
|
text: value,
|
|
4282
4302
|
showIcon: false,
|
|
@@ -4348,10 +4368,8 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4348
4368
|
const notify = useNotify();
|
|
4349
4369
|
const slots = useSlots();
|
|
4350
4370
|
const fileExplorerContext = useFileExplorer();
|
|
4351
|
-
const [localStorages, setLocalStorages] = useState(storages);
|
|
4352
4371
|
const [listings, setListings] = useState(() => /* @__PURE__ */ new Map());
|
|
4353
|
-
const fetchesInFlightRef = useRef(/* @__PURE__ */ new
|
|
4354
|
-
const listAttemptsRef = useRef(/* @__PURE__ */ new Set());
|
|
4372
|
+
const fetchesInFlightRef = useRef(/* @__PURE__ */ new Map());
|
|
4355
4373
|
const incompleteDirsRef = useRef(/* @__PURE__ */ new Set());
|
|
4356
4374
|
const incompleteDirs = useMemo(() => {
|
|
4357
4375
|
const next = incompletePaths(listings);
|
|
@@ -4360,13 +4378,15 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4360
4378
|
incompleteDirsRef.current = next;
|
|
4361
4379
|
return next;
|
|
4362
4380
|
}, [listings]);
|
|
4363
|
-
const
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
}, [
|
|
4369
|
-
|
|
4381
|
+
const [buildTree] = useState(createTreeBuilder);
|
|
4382
|
+
const { treeMap, parentToChildrenMap, rootNodes } = useMemo(() => buildTree(storages, {
|
|
4383
|
+
listings,
|
|
4384
|
+
forceUserHierarchy: showUserHierarchy,
|
|
4385
|
+
unsortedParents: incompleteDirs
|
|
4386
|
+
}), [
|
|
4387
|
+
buildTree,
|
|
4388
|
+
storages,
|
|
4389
|
+
listings,
|
|
4370
4390
|
showUserHierarchy,
|
|
4371
4391
|
incompleteDirs
|
|
4372
4392
|
]);
|
|
@@ -4427,11 +4447,6 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4427
4447
|
const isUploadSizeExceeded = (size) => {
|
|
4428
4448
|
return size > MAX_UPLOAD_SIZE;
|
|
4429
4449
|
};
|
|
4430
|
-
const rootNodes = useMemo(() => {
|
|
4431
|
-
const childPaths = /* @__PURE__ */ new Set();
|
|
4432
|
-
for (const children of Object.values(parentToChildrenMap)) for (const child of children) childPaths.add(child.path);
|
|
4433
|
-
return Object.values(treeMap).filter((node) => node.type === "directory" && node.path.endsWith("/") && !childPaths.has(node.path));
|
|
4434
|
-
}, [treeMap, parentToChildrenMap]);
|
|
4435
4450
|
const handleToggleExpand = useCallback((path) => {
|
|
4436
4451
|
setExpandedPaths((prev) => {
|
|
4437
4452
|
const next = new Set(prev);
|
|
@@ -4443,7 +4458,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4443
4458
|
setExpandedPaths(new Set([""]));
|
|
4444
4459
|
}, []);
|
|
4445
4460
|
const getStorageProviderAndClient = async (storageId) => {
|
|
4446
|
-
const storage =
|
|
4461
|
+
const storage = storages.find((s) => s.id === storageId);
|
|
4447
4462
|
if (!storage) {
|
|
4448
4463
|
notify.error(t.messages.storageUnavailable);
|
|
4449
4464
|
return;
|
|
@@ -4473,17 +4488,12 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4473
4488
|
const silent = !more && (options?.silent ?? false);
|
|
4474
4489
|
const nodeStorageId = node.storageId ?? "";
|
|
4475
4490
|
if (!options?.replace && fetchesInFlightRef.current.has(node.path)) return { corsError: false };
|
|
4476
|
-
|
|
4491
|
+
const request = silent ? void 0 : {};
|
|
4492
|
+
if (request) fetchesInFlightRef.current.set(node.path, request);
|
|
4493
|
+
const owns = () => request !== void 0 && fetchesInFlightRef.current.get(node.path) === request;
|
|
4477
4494
|
if (more) setListings((prev) => beginLoadingMore(prev, node.path));
|
|
4478
|
-
else
|
|
4479
|
-
if (options?.replace) {
|
|
4480
|
-
setListings((prev) => clearListingsUnder(prev, node.path));
|
|
4481
|
-
forgetPathsUnder(listAttemptsRef.current, node.path);
|
|
4482
|
-
}
|
|
4483
|
-
if (!silent) setLoadingPaths((prev) => new Set(prev).add(node.path));
|
|
4484
|
-
}
|
|
4495
|
+
else if (request) setLoadingPaths((prev) => new Set(prev).add(node.path));
|
|
4485
4496
|
const cursor = more ? listings.get(node.path)?.cursor : void 0;
|
|
4486
|
-
const pagesBefore = options?.replace ? 0 : listings.get(node.path)?.pagesLoaded ?? 0;
|
|
4487
4497
|
try {
|
|
4488
4498
|
const factory = await getStorageProviderAndClient(node.storageId);
|
|
4489
4499
|
if (!factory) throw new Error("Failed to connect to storage provider.");
|
|
@@ -4493,21 +4503,17 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4493
4503
|
const dir_path = node.root ? "" : node.relativePath ?? "";
|
|
4494
4504
|
const input = provider.listDirectoryInput(storage, dir_path, cursor ? { cursor } : {});
|
|
4495
4505
|
const objects = await client.listDirectory(input);
|
|
4496
|
-
const
|
|
4506
|
+
const entries = provider.convertDataToStorageObjects(objects);
|
|
4497
4507
|
const nextCursor = provider.nextPageCursor?.(objects);
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
};
|
|
4505
|
-
if (!silent) {
|
|
4506
|
-
setLocalStorages((prev) => prev.map((s) => s.id === storage.id ? updatedStorage : s));
|
|
4507
|
-
setListings((prev) => advanceListing(prev, node.path, nextCursor ? { cursor: nextCursor } : {}, pagesBefore));
|
|
4508
|
+
if (owns()) {
|
|
4509
|
+
const page = {
|
|
4510
|
+
entries,
|
|
4511
|
+
cursor: nextCursor
|
|
4512
|
+
};
|
|
4513
|
+
setListings((prev) => options?.replace ? replaceListing(prev, node.path, page) : advanceListing(prev, node.path, page));
|
|
4508
4514
|
}
|
|
4509
4515
|
}
|
|
4510
|
-
if (
|
|
4516
|
+
if (owns()) setHasCorsIssue((prev) => {
|
|
4511
4517
|
if (!prev.has(nodeStorageId)) return prev;
|
|
4512
4518
|
const next = new Map(prev);
|
|
4513
4519
|
next.delete(nodeStorageId);
|
|
@@ -4515,26 +4521,23 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4515
4521
|
});
|
|
4516
4522
|
return { corsError: false };
|
|
4517
4523
|
} catch (error) {
|
|
4518
|
-
const
|
|
4519
|
-
|
|
4520
|
-
if (
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
setHasCorsIssue((prev) => new Map(prev).set(nodeStorageId, true));
|
|
4525
|
-
}
|
|
4526
|
-
return { corsError: true };
|
|
4524
|
+
const isCorsError = error instanceof CorsError;
|
|
4525
|
+
const errorMessage = isCorsError ? error.message || "CORS error" : error instanceof Error ? error.message : "Unknown error";
|
|
4526
|
+
if (owns()) {
|
|
4527
|
+
setListings((prev) => recordListingError(options?.replace ? clearListingsUnder(prev, node.path) : prev, node.path, errorMessage));
|
|
4528
|
+
updateConnectionIssuesMessage((prev) => new Map(prev).set(nodeStorageId, `Failed to load contents for ${node?.displayName || node?.name}: ${errorMessage}`));
|
|
4529
|
+
if (isCorsError) setHasCorsIssue((prev) => new Map(prev).set(nodeStorageId, true));
|
|
4527
4530
|
}
|
|
4528
|
-
|
|
4529
|
-
updateConnectionIssuesMessage((prev) => new Map(prev).set(nodeStorageId, message));
|
|
4530
|
-
return { corsError: false };
|
|
4531
|
+
return { corsError: isCorsError };
|
|
4531
4532
|
} finally {
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4533
|
+
if (owns()) {
|
|
4534
|
+
fetchesInFlightRef.current.delete(node.path);
|
|
4535
|
+
if (!more) setLoadingPaths((prev) => {
|
|
4536
|
+
const next = new Set(prev);
|
|
4537
|
+
next.delete(node.path);
|
|
4538
|
+
return next;
|
|
4539
|
+
});
|
|
4540
|
+
}
|
|
4538
4541
|
}
|
|
4539
4542
|
});
|
|
4540
4543
|
const handleSelectTreeItem = async (path, node) => {
|
|
@@ -4556,8 +4559,8 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4556
4559
|
return next;
|
|
4557
4560
|
});
|
|
4558
4561
|
}, [normalizedSelectedPath]);
|
|
4559
|
-
const [
|
|
4560
|
-
const hydrationStuck =
|
|
4562
|
+
const [stuck, setStuck] = useState(null);
|
|
4563
|
+
const hydrationStuck = stuck?.target === normalizedSelectedPath;
|
|
4561
4564
|
const hydrationPagesRef = useRef({
|
|
4562
4565
|
path: "",
|
|
4563
4566
|
pages: 0
|
|
@@ -4577,18 +4580,19 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4577
4580
|
},
|
|
4578
4581
|
listings,
|
|
4579
4582
|
inFlight: fetchesInFlightRef.current,
|
|
4580
|
-
attempted: listAttemptsRef.current,
|
|
4581
4583
|
pagesPulled: hydrationPagesRef.current.pages
|
|
4582
4584
|
});
|
|
4583
4585
|
if (step.kind === "stuck") {
|
|
4584
|
-
|
|
4586
|
+
setStuck({
|
|
4587
|
+
target: normalizedSelectedPath,
|
|
4588
|
+
deepest: step.path
|
|
4589
|
+
});
|
|
4585
4590
|
return;
|
|
4586
4591
|
}
|
|
4587
4592
|
if (step.kind === "done") return;
|
|
4588
4593
|
const node = treeMap[step.path];
|
|
4589
4594
|
if (!node) return;
|
|
4590
4595
|
if (step.kind === "fetch") {
|
|
4591
|
-
listAttemptsRef.current.add(step.path);
|
|
4592
4596
|
fetchNodeChildren(node);
|
|
4593
4597
|
return;
|
|
4594
4598
|
}
|
|
@@ -4602,8 +4606,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4602
4606
|
useEffect(() => {
|
|
4603
4607
|
for (const path of expandedPaths) {
|
|
4604
4608
|
const node = treeMap[path];
|
|
4605
|
-
if (node?.type === "directory" && node.storageId && !
|
|
4606
|
-
listAttemptsRef.current.add(path);
|
|
4609
|
+
if (node?.type === "directory" && node.storageId && !listings.has(path) && !fetchesInFlightRef.current.has(path)) {
|
|
4607
4610
|
fetchNodeChildren(node);
|
|
4608
4611
|
return;
|
|
4609
4612
|
}
|
|
@@ -4806,7 +4809,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4806
4809
|
};
|
|
4807
4810
|
const openCreateFolder = async (node) => {
|
|
4808
4811
|
if (!isStorageDirectory(node)) return;
|
|
4809
|
-
if (!
|
|
4812
|
+
if (!isListed(listings, node.path)) await fetchNodeChildren(node);
|
|
4810
4813
|
setCreateFolderTarget(node);
|
|
4811
4814
|
};
|
|
4812
4815
|
const getCreateFolderActions = (node, storage) => {
|
|
@@ -4859,15 +4862,11 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4859
4862
|
icon: isFile ? /* @__PURE__ */ jsx(FileTextIcon, {}) : /* @__PURE__ */ jsx(FolderIcon, {}),
|
|
4860
4863
|
onSelect: () => handleSelectTreeItem(node.path, node)
|
|
4861
4864
|
}];
|
|
4862
|
-
const uriExtras = [{
|
|
4863
|
-
label:
|
|
4864
|
-
value
|
|
4865
|
+
const uriExtras = [pwUri, cspUri].filter((uri) => !!uri).map((value) => ({
|
|
4866
|
+
label: `${getUriScheme(value).toUpperCase()} URI`,
|
|
4867
|
+
value,
|
|
4865
4868
|
icon: /* @__PURE__ */ jsx(LinkIcon, {})
|
|
4866
|
-
}
|
|
4867
|
-
label: "S3 URI",
|
|
4868
|
-
value: cspUri,
|
|
4869
|
-
icon: /* @__PURE__ */ jsx(LinkIcon, {})
|
|
4870
|
-
}].filter((u) => u.value);
|
|
4869
|
+
}));
|
|
4871
4870
|
return assembleRowMenu({
|
|
4872
4871
|
lead,
|
|
4873
4872
|
actions,
|
|
@@ -4921,7 +4920,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
4921
4920
|
else if (selectedNode && selectedNode.type === "file") filesToDownload = [selectedNode];
|
|
4922
4921
|
if (filesToDownload.length === 0) return "";
|
|
4923
4922
|
const commands = filesToDownload.map((node) => {
|
|
4924
|
-
const storage =
|
|
4923
|
+
const storage = storages.find((s) => s.id === node.storageId);
|
|
4925
4924
|
if (!storage?.user || !storage.name) return "";
|
|
4926
4925
|
return `pw buckets cp ${shellSingleQuote(getPwUri(storage.user, storage.name, getObjectKeyFromNode(node)))} ${shellSingleQuote(`./${node.name}`)}`;
|
|
4927
4926
|
});
|
|
@@ -5053,7 +5052,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
5053
5052
|
notify.error(t.messages.uploadUnsupported);
|
|
5054
5053
|
return;
|
|
5055
5054
|
}
|
|
5056
|
-
const sessionId = fileExplorerContext.addUploadSession(storageName, cleanTargetPath, pendingUpload.uploadNodes, client, provider, targetNode, fetchNodeChildren);
|
|
5055
|
+
const sessionId = fileExplorerContext.addUploadSession(storageName, cleanTargetPath, pendingUpload.uploadNodes, client, provider, targetNode, (node) => fetchNodeChildren(node, { replace: true }));
|
|
5057
5056
|
const sessionQueueIndex = fileExplorerContext.getUploadQueueIndex(sessionId);
|
|
5058
5057
|
if (sessionQueueIndex === -1) {
|
|
5059
5058
|
notify.update(sessionId, {
|
|
@@ -5181,12 +5180,13 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
5181
5180
|
children: !selectedNode && normalizedSelectedPath ? hydrationStuck ? /* @__PURE__ */ jsx(NotFoundPreview, {
|
|
5182
5181
|
path: normalizedSelectedPath,
|
|
5183
5182
|
onRetry: () => {
|
|
5184
|
-
|
|
5183
|
+
const deepest = stuck?.deepest;
|
|
5185
5184
|
hydrationPagesRef.current = {
|
|
5186
5185
|
path: "",
|
|
5187
5186
|
pages: 0
|
|
5188
5187
|
};
|
|
5189
|
-
|
|
5188
|
+
setStuck(null);
|
|
5189
|
+
if (deepest) setListings((prev) => hasMore(prev, deepest) ? clearListingError(prev, deepest) : clearListingsUnder(prev, deepest));
|
|
5190
5190
|
}
|
|
5191
5191
|
}) : /* @__PURE__ */ jsx(ListSkeleton, {}) : !selectedNode && showUserHierarchy ? /* @__PURE__ */ jsxs("div", {
|
|
5192
5192
|
className: "overflow-auto h-full",
|
|
@@ -5391,7 +5391,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
5391
5391
|
onSelectAll: handleBatchCheckbox
|
|
5392
5392
|
})
|
|
5393
5393
|
}), /* @__PURE__ */ jsx(NoDataAvailablePreview, {
|
|
5394
|
-
selectedStorage:
|
|
5394
|
+
selectedStorage: storages.find((s) => s.id === selectedNode.storageId) || null,
|
|
5395
5395
|
canWrite: selectedNodeCanWrite,
|
|
5396
5396
|
onRefresh: handleRefresh,
|
|
5397
5397
|
error: hasCorsIssue.get(selectedNode.storageId ?? "") ? new CorsError(connectionIssuesMessage.get(selectedNode.storageId ?? "") || "") : null,
|
|
@@ -5424,7 +5424,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
5424
5424
|
})]
|
|
5425
5425
|
}), effectiveTab === "preview" && previewable ? /* @__PURE__ */ jsx(FilePreviewInline, {
|
|
5426
5426
|
node: selectedNode,
|
|
5427
|
-
storage:
|
|
5427
|
+
storage: storages.find((s) => s.id === selectedNode.storageId) ?? null,
|
|
5428
5428
|
getPresignedUrl,
|
|
5429
5429
|
onOpenFull: openPreview,
|
|
5430
5430
|
onDownload: downloadNode,
|
|
@@ -5551,7 +5551,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
5551
5551
|
open: previewOpen,
|
|
5552
5552
|
node: previewNode,
|
|
5553
5553
|
siblings: previewSiblings,
|
|
5554
|
-
storage:
|
|
5554
|
+
storage: storages.find((s) => s.id === previewNode?.storageId) ?? null,
|
|
5555
5555
|
getPresignedUrl,
|
|
5556
5556
|
onNavigate: setPreviewNode,
|
|
5557
5557
|
onClose: closePreview,
|
|
@@ -5658,7 +5658,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
5658
5658
|
open: accessDrawerOpen,
|
|
5659
5659
|
setOpen: setAccessDrawerOpen,
|
|
5660
5660
|
groups,
|
|
5661
|
-
storage:
|
|
5661
|
+
storage: storages.find((s) => s.id === selectedNode.storageId)
|
|
5662
5662
|
})
|
|
5663
5663
|
]
|
|
5664
5664
|
});
|