@noya-app/noya-file-explorer 0.0.15 → 0.0.17
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/.turbo/turbo-build.log +13 -13
- package/CHANGELOG.md +27 -0
- package/dist/index.css +916 -843
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +11207 -45
- package/dist/index.d.ts +11207 -45
- package/dist/index.js +1361 -160
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1399 -156
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
- package/src/MediaCollection.tsx +156 -97
- package/src/ResourceExplorer.tsx +1141 -0
- package/src/__tests__/deleteMediaItems.test.ts +7 -7
- package/src/__tests__/getDepthMap.test.ts +7 -7
- package/src/__tests__/getParentDirectories.test.ts +6 -6
- package/src/__tests__/getVisibleItems.test.ts +9 -9
- package/src/__tests__/moveMediaInsideFolder.test.ts +11 -11
- package/src/__tests__/movePathsIntoTarget.test.ts +9 -9
- package/src/__tests__/moveUpAFolder.test.ts +7 -7
- package/src/__tests__/renameMediaItemAndDescendantPaths.test.ts +6 -6
- package/src/__tests__/updateExpandedMap.test.ts +8 -8
- package/src/__tests__/validateMediaItemRename.test.ts +11 -11
- package/src/index.ts +2 -1
- package/src/utils/files.ts +28 -37
- package/src/utils/handleFileDrop.ts +165 -0
- package/src/utils/resourceUtils.ts +329 -0
- package/src/formatByteSize.ts +0 -8
package/dist/index.mjs
CHANGED
|
@@ -38,10 +38,10 @@ var require_access = __commonJS({
|
|
|
38
38
|
const accessed = _getPath(node, indexPath, options);
|
|
39
39
|
return accessed[accessed.length - 1];
|
|
40
40
|
}
|
|
41
|
-
let
|
|
42
|
-
while (
|
|
43
|
-
let index =
|
|
44
|
-
const children = options.getChildren(node,
|
|
41
|
+
let path7 = indexPath.slice();
|
|
42
|
+
while (path7.length > 0) {
|
|
43
|
+
let index = path7.shift();
|
|
44
|
+
const children = options.getChildren(node, path7);
|
|
45
45
|
const child = children[index];
|
|
46
46
|
if (!child) {
|
|
47
47
|
return void 0;
|
|
@@ -54,12 +54,12 @@ var require_access = __commonJS({
|
|
|
54
54
|
return _getPath(node, indexPath, options).slice(0, -1);
|
|
55
55
|
}
|
|
56
56
|
function _getPath(node, indexPath, options) {
|
|
57
|
-
let
|
|
57
|
+
let path7 = indexPath.slice();
|
|
58
58
|
let result = [node];
|
|
59
|
-
while (
|
|
60
|
-
let index =
|
|
59
|
+
while (path7.length > 0) {
|
|
60
|
+
let index = path7.shift();
|
|
61
61
|
const context = options.includeTraversalContext ? makeTraversalContext(result) : void 0;
|
|
62
|
-
const children = options.getChildren(node,
|
|
62
|
+
const children = options.getChildren(node, path7, context);
|
|
63
63
|
const child = children[index];
|
|
64
64
|
if (!child) {
|
|
65
65
|
return result;
|
|
@@ -74,20 +74,20 @@ var require_access = __commonJS({
|
|
|
74
74
|
const accessed = accessPath(node, indexPath, options);
|
|
75
75
|
return accessed[accessed.length - 1];
|
|
76
76
|
}
|
|
77
|
-
let
|
|
78
|
-
while (
|
|
79
|
-
let index =
|
|
80
|
-
node = options.getChildren(node,
|
|
77
|
+
let path7 = indexPath.slice();
|
|
78
|
+
while (path7.length > 0) {
|
|
79
|
+
let index = path7.shift();
|
|
80
|
+
node = options.getChildren(node, path7)[index];
|
|
81
81
|
}
|
|
82
82
|
return node;
|
|
83
83
|
}
|
|
84
84
|
function accessPath(node, indexPath, options) {
|
|
85
|
-
let
|
|
85
|
+
let path7 = indexPath.slice();
|
|
86
86
|
let result = [node];
|
|
87
|
-
while (
|
|
88
|
-
let index =
|
|
87
|
+
while (path7.length > 0) {
|
|
88
|
+
let index = path7.shift();
|
|
89
89
|
const context = options.includeTraversalContext ? makeTraversalContext(result) : void 0;
|
|
90
|
-
node = options.getChildren(node,
|
|
90
|
+
node = options.getChildren(node, path7, context)[index];
|
|
91
91
|
result.push(node);
|
|
92
92
|
}
|
|
93
93
|
return result;
|
|
@@ -129,9 +129,9 @@ var require_ancestors = __commonJS({
|
|
|
129
129
|
"../../node_modules/tree-visit/lib/ancestors.js"(exports) {
|
|
130
130
|
"use strict";
|
|
131
131
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
132
|
-
exports.ancestorPaths =
|
|
132
|
+
exports.ancestorPaths = ancestorPaths3;
|
|
133
133
|
var sort_1 = require_sort();
|
|
134
|
-
function
|
|
134
|
+
function ancestorPaths3(paths, options) {
|
|
135
135
|
var _a;
|
|
136
136
|
const result = /* @__PURE__ */ new Map();
|
|
137
137
|
const compare = (_a = options === null || options === void 0 ? void 0 : options.compare) !== null && _a !== void 0 ? _a : sort_1.comparePathsByComponent;
|
|
@@ -601,40 +601,40 @@ var require_transformPath = __commonJS({
|
|
|
601
601
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
602
602
|
exports.transformPath = transformPath;
|
|
603
603
|
var sort_1 = require_sort();
|
|
604
|
-
function commonAncestor(
|
|
605
|
-
const length = Math.min(
|
|
604
|
+
function commonAncestor(path7, otherPath) {
|
|
605
|
+
const length = Math.min(path7.length, otherPath.length);
|
|
606
606
|
for (let i = 0; i < length; i++) {
|
|
607
|
-
if (
|
|
608
|
-
return
|
|
607
|
+
if (path7[i] !== otherPath[i]) {
|
|
608
|
+
return path7.slice(0, i);
|
|
609
609
|
}
|
|
610
610
|
}
|
|
611
|
-
return
|
|
611
|
+
return path7.slice(0, length);
|
|
612
612
|
}
|
|
613
|
-
function transformPath(
|
|
614
|
-
if (otherPath.length >
|
|
615
|
-
return
|
|
613
|
+
function transformPath(path7, operation, otherPath, count = 1) {
|
|
614
|
+
if (otherPath.length > path7.length || (0, sort_1.comparePathsByComponent)(otherPath, path7) > 0) {
|
|
615
|
+
return path7;
|
|
616
616
|
}
|
|
617
617
|
if (otherPath.length === 0 && operation === "remove") {
|
|
618
618
|
return void 0;
|
|
619
619
|
}
|
|
620
|
-
const common = commonAncestor(
|
|
621
|
-
const adjustmentIndex = common.length ===
|
|
622
|
-
const pathValue =
|
|
620
|
+
const common = commonAncestor(path7, otherPath);
|
|
621
|
+
const adjustmentIndex = common.length === path7.length || common.length === otherPath.length ? common.length - 1 : common.length;
|
|
622
|
+
const pathValue = path7[adjustmentIndex];
|
|
623
623
|
const otherPathValue = otherPath[adjustmentIndex];
|
|
624
624
|
if (operation === "insert" && otherPathValue <= pathValue) {
|
|
625
|
-
const newPath = [...
|
|
625
|
+
const newPath = [...path7];
|
|
626
626
|
newPath[adjustmentIndex] += count;
|
|
627
627
|
return newPath;
|
|
628
628
|
} else if (operation === "remove") {
|
|
629
629
|
if (otherPathValue === pathValue) {
|
|
630
630
|
return void 0;
|
|
631
631
|
} else if (otherPathValue < pathValue) {
|
|
632
|
-
const newPath = [...
|
|
632
|
+
const newPath = [...path7];
|
|
633
633
|
newPath[adjustmentIndex] -= count;
|
|
634
634
|
return newPath;
|
|
635
635
|
}
|
|
636
636
|
}
|
|
637
|
-
return
|
|
637
|
+
return path7;
|
|
638
638
|
}
|
|
639
639
|
}
|
|
640
640
|
});
|
|
@@ -800,15 +800,15 @@ var require_operation = __commonJS({
|
|
|
800
800
|
switch (operation.type) {
|
|
801
801
|
case "insert": {
|
|
802
802
|
const otherPath = parentPath.concat(operation.index);
|
|
803
|
-
return transformedPaths.map((
|
|
803
|
+
return transformedPaths.map((path7) => path7 ? (0, transformPath_1.transformPath)(path7, "insert", otherPath, operation.nodes.length) : void 0);
|
|
804
804
|
}
|
|
805
805
|
case "remove": {
|
|
806
806
|
const otherPaths = [...operation.indexes].reverse().map((index) => parentPath.concat(index));
|
|
807
|
-
return transformedPaths.map((
|
|
807
|
+
return transformedPaths.map((path7) => {
|
|
808
808
|
for (const otherPath of otherPaths) {
|
|
809
|
-
|
|
809
|
+
path7 = path7 ? (0, transformPath_1.transformPath)(path7, "remove", otherPath) : void 0;
|
|
810
810
|
}
|
|
811
|
-
return
|
|
811
|
+
return path7;
|
|
812
812
|
});
|
|
813
813
|
}
|
|
814
814
|
case "removeThenInsert": {
|
|
@@ -945,22 +945,22 @@ var require_splice = __commonJS({
|
|
|
945
945
|
return _spliceWithPathTracking(node, options);
|
|
946
946
|
}
|
|
947
947
|
function _spliceWithPathTracking(node, options) {
|
|
948
|
-
const { path:
|
|
949
|
-
if (
|
|
948
|
+
const { path: path7, deleteCount = 0, nodes, track } = options;
|
|
949
|
+
if (path7.length === 0) {
|
|
950
950
|
throw new Error(`Can't splice at the root`);
|
|
951
951
|
}
|
|
952
|
-
const pathsToRemove = getPathsToRemove(
|
|
953
|
-
const operations = (0, operation_1.getInsertionOperations)(
|
|
952
|
+
const pathsToRemove = getPathsToRemove(path7, deleteCount);
|
|
953
|
+
const operations = (0, operation_1.getInsertionOperations)(path7, nodes, (0, operation_1.getRemovalOperations)(pathsToRemove));
|
|
954
954
|
const transformedPaths = track ? (0, operation_1.transformPathsByOperations)(track, operations) : [];
|
|
955
955
|
return {
|
|
956
956
|
node: (0, operation_1.applyOperations)(node, operations, options),
|
|
957
957
|
paths: transformedPaths
|
|
958
958
|
};
|
|
959
959
|
}
|
|
960
|
-
function getPathsToRemove(
|
|
960
|
+
function getPathsToRemove(path7, deleteCount) {
|
|
961
961
|
let pathsToRemove = [];
|
|
962
|
-
let parentPath =
|
|
963
|
-
let index =
|
|
962
|
+
let parentPath = path7.slice(0, -1);
|
|
963
|
+
let index = path7[path7.length - 1];
|
|
964
964
|
for (let i = 0; i < deleteCount; i++) {
|
|
965
965
|
pathsToRemove.push(parentPath.concat(index + i));
|
|
966
966
|
}
|
|
@@ -1100,15 +1100,6 @@ var require_lib = __commonJS({
|
|
|
1100
1100
|
}
|
|
1101
1101
|
});
|
|
1102
1102
|
|
|
1103
|
-
// src/formatByteSize.ts
|
|
1104
|
-
var byteSizeUnits = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
1105
|
-
function formatByteSize(size) {
|
|
1106
|
-
const unitIndex = Math.floor(Math.log(size) / Math.log(1024));
|
|
1107
|
-
const unit = byteSizeUnits[unitIndex];
|
|
1108
|
-
const value = size / Math.pow(1024, unitIndex);
|
|
1109
|
-
return `${value.toFixed(1)} ${unit}`;
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
1103
|
// src/MediaCollection.tsx
|
|
1113
1104
|
import {
|
|
1114
1105
|
ActionMenu,
|
|
@@ -1119,7 +1110,9 @@ import {
|
|
|
1119
1110
|
FileExplorerEmptyState,
|
|
1120
1111
|
FileExplorerLayout,
|
|
1121
1112
|
FileExplorerUploadButton,
|
|
1122
|
-
|
|
1113
|
+
formatByteSize,
|
|
1114
|
+
MediaThumbnail,
|
|
1115
|
+
useOpenConfirmationDialog
|
|
1123
1116
|
} from "@noya-app/noya-designsystem";
|
|
1124
1117
|
import {
|
|
1125
1118
|
DownloadIcon,
|
|
@@ -1236,11 +1229,19 @@ var createMediaItemTree = (mediaMap) => {
|
|
|
1236
1229
|
};
|
|
1237
1230
|
|
|
1238
1231
|
// src/MediaCollection.tsx
|
|
1239
|
-
import { path as
|
|
1232
|
+
import { path as path4 } from "imfs";
|
|
1240
1233
|
import React from "react";
|
|
1241
1234
|
|
|
1242
1235
|
// src/utils/files.ts
|
|
1236
|
+
var import_tree_visit3 = __toESM(require_lib());
|
|
1237
|
+
import { path as path3 } from "imfs";
|
|
1238
|
+
|
|
1239
|
+
// src/utils/resourceUtils.ts
|
|
1243
1240
|
var import_tree_visit2 = __toESM(require_lib());
|
|
1241
|
+
import {
|
|
1242
|
+
createResourceTree,
|
|
1243
|
+
rootResource
|
|
1244
|
+
} from "@noya-app/noya-schemas";
|
|
1244
1245
|
import { path as path2 } from "imfs";
|
|
1245
1246
|
var getVisibleItems = ({
|
|
1246
1247
|
expandedMap,
|
|
@@ -1251,7 +1252,7 @@ var getVisibleItems = ({
|
|
|
1251
1252
|
showRootItem
|
|
1252
1253
|
}) => {
|
|
1253
1254
|
const filteredItems = [];
|
|
1254
|
-
const relativeRootItem = tree.find(
|
|
1255
|
+
const relativeRootItem = tree.find(rootResource, (item) => item.id === rootItemId) ?? rootResource;
|
|
1255
1256
|
tree.visit(relativeRootItem, (item) => {
|
|
1256
1257
|
if (relativeRootItem.id === item.id) {
|
|
1257
1258
|
if (showRootItem) {
|
|
@@ -1259,13 +1260,16 @@ var getVisibleItems = ({
|
|
|
1259
1260
|
}
|
|
1260
1261
|
return;
|
|
1261
1262
|
}
|
|
1262
|
-
if (item.
|
|
1263
|
+
if (item.type === "file" && fileKindFilter === "all") {
|
|
1263
1264
|
filteredItems.push(item);
|
|
1264
1265
|
}
|
|
1265
|
-
if (item.
|
|
1266
|
+
if (item.type === "asset" && (fileKindFilter === "assets" || fileKindFilter === "all")) {
|
|
1266
1267
|
filteredItems.push(item);
|
|
1267
1268
|
}
|
|
1268
|
-
if (item.
|
|
1269
|
+
if (item.type === "directory" && (fileKindFilter === "directories" || fileKindFilter === "all")) {
|
|
1270
|
+
filteredItems.push(item);
|
|
1271
|
+
}
|
|
1272
|
+
if (item.type === "resource" && (fileKindFilter === "resources" || fileKindFilter === "all")) {
|
|
1269
1273
|
filteredItems.push(item);
|
|
1270
1274
|
}
|
|
1271
1275
|
if (!expandedMap[item.id] || !showAllDescendants) return "skip";
|
|
@@ -1277,7 +1281,7 @@ var basenameValidator = (basename) => {
|
|
|
1277
1281
|
const invalidCharsRegex = /[/\\<>:"|?*]/;
|
|
1278
1282
|
return !invalidCharsRegex.test(basename);
|
|
1279
1283
|
};
|
|
1280
|
-
var
|
|
1284
|
+
var validateResourceRename = ({
|
|
1281
1285
|
basename,
|
|
1282
1286
|
selectedItemPath,
|
|
1283
1287
|
media
|
|
@@ -1295,7 +1299,7 @@ var movePathsIntoTarget = ({
|
|
|
1295
1299
|
tree
|
|
1296
1300
|
}) => {
|
|
1297
1301
|
const ancestors = (0, import_tree_visit2.ancestorPaths)(
|
|
1298
|
-
sourceItemPaths.map((
|
|
1302
|
+
sourceItemPaths.map((path7) => path7.split("/"))
|
|
1299
1303
|
);
|
|
1300
1304
|
const mediaClone = { ...media };
|
|
1301
1305
|
for (const ancestor of ancestors) {
|
|
@@ -1313,7 +1317,7 @@ var movePathsIntoTarget = ({
|
|
|
1313
1317
|
ancestorPath,
|
|
1314
1318
|
newAncestorPath
|
|
1315
1319
|
);
|
|
1316
|
-
const newPathIsValid =
|
|
1320
|
+
const newPathIsValid = validateResourceRename({
|
|
1317
1321
|
basename: path2.basename(descendantPath),
|
|
1318
1322
|
selectedItemPath: newDescendantPath,
|
|
1319
1323
|
media
|
|
@@ -1332,17 +1336,17 @@ var moveUpAFolder = ({
|
|
|
1332
1336
|
selectedIds
|
|
1333
1337
|
}) => {
|
|
1334
1338
|
const indexPath = tree.findPath(
|
|
1335
|
-
|
|
1339
|
+
rootResource,
|
|
1336
1340
|
(item) => item.id === selectedIds[0]
|
|
1337
1341
|
);
|
|
1338
1342
|
if (!indexPath) return;
|
|
1339
1343
|
const grandparentFolder = tree.access(
|
|
1340
|
-
|
|
1344
|
+
rootResource,
|
|
1341
1345
|
indexPath.slice(0, indexPath.length - 2)
|
|
1342
1346
|
);
|
|
1343
1347
|
const grandparentFolderPath = tree.idToPathMap.get(grandparentFolder.id);
|
|
1344
1348
|
if (!grandparentFolderPath) return;
|
|
1345
|
-
const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((
|
|
1349
|
+
const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
|
|
1346
1350
|
return movePathsIntoTarget({
|
|
1347
1351
|
media,
|
|
1348
1352
|
targetItemPath: grandparentFolderPath,
|
|
@@ -1371,7 +1375,7 @@ var updateExpandedMap = ({
|
|
|
1371
1375
|
const newExpandedMap = { ...expandedMap };
|
|
1372
1376
|
const inner = (item2, expanded2) => {
|
|
1373
1377
|
if (!expandable) return {};
|
|
1374
|
-
if (item2.id ===
|
|
1378
|
+
if (item2.id === rootResource.id) return {};
|
|
1375
1379
|
if (!expanded2) {
|
|
1376
1380
|
const children = tree.getChildren(item2, []);
|
|
1377
1381
|
children.forEach((child) => inner(child, false));
|
|
@@ -1381,13 +1385,13 @@ var updateExpandedMap = ({
|
|
|
1381
1385
|
inner(item, expanded);
|
|
1382
1386
|
return newExpandedMap;
|
|
1383
1387
|
};
|
|
1384
|
-
var
|
|
1388
|
+
var deleteResources = ({
|
|
1385
1389
|
selectedIds,
|
|
1386
1390
|
media,
|
|
1387
1391
|
tree
|
|
1388
1392
|
}) => {
|
|
1389
1393
|
const itemsToDelete = selectedIds.flatMap((mediaItemId) => {
|
|
1390
|
-
const mediaItem = tree.
|
|
1394
|
+
const mediaItem = tree.resourcesWithRoot.find(
|
|
1391
1395
|
(item) => item.id === mediaItemId
|
|
1392
1396
|
);
|
|
1393
1397
|
if (!mediaItem) return [];
|
|
@@ -1408,7 +1412,7 @@ var moveMediaInsideFolder = ({
|
|
|
1408
1412
|
}) => {
|
|
1409
1413
|
const targetItemPath = tree.idToPathMap.get(targetItemId);
|
|
1410
1414
|
if (!targetItemPath) return media;
|
|
1411
|
-
const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((
|
|
1415
|
+
const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
|
|
1412
1416
|
return movePathsIntoTarget({
|
|
1413
1417
|
media,
|
|
1414
1418
|
sourceItemPaths,
|
|
@@ -1416,7 +1420,213 @@ var moveMediaInsideFolder = ({
|
|
|
1416
1420
|
tree
|
|
1417
1421
|
});
|
|
1418
1422
|
};
|
|
1419
|
-
var getParentDirectories = (
|
|
1423
|
+
var getParentDirectories = (resourceMap, folderId) => {
|
|
1424
|
+
const tree = createResourceTree(resourceMap);
|
|
1425
|
+
const indexPath = tree.findPath(rootResource, (item) => item.id === folderId);
|
|
1426
|
+
if (!indexPath) return [rootResource];
|
|
1427
|
+
return tree.accessPath(rootResource, indexPath);
|
|
1428
|
+
};
|
|
1429
|
+
var renameResourceAndDescendantPaths = ({
|
|
1430
|
+
newName,
|
|
1431
|
+
selectedItemPath,
|
|
1432
|
+
media,
|
|
1433
|
+
tree
|
|
1434
|
+
}) => {
|
|
1435
|
+
const mediaClone = { ...media };
|
|
1436
|
+
const selectedItem = mediaClone[selectedItemPath];
|
|
1437
|
+
if (!selectedItem) return mediaClone;
|
|
1438
|
+
const parentPath = path2.dirname(selectedItemPath);
|
|
1439
|
+
const newItemPath = path2.join(parentPath, newName);
|
|
1440
|
+
const descendants = tree.flat(selectedItem).map((item) => tree.idToPathMap.get(item.id));
|
|
1441
|
+
for (const descendantPath of descendants) {
|
|
1442
|
+
if (!descendantPath) continue;
|
|
1443
|
+
const newDescendantPath = descendantPath.replace(
|
|
1444
|
+
selectedItemPath,
|
|
1445
|
+
newItemPath
|
|
1446
|
+
);
|
|
1447
|
+
mediaClone[newDescendantPath] = {
|
|
1448
|
+
...mediaClone[descendantPath],
|
|
1449
|
+
path: newDescendantPath
|
|
1450
|
+
};
|
|
1451
|
+
delete mediaClone[descendantPath];
|
|
1452
|
+
}
|
|
1453
|
+
return mediaClone;
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
// src/utils/files.ts
|
|
1457
|
+
var mediaGetVisibleItems = ({
|
|
1458
|
+
expandedMap,
|
|
1459
|
+
fileKindFilter,
|
|
1460
|
+
rootItemId,
|
|
1461
|
+
tree,
|
|
1462
|
+
showAllDescendants,
|
|
1463
|
+
showRootItem
|
|
1464
|
+
}) => {
|
|
1465
|
+
const filteredItems = [];
|
|
1466
|
+
const relativeRootItem = tree.find(rootMediaItem, (item) => item.id === rootItemId) ?? rootMediaItem;
|
|
1467
|
+
tree.visit(relativeRootItem, (item) => {
|
|
1468
|
+
if (relativeRootItem.id === item.id) {
|
|
1469
|
+
if (showRootItem) {
|
|
1470
|
+
filteredItems.push(item);
|
|
1471
|
+
}
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
if (item.kind === "noyaFile" && fileKindFilter === "all") {
|
|
1475
|
+
filteredItems.push(item);
|
|
1476
|
+
}
|
|
1477
|
+
if (item.kind === "file" && fileKindFilter === "all") {
|
|
1478
|
+
filteredItems.push(item);
|
|
1479
|
+
}
|
|
1480
|
+
if (item.kind === "asset" && (fileKindFilter === "assets" || fileKindFilter === "all")) {
|
|
1481
|
+
filteredItems.push(item);
|
|
1482
|
+
}
|
|
1483
|
+
if (item.kind === "folder" && (fileKindFilter === "directories" || fileKindFilter === "all")) {
|
|
1484
|
+
filteredItems.push(item);
|
|
1485
|
+
}
|
|
1486
|
+
if (!expandedMap[item.id] || !showAllDescendants) return "skip";
|
|
1487
|
+
});
|
|
1488
|
+
return filteredItems;
|
|
1489
|
+
};
|
|
1490
|
+
var mediaValidateMediaItemRename = ({
|
|
1491
|
+
basename,
|
|
1492
|
+
selectedItemPath,
|
|
1493
|
+
media
|
|
1494
|
+
}) => {
|
|
1495
|
+
if (!basenameValidator(basename)) return false;
|
|
1496
|
+
const newItemPath = path3.join(path3.dirname(selectedItemPath), basename);
|
|
1497
|
+
const newPathExists = media[newItemPath];
|
|
1498
|
+
if (newPathExists) return false;
|
|
1499
|
+
return true;
|
|
1500
|
+
};
|
|
1501
|
+
var mediaMovePathsIntoTarget = ({
|
|
1502
|
+
media,
|
|
1503
|
+
sourceItemPaths,
|
|
1504
|
+
targetItemPath,
|
|
1505
|
+
tree
|
|
1506
|
+
}) => {
|
|
1507
|
+
const ancestors = (0, import_tree_visit3.ancestorPaths)(
|
|
1508
|
+
sourceItemPaths.map((path7) => path7.split("/"))
|
|
1509
|
+
);
|
|
1510
|
+
const mediaClone = { ...media };
|
|
1511
|
+
for (const ancestor of ancestors) {
|
|
1512
|
+
const ancestorPath = ancestor.join("/");
|
|
1513
|
+
const ancestorItem = mediaClone[ancestorPath];
|
|
1514
|
+
const newAncestorPath = path3.join(
|
|
1515
|
+
targetItemPath,
|
|
1516
|
+
path3.basename(ancestorPath)
|
|
1517
|
+
);
|
|
1518
|
+
if (!ancestorItem) continue;
|
|
1519
|
+
const descendantPaths = tree.flat(ancestorItem).map((item) => tree.idToPathMap.get(item.id));
|
|
1520
|
+
for (const descendantPath of descendantPaths) {
|
|
1521
|
+
if (!descendantPath) continue;
|
|
1522
|
+
const newDescendantPath = descendantPath.replace(
|
|
1523
|
+
ancestorPath,
|
|
1524
|
+
newAncestorPath
|
|
1525
|
+
);
|
|
1526
|
+
const newPathIsValid = mediaValidateMediaItemRename({
|
|
1527
|
+
basename: path3.basename(descendantPath),
|
|
1528
|
+
selectedItemPath: newDescendantPath,
|
|
1529
|
+
media
|
|
1530
|
+
});
|
|
1531
|
+
if (newPathIsValid) {
|
|
1532
|
+
mediaClone[newDescendantPath] = mediaClone[descendantPath];
|
|
1533
|
+
delete mediaClone[descendantPath];
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
return mediaClone;
|
|
1538
|
+
};
|
|
1539
|
+
var mediaMoveUpAFolder = ({
|
|
1540
|
+
tree,
|
|
1541
|
+
media,
|
|
1542
|
+
selectedIds
|
|
1543
|
+
}) => {
|
|
1544
|
+
const indexPath = tree.findPath(
|
|
1545
|
+
rootMediaItem,
|
|
1546
|
+
(item) => item.id === selectedIds[0]
|
|
1547
|
+
);
|
|
1548
|
+
if (!indexPath) return;
|
|
1549
|
+
const grandparentFolder = tree.access(
|
|
1550
|
+
rootMediaItem,
|
|
1551
|
+
indexPath.slice(0, indexPath.length - 2)
|
|
1552
|
+
);
|
|
1553
|
+
const grandparentFolderPath = tree.idToPathMap.get(grandparentFolder.id);
|
|
1554
|
+
if (!grandparentFolderPath) return;
|
|
1555
|
+
const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
|
|
1556
|
+
return mediaMovePathsIntoTarget({
|
|
1557
|
+
media,
|
|
1558
|
+
targetItemPath: grandparentFolderPath,
|
|
1559
|
+
sourceItemPaths,
|
|
1560
|
+
tree
|
|
1561
|
+
});
|
|
1562
|
+
};
|
|
1563
|
+
var mediaGetDepthMap = (item, tree, showAllDescendants) => {
|
|
1564
|
+
const depthMap = {};
|
|
1565
|
+
tree.visit(item, (item2, indexPath) => {
|
|
1566
|
+
if (showAllDescendants) {
|
|
1567
|
+
depthMap[item2.id] = Math.max(indexPath.length - 1, 0);
|
|
1568
|
+
} else {
|
|
1569
|
+
depthMap[item2.id] = 0;
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
return depthMap;
|
|
1573
|
+
};
|
|
1574
|
+
var mediaUpdateExpandedMap = ({
|
|
1575
|
+
item,
|
|
1576
|
+
expanded,
|
|
1577
|
+
expandable,
|
|
1578
|
+
expandedMap,
|
|
1579
|
+
tree
|
|
1580
|
+
}) => {
|
|
1581
|
+
const newExpandedMap = { ...expandedMap };
|
|
1582
|
+
const inner = (item2, expanded2) => {
|
|
1583
|
+
if (!expandable) return {};
|
|
1584
|
+
if (item2.id === rootMediaItem.id) return {};
|
|
1585
|
+
if (!expanded2) {
|
|
1586
|
+
const children = tree.getChildren(item2, []);
|
|
1587
|
+
children.forEach((child) => inner(child, false));
|
|
1588
|
+
}
|
|
1589
|
+
newExpandedMap[item2.id] = expanded2;
|
|
1590
|
+
};
|
|
1591
|
+
inner(item, expanded);
|
|
1592
|
+
return newExpandedMap;
|
|
1593
|
+
};
|
|
1594
|
+
var mediaDeleteMediaItems = ({
|
|
1595
|
+
selectedIds,
|
|
1596
|
+
media,
|
|
1597
|
+
tree
|
|
1598
|
+
}) => {
|
|
1599
|
+
const itemsToDelete = selectedIds.flatMap((mediaItemId) => {
|
|
1600
|
+
const mediaItem = tree.mediaItemsWithRoot.find(
|
|
1601
|
+
(item) => item.id === mediaItemId
|
|
1602
|
+
);
|
|
1603
|
+
if (!mediaItem) return [];
|
|
1604
|
+
return tree.flat(mediaItem);
|
|
1605
|
+
});
|
|
1606
|
+
const itemKeysToDelete = new Set(
|
|
1607
|
+
itemsToDelete.map((item) => tree.idToPathMap.get(item.id))
|
|
1608
|
+
);
|
|
1609
|
+
return Object.fromEntries(
|
|
1610
|
+
Object.entries(media).filter(([key]) => !itemKeysToDelete.has(key))
|
|
1611
|
+
);
|
|
1612
|
+
};
|
|
1613
|
+
var mediaMoveMediaInsideFolder = ({
|
|
1614
|
+
sourceItemIds,
|
|
1615
|
+
targetItemId,
|
|
1616
|
+
media,
|
|
1617
|
+
tree
|
|
1618
|
+
}) => {
|
|
1619
|
+
const targetItemPath = tree.idToPathMap.get(targetItemId);
|
|
1620
|
+
if (!targetItemPath) return media;
|
|
1621
|
+
const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
|
|
1622
|
+
return mediaMovePathsIntoTarget({
|
|
1623
|
+
media,
|
|
1624
|
+
sourceItemPaths,
|
|
1625
|
+
targetItemPath,
|
|
1626
|
+
tree
|
|
1627
|
+
});
|
|
1628
|
+
};
|
|
1629
|
+
var mediaGetParentDirectories = (mediaMap, folderId) => {
|
|
1420
1630
|
const tree = createMediaItemTree(mediaMap);
|
|
1421
1631
|
const indexPath = tree.findPath(
|
|
1422
1632
|
rootMediaItem,
|
|
@@ -1425,7 +1635,7 @@ var getParentDirectories = (mediaMap, folderId) => {
|
|
|
1425
1635
|
if (!indexPath) return [rootMediaItem];
|
|
1426
1636
|
return tree.accessPath(rootMediaItem, indexPath);
|
|
1427
1637
|
};
|
|
1428
|
-
var
|
|
1638
|
+
var mediaRenameMediaItemAndDescendantPaths = ({
|
|
1429
1639
|
newName,
|
|
1430
1640
|
selectedItemPath,
|
|
1431
1641
|
media,
|
|
@@ -1434,8 +1644,8 @@ var renameMediaItemAndDescendantPaths = ({
|
|
|
1434
1644
|
const mediaClone = { ...media };
|
|
1435
1645
|
const selectedItem = mediaClone[selectedItemPath];
|
|
1436
1646
|
if (!selectedItem) return mediaClone;
|
|
1437
|
-
const parentPath =
|
|
1438
|
-
const newItemPath =
|
|
1647
|
+
const parentPath = path3.dirname(selectedItemPath);
|
|
1648
|
+
const newItemPath = path3.join(parentPath, newName);
|
|
1439
1649
|
const descendants = tree.flat(selectedItem).map((item) => tree.idToPathMap.get(item.id));
|
|
1440
1650
|
for (const descendantPath of descendants) {
|
|
1441
1651
|
if (!descendantPath) continue;
|
|
@@ -1456,7 +1666,7 @@ var extensionToContentType = {
|
|
|
1456
1666
|
jpeg: "image/jpeg"
|
|
1457
1667
|
};
|
|
1458
1668
|
function encodeFileContentForThumbnail(pathProp, item) {
|
|
1459
|
-
const extension =
|
|
1669
|
+
const extension = path4.extname(pathProp).slice(1);
|
|
1460
1670
|
const contentType = extensionToContentType[extension];
|
|
1461
1671
|
if (contentType) {
|
|
1462
1672
|
if (item.encoding === "base64") {
|
|
@@ -1483,7 +1693,8 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1483
1693
|
item,
|
|
1484
1694
|
selected,
|
|
1485
1695
|
size,
|
|
1486
|
-
path: pathProp
|
|
1696
|
+
path: pathProp,
|
|
1697
|
+
renderThumbnailIcon
|
|
1487
1698
|
}) => {
|
|
1488
1699
|
const asset = useAsset(item.kind === "asset" ? item.assetId : void 0);
|
|
1489
1700
|
const isRoot = item.id === rootMediaItem.id;
|
|
@@ -1491,9 +1702,13 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1491
1702
|
const isFile = item.kind === "file";
|
|
1492
1703
|
let contentType;
|
|
1493
1704
|
let url;
|
|
1705
|
+
let width;
|
|
1706
|
+
let height;
|
|
1494
1707
|
if (asset) {
|
|
1495
1708
|
contentType = asset.contentType;
|
|
1496
1709
|
url = asset.url;
|
|
1710
|
+
width = asset.width ?? void 0;
|
|
1711
|
+
height = asset.height ?? void 0;
|
|
1497
1712
|
} else if (isFile && pathProp) {
|
|
1498
1713
|
const encoded = encodeFileContentForThumbnail(pathProp, item);
|
|
1499
1714
|
if (encoded) {
|
|
@@ -1501,7 +1716,8 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1501
1716
|
url = encoded.url;
|
|
1502
1717
|
}
|
|
1503
1718
|
}
|
|
1504
|
-
const fileName = pathProp ?
|
|
1719
|
+
const fileName = pathProp ? path4.basename(pathProp) : void 0;
|
|
1720
|
+
const dimensions = width && height ? { width, height } : void 0;
|
|
1505
1721
|
return /* @__PURE__ */ React.createElement(
|
|
1506
1722
|
MediaThumbnail,
|
|
1507
1723
|
{
|
|
@@ -1510,7 +1726,9 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1510
1726
|
url,
|
|
1511
1727
|
selected,
|
|
1512
1728
|
size,
|
|
1513
|
-
fileName
|
|
1729
|
+
fileName,
|
|
1730
|
+
renderThumbnailIcon,
|
|
1731
|
+
dimensions
|
|
1514
1732
|
}
|
|
1515
1733
|
);
|
|
1516
1734
|
}
|
|
@@ -1542,7 +1760,10 @@ var MediaCollection = memo(
|
|
|
1542
1760
|
sortable = false,
|
|
1543
1761
|
renderEmptyState,
|
|
1544
1762
|
sharedDragProps,
|
|
1545
|
-
onClickItem
|
|
1763
|
+
onClickItem,
|
|
1764
|
+
renderThumbnailIcon,
|
|
1765
|
+
onDidDeleteItems,
|
|
1766
|
+
onAssetsUploaded
|
|
1546
1767
|
}, ref) {
|
|
1547
1768
|
const setMedia = useCallback(
|
|
1548
1769
|
(...args) => {
|
|
@@ -1583,7 +1804,7 @@ var MediaCollection = memo(
|
|
|
1583
1804
|
const assets = useAssets();
|
|
1584
1805
|
const [expandedMap, setExpandedMap] = useState({});
|
|
1585
1806
|
const visibleItems = useMemo(
|
|
1586
|
-
() =>
|
|
1807
|
+
() => mediaGetVisibleItems({
|
|
1587
1808
|
expandedMap,
|
|
1588
1809
|
fileKindFilter,
|
|
1589
1810
|
rootItemId,
|
|
@@ -1601,7 +1822,7 @@ var MediaCollection = memo(
|
|
|
1601
1822
|
]
|
|
1602
1823
|
);
|
|
1603
1824
|
const depthMap = useMemo(
|
|
1604
|
-
() =>
|
|
1825
|
+
() => mediaGetDepthMap(rootMediaItem, treeWithTempItem, showAllDescendants),
|
|
1605
1826
|
[treeWithTempItem, showAllDescendants]
|
|
1606
1827
|
);
|
|
1607
1828
|
const collectionRef = useRef(null);
|
|
@@ -1624,7 +1845,7 @@ var MediaCollection = memo(
|
|
|
1624
1845
|
const itemPath = tree.idToPathMap.get(item.id);
|
|
1625
1846
|
const firstSelectedPath = tree.idToPathMap.get(selectedIds[0]);
|
|
1626
1847
|
if (!itemPath || !firstSelectedPath) return false;
|
|
1627
|
-
return itemPath.startsWith(
|
|
1848
|
+
return itemPath.startsWith(path4.dirname(firstSelectedPath));
|
|
1628
1849
|
});
|
|
1629
1850
|
useEffect(() => {
|
|
1630
1851
|
if (initialExpanded) {
|
|
@@ -1640,17 +1861,39 @@ var MediaCollection = memo(
|
|
|
1640
1861
|
},
|
|
1641
1862
|
[expandedMap, expandable]
|
|
1642
1863
|
);
|
|
1864
|
+
const openConfirmationDialog = useOpenConfirmationDialog();
|
|
1643
1865
|
const handleDelete = useCallback(
|
|
1644
|
-
(selectedIds2) => {
|
|
1645
|
-
const
|
|
1866
|
+
async (selectedIds2) => {
|
|
1867
|
+
const ok = await openConfirmationDialog({
|
|
1868
|
+
title: "Delete items",
|
|
1869
|
+
description: "Are you sure you want to delete these items? This action cannot be undone."
|
|
1870
|
+
});
|
|
1871
|
+
if (!ok) return;
|
|
1872
|
+
const deletedItems = Object.entries(media).flatMap(
|
|
1873
|
+
([path7, item]) => {
|
|
1874
|
+
if (selectedIds2.includes(item.id)) {
|
|
1875
|
+
return [[path7, item]];
|
|
1876
|
+
}
|
|
1877
|
+
return [];
|
|
1878
|
+
}
|
|
1879
|
+
);
|
|
1880
|
+
const newMedia = mediaDeleteMediaItems({
|
|
1646
1881
|
selectedIds: selectedIds2,
|
|
1647
1882
|
media,
|
|
1648
1883
|
tree
|
|
1649
1884
|
});
|
|
1650
1885
|
setSelectedIds([rootMediaItem.id]);
|
|
1651
1886
|
setMedia({ name: "Delete items", timestamp: Date.now() }, newMedia);
|
|
1887
|
+
onDidDeleteItems?.(deletedItems);
|
|
1652
1888
|
},
|
|
1653
|
-
[
|
|
1889
|
+
[
|
|
1890
|
+
media,
|
|
1891
|
+
setMedia,
|
|
1892
|
+
setSelectedIds,
|
|
1893
|
+
tree,
|
|
1894
|
+
onDidDeleteItems,
|
|
1895
|
+
openConfirmationDialog
|
|
1896
|
+
]
|
|
1654
1897
|
);
|
|
1655
1898
|
const onRename = useCallback(
|
|
1656
1899
|
(selectedItem, newName) => {
|
|
@@ -1659,7 +1902,7 @@ var MediaCollection = memo(
|
|
|
1659
1902
|
selectedItem.id
|
|
1660
1903
|
);
|
|
1661
1904
|
if (!selectedItemPath) return;
|
|
1662
|
-
const renameIsValid =
|
|
1905
|
+
const renameIsValid = mediaValidateMediaItemRename({
|
|
1663
1906
|
basename: newName,
|
|
1664
1907
|
selectedItemPath,
|
|
1665
1908
|
media: temp.media
|
|
@@ -1668,7 +1911,7 @@ var MediaCollection = memo(
|
|
|
1668
1911
|
setTempItem(void 0);
|
|
1669
1912
|
return;
|
|
1670
1913
|
}
|
|
1671
|
-
const mediaWithRenamedDescendantPaths =
|
|
1914
|
+
const mediaWithRenamedDescendantPaths = mediaRenameMediaItemAndDescendantPaths({
|
|
1672
1915
|
newName,
|
|
1673
1916
|
selectedItemPath,
|
|
1674
1917
|
media: temp.media,
|
|
@@ -1688,7 +1931,7 @@ var MediaCollection = memo(
|
|
|
1688
1931
|
const currentFolderPath = tree.idToPathMap.get(currentFolderId);
|
|
1689
1932
|
if (!currentFolderPath) return;
|
|
1690
1933
|
setTempItem([
|
|
1691
|
-
|
|
1934
|
+
path4.join(currentFolderPath, PLACEHOLDER_ITEM_NAME),
|
|
1692
1935
|
newFolder
|
|
1693
1936
|
]);
|
|
1694
1937
|
setTimeout(() => {
|
|
@@ -1708,7 +1951,7 @@ var MediaCollection = memo(
|
|
|
1708
1951
|
);
|
|
1709
1952
|
if (!currentFolderPath) return;
|
|
1710
1953
|
setTempItem([
|
|
1711
|
-
|
|
1954
|
+
path4.join(currentFolderPath, PLACEHOLDER_ITEM_NAME),
|
|
1712
1955
|
newFile
|
|
1713
1956
|
]);
|
|
1714
1957
|
setTimeout(() => {
|
|
@@ -1719,7 +1962,7 @@ var MediaCollection = memo(
|
|
|
1719
1962
|
);
|
|
1720
1963
|
const handleMoveUpAFolder = useCallback(
|
|
1721
1964
|
(selectedIds2) => {
|
|
1722
|
-
const newMedia =
|
|
1965
|
+
const newMedia = mediaMoveUpAFolder({
|
|
1723
1966
|
tree,
|
|
1724
1967
|
media,
|
|
1725
1968
|
selectedIds: selectedIds2
|
|
@@ -1739,30 +1982,35 @@ var MediaCollection = memo(
|
|
|
1739
1982
|
if (!parentPath) return;
|
|
1740
1983
|
const uploadPromises = files.map(async (file) => {
|
|
1741
1984
|
const asset = await assetManager.create(file);
|
|
1742
|
-
const assetPath =
|
|
1985
|
+
const assetPath = path4.join(parentPath, path4.basename(file.name));
|
|
1743
1986
|
return {
|
|
1744
1987
|
assetPath,
|
|
1745
1988
|
asset: createMediaAsset({ assetId: asset.id })
|
|
1746
1989
|
};
|
|
1747
1990
|
});
|
|
1748
1991
|
setIsUploading(true);
|
|
1749
|
-
const
|
|
1992
|
+
const uploadedAssets = await Promise.all(uploadPromises);
|
|
1993
|
+
const newMediaMap = Object.fromEntries(
|
|
1994
|
+
uploadedAssets.map(({ assetPath, asset }) => [assetPath, asset])
|
|
1995
|
+
);
|
|
1750
1996
|
setMedia(
|
|
1751
1997
|
{ name: "Add media items", timestamp: Date.now() },
|
|
1752
1998
|
{
|
|
1753
1999
|
...media,
|
|
1754
|
-
...
|
|
1755
|
-
newMediaMap.map(({ assetPath, asset }) => [assetPath, asset])
|
|
1756
|
-
)
|
|
2000
|
+
...newMediaMap
|
|
1757
2001
|
}
|
|
1758
2002
|
);
|
|
2003
|
+
onAssetsUploaded?.(newMediaMap);
|
|
1759
2004
|
} catch (error) {
|
|
1760
|
-
|
|
2005
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2006
|
+
} else {
|
|
2007
|
+
console.error("Failed to upload files:", error);
|
|
2008
|
+
}
|
|
1761
2009
|
} finally {
|
|
1762
2010
|
setIsUploading(false);
|
|
1763
2011
|
}
|
|
1764
2012
|
},
|
|
1765
|
-
[tree.idToPathMap, setMedia, media, assetManager]
|
|
2013
|
+
[tree.idToPathMap, setMedia, media, assetManager, onAssetsUploaded]
|
|
1766
2014
|
);
|
|
1767
2015
|
const handleDownload = useCallback(
|
|
1768
2016
|
async (selectedItems) => {
|
|
@@ -1806,7 +2054,10 @@ var MediaCollection = memo(
|
|
|
1806
2054
|
}
|
|
1807
2055
|
);
|
|
1808
2056
|
} catch (error) {
|
|
1809
|
-
|
|
2057
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2058
|
+
} else {
|
|
2059
|
+
console.error("Failed to upload files:", error);
|
|
2060
|
+
}
|
|
1810
2061
|
}
|
|
1811
2062
|
},
|
|
1812
2063
|
[media, setMedia, assetManager, tree]
|
|
@@ -1819,10 +2070,7 @@ var MediaCollection = memo(
|
|
|
1819
2070
|
);
|
|
1820
2071
|
const handleMoveMediaInsideFolder = useCallback(
|
|
1821
2072
|
(sourceItem, targetItem) => {
|
|
1822
|
-
const
|
|
1823
|
-
const targetItemPath = tree.idToPathMap.get(targetItem.id);
|
|
1824
|
-
if (!sourceItemPath || !targetItemPath) return;
|
|
1825
|
-
const newMedia = moveMediaInsideFolder({
|
|
2073
|
+
const newMedia = mediaMoveMediaInsideFolder({
|
|
1826
2074
|
sourceItemIds: [sourceItem.id],
|
|
1827
2075
|
targetItemId: targetItem.id,
|
|
1828
2076
|
media,
|
|
@@ -1859,12 +2107,12 @@ var MediaCollection = memo(
|
|
|
1859
2107
|
],
|
|
1860
2108
|
[
|
|
1861
2109
|
onlySingleFolderSelected && {
|
|
1862
|
-
title: "
|
|
2110
|
+
title: "Upload Files",
|
|
1863
2111
|
value: "upload",
|
|
1864
2112
|
icon: /* @__PURE__ */ React.createElement(UploadIcon, null)
|
|
1865
2113
|
},
|
|
1866
2114
|
onlySingleFolderSelected && {
|
|
1867
|
-
title: "Add
|
|
2115
|
+
title: "Add Folder",
|
|
1868
2116
|
value: "addFolder",
|
|
1869
2117
|
icon: /* @__PURE__ */ React.createElement(FolderIcon, null)
|
|
1870
2118
|
},
|
|
@@ -1941,7 +2189,7 @@ var MediaCollection = memo(
|
|
|
1941
2189
|
const handleSetExpanded = useCallback(
|
|
1942
2190
|
(item, expanded) => {
|
|
1943
2191
|
setExpandedMap(
|
|
1944
|
-
(prev) =>
|
|
2192
|
+
(prev) => mediaUpdateExpandedMap({
|
|
1945
2193
|
item,
|
|
1946
2194
|
expanded,
|
|
1947
2195
|
expandable,
|
|
@@ -1988,7 +2236,8 @@ var MediaCollection = memo(
|
|
|
1988
2236
|
moveUpAFolder: handleMoveUpAFolder,
|
|
1989
2237
|
replace: handleReplace,
|
|
1990
2238
|
preview: handlePreview,
|
|
1991
|
-
moveMediaInsideFolder: handleMoveMediaInsideFolder
|
|
2239
|
+
moveMediaInsideFolder: handleMoveMediaInsideFolder,
|
|
2240
|
+
getItemAtIndex: (index) => visibleItems[index]
|
|
1992
2241
|
}));
|
|
1993
2242
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
1994
2243
|
FileExplorerLayout,
|
|
@@ -2030,6 +2279,7 @@ var MediaCollection = memo(
|
|
|
2030
2279
|
return "Enter folder name";
|
|
2031
2280
|
case "asset":
|
|
2032
2281
|
case "file":
|
|
2282
|
+
case "noyaFile":
|
|
2033
2283
|
return "Enter file name";
|
|
2034
2284
|
}
|
|
2035
2285
|
},
|
|
@@ -2052,7 +2302,8 @@ var MediaCollection = memo(
|
|
|
2052
2302
|
MediaThumbnailInternal,
|
|
2053
2303
|
{
|
|
2054
2304
|
...props,
|
|
2055
|
-
path: tree.idToPathMap.get(props.item.id)
|
|
2305
|
+
path: tree.idToPathMap.get(props.item.id),
|
|
2306
|
+
renderThumbnailIcon
|
|
2056
2307
|
}
|
|
2057
2308
|
),
|
|
2058
2309
|
renderAction,
|
|
@@ -2081,92 +2332,1084 @@ var MediaCollection = memo(
|
|
|
2081
2332
|
if (sourceListId !== targetListId) {
|
|
2082
2333
|
return false;
|
|
2083
2334
|
}
|
|
2335
|
+
if (sourceListId !== sortableId || targetListId !== sortableId) {
|
|
2336
|
+
return false;
|
|
2337
|
+
}
|
|
2084
2338
|
const sourceItem = visibleItems[sourceIndex];
|
|
2085
2339
|
const targetItem = visibleItems[targetIndex];
|
|
2086
|
-
|
|
2087
|
-
|
|
2340
|
+
return acceptsMediaItemDrop({
|
|
2341
|
+
position,
|
|
2342
|
+
sourceItem,
|
|
2343
|
+
targetItem,
|
|
2344
|
+
tree
|
|
2345
|
+
});
|
|
2346
|
+
},
|
|
2347
|
+
onMoveItem: ({
|
|
2348
|
+
sourceListId,
|
|
2349
|
+
sourceIndex,
|
|
2350
|
+
targetListId,
|
|
2351
|
+
targetIndex,
|
|
2352
|
+
position
|
|
2353
|
+
}) => {
|
|
2354
|
+
if (sourceListId !== sortableId || targetListId !== sortableId) {
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
const sourceItem = visibleItems[sourceIndex];
|
|
2358
|
+
const targetItem = visibleItems[targetIndex];
|
|
2359
|
+
if (position === "inside") {
|
|
2360
|
+
handleMoveMediaInsideFolder(sourceItem, targetItem);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
)
|
|
2365
|
+
));
|
|
2366
|
+
})
|
|
2367
|
+
);
|
|
2368
|
+
function acceptsMediaItemDrop(parameters) {
|
|
2369
|
+
const { position, sourceItem, targetItem, tree } = parameters;
|
|
2370
|
+
if (position !== "inside" || targetItem.kind === "asset") {
|
|
2371
|
+
return false;
|
|
2372
|
+
}
|
|
2373
|
+
const sourcePath = tree.findPath(
|
|
2374
|
+
rootMediaItem,
|
|
2375
|
+
(item) => item.id === sourceItem.id
|
|
2376
|
+
);
|
|
2377
|
+
const targetPath = tree.findPath(
|
|
2378
|
+
rootMediaItem,
|
|
2379
|
+
(item) => item.id === targetItem.id
|
|
2380
|
+
);
|
|
2381
|
+
if (!sourcePath || !targetPath) return false;
|
|
2382
|
+
if (isDeepEqual(sourcePath, targetPath.slice(0, sourcePath.length))) {
|
|
2383
|
+
return false;
|
|
2384
|
+
}
|
|
2385
|
+
return true;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
// src/ResourceExplorer.tsx
|
|
2389
|
+
import {
|
|
2390
|
+
ActionMenu as ActionMenu2,
|
|
2391
|
+
Chip,
|
|
2392
|
+
createSectionedMenu as createSectionedMenu2,
|
|
2393
|
+
cssVars as cssVars2,
|
|
2394
|
+
FileExplorerCollection as FileExplorerCollection2,
|
|
2395
|
+
FileExplorerDetail as FileExplorerDetail2,
|
|
2396
|
+
FileExplorerEmptyState as FileExplorerEmptyState2,
|
|
2397
|
+
FileExplorerLayout as FileExplorerLayout2,
|
|
2398
|
+
FileExplorerUploadButton as FileExplorerUploadButton2,
|
|
2399
|
+
formatByteSize as formatByteSize2,
|
|
2400
|
+
MediaThumbnail as MediaThumbnail2,
|
|
2401
|
+
useOpenConfirmationDialog as useOpenConfirmationDialog2
|
|
2402
|
+
} from "@noya-app/noya-designsystem";
|
|
2403
|
+
import {
|
|
2404
|
+
DownloadIcon as DownloadIcon2,
|
|
2405
|
+
FolderIcon as FolderIcon2,
|
|
2406
|
+
InputIcon as InputIcon2,
|
|
2407
|
+
OpenInNewWindowIcon as OpenInNewWindowIcon2,
|
|
2408
|
+
ResetIcon as ResetIcon2,
|
|
2409
|
+
TrashIcon as TrashIcon2,
|
|
2410
|
+
UpdateIcon as UpdateIcon2,
|
|
2411
|
+
UploadIcon as UploadIcon2
|
|
2412
|
+
} from "@noya-app/noya-icons";
|
|
2413
|
+
import {
|
|
2414
|
+
useAsset as useAsset2,
|
|
2415
|
+
useAssetManager as useAssetManager2,
|
|
2416
|
+
useAssets as useAssets2
|
|
2417
|
+
} from "@noya-app/noya-multiplayer-react";
|
|
2418
|
+
import {
|
|
2419
|
+
createAssetResource as createAssetResource2,
|
|
2420
|
+
createDirectoryResource as createDirectoryResource2,
|
|
2421
|
+
createResourceTree as createResourceTree2,
|
|
2422
|
+
diffResourceMaps,
|
|
2423
|
+
PLACEHOLDER_ITEM_NAME as PLACEHOLDER_ITEM_NAME2,
|
|
2424
|
+
rootResource as rootResource2,
|
|
2425
|
+
rootResourceName
|
|
2426
|
+
} from "@noya-app/noya-schemas";
|
|
2427
|
+
import { Base64 as Base642, groupBy as groupBy2, isDeepEqual as isDeepEqual2, uuid as uuid3 } from "@noya-app/noya-utils";
|
|
2428
|
+
import {
|
|
2429
|
+
AutoSizer,
|
|
2430
|
+
downloadUrl as downloadUrl2,
|
|
2431
|
+
memoGeneric as memoGeneric2,
|
|
2432
|
+
useControlledOrUncontrolled as useControlledOrUncontrolled2
|
|
2433
|
+
} from "@noya-app/react-utils";
|
|
2434
|
+
import { fileOpen as fileOpen2 } from "browser-fs-access";
|
|
2435
|
+
import {
|
|
2436
|
+
forwardRef as forwardRef2,
|
|
2437
|
+
memo as memo2,
|
|
2438
|
+
useCallback as useCallback2,
|
|
2439
|
+
useEffect as useEffect2,
|
|
2440
|
+
useImperativeHandle as useImperativeHandle2,
|
|
2441
|
+
useMemo as useMemo2,
|
|
2442
|
+
useRef as useRef2,
|
|
2443
|
+
useState as useState2
|
|
2444
|
+
} from "react";
|
|
2445
|
+
import { path as path6 } from "imfs";
|
|
2446
|
+
import React2 from "react";
|
|
2447
|
+
|
|
2448
|
+
// src/utils/handleFileDrop.ts
|
|
2449
|
+
import {
|
|
2450
|
+
createAssetResource,
|
|
2451
|
+
createDirectoryResource
|
|
2452
|
+
} from "@noya-app/noya-schemas";
|
|
2453
|
+
import { Base64, uuid as uuid2 } from "@noya-app/noya-utils";
|
|
2454
|
+
import { path as path5 } from "imfs";
|
|
2455
|
+
function isDirectoryEntry(entry) {
|
|
2456
|
+
return entry.isDirectory;
|
|
2457
|
+
}
|
|
2458
|
+
function isFileEntry(entry) {
|
|
2459
|
+
return entry.isFile;
|
|
2460
|
+
}
|
|
2461
|
+
async function handleDataTransfer({
|
|
2462
|
+
accessibleByFileId,
|
|
2463
|
+
dataTransfer,
|
|
2464
|
+
rootItemPath,
|
|
2465
|
+
resourceMap
|
|
2466
|
+
}) {
|
|
2467
|
+
try {
|
|
2468
|
+
const dataTransferItems = Array.from(dataTransfer.items ?? []);
|
|
2469
|
+
const supportsEntries = dataTransferItems.some(
|
|
2470
|
+
(item) => typeof item?.webkitGetAsEntry === "function"
|
|
2471
|
+
);
|
|
2472
|
+
const collectFromEntry = async (entry, basePath) => {
|
|
2473
|
+
if (!entry) return [];
|
|
2474
|
+
if (isFileEntry(entry)) {
|
|
2475
|
+
const file = await new Promise(
|
|
2476
|
+
(resolve) => entry.file((f) => resolve(f))
|
|
2477
|
+
);
|
|
2478
|
+
return [
|
|
2479
|
+
{
|
|
2480
|
+
file,
|
|
2481
|
+
relativePath: path5.join(basePath, file.name)
|
|
2482
|
+
}
|
|
2483
|
+
];
|
|
2484
|
+
}
|
|
2485
|
+
if (isDirectoryEntry(entry)) {
|
|
2486
|
+
const reader = entry.createReader();
|
|
2487
|
+
const readAll = async () => {
|
|
2488
|
+
const all = [];
|
|
2489
|
+
while (true) {
|
|
2490
|
+
const entries = await new Promise(
|
|
2491
|
+
(resolve) => reader.readEntries((ents) => resolve(ents))
|
|
2492
|
+
);
|
|
2493
|
+
if (!entries.length) break;
|
|
2494
|
+
all.push(...entries);
|
|
2495
|
+
}
|
|
2496
|
+
return all;
|
|
2497
|
+
};
|
|
2498
|
+
const children = await readAll();
|
|
2499
|
+
const results = await Promise.all(
|
|
2500
|
+
children.map(
|
|
2501
|
+
(child) => collectFromEntry(child, path5.join(basePath, entry.name))
|
|
2502
|
+
)
|
|
2503
|
+
);
|
|
2504
|
+
return results.flat();
|
|
2505
|
+
}
|
|
2506
|
+
return [];
|
|
2507
|
+
};
|
|
2508
|
+
let dropped = [];
|
|
2509
|
+
if (supportsEntries) {
|
|
2510
|
+
const topLevelEntries = dataTransferItems.flatMap((item) => {
|
|
2511
|
+
const entry = item.webkitGetAsEntry?.();
|
|
2512
|
+
if (!entry) return [];
|
|
2513
|
+
return [entry];
|
|
2514
|
+
});
|
|
2515
|
+
const nested = await Promise.all(
|
|
2516
|
+
topLevelEntries.map((entry) => collectFromEntry(entry, ""))
|
|
2517
|
+
);
|
|
2518
|
+
dropped = nested.flat();
|
|
2519
|
+
} else {
|
|
2520
|
+
const files = Array.from(dataTransfer.files);
|
|
2521
|
+
if (files.length === 0) return;
|
|
2522
|
+
dropped = files.map((file) => ({
|
|
2523
|
+
file,
|
|
2524
|
+
// Best effort: try webkitRelativePath; fall back to name
|
|
2525
|
+
relativePath: file.webkitRelativePath && file.webkitRelativePath.length > 0 ? file.webkitRelativePath : file.name
|
|
2526
|
+
}));
|
|
2527
|
+
}
|
|
2528
|
+
if (dropped.length === 0) return;
|
|
2529
|
+
const folderRelativePaths = /* @__PURE__ */ new Set();
|
|
2530
|
+
for (const { relativePath } of dropped) {
|
|
2531
|
+
const dir = path5.dirname(relativePath);
|
|
2532
|
+
if (dir && dir !== ".") {
|
|
2533
|
+
const parts = dir.split("/").filter(Boolean);
|
|
2534
|
+
let acc = "";
|
|
2535
|
+
for (const part of parts) {
|
|
2536
|
+
acc = acc ? path5.join(acc, part) : part;
|
|
2537
|
+
folderRelativePaths.add(acc);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
const folderEntries = Array.from(folderRelativePaths).map((rel) => path5.join(rootItemPath, rel)).filter((full) => !resourceMap[full]).map((full) => [
|
|
2542
|
+
full,
|
|
2543
|
+
createDirectoryResource({
|
|
2544
|
+
id: uuid2(),
|
|
2545
|
+
path: full,
|
|
2546
|
+
accessibleByFileId,
|
|
2547
|
+
stableId: uuid2()
|
|
2548
|
+
})
|
|
2549
|
+
]);
|
|
2550
|
+
const uploadResults = await Promise.all(
|
|
2551
|
+
dropped.map(
|
|
2552
|
+
async ({ file, relativePath }) => {
|
|
2553
|
+
return [
|
|
2554
|
+
path5.join(rootItemPath, relativePath),
|
|
2555
|
+
createAssetResource({
|
|
2556
|
+
id: uuid2(),
|
|
2557
|
+
asset: {
|
|
2558
|
+
content: Base64.encode(await file.arrayBuffer()),
|
|
2559
|
+
contentType: file.type,
|
|
2560
|
+
encoding: "base64"
|
|
2561
|
+
},
|
|
2562
|
+
path: path5.join(rootItemPath, relativePath),
|
|
2563
|
+
accessibleByFileId,
|
|
2564
|
+
stableId: uuid2()
|
|
2565
|
+
})
|
|
2566
|
+
];
|
|
2567
|
+
}
|
|
2568
|
+
)
|
|
2569
|
+
);
|
|
2570
|
+
return {
|
|
2571
|
+
...resourceMap,
|
|
2572
|
+
...Object.fromEntries([...folderEntries, ...uploadResults])
|
|
2573
|
+
};
|
|
2574
|
+
} catch (error) {
|
|
2575
|
+
console.error("Failed to upload dropped files:", error);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
// src/ResourceExplorer.tsx
|
|
2580
|
+
var gridThumbnailDimension = {
|
|
2581
|
+
width: 800,
|
|
2582
|
+
height: 800
|
|
2583
|
+
};
|
|
2584
|
+
var ResourceThumbnail = memoGeneric2(
|
|
2585
|
+
({
|
|
2586
|
+
item,
|
|
2587
|
+
selected,
|
|
2588
|
+
size,
|
|
2589
|
+
path: pathProp,
|
|
2590
|
+
renderThumbnailIcon,
|
|
2591
|
+
className,
|
|
2592
|
+
url: urlProp,
|
|
2593
|
+
contentType: contentTypeProp,
|
|
2594
|
+
viewType
|
|
2595
|
+
}) => {
|
|
2596
|
+
const asset = useAsset2(item.type === "asset" ? item.assetId : void 0);
|
|
2597
|
+
const isRoot = item.id === rootResource2.id;
|
|
2598
|
+
const isFolder = item.type === "directory";
|
|
2599
|
+
let contentType;
|
|
2600
|
+
let url;
|
|
2601
|
+
if (asset) {
|
|
2602
|
+
contentType = asset.contentType;
|
|
2603
|
+
url = asset.url;
|
|
2604
|
+
} else if (urlProp) {
|
|
2605
|
+
url = urlProp;
|
|
2606
|
+
contentType = contentTypeProp;
|
|
2607
|
+
}
|
|
2608
|
+
const fileName = pathProp ? path6.basename(pathProp) : void 0;
|
|
2609
|
+
return /* @__PURE__ */ React2.createElement(
|
|
2610
|
+
MediaThumbnail2,
|
|
2611
|
+
{
|
|
2612
|
+
contentType,
|
|
2613
|
+
iconName: isRoot ? "HomeIcon" : isFolder ? "FolderIcon" : void 0,
|
|
2614
|
+
url,
|
|
2615
|
+
selected,
|
|
2616
|
+
size,
|
|
2617
|
+
fileName,
|
|
2618
|
+
renderThumbnailIcon,
|
|
2619
|
+
dimensions: viewType === "grid" ? gridThumbnailDimension : void 0,
|
|
2620
|
+
className
|
|
2621
|
+
}
|
|
2622
|
+
);
|
|
2623
|
+
}
|
|
2624
|
+
);
|
|
2625
|
+
var ResourceExplorer = memo2(
|
|
2626
|
+
forwardRef2(
|
|
2627
|
+
function ResourceExplorer2({
|
|
2628
|
+
parentFileId,
|
|
2629
|
+
sortableId,
|
|
2630
|
+
onSelectionChange,
|
|
2631
|
+
selectedIds: selectedIdsProp,
|
|
2632
|
+
media,
|
|
2633
|
+
setMedia: setMediaProp,
|
|
2634
|
+
readOnly = false,
|
|
2635
|
+
viewType = "list",
|
|
2636
|
+
fileKindFilter = "all",
|
|
2637
|
+
showRootItem = false,
|
|
2638
|
+
initialExpanded,
|
|
2639
|
+
expandable = true,
|
|
2640
|
+
renamable = true,
|
|
2641
|
+
onDoubleClickItem,
|
|
2642
|
+
rootItemId = rootResource2.id,
|
|
2643
|
+
title,
|
|
2644
|
+
size = "medium",
|
|
2645
|
+
right,
|
|
2646
|
+
renderAction: renderActionProp,
|
|
2647
|
+
className,
|
|
2648
|
+
showUploadButton = true,
|
|
2649
|
+
showAllDescendants = true,
|
|
2650
|
+
scrollable = false,
|
|
2651
|
+
sortable = false,
|
|
2652
|
+
renderEmptyState,
|
|
2653
|
+
sharedDragProps,
|
|
2654
|
+
onClickItem,
|
|
2655
|
+
renderThumbnailIcon,
|
|
2656
|
+
onDidDeleteItems,
|
|
2657
|
+
onAssetsUploaded,
|
|
2658
|
+
itemClassName,
|
|
2659
|
+
itemStyle,
|
|
2660
|
+
publishedResources,
|
|
2661
|
+
virtualized = false,
|
|
2662
|
+
renderUser
|
|
2663
|
+
}, ref) {
|
|
2664
|
+
const setMedia = useCallback2(
|
|
2665
|
+
(...args) => {
|
|
2666
|
+
setMediaProp?.(...args);
|
|
2667
|
+
},
|
|
2668
|
+
[setMediaProp]
|
|
2669
|
+
);
|
|
2670
|
+
const tree = useMemo2(() => createResourceTree2(media), [media]);
|
|
2671
|
+
const [tempItem, setTempItem] = useState2(
|
|
2672
|
+
void 0
|
|
2673
|
+
);
|
|
2674
|
+
const mediaWithTempItem = useMemo2(
|
|
2675
|
+
() => ({
|
|
2676
|
+
...media,
|
|
2677
|
+
...tempItem ? { [tempItem[0]]: tempItem[1] } : {}
|
|
2678
|
+
}),
|
|
2679
|
+
[media, tempItem]
|
|
2680
|
+
);
|
|
2681
|
+
const treeWithTempItem = useMemo2(
|
|
2682
|
+
() => createResourceTree2(mediaWithTempItem),
|
|
2683
|
+
[mediaWithTempItem]
|
|
2684
|
+
);
|
|
2685
|
+
const temp = useMemo2(
|
|
2686
|
+
() => ({
|
|
2687
|
+
media: mediaWithTempItem,
|
|
2688
|
+
tree: treeWithTempItem
|
|
2689
|
+
}),
|
|
2690
|
+
[mediaWithTempItem, treeWithTempItem]
|
|
2691
|
+
);
|
|
2692
|
+
const [selectedIds, setSelectedIds] = useControlledOrUncontrolled2({
|
|
2693
|
+
defaultValue: [],
|
|
2694
|
+
value: selectedIdsProp,
|
|
2695
|
+
onChange: onSelectionChange
|
|
2696
|
+
});
|
|
2697
|
+
const assetManager = useAssetManager2();
|
|
2698
|
+
const assets = useAssets2();
|
|
2699
|
+
const [expandedMap, setExpandedMap] = useState2({});
|
|
2700
|
+
const visibleItems = useMemo2(
|
|
2701
|
+
() => getVisibleItems({
|
|
2702
|
+
expandedMap,
|
|
2703
|
+
fileKindFilter,
|
|
2704
|
+
rootItemId,
|
|
2705
|
+
tree: treeWithTempItem,
|
|
2706
|
+
showAllDescendants,
|
|
2707
|
+
showRootItem
|
|
2708
|
+
}),
|
|
2709
|
+
[
|
|
2710
|
+
expandedMap,
|
|
2711
|
+
fileKindFilter,
|
|
2712
|
+
rootItemId,
|
|
2713
|
+
treeWithTempItem,
|
|
2714
|
+
showAllDescendants,
|
|
2715
|
+
showRootItem
|
|
2716
|
+
]
|
|
2717
|
+
);
|
|
2718
|
+
const depthMap = useMemo2(
|
|
2719
|
+
() => getDepthMap(rootResource2, treeWithTempItem, showAllDescendants),
|
|
2720
|
+
[treeWithTempItem, showAllDescendants]
|
|
2721
|
+
);
|
|
2722
|
+
const collectionRef = useRef2(null);
|
|
2723
|
+
const selectedResources = useMemo2(
|
|
2724
|
+
() => treeWithTempItem.resourcesWithRoot.filter(
|
|
2725
|
+
(item) => selectedIds.includes(item.id)
|
|
2726
|
+
),
|
|
2727
|
+
[treeWithTempItem, selectedIds]
|
|
2728
|
+
);
|
|
2729
|
+
const groupedItems = groupBy2(selectedResources, (item) => item.type);
|
|
2730
|
+
const selectedAssetItems = groupedItems.asset ?? [];
|
|
2731
|
+
const selectedFolderItems = groupedItems.folder ?? [];
|
|
2732
|
+
const singleItemSelected = selectedResources.length === 1;
|
|
2733
|
+
const onlyAssetsSelected = selectedAssetItems.length > 0 && selectedAssetItems.length === selectedResources.length;
|
|
2734
|
+
const onlyFoldersSelected = selectedFolderItems.length > 0 && selectedFolderItems.length === selectedResources.length;
|
|
2735
|
+
const onlySingleFolderSelected = onlyFoldersSelected && selectedFolderItems.length === 1;
|
|
2736
|
+
const onlySingleAssetSelected = onlyAssetsSelected && selectedAssetItems.length === 1;
|
|
2737
|
+
const rootSelected = selectedIds.includes(rootResource2.id);
|
|
2738
|
+
const sameParentSelected = selectedResources.every((item) => {
|
|
2739
|
+
const itemPath = tree.idToPathMap.get(item.id);
|
|
2740
|
+
const firstSelectedPath = tree.idToPathMap.get(selectedIds[0]);
|
|
2741
|
+
if (!itemPath || !firstSelectedPath) return false;
|
|
2742
|
+
return itemPath.startsWith(path6.dirname(firstSelectedPath));
|
|
2743
|
+
});
|
|
2744
|
+
useEffect2(() => {
|
|
2745
|
+
if (initialExpanded) {
|
|
2746
|
+
setExpandedMap(initialExpanded);
|
|
2747
|
+
}
|
|
2748
|
+
}, [initialExpanded]);
|
|
2749
|
+
const getExpanded = useCallback2(
|
|
2750
|
+
(item) => {
|
|
2751
|
+
if (!expandable) return void 0;
|
|
2752
|
+
if (item.type !== "directory") return void 0;
|
|
2753
|
+
if (item.id === rootResource2.id) return void 0;
|
|
2754
|
+
return expandedMap[item.id] ?? false;
|
|
2755
|
+
},
|
|
2756
|
+
[expandedMap, expandable]
|
|
2757
|
+
);
|
|
2758
|
+
const openConfirmationDialog = useOpenConfirmationDialog2();
|
|
2759
|
+
const handleDelete = useCallback2(
|
|
2760
|
+
async (selectedIds2) => {
|
|
2761
|
+
const ok = await openConfirmationDialog({
|
|
2762
|
+
title: "Delete items",
|
|
2763
|
+
description: "Are you sure you want to delete these items? This action cannot be undone."
|
|
2764
|
+
});
|
|
2765
|
+
if (!ok) return;
|
|
2766
|
+
const deletedItems = Object.entries(media).flatMap(
|
|
2767
|
+
([path7, item]) => {
|
|
2768
|
+
if (selectedIds2.includes(item.id)) {
|
|
2769
|
+
return [[path7, item]];
|
|
2770
|
+
}
|
|
2771
|
+
return [];
|
|
2088
2772
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2773
|
+
);
|
|
2774
|
+
const newMedia = deleteResources({
|
|
2775
|
+
selectedIds: selectedIds2,
|
|
2776
|
+
media,
|
|
2777
|
+
tree
|
|
2778
|
+
});
|
|
2779
|
+
setSelectedIds([rootResource2.id]);
|
|
2780
|
+
setMedia({ name: "Delete items", timestamp: Date.now() }, newMedia);
|
|
2781
|
+
onDidDeleteItems?.(deletedItems);
|
|
2782
|
+
},
|
|
2783
|
+
[
|
|
2784
|
+
media,
|
|
2785
|
+
setMedia,
|
|
2786
|
+
setSelectedIds,
|
|
2787
|
+
tree,
|
|
2788
|
+
onDidDeleteItems,
|
|
2789
|
+
openConfirmationDialog
|
|
2790
|
+
]
|
|
2791
|
+
);
|
|
2792
|
+
const onRename = useCallback2(
|
|
2793
|
+
(selectedItem, newName) => {
|
|
2794
|
+
if (!renamable) return;
|
|
2795
|
+
const selectedItemPath = treeWithTempItem.idToPathMap.get(
|
|
2796
|
+
selectedItem.id
|
|
2797
|
+
);
|
|
2798
|
+
if (!selectedItemPath) return;
|
|
2799
|
+
const renameIsValid = validateResourceRename({
|
|
2800
|
+
basename: newName,
|
|
2801
|
+
selectedItemPath,
|
|
2802
|
+
media: temp.media
|
|
2803
|
+
});
|
|
2804
|
+
if (!renameIsValid) {
|
|
2805
|
+
setTempItem(void 0);
|
|
2806
|
+
return;
|
|
2807
|
+
}
|
|
2808
|
+
const mediaWithRenamedDescendantPaths = renameResourceAndDescendantPaths({
|
|
2809
|
+
newName,
|
|
2810
|
+
selectedItemPath,
|
|
2811
|
+
media: temp.media,
|
|
2812
|
+
tree: temp.tree
|
|
2813
|
+
});
|
|
2814
|
+
setMedia(
|
|
2815
|
+
{ name: "Rename media item", timestamp: Date.now() },
|
|
2816
|
+
mediaWithRenamedDescendantPaths
|
|
2817
|
+
);
|
|
2818
|
+
setTempItem(void 0);
|
|
2819
|
+
},
|
|
2820
|
+
[
|
|
2821
|
+
renamable,
|
|
2822
|
+
setMedia,
|
|
2823
|
+
temp.media,
|
|
2824
|
+
temp.tree,
|
|
2825
|
+
treeWithTempItem.idToPathMap
|
|
2826
|
+
]
|
|
2827
|
+
);
|
|
2828
|
+
const handleAddFolder = useCallback2(
|
|
2829
|
+
(currentFolderId) => {
|
|
2830
|
+
const currentFolderPath = tree.idToPathMap.get(currentFolderId);
|
|
2831
|
+
if (!currentFolderPath) return;
|
|
2832
|
+
const newFolderPath = path6.join(
|
|
2833
|
+
currentFolderPath,
|
|
2834
|
+
PLACEHOLDER_ITEM_NAME2
|
|
2835
|
+
);
|
|
2836
|
+
const newFolder = createDirectoryResource2({
|
|
2837
|
+
path: newFolderPath,
|
|
2838
|
+
accessibleByFileId: parentFileId,
|
|
2839
|
+
id: newFolderPath,
|
|
2840
|
+
stableId: uuid3()
|
|
2841
|
+
});
|
|
2842
|
+
setTempItem([newFolderPath, newFolder]);
|
|
2843
|
+
setTimeout(() => {
|
|
2844
|
+
collectionRef.current?.editName(newFolder.id);
|
|
2845
|
+
}, 50);
|
|
2846
|
+
},
|
|
2847
|
+
[parentFileId, tree]
|
|
2848
|
+
);
|
|
2849
|
+
const handleMoveUpAFolder = useCallback2(
|
|
2850
|
+
(selectedIds2) => {
|
|
2851
|
+
const newMedia = moveUpAFolder({
|
|
2852
|
+
tree,
|
|
2853
|
+
media,
|
|
2854
|
+
selectedIds: selectedIds2
|
|
2855
|
+
});
|
|
2856
|
+
if (!newMedia) return;
|
|
2857
|
+
setMedia({ name: "Move items", timestamp: Date.now() }, newMedia);
|
|
2858
|
+
},
|
|
2859
|
+
[media, tree, setMedia]
|
|
2860
|
+
);
|
|
2861
|
+
const [isUploading, setIsUploading] = useState2(false);
|
|
2862
|
+
const handleUpload = useCallback2(
|
|
2863
|
+
async (selectedId) => {
|
|
2864
|
+
try {
|
|
2865
|
+
const files = await fileOpen2({ multiple: true });
|
|
2866
|
+
if (!files || !Array.isArray(files) || files.length === 0) return;
|
|
2867
|
+
const parentPath = tree.idToPathMap.get(selectedId);
|
|
2868
|
+
if (!parentPath) return;
|
|
2869
|
+
const uploadPromises = files.map(async (file) => {
|
|
2870
|
+
const assetPath = path6.join(parentPath, path6.basename(file.name));
|
|
2871
|
+
return {
|
|
2872
|
+
assetPath,
|
|
2873
|
+
asset: createAssetResource2({
|
|
2874
|
+
id: uuid3(),
|
|
2875
|
+
asset: {
|
|
2876
|
+
content: Base642.encode(await file.arrayBuffer()),
|
|
2877
|
+
contentType: file.type,
|
|
2878
|
+
encoding: "base64"
|
|
2879
|
+
},
|
|
2880
|
+
path: assetPath,
|
|
2881
|
+
accessibleByFileId: parentFileId,
|
|
2882
|
+
stableId: uuid3()
|
|
2883
|
+
})
|
|
2884
|
+
};
|
|
2885
|
+
});
|
|
2886
|
+
setIsUploading(true);
|
|
2887
|
+
const uploadedAssets = await Promise.all(uploadPromises);
|
|
2888
|
+
const newMediaMap = Object.fromEntries(
|
|
2889
|
+
uploadedAssets.map(({ assetPath, asset }) => [assetPath, asset])
|
|
2092
2890
|
);
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2891
|
+
setMedia(
|
|
2892
|
+
{ name: "Add media items", timestamp: Date.now() },
|
|
2893
|
+
{
|
|
2894
|
+
...media,
|
|
2895
|
+
...newMediaMap
|
|
2896
|
+
}
|
|
2096
2897
|
);
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2898
|
+
onAssetsUploaded?.(newMediaMap);
|
|
2899
|
+
} catch (error) {
|
|
2900
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2901
|
+
} else {
|
|
2902
|
+
console.error("Failed to upload files:", error);
|
|
2903
|
+
}
|
|
2904
|
+
} finally {
|
|
2905
|
+
setIsUploading(false);
|
|
2906
|
+
}
|
|
2907
|
+
},
|
|
2908
|
+
[tree, setMedia, media, onAssetsUploaded, parentFileId]
|
|
2909
|
+
);
|
|
2910
|
+
const handleDownload = useCallback2(
|
|
2911
|
+
async (selectedItems) => {
|
|
2912
|
+
const downloadPromises = selectedItems.filter((item) => item.type === "asset").map(async (item) => {
|
|
2913
|
+
const asset = assets.find((a) => a.id === item.assetId);
|
|
2914
|
+
if (!asset?.url) return;
|
|
2915
|
+
return downloadUrl2(asset.url, tree.getNameForId(item.id));
|
|
2916
|
+
});
|
|
2917
|
+
await Promise.all(downloadPromises);
|
|
2918
|
+
},
|
|
2919
|
+
[assets, tree]
|
|
2920
|
+
);
|
|
2921
|
+
const handlePreview = useCallback2(
|
|
2922
|
+
async (selectedItems) => {
|
|
2923
|
+
const previewPromises = selectedItems.filter((item) => item.type === "asset").map(async (item) => {
|
|
2924
|
+
const asset = assets.find((a) => a.id === item.assetId);
|
|
2925
|
+
if (!asset?.url) return;
|
|
2926
|
+
return window?.open(asset.url, "_blank");
|
|
2927
|
+
});
|
|
2928
|
+
await Promise.all(previewPromises);
|
|
2929
|
+
},
|
|
2930
|
+
[assets]
|
|
2931
|
+
);
|
|
2932
|
+
const handleReplace = useCallback2(
|
|
2933
|
+
async (selectedItem) => {
|
|
2934
|
+
try {
|
|
2935
|
+
const file = await fileOpen2();
|
|
2936
|
+
if (!file) return;
|
|
2937
|
+
const asset = await assetManager.create(file);
|
|
2938
|
+
const oldFile = selectedItem;
|
|
2939
|
+
const oldFilePath = tree.idToPathMap.get(oldFile.id);
|
|
2940
|
+
if (!oldFilePath || oldFile.type !== "asset") return;
|
|
2941
|
+
setMedia(
|
|
2942
|
+
{ name: "Replace media file", timestamp: Date.now() },
|
|
2943
|
+
{
|
|
2944
|
+
...media,
|
|
2945
|
+
[oldFilePath]: createAssetResource2({
|
|
2946
|
+
...oldFile,
|
|
2947
|
+
assetId: asset.id
|
|
2948
|
+
})
|
|
2949
|
+
}
|
|
2950
|
+
);
|
|
2951
|
+
} catch (error) {
|
|
2952
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2953
|
+
} else {
|
|
2954
|
+
console.error("Failed to upload files:", error);
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
},
|
|
2958
|
+
[media, setMedia, assetManager, tree]
|
|
2959
|
+
);
|
|
2960
|
+
const handleRename = useCallback2(
|
|
2961
|
+
(selectedItemId) => {
|
|
2962
|
+
collectionRef.current?.editName(selectedItemId);
|
|
2963
|
+
},
|
|
2964
|
+
[collectionRef]
|
|
2965
|
+
);
|
|
2966
|
+
const handleMoveMediaInsideFolder = useCallback2(
|
|
2967
|
+
(sourceItems, targetItem) => {
|
|
2968
|
+
const newMedia = moveMediaInsideFolder({
|
|
2969
|
+
sourceItemIds: sourceItems.map((item) => item.id),
|
|
2970
|
+
targetItemId: targetItem.id,
|
|
2971
|
+
media,
|
|
2972
|
+
tree
|
|
2973
|
+
});
|
|
2974
|
+
setMedia(
|
|
2975
|
+
{
|
|
2976
|
+
name: "Move media file inside folder",
|
|
2977
|
+
timestamp: Date.now()
|
|
2978
|
+
},
|
|
2979
|
+
newMedia
|
|
2980
|
+
);
|
|
2981
|
+
},
|
|
2982
|
+
[media, setMedia, tree]
|
|
2983
|
+
);
|
|
2984
|
+
const assetContextMenuItems = useMemo2(() => {
|
|
2985
|
+
return createSectionedMenu2(
|
|
2986
|
+
[
|
|
2987
|
+
!rootSelected && singleItemSelected && {
|
|
2988
|
+
title: "Rename",
|
|
2989
|
+
value: "rename",
|
|
2990
|
+
icon: /* @__PURE__ */ React2.createElement(InputIcon2, null)
|
|
2991
|
+
},
|
|
2992
|
+
onlySingleAssetSelected && {
|
|
2993
|
+
title: "Replace",
|
|
2994
|
+
value: "replace",
|
|
2995
|
+
icon: /* @__PURE__ */ React2.createElement(UpdateIcon2, null)
|
|
2996
|
+
},
|
|
2997
|
+
!rootSelected && {
|
|
2998
|
+
title: "Delete",
|
|
2999
|
+
value: "delete",
|
|
3000
|
+
icon: /* @__PURE__ */ React2.createElement(TrashIcon2, null)
|
|
2100
3001
|
}
|
|
3002
|
+
],
|
|
3003
|
+
[
|
|
3004
|
+
onlySingleFolderSelected && {
|
|
3005
|
+
title: "Upload Files",
|
|
3006
|
+
value: "upload",
|
|
3007
|
+
icon: /* @__PURE__ */ React2.createElement(UploadIcon2, null)
|
|
3008
|
+
},
|
|
3009
|
+
onlySingleFolderSelected && {
|
|
3010
|
+
title: "Add Folder",
|
|
3011
|
+
value: "addFolder",
|
|
3012
|
+
icon: /* @__PURE__ */ React2.createElement(FolderIcon2, null)
|
|
3013
|
+
},
|
|
3014
|
+
onlyAssetsSelected && tree.resourcesWithRoot.length > 0 && {
|
|
3015
|
+
title: "Download",
|
|
3016
|
+
value: "download",
|
|
3017
|
+
icon: /* @__PURE__ */ React2.createElement(DownloadIcon2, null)
|
|
3018
|
+
},
|
|
3019
|
+
onlySingleAssetSelected && {
|
|
3020
|
+
title: "Preview",
|
|
3021
|
+
value: "preview",
|
|
3022
|
+
icon: /* @__PURE__ */ React2.createElement(OpenInNewWindowIcon2, null)
|
|
3023
|
+
}
|
|
3024
|
+
],
|
|
3025
|
+
[
|
|
3026
|
+
!rootSelected && sameParentSelected && {
|
|
3027
|
+
title: "Move up a folder",
|
|
3028
|
+
value: "move",
|
|
3029
|
+
icon: /* @__PURE__ */ React2.createElement(ResetIcon2, null)
|
|
3030
|
+
}
|
|
3031
|
+
]
|
|
3032
|
+
);
|
|
3033
|
+
}, [
|
|
3034
|
+
rootSelected,
|
|
3035
|
+
singleItemSelected,
|
|
3036
|
+
onlySingleAssetSelected,
|
|
3037
|
+
onlySingleFolderSelected,
|
|
3038
|
+
onlyAssetsSelected,
|
|
3039
|
+
tree.resourcesWithRoot.length,
|
|
3040
|
+
sameParentSelected
|
|
3041
|
+
]);
|
|
3042
|
+
const handleMenuAction = useCallback2(
|
|
3043
|
+
async (action, selectedItems) => {
|
|
3044
|
+
if (selectedItems.length === 0) return;
|
|
3045
|
+
switch (action) {
|
|
3046
|
+
case "rename":
|
|
3047
|
+
handleRename(selectedItems[0].id);
|
|
3048
|
+
return;
|
|
3049
|
+
case "delete":
|
|
3050
|
+
handleDelete(selectedIds);
|
|
3051
|
+
return;
|
|
3052
|
+
case "replace":
|
|
3053
|
+
handleReplace(selectedItems[0]);
|
|
3054
|
+
return;
|
|
3055
|
+
case "upload":
|
|
3056
|
+
handleUpload(selectedItems[0].id);
|
|
3057
|
+
return;
|
|
3058
|
+
case "addFolder":
|
|
3059
|
+
handleAddFolder(selectedItems[0].id);
|
|
3060
|
+
return;
|
|
3061
|
+
case "preview":
|
|
3062
|
+
handlePreview(selectedItems);
|
|
3063
|
+
return;
|
|
3064
|
+
case "download":
|
|
3065
|
+
handleDownload(selectedItems);
|
|
3066
|
+
return;
|
|
3067
|
+
case "move":
|
|
3068
|
+
handleMoveUpAFolder(selectedIds);
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
},
|
|
3072
|
+
[
|
|
3073
|
+
handleRename,
|
|
3074
|
+
handleDelete,
|
|
3075
|
+
selectedIds,
|
|
3076
|
+
handleReplace,
|
|
3077
|
+
handleUpload,
|
|
3078
|
+
handleAddFolder,
|
|
3079
|
+
handlePreview,
|
|
3080
|
+
handleDownload,
|
|
3081
|
+
handleMoveUpAFolder
|
|
3082
|
+
]
|
|
3083
|
+
);
|
|
3084
|
+
const handleSetExpanded = useCallback2(
|
|
3085
|
+
(item, expanded) => {
|
|
3086
|
+
setExpandedMap(
|
|
3087
|
+
(prev) => updateExpandedMap({
|
|
3088
|
+
item,
|
|
3089
|
+
expanded,
|
|
3090
|
+
expandable,
|
|
3091
|
+
expandedMap: prev,
|
|
3092
|
+
tree
|
|
3093
|
+
})
|
|
3094
|
+
);
|
|
3095
|
+
},
|
|
3096
|
+
[expandable, tree]
|
|
3097
|
+
);
|
|
3098
|
+
const renderAction = useMemo2(() => {
|
|
3099
|
+
if (renderActionProp) return renderActionProp;
|
|
3100
|
+
return ({
|
|
3101
|
+
selected,
|
|
3102
|
+
onOpenChange
|
|
3103
|
+
}) => /* @__PURE__ */ React2.createElement(
|
|
3104
|
+
"div",
|
|
3105
|
+
{
|
|
3106
|
+
style: {
|
|
3107
|
+
minWidth: "75px",
|
|
3108
|
+
display: "flex",
|
|
3109
|
+
justifyContent: "flex-end"
|
|
3110
|
+
}
|
|
3111
|
+
},
|
|
3112
|
+
/* @__PURE__ */ React2.createElement(
|
|
3113
|
+
ActionMenu2,
|
|
3114
|
+
{
|
|
3115
|
+
menuItems: assetContextMenuItems,
|
|
3116
|
+
onSelect: (action) => handleMenuAction(action, selectedResources),
|
|
3117
|
+
selected,
|
|
3118
|
+
onOpenChange,
|
|
3119
|
+
variant: viewType === "grid" ? "normal" : "bare",
|
|
3120
|
+
style: {
|
|
3121
|
+
backgroundColor: selected ? cssVars2.colors.selectedListItemBackground : "transparent",
|
|
3122
|
+
color: selected ? cssVars2.colors.selectedListItemText : void 0
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
)
|
|
3126
|
+
);
|
|
3127
|
+
}, [
|
|
3128
|
+
assetContextMenuItems,
|
|
3129
|
+
handleMenuAction,
|
|
3130
|
+
renderActionProp,
|
|
3131
|
+
selectedResources,
|
|
3132
|
+
viewType
|
|
3133
|
+
]);
|
|
3134
|
+
useImperativeHandle2(ref, () => ({
|
|
3135
|
+
upload: (selectedId) => handleUpload(selectedId),
|
|
3136
|
+
delete: handleDelete,
|
|
3137
|
+
download: handleDownload,
|
|
3138
|
+
rename: handleRename,
|
|
3139
|
+
addFolder: handleAddFolder,
|
|
3140
|
+
moveUpAFolder: handleMoveUpAFolder,
|
|
3141
|
+
replace: handleReplace,
|
|
3142
|
+
preview: handlePreview,
|
|
3143
|
+
moveMediaInsideFolder: handleMoveMediaInsideFolder,
|
|
3144
|
+
getItemAtIndex: (index) => visibleItems[index]
|
|
3145
|
+
}));
|
|
3146
|
+
const diffResources = useMemo2(() => {
|
|
3147
|
+
if (!publishedResources) return;
|
|
3148
|
+
const diff = diffResourceMaps(publishedResources, media, "stableId");
|
|
3149
|
+
return {
|
|
3150
|
+
added: new Set(
|
|
3151
|
+
diff.addedResources.map((resource) => resource.stableId)
|
|
3152
|
+
),
|
|
3153
|
+
removed: new Set(
|
|
3154
|
+
diff.removedResources.map((resource) => resource.stableId)
|
|
3155
|
+
),
|
|
3156
|
+
modified: new Set(
|
|
3157
|
+
diff.modifiedResources.map((resource) => resource.stableId)
|
|
3158
|
+
)
|
|
3159
|
+
};
|
|
3160
|
+
}, [media, publishedResources]);
|
|
3161
|
+
const keyExtractor = useCallback2((item) => item.id, []);
|
|
3162
|
+
const renderCollection = (virtualizedSize) => /* @__PURE__ */ React2.createElement(
|
|
3163
|
+
FileExplorerCollection2,
|
|
3164
|
+
{
|
|
3165
|
+
ref: collectionRef,
|
|
3166
|
+
sortableId,
|
|
3167
|
+
scrollable,
|
|
3168
|
+
sharedDragProps,
|
|
3169
|
+
items: visibleItems,
|
|
3170
|
+
viewType,
|
|
3171
|
+
size,
|
|
3172
|
+
getId: keyExtractor,
|
|
3173
|
+
getName: (file) => {
|
|
3174
|
+
if (file.id === tempItem?.[1].id) {
|
|
3175
|
+
return "";
|
|
3176
|
+
}
|
|
3177
|
+
return treeWithTempItem.getNameForId(file.id);
|
|
3178
|
+
},
|
|
3179
|
+
expandable,
|
|
3180
|
+
sortable,
|
|
3181
|
+
getPlaceholder: (item) => {
|
|
3182
|
+
switch (item.type) {
|
|
3183
|
+
case "directory":
|
|
3184
|
+
return "Enter folder name";
|
|
3185
|
+
case "resource":
|
|
3186
|
+
case "asset":
|
|
3187
|
+
case "file":
|
|
3188
|
+
return "Enter file name";
|
|
3189
|
+
}
|
|
3190
|
+
},
|
|
3191
|
+
getExpanded,
|
|
3192
|
+
setExpanded: handleSetExpanded,
|
|
3193
|
+
getRenamable: (item) => {
|
|
3194
|
+
if (item.id === rootResource2.id) return false;
|
|
2101
3195
|
return true;
|
|
2102
3196
|
},
|
|
2103
|
-
|
|
3197
|
+
getDepth: (item) => depthMap[item.id],
|
|
3198
|
+
menuItems: assetContextMenuItems,
|
|
3199
|
+
onSelectMenuItem: handleMenuAction,
|
|
3200
|
+
onSelectionChange: setSelectedIds,
|
|
3201
|
+
onClickItem,
|
|
3202
|
+
onClick: () => {
|
|
3203
|
+
setSelectedIds([]);
|
|
3204
|
+
},
|
|
3205
|
+
onDoubleClickItem,
|
|
3206
|
+
onRename,
|
|
3207
|
+
renamable,
|
|
3208
|
+
selectedIds,
|
|
3209
|
+
itemClassName,
|
|
3210
|
+
itemStyle,
|
|
3211
|
+
virtualized: virtualizedSize,
|
|
3212
|
+
renderThumbnail: (props) => /* @__PURE__ */ React2.createElement(
|
|
3213
|
+
ResourceThumbnail,
|
|
3214
|
+
{
|
|
3215
|
+
...props,
|
|
3216
|
+
path: tree.idToPathMap.get(props.item.id),
|
|
3217
|
+
renderThumbnailIcon,
|
|
3218
|
+
viewType
|
|
3219
|
+
}
|
|
3220
|
+
),
|
|
3221
|
+
renderAction,
|
|
3222
|
+
renderRight: (file) => {
|
|
3223
|
+
if (file.type !== "asset") return null;
|
|
3224
|
+
const publishStatus = getPublishStatus({
|
|
3225
|
+
resource: file,
|
|
3226
|
+
diff: diffResources
|
|
3227
|
+
});
|
|
3228
|
+
return /* @__PURE__ */ React2.createElement(
|
|
3229
|
+
"div",
|
|
3230
|
+
{
|
|
3231
|
+
style: { display: "flex", alignItems: "center", gap: "1.5px" }
|
|
3232
|
+
},
|
|
3233
|
+
publishStatus && /* @__PURE__ */ React2.createElement(
|
|
3234
|
+
Chip,
|
|
3235
|
+
{
|
|
3236
|
+
colorScheme: publishStatus === "Modified" ? "info" : publishStatus === "Added" ? "secondary" : "primary"
|
|
3237
|
+
},
|
|
3238
|
+
publishStatus
|
|
3239
|
+
),
|
|
3240
|
+
renderUser?.(file)
|
|
3241
|
+
);
|
|
3242
|
+
},
|
|
3243
|
+
renderDetail: (file, selected) => {
|
|
3244
|
+
if (file.type !== "asset") return null;
|
|
3245
|
+
const asset = assets.find((a) => a.id === file.assetId);
|
|
3246
|
+
if (!asset) return null;
|
|
3247
|
+
return /* @__PURE__ */ React2.createElement(
|
|
3248
|
+
FileExplorerDetail2,
|
|
3249
|
+
{
|
|
3250
|
+
selected,
|
|
3251
|
+
size,
|
|
3252
|
+
style: { minWidth: "75px", textAlign: "right" }
|
|
3253
|
+
},
|
|
3254
|
+
formatByteSize2(asset.size)
|
|
3255
|
+
);
|
|
3256
|
+
},
|
|
3257
|
+
renderEmptyState: () => renderEmptyState?.() ?? /* @__PURE__ */ React2.createElement(FileExplorerEmptyState2, null),
|
|
3258
|
+
itemRoleDescription: "clickable file item",
|
|
3259
|
+
getDropTargetParentIndex: (overIndex) => {
|
|
3260
|
+
const item = visibleItems[overIndex];
|
|
3261
|
+
const parentIndex = visibleItems.findIndex(
|
|
3262
|
+
(i) => i.id === tree.getParentIdForId(item.id)
|
|
3263
|
+
);
|
|
3264
|
+
return parentIndex === -1 ? void 0 : parentIndex;
|
|
3265
|
+
},
|
|
3266
|
+
acceptsDrop: ({
|
|
3267
|
+
sourceIndex,
|
|
3268
|
+
targetIndex,
|
|
3269
|
+
position,
|
|
3270
|
+
sourceListId,
|
|
3271
|
+
targetListId
|
|
3272
|
+
}) => {
|
|
3273
|
+
if (sourceListId !== targetListId) {
|
|
3274
|
+
return false;
|
|
3275
|
+
}
|
|
3276
|
+
if (sourceListId !== sortableId || targetListId !== sortableId) {
|
|
3277
|
+
return false;
|
|
3278
|
+
}
|
|
2104
3279
|
const sourceItem = visibleItems[sourceIndex];
|
|
2105
3280
|
const targetItem = visibleItems[targetIndex];
|
|
2106
|
-
|
|
2107
|
-
|
|
3281
|
+
return acceptsResourceDrop({
|
|
3282
|
+
position,
|
|
3283
|
+
sourceItem,
|
|
3284
|
+
targetItem,
|
|
3285
|
+
tree
|
|
3286
|
+
});
|
|
3287
|
+
},
|
|
3288
|
+
onMoveItem: ({
|
|
3289
|
+
sourceListId,
|
|
3290
|
+
sourceIndex,
|
|
3291
|
+
targetListId,
|
|
3292
|
+
targetIndex,
|
|
3293
|
+
position
|
|
3294
|
+
}) => {
|
|
3295
|
+
if (sourceListId !== sortableId || targetListId !== sortableId || position !== "inside") {
|
|
3296
|
+
return;
|
|
2108
3297
|
}
|
|
3298
|
+
const selectedItems = visibleItems.filter(
|
|
3299
|
+
(item) => selectedIds.includes(item.id)
|
|
3300
|
+
);
|
|
3301
|
+
const sourceItem = visibleItems[sourceIndex];
|
|
3302
|
+
const itemsToMove = selectedIds.includes(sourceItem.id) ? selectedItems : [sourceItem];
|
|
3303
|
+
const targetItem = visibleItems[targetIndex];
|
|
3304
|
+
handleMoveMediaInsideFolder(itemsToMove, targetItem);
|
|
2109
3305
|
},
|
|
2110
3306
|
onFilesDrop: async (event) => {
|
|
2111
3307
|
event.preventDefault();
|
|
2112
|
-
const
|
|
2113
|
-
if (
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
const rootItemPath = tree.idToPathMap.get(rootItemId);
|
|
2126
|
-
if (!rootItemPath) return;
|
|
2127
|
-
setMedia(
|
|
2128
|
-
{ name: "Add media files", timestamp: Date.now() },
|
|
2129
|
-
{
|
|
2130
|
-
...media,
|
|
2131
|
-
...Object.fromEntries(
|
|
2132
|
-
newMediaItems.map((item) => [
|
|
2133
|
-
path3.join(rootItemPath, item.name),
|
|
2134
|
-
item.asset
|
|
2135
|
-
])
|
|
2136
|
-
)
|
|
2137
|
-
}
|
|
2138
|
-
);
|
|
2139
|
-
} catch (error) {
|
|
2140
|
-
console.error("Failed to upload dropped files:", error);
|
|
2141
|
-
}
|
|
3308
|
+
const rootItemPath = tree.idToPathMap.get(rootItemId);
|
|
3309
|
+
if (!rootItemPath) return;
|
|
3310
|
+
const newMedia = await handleDataTransfer({
|
|
3311
|
+
dataTransfer: event.dataTransfer,
|
|
3312
|
+
rootItemPath,
|
|
3313
|
+
resourceMap: media,
|
|
3314
|
+
accessibleByFileId: parentFileId
|
|
3315
|
+
});
|
|
3316
|
+
if (!newMedia) return;
|
|
3317
|
+
setMedia(
|
|
3318
|
+
{ name: "Add media files", timestamp: Date.now() },
|
|
3319
|
+
newMedia
|
|
3320
|
+
);
|
|
2142
3321
|
}
|
|
2143
3322
|
}
|
|
2144
|
-
)
|
|
2145
|
-
|
|
2146
|
-
|
|
3323
|
+
);
|
|
3324
|
+
return /* @__PURE__ */ React2.createElement(
|
|
3325
|
+
FileExplorerLayout2,
|
|
3326
|
+
{
|
|
3327
|
+
title: title ?? rootResourceName,
|
|
3328
|
+
right: !readOnly && /* @__PURE__ */ React2.createElement(
|
|
3329
|
+
FileExplorerUploadButton2,
|
|
3330
|
+
{
|
|
3331
|
+
showUploadButton,
|
|
3332
|
+
onUpload: () => handleUpload(rootResource2.id),
|
|
3333
|
+
isUploading
|
|
3334
|
+
},
|
|
3335
|
+
right
|
|
3336
|
+
),
|
|
3337
|
+
className
|
|
3338
|
+
},
|
|
3339
|
+
virtualized ? /* @__PURE__ */ React2.createElement(AutoSizer, null, ({ width, height }) => (
|
|
3340
|
+
// add 24px to account for the -mx-3 on the Collection component
|
|
3341
|
+
renderCollection({ width: width + 24, height })
|
|
3342
|
+
)) : renderCollection(void 0)
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
)
|
|
2147
3346
|
);
|
|
3347
|
+
function acceptsResourceDrop(parameters) {
|
|
3348
|
+
const { position, sourceItem, targetItem, tree } = parameters;
|
|
3349
|
+
if (position !== "inside" || targetItem.type === "asset") {
|
|
3350
|
+
return false;
|
|
3351
|
+
}
|
|
3352
|
+
const sourcePath = tree.findPath(
|
|
3353
|
+
rootResource2,
|
|
3354
|
+
(item) => item.id === sourceItem.id
|
|
3355
|
+
);
|
|
3356
|
+
const targetPath = tree.findPath(
|
|
3357
|
+
rootResource2,
|
|
3358
|
+
(item) => item.id === targetItem.id
|
|
3359
|
+
);
|
|
3360
|
+
if (!sourcePath || !targetPath) return false;
|
|
3361
|
+
if (isDeepEqual2(sourcePath, targetPath.slice(0, sourcePath.length))) {
|
|
3362
|
+
return false;
|
|
3363
|
+
}
|
|
3364
|
+
return true;
|
|
3365
|
+
}
|
|
3366
|
+
function getPublishStatus({
|
|
3367
|
+
resource,
|
|
3368
|
+
diff
|
|
3369
|
+
}) {
|
|
3370
|
+
if (!diff) return void 0;
|
|
3371
|
+
return diff.modified.has(resource.stableId) ? "Modified" : diff.added.has(resource.stableId) ? "Added" : diff.removed.has(resource.stableId) ? "Removed" : (
|
|
3372
|
+
// We don't have to check for the specific ID, since if anything had been published
|
|
3373
|
+
// but removed, it will be in the removed set
|
|
3374
|
+
"Published"
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
2148
3377
|
export {
|
|
2149
3378
|
MediaCollection,
|
|
2150
3379
|
PLACEHOLDER_ITEM_NAME,
|
|
3380
|
+
ResourceExplorer,
|
|
3381
|
+
ResourceThumbnail,
|
|
3382
|
+
acceptsMediaItemDrop,
|
|
3383
|
+
acceptsResourceDrop,
|
|
2151
3384
|
basenameValidator,
|
|
2152
3385
|
createMediaAsset,
|
|
2153
3386
|
createMediaFile,
|
|
2154
3387
|
createMediaFolder,
|
|
2155
3388
|
createMediaItem,
|
|
2156
3389
|
createMediaItemTree,
|
|
2157
|
-
|
|
2158
|
-
formatByteSize,
|
|
3390
|
+
deleteResources,
|
|
2159
3391
|
getDepthMap,
|
|
2160
3392
|
getParentDirectories,
|
|
2161
3393
|
getVisibleItems,
|
|
3394
|
+
gridThumbnailDimension,
|
|
3395
|
+
mediaDeleteMediaItems,
|
|
3396
|
+
mediaGetDepthMap,
|
|
3397
|
+
mediaGetParentDirectories,
|
|
3398
|
+
mediaGetVisibleItems,
|
|
3399
|
+
mediaMoveMediaInsideFolder,
|
|
3400
|
+
mediaMovePathsIntoTarget,
|
|
3401
|
+
mediaMoveUpAFolder,
|
|
3402
|
+
mediaRenameMediaItemAndDescendantPaths,
|
|
3403
|
+
mediaUpdateExpandedMap,
|
|
3404
|
+
mediaValidateMediaItemRename,
|
|
2162
3405
|
moveMediaInsideFolder,
|
|
2163
3406
|
movePathsIntoTarget,
|
|
2164
3407
|
moveUpAFolder,
|
|
2165
|
-
|
|
3408
|
+
renameResourceAndDescendantPaths,
|
|
2166
3409
|
rootMediaItem,
|
|
2167
3410
|
rootMediaItemName,
|
|
2168
3411
|
rootMediaItemPath,
|
|
2169
3412
|
updateExpandedMap,
|
|
2170
|
-
|
|
3413
|
+
validateResourceRename
|
|
2171
3414
|
};
|
|
2172
3415
|
//# sourceMappingURL=index.mjs.map
|