@noya-app/noya-file-explorer 0.0.16 → 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 +13 -0
- package/dist/index.css +853 -894
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +624 -33
- package/dist/index.d.ts +624 -33
- package/dist/index.js +1346 -265
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1384 -262
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/MediaCollection.tsx +74 -53
- 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 -0
- package/src/utils/files.ts +25 -37
- package/src/utils/handleFileDrop.ts +38 -15
- package/src/utils/resourceUtils.ts +329 -0
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
|
}
|
|
@@ -1111,7 +1111,8 @@ import {
|
|
|
1111
1111
|
FileExplorerLayout,
|
|
1112
1112
|
FileExplorerUploadButton,
|
|
1113
1113
|
formatByteSize,
|
|
1114
|
-
MediaThumbnail
|
|
1114
|
+
MediaThumbnail,
|
|
1115
|
+
useOpenConfirmationDialog
|
|
1115
1116
|
} from "@noya-app/noya-designsystem";
|
|
1116
1117
|
import {
|
|
1117
1118
|
DownloadIcon,
|
|
@@ -1232,7 +1233,15 @@ import { path as path4 } from "imfs";
|
|
|
1232
1233
|
import React from "react";
|
|
1233
1234
|
|
|
1234
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
|
|
1235
1240
|
var import_tree_visit2 = __toESM(require_lib());
|
|
1241
|
+
import {
|
|
1242
|
+
createResourceTree,
|
|
1243
|
+
rootResource
|
|
1244
|
+
} from "@noya-app/noya-schemas";
|
|
1236
1245
|
import { path as path2 } from "imfs";
|
|
1237
1246
|
var getVisibleItems = ({
|
|
1238
1247
|
expandedMap,
|
|
@@ -1243,7 +1252,7 @@ var getVisibleItems = ({
|
|
|
1243
1252
|
showRootItem
|
|
1244
1253
|
}) => {
|
|
1245
1254
|
const filteredItems = [];
|
|
1246
|
-
const relativeRootItem = tree.find(
|
|
1255
|
+
const relativeRootItem = tree.find(rootResource, (item) => item.id === rootItemId) ?? rootResource;
|
|
1247
1256
|
tree.visit(relativeRootItem, (item) => {
|
|
1248
1257
|
if (relativeRootItem.id === item.id) {
|
|
1249
1258
|
if (showRootItem) {
|
|
@@ -1251,16 +1260,16 @@ var getVisibleItems = ({
|
|
|
1251
1260
|
}
|
|
1252
1261
|
return;
|
|
1253
1262
|
}
|
|
1254
|
-
if (item.
|
|
1263
|
+
if (item.type === "file" && fileKindFilter === "all") {
|
|
1255
1264
|
filteredItems.push(item);
|
|
1256
1265
|
}
|
|
1257
|
-
if (item.
|
|
1266
|
+
if (item.type === "asset" && (fileKindFilter === "assets" || fileKindFilter === "all")) {
|
|
1258
1267
|
filteredItems.push(item);
|
|
1259
1268
|
}
|
|
1260
|
-
if (item.
|
|
1269
|
+
if (item.type === "directory" && (fileKindFilter === "directories" || fileKindFilter === "all")) {
|
|
1261
1270
|
filteredItems.push(item);
|
|
1262
1271
|
}
|
|
1263
|
-
if (item.
|
|
1272
|
+
if (item.type === "resource" && (fileKindFilter === "resources" || fileKindFilter === "all")) {
|
|
1264
1273
|
filteredItems.push(item);
|
|
1265
1274
|
}
|
|
1266
1275
|
if (!expandedMap[item.id] || !showAllDescendants) return "skip";
|
|
@@ -1272,7 +1281,7 @@ var basenameValidator = (basename) => {
|
|
|
1272
1281
|
const invalidCharsRegex = /[/\\<>:"|?*]/;
|
|
1273
1282
|
return !invalidCharsRegex.test(basename);
|
|
1274
1283
|
};
|
|
1275
|
-
var
|
|
1284
|
+
var validateResourceRename = ({
|
|
1276
1285
|
basename,
|
|
1277
1286
|
selectedItemPath,
|
|
1278
1287
|
media
|
|
@@ -1290,7 +1299,7 @@ var movePathsIntoTarget = ({
|
|
|
1290
1299
|
tree
|
|
1291
1300
|
}) => {
|
|
1292
1301
|
const ancestors = (0, import_tree_visit2.ancestorPaths)(
|
|
1293
|
-
sourceItemPaths.map((
|
|
1302
|
+
sourceItemPaths.map((path7) => path7.split("/"))
|
|
1294
1303
|
);
|
|
1295
1304
|
const mediaClone = { ...media };
|
|
1296
1305
|
for (const ancestor of ancestors) {
|
|
@@ -1308,7 +1317,7 @@ var movePathsIntoTarget = ({
|
|
|
1308
1317
|
ancestorPath,
|
|
1309
1318
|
newAncestorPath
|
|
1310
1319
|
);
|
|
1311
|
-
const newPathIsValid =
|
|
1320
|
+
const newPathIsValid = validateResourceRename({
|
|
1312
1321
|
basename: path2.basename(descendantPath),
|
|
1313
1322
|
selectedItemPath: newDescendantPath,
|
|
1314
1323
|
media
|
|
@@ -1327,17 +1336,17 @@ var moveUpAFolder = ({
|
|
|
1327
1336
|
selectedIds
|
|
1328
1337
|
}) => {
|
|
1329
1338
|
const indexPath = tree.findPath(
|
|
1330
|
-
|
|
1339
|
+
rootResource,
|
|
1331
1340
|
(item) => item.id === selectedIds[0]
|
|
1332
1341
|
);
|
|
1333
1342
|
if (!indexPath) return;
|
|
1334
1343
|
const grandparentFolder = tree.access(
|
|
1335
|
-
|
|
1344
|
+
rootResource,
|
|
1336
1345
|
indexPath.slice(0, indexPath.length - 2)
|
|
1337
1346
|
);
|
|
1338
1347
|
const grandparentFolderPath = tree.idToPathMap.get(grandparentFolder.id);
|
|
1339
1348
|
if (!grandparentFolderPath) return;
|
|
1340
|
-
const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((
|
|
1349
|
+
const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
|
|
1341
1350
|
return movePathsIntoTarget({
|
|
1342
1351
|
media,
|
|
1343
1352
|
targetItemPath: grandparentFolderPath,
|
|
@@ -1366,7 +1375,7 @@ var updateExpandedMap = ({
|
|
|
1366
1375
|
const newExpandedMap = { ...expandedMap };
|
|
1367
1376
|
const inner = (item2, expanded2) => {
|
|
1368
1377
|
if (!expandable) return {};
|
|
1369
|
-
if (item2.id ===
|
|
1378
|
+
if (item2.id === rootResource.id) return {};
|
|
1370
1379
|
if (!expanded2) {
|
|
1371
1380
|
const children = tree.getChildren(item2, []);
|
|
1372
1381
|
children.forEach((child) => inner(child, false));
|
|
@@ -1376,13 +1385,13 @@ var updateExpandedMap = ({
|
|
|
1376
1385
|
inner(item, expanded);
|
|
1377
1386
|
return newExpandedMap;
|
|
1378
1387
|
};
|
|
1379
|
-
var
|
|
1388
|
+
var deleteResources = ({
|
|
1380
1389
|
selectedIds,
|
|
1381
1390
|
media,
|
|
1382
1391
|
tree
|
|
1383
1392
|
}) => {
|
|
1384
1393
|
const itemsToDelete = selectedIds.flatMap((mediaItemId) => {
|
|
1385
|
-
const mediaItem = tree.
|
|
1394
|
+
const mediaItem = tree.resourcesWithRoot.find(
|
|
1386
1395
|
(item) => item.id === mediaItemId
|
|
1387
1396
|
);
|
|
1388
1397
|
if (!mediaItem) return [];
|
|
@@ -1403,7 +1412,7 @@ var moveMediaInsideFolder = ({
|
|
|
1403
1412
|
}) => {
|
|
1404
1413
|
const targetItemPath = tree.idToPathMap.get(targetItemId);
|
|
1405
1414
|
if (!targetItemPath) return media;
|
|
1406
|
-
const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((
|
|
1415
|
+
const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
|
|
1407
1416
|
return movePathsIntoTarget({
|
|
1408
1417
|
media,
|
|
1409
1418
|
sourceItemPaths,
|
|
@@ -1411,16 +1420,13 @@ var moveMediaInsideFolder = ({
|
|
|
1411
1420
|
tree
|
|
1412
1421
|
});
|
|
1413
1422
|
};
|
|
1414
|
-
var getParentDirectories = (
|
|
1415
|
-
const tree =
|
|
1416
|
-
const indexPath = tree.findPath(
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
);
|
|
1420
|
-
if (!indexPath) return [rootMediaItem];
|
|
1421
|
-
return tree.accessPath(rootMediaItem, indexPath);
|
|
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);
|
|
1422
1428
|
};
|
|
1423
|
-
var
|
|
1429
|
+
var renameResourceAndDescendantPaths = ({
|
|
1424
1430
|
newName,
|
|
1425
1431
|
selectedItemPath,
|
|
1426
1432
|
media,
|
|
@@ -1438,175 +1444,280 @@ var renameMediaItemAndDescendantPaths = ({
|
|
|
1438
1444
|
selectedItemPath,
|
|
1439
1445
|
newItemPath
|
|
1440
1446
|
);
|
|
1441
|
-
mediaClone[newDescendantPath] =
|
|
1447
|
+
mediaClone[newDescendantPath] = {
|
|
1448
|
+
...mediaClone[descendantPath],
|
|
1449
|
+
path: newDescendantPath
|
|
1450
|
+
};
|
|
1442
1451
|
delete mediaClone[descendantPath];
|
|
1443
1452
|
}
|
|
1444
1453
|
return mediaClone;
|
|
1445
1454
|
};
|
|
1446
1455
|
|
|
1447
|
-
// src/utils/
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
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 = ({
|
|
1458
1502
|
media,
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
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)
|
|
1465
1517
|
);
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
{
|
|
1474
|
-
file,
|
|
1475
|
-
relativePath: path3.join(basePath, file.name)
|
|
1476
|
-
}
|
|
1477
|
-
];
|
|
1478
|
-
}
|
|
1479
|
-
if (isDirectoryEntry(entry)) {
|
|
1480
|
-
const reader = entry.createReader();
|
|
1481
|
-
const readAll = async () => {
|
|
1482
|
-
const all = [];
|
|
1483
|
-
while (true) {
|
|
1484
|
-
const entries = await new Promise(
|
|
1485
|
-
(resolve) => reader.readEntries((ents) => resolve(ents))
|
|
1486
|
-
);
|
|
1487
|
-
if (!entries.length) break;
|
|
1488
|
-
all.push(...entries);
|
|
1489
|
-
}
|
|
1490
|
-
return all;
|
|
1491
|
-
};
|
|
1492
|
-
const children = await readAll();
|
|
1493
|
-
const results = await Promise.all(
|
|
1494
|
-
children.map(
|
|
1495
|
-
(child) => collectFromEntry(child, path3.join(basePath, entry.name))
|
|
1496
|
-
)
|
|
1497
|
-
);
|
|
1498
|
-
return results.flat();
|
|
1499
|
-
}
|
|
1500
|
-
return [];
|
|
1501
|
-
};
|
|
1502
|
-
let dropped = [];
|
|
1503
|
-
if (supportsEntries) {
|
|
1504
|
-
const topLevelEntries = dataTransferItems.flatMap((item) => {
|
|
1505
|
-
const entry = item.webkitGetAsEntry?.();
|
|
1506
|
-
if (!entry) return [];
|
|
1507
|
-
return [entry];
|
|
1508
|
-
});
|
|
1509
|
-
const nested = await Promise.all(
|
|
1510
|
-
topLevelEntries.map((entry) => collectFromEntry(entry, ""))
|
|
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
|
|
1511
1525
|
);
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
}));
|
|
1521
|
-
}
|
|
1522
|
-
if (dropped.length === 0) return;
|
|
1523
|
-
const folderRelativePaths = /* @__PURE__ */ new Set();
|
|
1524
|
-
for (const { relativePath } of dropped) {
|
|
1525
|
-
const dir = path3.dirname(relativePath);
|
|
1526
|
-
if (dir && dir !== ".") {
|
|
1527
|
-
const parts = dir.split("/").filter(Boolean);
|
|
1528
|
-
let acc = "";
|
|
1529
|
-
for (const part of parts) {
|
|
1530
|
-
acc = acc ? path3.join(acc, part) : part;
|
|
1531
|
-
folderRelativePaths.add(acc);
|
|
1532
|
-
}
|
|
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];
|
|
1533
1534
|
}
|
|
1534
1535
|
}
|
|
1535
|
-
const folderEntries = Array.from(folderRelativePaths).map((rel) => path3.join(rootItemPath, rel)).filter((full) => !media[full]).map((full) => [full, createMediaFolder()]);
|
|
1536
|
-
const uploadResults = await Promise.all(
|
|
1537
|
-
dropped.map(
|
|
1538
|
-
async ({ file, relativePath }) => {
|
|
1539
|
-
const asset = await uploadAsset(file);
|
|
1540
|
-
return [
|
|
1541
|
-
path3.join(rootItemPath, relativePath),
|
|
1542
|
-
createMediaAsset({ assetId: asset.id })
|
|
1543
|
-
];
|
|
1544
|
-
}
|
|
1545
|
-
)
|
|
1546
|
-
);
|
|
1547
|
-
return {
|
|
1548
|
-
...media,
|
|
1549
|
-
...Object.fromEntries([...folderEntries, ...uploadResults])
|
|
1550
|
-
};
|
|
1551
|
-
} catch (error) {
|
|
1552
|
-
console.error("Failed to upload dropped files:", error);
|
|
1553
1536
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
// src/MediaCollection.tsx
|
|
1557
|
-
var extensionToContentType = {
|
|
1558
|
-
svg: "image/svg+xml",
|
|
1559
|
-
png: "image/png",
|
|
1560
|
-
jpeg: "image/jpeg"
|
|
1537
|
+
return mediaClone;
|
|
1561
1538
|
};
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
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);
|
|
1571
1568
|
} else {
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
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) => {
|
|
1630
|
+
const tree = createMediaItemTree(mediaMap);
|
|
1631
|
+
const indexPath = tree.findPath(
|
|
1632
|
+
rootMediaItem,
|
|
1633
|
+
(item) => item.id === folderId
|
|
1634
|
+
);
|
|
1635
|
+
if (!indexPath) return [rootMediaItem];
|
|
1636
|
+
return tree.accessPath(rootMediaItem, indexPath);
|
|
1637
|
+
};
|
|
1638
|
+
var mediaRenameMediaItemAndDescendantPaths = ({
|
|
1639
|
+
newName,
|
|
1640
|
+
selectedItemPath,
|
|
1641
|
+
media,
|
|
1642
|
+
tree
|
|
1643
|
+
}) => {
|
|
1644
|
+
const mediaClone = { ...media };
|
|
1645
|
+
const selectedItem = mediaClone[selectedItemPath];
|
|
1646
|
+
if (!selectedItem) return mediaClone;
|
|
1647
|
+
const parentPath = path3.dirname(selectedItemPath);
|
|
1648
|
+
const newItemPath = path3.join(parentPath, newName);
|
|
1649
|
+
const descendants = tree.flat(selectedItem).map((item) => tree.idToPathMap.get(item.id));
|
|
1650
|
+
for (const descendantPath of descendants) {
|
|
1651
|
+
if (!descendantPath) continue;
|
|
1652
|
+
const newDescendantPath = descendantPath.replace(
|
|
1653
|
+
selectedItemPath,
|
|
1654
|
+
newItemPath
|
|
1655
|
+
);
|
|
1656
|
+
mediaClone[newDescendantPath] = mediaClone[descendantPath];
|
|
1657
|
+
delete mediaClone[descendantPath];
|
|
1658
|
+
}
|
|
1659
|
+
return mediaClone;
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
// src/MediaCollection.tsx
|
|
1663
|
+
var extensionToContentType = {
|
|
1664
|
+
svg: "image/svg+xml",
|
|
1665
|
+
png: "image/png",
|
|
1666
|
+
jpeg: "image/jpeg"
|
|
1667
|
+
};
|
|
1668
|
+
function encodeFileContentForThumbnail(pathProp, item) {
|
|
1669
|
+
const extension = path4.extname(pathProp).slice(1);
|
|
1670
|
+
const contentType = extensionToContentType[extension];
|
|
1671
|
+
if (contentType) {
|
|
1672
|
+
if (item.encoding === "base64") {
|
|
1673
|
+
return {
|
|
1674
|
+
contentType,
|
|
1675
|
+
url: `data:${contentType};base64,${item.content}`
|
|
1676
|
+
};
|
|
1677
|
+
} else {
|
|
1678
|
+
try {
|
|
1679
|
+
return {
|
|
1680
|
+
contentType,
|
|
1681
|
+
url: `data:${contentType},${encodeURIComponent(item.content)}`
|
|
1682
|
+
};
|
|
1683
|
+
} catch (error) {
|
|
1684
|
+
console.warn("Failed to encode content:", error);
|
|
1685
|
+
return { contentType };
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
return void 0;
|
|
1690
|
+
}
|
|
1691
|
+
var MediaThumbnailInternal = memoGeneric(
|
|
1692
|
+
({
|
|
1693
|
+
item,
|
|
1694
|
+
selected,
|
|
1695
|
+
size,
|
|
1696
|
+
path: pathProp,
|
|
1697
|
+
renderThumbnailIcon
|
|
1698
|
+
}) => {
|
|
1699
|
+
const asset = useAsset(item.kind === "asset" ? item.assetId : void 0);
|
|
1700
|
+
const isRoot = item.id === rootMediaItem.id;
|
|
1701
|
+
const isFolder = item.kind === "folder";
|
|
1702
|
+
const isFile = item.kind === "file";
|
|
1703
|
+
let contentType;
|
|
1704
|
+
let url;
|
|
1705
|
+
let width;
|
|
1706
|
+
let height;
|
|
1707
|
+
if (asset) {
|
|
1708
|
+
contentType = asset.contentType;
|
|
1709
|
+
url = asset.url;
|
|
1710
|
+
width = asset.width ?? void 0;
|
|
1711
|
+
height = asset.height ?? void 0;
|
|
1712
|
+
} else if (isFile && pathProp) {
|
|
1713
|
+
const encoded = encodeFileContentForThumbnail(pathProp, item);
|
|
1714
|
+
if (encoded) {
|
|
1715
|
+
contentType = encoded.contentType;
|
|
1716
|
+
url = encoded.url;
|
|
1717
|
+
}
|
|
1608
1718
|
}
|
|
1609
1719
|
const fileName = pathProp ? path4.basename(pathProp) : void 0;
|
|
1720
|
+
const dimensions = width && height ? { width, height } : void 0;
|
|
1610
1721
|
return /* @__PURE__ */ React.createElement(
|
|
1611
1722
|
MediaThumbnail,
|
|
1612
1723
|
{
|
|
@@ -1616,7 +1727,8 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1616
1727
|
selected,
|
|
1617
1728
|
size,
|
|
1618
1729
|
fileName,
|
|
1619
|
-
renderThumbnailIcon
|
|
1730
|
+
renderThumbnailIcon,
|
|
1731
|
+
dimensions
|
|
1620
1732
|
}
|
|
1621
1733
|
);
|
|
1622
1734
|
}
|
|
@@ -1650,7 +1762,8 @@ var MediaCollection = memo(
|
|
|
1650
1762
|
sharedDragProps,
|
|
1651
1763
|
onClickItem,
|
|
1652
1764
|
renderThumbnailIcon,
|
|
1653
|
-
onDidDeleteItems
|
|
1765
|
+
onDidDeleteItems,
|
|
1766
|
+
onAssetsUploaded
|
|
1654
1767
|
}, ref) {
|
|
1655
1768
|
const setMedia = useCallback(
|
|
1656
1769
|
(...args) => {
|
|
@@ -1691,7 +1804,7 @@ var MediaCollection = memo(
|
|
|
1691
1804
|
const assets = useAssets();
|
|
1692
1805
|
const [expandedMap, setExpandedMap] = useState({});
|
|
1693
1806
|
const visibleItems = useMemo(
|
|
1694
|
-
() =>
|
|
1807
|
+
() => mediaGetVisibleItems({
|
|
1695
1808
|
expandedMap,
|
|
1696
1809
|
fileKindFilter,
|
|
1697
1810
|
rootItemId,
|
|
@@ -1709,7 +1822,7 @@ var MediaCollection = memo(
|
|
|
1709
1822
|
]
|
|
1710
1823
|
);
|
|
1711
1824
|
const depthMap = useMemo(
|
|
1712
|
-
() =>
|
|
1825
|
+
() => mediaGetDepthMap(rootMediaItem, treeWithTempItem, showAllDescendants),
|
|
1713
1826
|
[treeWithTempItem, showAllDescendants]
|
|
1714
1827
|
);
|
|
1715
1828
|
const collectionRef = useRef(null);
|
|
@@ -1748,17 +1861,23 @@ var MediaCollection = memo(
|
|
|
1748
1861
|
},
|
|
1749
1862
|
[expandedMap, expandable]
|
|
1750
1863
|
);
|
|
1864
|
+
const openConfirmationDialog = useOpenConfirmationDialog();
|
|
1751
1865
|
const handleDelete = useCallback(
|
|
1752
|
-
(selectedIds2) => {
|
|
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;
|
|
1753
1872
|
const deletedItems = Object.entries(media).flatMap(
|
|
1754
|
-
([
|
|
1873
|
+
([path7, item]) => {
|
|
1755
1874
|
if (selectedIds2.includes(item.id)) {
|
|
1756
|
-
return [[
|
|
1875
|
+
return [[path7, item]];
|
|
1757
1876
|
}
|
|
1758
1877
|
return [];
|
|
1759
1878
|
}
|
|
1760
1879
|
);
|
|
1761
|
-
const newMedia =
|
|
1880
|
+
const newMedia = mediaDeleteMediaItems({
|
|
1762
1881
|
selectedIds: selectedIds2,
|
|
1763
1882
|
media,
|
|
1764
1883
|
tree
|
|
@@ -1767,7 +1886,14 @@ var MediaCollection = memo(
|
|
|
1767
1886
|
setMedia({ name: "Delete items", timestamp: Date.now() }, newMedia);
|
|
1768
1887
|
onDidDeleteItems?.(deletedItems);
|
|
1769
1888
|
},
|
|
1770
|
-
[
|
|
1889
|
+
[
|
|
1890
|
+
media,
|
|
1891
|
+
setMedia,
|
|
1892
|
+
setSelectedIds,
|
|
1893
|
+
tree,
|
|
1894
|
+
onDidDeleteItems,
|
|
1895
|
+
openConfirmationDialog
|
|
1896
|
+
]
|
|
1771
1897
|
);
|
|
1772
1898
|
const onRename = useCallback(
|
|
1773
1899
|
(selectedItem, newName) => {
|
|
@@ -1776,7 +1902,7 @@ var MediaCollection = memo(
|
|
|
1776
1902
|
selectedItem.id
|
|
1777
1903
|
);
|
|
1778
1904
|
if (!selectedItemPath) return;
|
|
1779
|
-
const renameIsValid =
|
|
1905
|
+
const renameIsValid = mediaValidateMediaItemRename({
|
|
1780
1906
|
basename: newName,
|
|
1781
1907
|
selectedItemPath,
|
|
1782
1908
|
media: temp.media
|
|
@@ -1785,7 +1911,7 @@ var MediaCollection = memo(
|
|
|
1785
1911
|
setTempItem(void 0);
|
|
1786
1912
|
return;
|
|
1787
1913
|
}
|
|
1788
|
-
const mediaWithRenamedDescendantPaths =
|
|
1914
|
+
const mediaWithRenamedDescendantPaths = mediaRenameMediaItemAndDescendantPaths({
|
|
1789
1915
|
newName,
|
|
1790
1916
|
selectedItemPath,
|
|
1791
1917
|
media: temp.media,
|
|
@@ -1836,7 +1962,7 @@ var MediaCollection = memo(
|
|
|
1836
1962
|
);
|
|
1837
1963
|
const handleMoveUpAFolder = useCallback(
|
|
1838
1964
|
(selectedIds2) => {
|
|
1839
|
-
const newMedia =
|
|
1965
|
+
const newMedia = mediaMoveUpAFolder({
|
|
1840
1966
|
tree,
|
|
1841
1967
|
media,
|
|
1842
1968
|
selectedIds: selectedIds2
|
|
@@ -1863,23 +1989,28 @@ var MediaCollection = memo(
|
|
|
1863
1989
|
};
|
|
1864
1990
|
});
|
|
1865
1991
|
setIsUploading(true);
|
|
1866
|
-
const
|
|
1992
|
+
const uploadedAssets = await Promise.all(uploadPromises);
|
|
1993
|
+
const newMediaMap = Object.fromEntries(
|
|
1994
|
+
uploadedAssets.map(({ assetPath, asset }) => [assetPath, asset])
|
|
1995
|
+
);
|
|
1867
1996
|
setMedia(
|
|
1868
1997
|
{ name: "Add media items", timestamp: Date.now() },
|
|
1869
1998
|
{
|
|
1870
1999
|
...media,
|
|
1871
|
-
...
|
|
1872
|
-
newMediaMap.map(({ assetPath, asset }) => [assetPath, asset])
|
|
1873
|
-
)
|
|
2000
|
+
...newMediaMap
|
|
1874
2001
|
}
|
|
1875
2002
|
);
|
|
2003
|
+
onAssetsUploaded?.(newMediaMap);
|
|
1876
2004
|
} catch (error) {
|
|
1877
|
-
|
|
2005
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2006
|
+
} else {
|
|
2007
|
+
console.error("Failed to upload files:", error);
|
|
2008
|
+
}
|
|
1878
2009
|
} finally {
|
|
1879
2010
|
setIsUploading(false);
|
|
1880
2011
|
}
|
|
1881
2012
|
},
|
|
1882
|
-
[tree.idToPathMap, setMedia, media, assetManager]
|
|
2013
|
+
[tree.idToPathMap, setMedia, media, assetManager, onAssetsUploaded]
|
|
1883
2014
|
);
|
|
1884
2015
|
const handleDownload = useCallback(
|
|
1885
2016
|
async (selectedItems) => {
|
|
@@ -1923,7 +2054,10 @@ var MediaCollection = memo(
|
|
|
1923
2054
|
}
|
|
1924
2055
|
);
|
|
1925
2056
|
} catch (error) {
|
|
1926
|
-
|
|
2057
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2058
|
+
} else {
|
|
2059
|
+
console.error("Failed to upload files:", error);
|
|
2060
|
+
}
|
|
1927
2061
|
}
|
|
1928
2062
|
},
|
|
1929
2063
|
[media, setMedia, assetManager, tree]
|
|
@@ -1936,7 +2070,7 @@ var MediaCollection = memo(
|
|
|
1936
2070
|
);
|
|
1937
2071
|
const handleMoveMediaInsideFolder = useCallback(
|
|
1938
2072
|
(sourceItem, targetItem) => {
|
|
1939
|
-
const newMedia =
|
|
2073
|
+
const newMedia = mediaMoveMediaInsideFolder({
|
|
1940
2074
|
sourceItemIds: [sourceItem.id],
|
|
1941
2075
|
targetItemId: targetItem.id,
|
|
1942
2076
|
media,
|
|
@@ -2055,7 +2189,7 @@ var MediaCollection = memo(
|
|
|
2055
2189
|
const handleSetExpanded = useCallback(
|
|
2056
2190
|
(item, expanded) => {
|
|
2057
2191
|
setExpandedMap(
|
|
2058
|
-
(prev) =>
|
|
2192
|
+
(prev) => mediaUpdateExpandedMap({
|
|
2059
2193
|
item,
|
|
2060
2194
|
expanded,
|
|
2061
2195
|
expandable,
|
|
@@ -2225,22 +2359,6 @@ var MediaCollection = memo(
|
|
|
2225
2359
|
if (position === "inside") {
|
|
2226
2360
|
handleMoveMediaInsideFolder(sourceItem, targetItem);
|
|
2227
2361
|
}
|
|
2228
|
-
},
|
|
2229
|
-
onFilesDrop: async (event) => {
|
|
2230
|
-
event.preventDefault();
|
|
2231
|
-
const rootItemPath = tree.idToPathMap.get(rootItemId);
|
|
2232
|
-
if (!rootItemPath) return;
|
|
2233
|
-
const newMedia = await handleDataTransfer({
|
|
2234
|
-
dataTransfer: event.dataTransfer,
|
|
2235
|
-
rootItemPath,
|
|
2236
|
-
media,
|
|
2237
|
-
uploadAsset: (file) => assetManager.create(file)
|
|
2238
|
-
});
|
|
2239
|
-
if (!newMedia) return;
|
|
2240
|
-
setMedia(
|
|
2241
|
-
{ name: "Add media files", timestamp: Date.now() },
|
|
2242
|
-
newMedia
|
|
2243
|
-
);
|
|
2244
2362
|
}
|
|
2245
2363
|
}
|
|
2246
2364
|
)
|
|
@@ -2266,28 +2384,1032 @@ function acceptsMediaItemDrop(parameters) {
|
|
|
2266
2384
|
}
|
|
2267
2385
|
return true;
|
|
2268
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 [];
|
|
2772
|
+
}
|
|
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])
|
|
2890
|
+
);
|
|
2891
|
+
setMedia(
|
|
2892
|
+
{ name: "Add media items", timestamp: Date.now() },
|
|
2893
|
+
{
|
|
2894
|
+
...media,
|
|
2895
|
+
...newMediaMap
|
|
2896
|
+
}
|
|
2897
|
+
);
|
|
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)
|
|
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;
|
|
3195
|
+
return true;
|
|
3196
|
+
},
|
|
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
|
+
}
|
|
3279
|
+
const sourceItem = visibleItems[sourceIndex];
|
|
3280
|
+
const targetItem = visibleItems[targetIndex];
|
|
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;
|
|
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);
|
|
3305
|
+
},
|
|
3306
|
+
onFilesDrop: async (event) => {
|
|
3307
|
+
event.preventDefault();
|
|
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
|
+
);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
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
|
+
)
|
|
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
|
+
}
|
|
2269
3377
|
export {
|
|
2270
3378
|
MediaCollection,
|
|
2271
3379
|
PLACEHOLDER_ITEM_NAME,
|
|
3380
|
+
ResourceExplorer,
|
|
3381
|
+
ResourceThumbnail,
|
|
2272
3382
|
acceptsMediaItemDrop,
|
|
3383
|
+
acceptsResourceDrop,
|
|
2273
3384
|
basenameValidator,
|
|
2274
3385
|
createMediaAsset,
|
|
2275
3386
|
createMediaFile,
|
|
2276
3387
|
createMediaFolder,
|
|
2277
3388
|
createMediaItem,
|
|
2278
3389
|
createMediaItemTree,
|
|
2279
|
-
|
|
3390
|
+
deleteResources,
|
|
2280
3391
|
getDepthMap,
|
|
2281
3392
|
getParentDirectories,
|
|
2282
3393
|
getVisibleItems,
|
|
3394
|
+
gridThumbnailDimension,
|
|
3395
|
+
mediaDeleteMediaItems,
|
|
3396
|
+
mediaGetDepthMap,
|
|
3397
|
+
mediaGetParentDirectories,
|
|
3398
|
+
mediaGetVisibleItems,
|
|
3399
|
+
mediaMoveMediaInsideFolder,
|
|
3400
|
+
mediaMovePathsIntoTarget,
|
|
3401
|
+
mediaMoveUpAFolder,
|
|
3402
|
+
mediaRenameMediaItemAndDescendantPaths,
|
|
3403
|
+
mediaUpdateExpandedMap,
|
|
3404
|
+
mediaValidateMediaItemRename,
|
|
2283
3405
|
moveMediaInsideFolder,
|
|
2284
3406
|
movePathsIntoTarget,
|
|
2285
3407
|
moveUpAFolder,
|
|
2286
|
-
|
|
3408
|
+
renameResourceAndDescendantPaths,
|
|
2287
3409
|
rootMediaItem,
|
|
2288
3410
|
rootMediaItemName,
|
|
2289
3411
|
rootMediaItemPath,
|
|
2290
3412
|
updateExpandedMap,
|
|
2291
|
-
|
|
3413
|
+
validateResourceRename
|
|
2292
3414
|
};
|
|
2293
3415
|
//# sourceMappingURL=index.mjs.map
|