@noya-app/noya-file-explorer 0.0.31 → 0.0.32
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 +11 -11
- package/CHANGELOG.md +12 -0
- package/dist/index.css +84 -11
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +731 -211
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +759 -212
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/GitFileExplorer.tsx +432 -0
- package/src/git/gitFileTree.ts +110 -0
- package/src/git/useGitFileOperations.ts +184 -0
- package/src/git/useGitFileTree.ts +91 -0
- package/src/index.ts +1 -0
- package/src/utils/handleFileDrop.ts +2 -84
package/dist/index.mjs
CHANGED
|
@@ -1100,10 +1100,620 @@ var require_lib = __commonJS({
|
|
|
1100
1100
|
}
|
|
1101
1101
|
});
|
|
1102
1102
|
|
|
1103
|
+
// src/GitFileExplorer.tsx
|
|
1104
|
+
import {
|
|
1105
|
+
Button,
|
|
1106
|
+
createSectionedMenu,
|
|
1107
|
+
cx,
|
|
1108
|
+
DropdownMenu,
|
|
1109
|
+
IconButton,
|
|
1110
|
+
List,
|
|
1111
|
+
MediaThumbnail,
|
|
1112
|
+
Section,
|
|
1113
|
+
Small,
|
|
1114
|
+
useOpenConfirmationDialog
|
|
1115
|
+
} from "@noya-app/noya-designsystem";
|
|
1116
|
+
import {
|
|
1117
|
+
InputIcon,
|
|
1118
|
+
PlusIcon,
|
|
1119
|
+
TrashIcon,
|
|
1120
|
+
UploadIcon
|
|
1121
|
+
} from "@noya-app/noya-icons";
|
|
1122
|
+
import { useFileDropTarget } from "@noya-app/react-utils";
|
|
1123
|
+
import React, {
|
|
1124
|
+
forwardRef,
|
|
1125
|
+
memo,
|
|
1126
|
+
useCallback as useCallback3,
|
|
1127
|
+
useEffect,
|
|
1128
|
+
useImperativeHandle,
|
|
1129
|
+
useMemo as useMemo2,
|
|
1130
|
+
useRef,
|
|
1131
|
+
useState as useState3
|
|
1132
|
+
} from "react";
|
|
1133
|
+
|
|
1134
|
+
// src/git/gitFileTree.ts
|
|
1135
|
+
function parseFilesToTree(files) {
|
|
1136
|
+
const items = [];
|
|
1137
|
+
const seenDirs = /* @__PURE__ */ new Set();
|
|
1138
|
+
const sortedFiles = [...files].sort();
|
|
1139
|
+
for (const filePath of sortedFiles) {
|
|
1140
|
+
const parts = filePath.split("/");
|
|
1141
|
+
let currentPath = "";
|
|
1142
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1143
|
+
currentPath = currentPath ? `${currentPath}/${parts[i]}` : parts[i];
|
|
1144
|
+
if (!seenDirs.has(currentPath)) {
|
|
1145
|
+
seenDirs.add(currentPath);
|
|
1146
|
+
items.push({
|
|
1147
|
+
id: `dir:${currentPath}`,
|
|
1148
|
+
name: parts[i],
|
|
1149
|
+
path: currentPath,
|
|
1150
|
+
isDirectory: true,
|
|
1151
|
+
depth: i
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
items.push({
|
|
1156
|
+
id: `file:${filePath}`,
|
|
1157
|
+
name: parts[parts.length - 1],
|
|
1158
|
+
path: filePath,
|
|
1159
|
+
isDirectory: false,
|
|
1160
|
+
depth: parts.length - 1
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
return items;
|
|
1164
|
+
}
|
|
1165
|
+
function getVisibleItems(items, expandedDirs) {
|
|
1166
|
+
const visible = [];
|
|
1167
|
+
const collapsedPrefixes = [];
|
|
1168
|
+
for (const item of items) {
|
|
1169
|
+
const isHidden = collapsedPrefixes.some(
|
|
1170
|
+
(prefix) => item.path.startsWith(prefix + "/")
|
|
1171
|
+
);
|
|
1172
|
+
if (isHidden) continue;
|
|
1173
|
+
visible.push(item);
|
|
1174
|
+
if (item.isDirectory && !expandedDirs.has(item.path)) {
|
|
1175
|
+
collapsedPrefixes.push(item.path);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return visible;
|
|
1179
|
+
}
|
|
1180
|
+
function createTempFileItem(name = "") {
|
|
1181
|
+
return {
|
|
1182
|
+
id: "temp:new-file",
|
|
1183
|
+
name,
|
|
1184
|
+
path: name,
|
|
1185
|
+
isDirectory: false,
|
|
1186
|
+
depth: 0
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
function isTempItem(item) {
|
|
1190
|
+
return item.id === "temp:new-file";
|
|
1191
|
+
}
|
|
1192
|
+
function computeRenamedPath(oldPath, newName) {
|
|
1193
|
+
const pathParts = oldPath.split("/");
|
|
1194
|
+
pathParts[pathParts.length - 1] = newName;
|
|
1195
|
+
return pathParts.join("/");
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// src/git/useGitFileOperations.ts
|
|
1199
|
+
import {
|
|
1200
|
+
collectDroppedFiles,
|
|
1201
|
+
readFileAsText
|
|
1202
|
+
} from "@noya-app/react-utils";
|
|
1203
|
+
import { fileOpen } from "browser-fs-access";
|
|
1204
|
+
import { useCallback, useState } from "react";
|
|
1205
|
+
function useGitFileOperations({
|
|
1206
|
+
repoId,
|
|
1207
|
+
repoFilesState,
|
|
1208
|
+
gitManager
|
|
1209
|
+
}) {
|
|
1210
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
1211
|
+
const createFile = useCallback(
|
|
1212
|
+
async (path7, content = "") => {
|
|
1213
|
+
try {
|
|
1214
|
+
await gitManager.patchFiles(
|
|
1215
|
+
repoId,
|
|
1216
|
+
{ create: [{ path: path7, content }] },
|
|
1217
|
+
repoFilesState.ref
|
|
1218
|
+
);
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
alert(`Failed to create file: ${error}`);
|
|
1221
|
+
throw error;
|
|
1222
|
+
}
|
|
1223
|
+
},
|
|
1224
|
+
[gitManager, repoId, repoFilesState.ref]
|
|
1225
|
+
);
|
|
1226
|
+
const renameFile = useCallback(
|
|
1227
|
+
async (item, newName) => {
|
|
1228
|
+
if (isTempItem(item)) {
|
|
1229
|
+
if (!newName) return;
|
|
1230
|
+
await createFile(newName);
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
if (item.isDirectory) {
|
|
1234
|
+
alert("Renaming directories is not yet supported");
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
if (newName === item.name) return;
|
|
1238
|
+
const newPath = computeRenamedPath(item.path, newName);
|
|
1239
|
+
try {
|
|
1240
|
+
await gitManager.patchFiles(
|
|
1241
|
+
repoId,
|
|
1242
|
+
{ rename: [{ oldPath: item.path, newPath }] },
|
|
1243
|
+
repoFilesState.ref
|
|
1244
|
+
);
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
alert(`Failed to rename file: ${error}`);
|
|
1247
|
+
throw error;
|
|
1248
|
+
}
|
|
1249
|
+
},
|
|
1250
|
+
[gitManager, repoId, repoFilesState.ref, createFile]
|
|
1251
|
+
);
|
|
1252
|
+
const deleteFiles = useCallback(
|
|
1253
|
+
async (items) => {
|
|
1254
|
+
const pathsToDelete = /* @__PURE__ */ new Set();
|
|
1255
|
+
for (const item of items) {
|
|
1256
|
+
if (item.isDirectory) {
|
|
1257
|
+
const dirPrefix = item.path + "/";
|
|
1258
|
+
for (const filePath of repoFilesState.files) {
|
|
1259
|
+
if (filePath.startsWith(dirPrefix)) {
|
|
1260
|
+
pathsToDelete.add(filePath);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
} else {
|
|
1264
|
+
pathsToDelete.add(item.path);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (pathsToDelete.size === 0) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
try {
|
|
1271
|
+
await gitManager.patchFiles(
|
|
1272
|
+
repoId,
|
|
1273
|
+
{ delete: Array.from(pathsToDelete).map((path7) => ({ path: path7 })) },
|
|
1274
|
+
repoFilesState.ref
|
|
1275
|
+
);
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
alert(`Failed to delete files: ${error}`);
|
|
1278
|
+
throw error;
|
|
1279
|
+
}
|
|
1280
|
+
},
|
|
1281
|
+
[gitManager, repoId, repoFilesState.ref, repoFilesState.files]
|
|
1282
|
+
);
|
|
1283
|
+
const uploadFiles = useCallback(async () => {
|
|
1284
|
+
try {
|
|
1285
|
+
const files = await fileOpen({ multiple: true });
|
|
1286
|
+
if (!files || Array.isArray(files) && files.length === 0) return;
|
|
1287
|
+
const fileArray = Array.isArray(files) ? files : [files];
|
|
1288
|
+
setIsUploading(true);
|
|
1289
|
+
const createOperations = await Promise.all(
|
|
1290
|
+
fileArray.map(async (file) => ({
|
|
1291
|
+
path: file.name,
|
|
1292
|
+
content: await readFileAsText(file)
|
|
1293
|
+
}))
|
|
1294
|
+
);
|
|
1295
|
+
await gitManager.patchFiles(
|
|
1296
|
+
repoId,
|
|
1297
|
+
{ create: createOperations },
|
|
1298
|
+
repoFilesState.ref
|
|
1299
|
+
);
|
|
1300
|
+
} catch (error) {
|
|
1301
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1302
|
+
} else {
|
|
1303
|
+
alert(`Failed to upload files: ${error}`);
|
|
1304
|
+
}
|
|
1305
|
+
} finally {
|
|
1306
|
+
setIsUploading(false);
|
|
1307
|
+
}
|
|
1308
|
+
}, [gitManager, repoId, repoFilesState.ref]);
|
|
1309
|
+
const handleFileDrop = useCallback(
|
|
1310
|
+
async (event) => {
|
|
1311
|
+
event.preventDefault();
|
|
1312
|
+
try {
|
|
1313
|
+
setIsUploading(true);
|
|
1314
|
+
const droppedFiles = await collectDroppedFiles(event.dataTransfer);
|
|
1315
|
+
if (droppedFiles.length === 0) return;
|
|
1316
|
+
const createOperations = await Promise.all(
|
|
1317
|
+
droppedFiles.map(async ({ file, relativePath }) => ({
|
|
1318
|
+
path: relativePath,
|
|
1319
|
+
content: await readFileAsText(file)
|
|
1320
|
+
}))
|
|
1321
|
+
);
|
|
1322
|
+
await gitManager.patchFiles(
|
|
1323
|
+
repoId,
|
|
1324
|
+
{ create: createOperations },
|
|
1325
|
+
repoFilesState.ref
|
|
1326
|
+
);
|
|
1327
|
+
} catch (error) {
|
|
1328
|
+
alert(`Failed to upload files: ${error}`);
|
|
1329
|
+
} finally {
|
|
1330
|
+
setIsUploading(false);
|
|
1331
|
+
}
|
|
1332
|
+
},
|
|
1333
|
+
[gitManager, repoId, repoFilesState.ref]
|
|
1334
|
+
);
|
|
1335
|
+
return {
|
|
1336
|
+
isUploading,
|
|
1337
|
+
createFile,
|
|
1338
|
+
renameFile,
|
|
1339
|
+
deleteFiles,
|
|
1340
|
+
uploadFiles,
|
|
1341
|
+
handleFileDrop
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// src/git/useGitFileTree.ts
|
|
1346
|
+
import { useCallback as useCallback2, useMemo, useState as useState2 } from "react";
|
|
1347
|
+
function useGitFileTree({ repoFilesState }) {
|
|
1348
|
+
const [expandedDirs, setExpandedDirs] = useState2(
|
|
1349
|
+
() => /* @__PURE__ */ new Set()
|
|
1350
|
+
);
|
|
1351
|
+
const [tempItem, setTempItem] = useState2(void 0);
|
|
1352
|
+
const allItems = useMemo(
|
|
1353
|
+
() => parseFilesToTree(repoFilesState.files),
|
|
1354
|
+
[repoFilesState.files]
|
|
1355
|
+
);
|
|
1356
|
+
const allItemsWithTemp = useMemo(() => {
|
|
1357
|
+
if (!tempItem) return allItems;
|
|
1358
|
+
return [...allItems, tempItem];
|
|
1359
|
+
}, [allItems, tempItem]);
|
|
1360
|
+
const visibleItems = useMemo(
|
|
1361
|
+
() => getVisibleItems(allItemsWithTemp, expandedDirs),
|
|
1362
|
+
[allItemsWithTemp, expandedDirs]
|
|
1363
|
+
);
|
|
1364
|
+
const getExpanded = useCallback2(
|
|
1365
|
+
(item) => {
|
|
1366
|
+
if (!item.isDirectory) return void 0;
|
|
1367
|
+
return expandedDirs.has(item.path);
|
|
1368
|
+
},
|
|
1369
|
+
[expandedDirs]
|
|
1370
|
+
);
|
|
1371
|
+
const setExpanded = useCallback2((item, expanded) => {
|
|
1372
|
+
if (!item.isDirectory) return;
|
|
1373
|
+
setExpandedDirs((prev) => {
|
|
1374
|
+
const next = new Set(prev);
|
|
1375
|
+
if (expanded) {
|
|
1376
|
+
next.add(item.path);
|
|
1377
|
+
} else {
|
|
1378
|
+
next.delete(item.path);
|
|
1379
|
+
}
|
|
1380
|
+
return next;
|
|
1381
|
+
});
|
|
1382
|
+
}, []);
|
|
1383
|
+
const toggleExpanded = useCallback2((item) => {
|
|
1384
|
+
if (!item.isDirectory) return;
|
|
1385
|
+
setExpandedDirs((prev) => {
|
|
1386
|
+
const next = new Set(prev);
|
|
1387
|
+
if (next.has(item.path)) {
|
|
1388
|
+
next.delete(item.path);
|
|
1389
|
+
} else {
|
|
1390
|
+
next.add(item.path);
|
|
1391
|
+
}
|
|
1392
|
+
return next;
|
|
1393
|
+
});
|
|
1394
|
+
}, []);
|
|
1395
|
+
const addTempItem = useCallback2(() => {
|
|
1396
|
+
const newItem = createTempFileItem();
|
|
1397
|
+
setTempItem(newItem);
|
|
1398
|
+
return newItem;
|
|
1399
|
+
}, []);
|
|
1400
|
+
const clearTempItem = useCallback2(() => {
|
|
1401
|
+
setTempItem(void 0);
|
|
1402
|
+
}, []);
|
|
1403
|
+
return {
|
|
1404
|
+
visibleItems,
|
|
1405
|
+
tempItem,
|
|
1406
|
+
getExpanded,
|
|
1407
|
+
setExpanded,
|
|
1408
|
+
toggleExpanded,
|
|
1409
|
+
addTempItem,
|
|
1410
|
+
clearTempItem
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// src/GitFileExplorer.tsx
|
|
1415
|
+
function useDelayedTrue(condition, delayMs) {
|
|
1416
|
+
const [delayedValue, setDelayedValue] = useState3(false);
|
|
1417
|
+
useEffect(() => {
|
|
1418
|
+
if (!condition) {
|
|
1419
|
+
setDelayedValue(false);
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
const timeout = setTimeout(() => {
|
|
1423
|
+
setDelayedValue(true);
|
|
1424
|
+
}, delayMs);
|
|
1425
|
+
return () => clearTimeout(timeout);
|
|
1426
|
+
}, [condition, delayMs]);
|
|
1427
|
+
return delayedValue;
|
|
1428
|
+
}
|
|
1429
|
+
var GitFileExplorerInner = memo(
|
|
1430
|
+
forwardRef(function GitFileExplorer({
|
|
1431
|
+
repoId,
|
|
1432
|
+
repoFilesState,
|
|
1433
|
+
gitManager,
|
|
1434
|
+
selectedIds: selectedIdsProp,
|
|
1435
|
+
onSelectionChange,
|
|
1436
|
+
onFileSelect,
|
|
1437
|
+
className,
|
|
1438
|
+
title = "Files"
|
|
1439
|
+
}, ref) {
|
|
1440
|
+
const [internalSelectedIds, setInternalSelectedIds] = useState3(
|
|
1441
|
+
[]
|
|
1442
|
+
);
|
|
1443
|
+
const selectedIds = selectedIdsProp ?? internalSelectedIds;
|
|
1444
|
+
const baseSetSelectedIds = onSelectionChange ?? setInternalSelectedIds;
|
|
1445
|
+
const dropTargetRef = useRef(null);
|
|
1446
|
+
const collectionRef = useRef(null);
|
|
1447
|
+
const openConfirmationDialog = useOpenConfirmationDialog();
|
|
1448
|
+
const {
|
|
1449
|
+
visibleItems,
|
|
1450
|
+
getExpanded,
|
|
1451
|
+
setExpanded,
|
|
1452
|
+
toggleExpanded,
|
|
1453
|
+
addTempItem,
|
|
1454
|
+
clearTempItem
|
|
1455
|
+
} = useGitFileTree({ repoFilesState });
|
|
1456
|
+
const setSelectedIds = useCallback3(
|
|
1457
|
+
(ids) => {
|
|
1458
|
+
baseSetSelectedIds(ids);
|
|
1459
|
+
if (ids.length === 1) {
|
|
1460
|
+
const item = visibleItems.find((i) => i.id === ids[0]);
|
|
1461
|
+
if (item && !item.isDirectory) {
|
|
1462
|
+
onFileSelect?.(item.path);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
},
|
|
1466
|
+
[baseSetSelectedIds, visibleItems, onFileSelect]
|
|
1467
|
+
);
|
|
1468
|
+
const {
|
|
1469
|
+
isUploading,
|
|
1470
|
+
renameFile,
|
|
1471
|
+
deleteFiles,
|
|
1472
|
+
uploadFiles,
|
|
1473
|
+
handleFileDrop
|
|
1474
|
+
} = useGitFileOperations({ repoId, repoFilesState, gitManager });
|
|
1475
|
+
const { dropTargetProps, isDropTargetActive } = useFileDropTarget(
|
|
1476
|
+
dropTargetRef,
|
|
1477
|
+
handleFileDrop
|
|
1478
|
+
);
|
|
1479
|
+
const handleAddFile = useCallback3(() => {
|
|
1480
|
+
const newItem = addTempItem();
|
|
1481
|
+
setTimeout(() => {
|
|
1482
|
+
collectionRef.current?.editName(newItem.id);
|
|
1483
|
+
}, 50);
|
|
1484
|
+
}, [addTempItem]);
|
|
1485
|
+
const handleStartRename = useCallback3((itemId) => {
|
|
1486
|
+
collectionRef.current?.editName(itemId);
|
|
1487
|
+
}, []);
|
|
1488
|
+
const handleRename = useCallback3(
|
|
1489
|
+
async (item, newName) => {
|
|
1490
|
+
if (isTempItem(item)) {
|
|
1491
|
+
clearTempItem();
|
|
1492
|
+
if (!newName) return;
|
|
1493
|
+
}
|
|
1494
|
+
await renameFile(item, newName);
|
|
1495
|
+
},
|
|
1496
|
+
[renameFile, clearTempItem]
|
|
1497
|
+
);
|
|
1498
|
+
const handleDelete = useCallback3(
|
|
1499
|
+
async (items) => {
|
|
1500
|
+
if (items.length === 0) return;
|
|
1501
|
+
const fileCount = items.filter((item) => !item.isDirectory).length;
|
|
1502
|
+
const dirCount = items.filter((item) => item.isDirectory).length;
|
|
1503
|
+
let description;
|
|
1504
|
+
if (dirCount > 0 && fileCount > 0) {
|
|
1505
|
+
description = `Are you sure you want to delete ${fileCount} file(s) and ${dirCount} folder(s)? This action cannot be undone.`;
|
|
1506
|
+
} else if (dirCount > 0) {
|
|
1507
|
+
description = `Are you sure you want to delete ${dirCount} folder(s) and all their contents? This action cannot be undone.`;
|
|
1508
|
+
} else {
|
|
1509
|
+
description = `Are you sure you want to delete ${fileCount} file(s)? This action cannot be undone.`;
|
|
1510
|
+
}
|
|
1511
|
+
const confirmed = await openConfirmationDialog({
|
|
1512
|
+
title: "Delete",
|
|
1513
|
+
description
|
|
1514
|
+
});
|
|
1515
|
+
if (!confirmed) return;
|
|
1516
|
+
await deleteFiles(items);
|
|
1517
|
+
setSelectedIds([]);
|
|
1518
|
+
},
|
|
1519
|
+
[deleteFiles, setSelectedIds, openConfirmationDialog]
|
|
1520
|
+
);
|
|
1521
|
+
const handleDoubleClick = useCallback3(
|
|
1522
|
+
(itemId) => {
|
|
1523
|
+
const item = visibleItems.find((i) => i.id === itemId);
|
|
1524
|
+
if (!item) return;
|
|
1525
|
+
if (item.isDirectory) {
|
|
1526
|
+
toggleExpanded(item);
|
|
1527
|
+
} else {
|
|
1528
|
+
onFileSelect?.(item.path);
|
|
1529
|
+
}
|
|
1530
|
+
},
|
|
1531
|
+
[visibleItems, toggleExpanded, onFileSelect]
|
|
1532
|
+
);
|
|
1533
|
+
const headerMenuItems = useMemo2(
|
|
1534
|
+
() => createSectionedMenu([
|
|
1535
|
+
{
|
|
1536
|
+
title: "New File",
|
|
1537
|
+
value: "newFile",
|
|
1538
|
+
icon: /* @__PURE__ */ React.createElement(PlusIcon, null)
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
title: "Upload Files",
|
|
1542
|
+
value: "uploadFiles",
|
|
1543
|
+
icon: /* @__PURE__ */ React.createElement(UploadIcon, null)
|
|
1544
|
+
}
|
|
1545
|
+
]),
|
|
1546
|
+
[]
|
|
1547
|
+
);
|
|
1548
|
+
const handleHeaderMenuAction = useCallback3(
|
|
1549
|
+
(action) => {
|
|
1550
|
+
switch (action) {
|
|
1551
|
+
case "newFile":
|
|
1552
|
+
handleAddFile();
|
|
1553
|
+
break;
|
|
1554
|
+
case "uploadFiles":
|
|
1555
|
+
uploadFiles();
|
|
1556
|
+
break;
|
|
1557
|
+
}
|
|
1558
|
+
},
|
|
1559
|
+
[handleAddFile, uploadFiles]
|
|
1560
|
+
);
|
|
1561
|
+
const handleMenuAction = useCallback3(
|
|
1562
|
+
(action, items) => {
|
|
1563
|
+
switch (action) {
|
|
1564
|
+
case "addFile":
|
|
1565
|
+
handleAddFile();
|
|
1566
|
+
break;
|
|
1567
|
+
case "rename":
|
|
1568
|
+
if (items.length === 1) {
|
|
1569
|
+
handleStartRename(items[0].id);
|
|
1570
|
+
}
|
|
1571
|
+
break;
|
|
1572
|
+
case "delete":
|
|
1573
|
+
handleDelete(items);
|
|
1574
|
+
break;
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
[handleAddFile, handleStartRename, handleDelete]
|
|
1578
|
+
);
|
|
1579
|
+
const menuItems = useMemo2(() => {
|
|
1580
|
+
const singleSelected = selectedIds.length === 1;
|
|
1581
|
+
const hasSelection = selectedIds.length > 0;
|
|
1582
|
+
const selectedItem = singleSelected ? visibleItems.find((item) => selectedIds.includes(item.id)) : void 0;
|
|
1583
|
+
const isFile = selectedItem && !selectedItem.isDirectory;
|
|
1584
|
+
return createSectionedMenu(
|
|
1585
|
+
[
|
|
1586
|
+
{
|
|
1587
|
+
title: "Add File",
|
|
1588
|
+
value: "addFile",
|
|
1589
|
+
icon: /* @__PURE__ */ React.createElement(PlusIcon, null)
|
|
1590
|
+
}
|
|
1591
|
+
],
|
|
1592
|
+
[
|
|
1593
|
+
singleSelected && isFile && {
|
|
1594
|
+
title: "Rename",
|
|
1595
|
+
value: "rename",
|
|
1596
|
+
icon: /* @__PURE__ */ React.createElement(InputIcon, null)
|
|
1597
|
+
},
|
|
1598
|
+
hasSelection && {
|
|
1599
|
+
title: "Delete",
|
|
1600
|
+
value: "delete",
|
|
1601
|
+
icon: /* @__PURE__ */ React.createElement(TrashIcon, null)
|
|
1602
|
+
}
|
|
1603
|
+
]
|
|
1604
|
+
);
|
|
1605
|
+
}, [selectedIds, visibleItems]);
|
|
1606
|
+
useImperativeHandle(ref, () => ({
|
|
1607
|
+
addFile: handleAddFile,
|
|
1608
|
+
delete: (ids) => {
|
|
1609
|
+
const items = visibleItems.filter((item) => ids.includes(item.id));
|
|
1610
|
+
handleDelete(items);
|
|
1611
|
+
},
|
|
1612
|
+
rename: (id) => {
|
|
1613
|
+
handleStartRename(id);
|
|
1614
|
+
}
|
|
1615
|
+
}));
|
|
1616
|
+
const isRefreshing = repoFilesState.fetchState === "refreshing";
|
|
1617
|
+
const isLoading = repoFilesState.fetchState === "loading";
|
|
1618
|
+
const showLoading = useDelayedTrue(isLoading, 500);
|
|
1619
|
+
const renderEmptyState = useCallback3(() => {
|
|
1620
|
+
const hasError = !!repoFilesState.error;
|
|
1621
|
+
let content = null;
|
|
1622
|
+
if (isLoading && showLoading) {
|
|
1623
|
+
content = /* @__PURE__ */ React.createElement(Small, null, "Loading files...");
|
|
1624
|
+
} else if (isLoading) {
|
|
1625
|
+
content = null;
|
|
1626
|
+
} else if (hasError) {
|
|
1627
|
+
content = /* @__PURE__ */ React.createElement(Small, null, "Error: ", repoFilesState.error);
|
|
1628
|
+
} else {
|
|
1629
|
+
content = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Small, null, "No files yet"), /* @__PURE__ */ React.createElement(Button, { onClick: handleAddFile }, "Add a file"));
|
|
1630
|
+
}
|
|
1631
|
+
return /* @__PURE__ */ React.createElement("div", { className: "n-mx-3 n-flex-1 n-flex n-flex-col n-items-center n-justify-center n-gap-2" }, content);
|
|
1632
|
+
}, [repoFilesState.error, handleAddFile, isLoading, showLoading]);
|
|
1633
|
+
return /* @__PURE__ */ React.createElement(
|
|
1634
|
+
Section,
|
|
1635
|
+
{
|
|
1636
|
+
title,
|
|
1637
|
+
className: cx("n-px-3", className),
|
|
1638
|
+
right: /* @__PURE__ */ React.createElement("div", { className: "n-flex n-items-center n-gap-1" }, isRefreshing && /* @__PURE__ */ React.createElement(Small, { color: "textDisabled" }, "Syncing..."), isUploading && /* @__PURE__ */ React.createElement(Small, { color: "textDisabled" }, "Uploading..."), /* @__PURE__ */ React.createElement(
|
|
1639
|
+
DropdownMenu,
|
|
1640
|
+
{
|
|
1641
|
+
items: headerMenuItems,
|
|
1642
|
+
onSelect: handleHeaderMenuAction
|
|
1643
|
+
},
|
|
1644
|
+
/* @__PURE__ */ React.createElement(IconButton, { iconName: "DotsVerticalIcon" })
|
|
1645
|
+
))
|
|
1646
|
+
},
|
|
1647
|
+
/* @__PURE__ */ React.createElement(
|
|
1648
|
+
"div",
|
|
1649
|
+
{
|
|
1650
|
+
ref: dropTargetRef,
|
|
1651
|
+
className: cx(
|
|
1652
|
+
"n-flex n-flex-col n-flex-1 -n-mx-3",
|
|
1653
|
+
isDropTargetActive && "n-bg-blue-500/10 n-ring-2 n-ring-blue-500 n-ring-inset"
|
|
1654
|
+
),
|
|
1655
|
+
...dropTargetProps
|
|
1656
|
+
},
|
|
1657
|
+
/* @__PURE__ */ React.createElement(
|
|
1658
|
+
List,
|
|
1659
|
+
{
|
|
1660
|
+
ref: collectionRef,
|
|
1661
|
+
className: "n-flex-1",
|
|
1662
|
+
scrollable: true,
|
|
1663
|
+
expandable: true,
|
|
1664
|
+
renamable: true,
|
|
1665
|
+
size: "small",
|
|
1666
|
+
items: visibleItems,
|
|
1667
|
+
getId: (item) => item.id,
|
|
1668
|
+
getName: (item) => isTempItem(item) ? "" : item.name,
|
|
1669
|
+
getDepth: (item) => item.depth,
|
|
1670
|
+
getExpanded,
|
|
1671
|
+
setExpanded,
|
|
1672
|
+
getRenamable: (item) => !item.isDirectory,
|
|
1673
|
+
getPlaceholder: () => "Enter file name",
|
|
1674
|
+
selectedIds,
|
|
1675
|
+
onSelectionChange: setSelectedIds,
|
|
1676
|
+
onDoubleClickItem: handleDoubleClick,
|
|
1677
|
+
onRename: handleRename,
|
|
1678
|
+
menuItems,
|
|
1679
|
+
onSelectMenuItem: handleMenuAction,
|
|
1680
|
+
renderEmptyState,
|
|
1681
|
+
renameSelectsBeforeDot: true,
|
|
1682
|
+
renderThumbnail: ({ item, selected }) => /* @__PURE__ */ React.createElement(
|
|
1683
|
+
MediaThumbnail,
|
|
1684
|
+
{
|
|
1685
|
+
iconName: item.isDirectory ? "FolderIcon" : void 0,
|
|
1686
|
+
fileName: item.isDirectory ? void 0 : item.name,
|
|
1687
|
+
selected,
|
|
1688
|
+
size: "small"
|
|
1689
|
+
}
|
|
1690
|
+
)
|
|
1691
|
+
}
|
|
1692
|
+
)
|
|
1693
|
+
)
|
|
1694
|
+
);
|
|
1695
|
+
})
|
|
1696
|
+
);
|
|
1697
|
+
var GitFileExplorer2 = memo(
|
|
1698
|
+
forwardRef(function GitFileExplorer3(props, ref) {
|
|
1699
|
+
if (!props.repoFilesState) {
|
|
1700
|
+
return /* @__PURE__ */ React.createElement(Section, { title: props.title, className: cx("n-px-3", props.className) }, null);
|
|
1701
|
+
}
|
|
1702
|
+
return /* @__PURE__ */ React.createElement(
|
|
1703
|
+
GitFileExplorerInner,
|
|
1704
|
+
{
|
|
1705
|
+
...props,
|
|
1706
|
+
repoFilesState: props.repoFilesState,
|
|
1707
|
+
ref
|
|
1708
|
+
}
|
|
1709
|
+
);
|
|
1710
|
+
})
|
|
1711
|
+
);
|
|
1712
|
+
|
|
1103
1713
|
// src/MediaCollection.tsx
|
|
1104
1714
|
import {
|
|
1105
1715
|
ActionMenu,
|
|
1106
|
-
createSectionedMenu,
|
|
1716
|
+
createSectionedMenu as createSectionedMenu2,
|
|
1107
1717
|
cssVars,
|
|
1108
1718
|
FileExplorerCollection,
|
|
1109
1719
|
FileExplorerDetail,
|
|
@@ -1111,18 +1721,18 @@ import {
|
|
|
1111
1721
|
FileExplorerLayout,
|
|
1112
1722
|
FileExplorerUploadButton,
|
|
1113
1723
|
formatByteSize,
|
|
1114
|
-
MediaThumbnail,
|
|
1115
|
-
useOpenConfirmationDialog
|
|
1724
|
+
MediaThumbnail as MediaThumbnail2,
|
|
1725
|
+
useOpenConfirmationDialog as useOpenConfirmationDialog2
|
|
1116
1726
|
} from "@noya-app/noya-designsystem";
|
|
1117
1727
|
import {
|
|
1118
1728
|
DownloadIcon,
|
|
1119
1729
|
FolderIcon,
|
|
1120
|
-
InputIcon,
|
|
1730
|
+
InputIcon as InputIcon2,
|
|
1121
1731
|
OpenInNewWindowIcon,
|
|
1122
1732
|
ResetIcon,
|
|
1123
|
-
TrashIcon,
|
|
1733
|
+
TrashIcon as TrashIcon2,
|
|
1124
1734
|
UpdateIcon,
|
|
1125
|
-
UploadIcon
|
|
1735
|
+
UploadIcon as UploadIcon2
|
|
1126
1736
|
} from "@noya-app/noya-icons";
|
|
1127
1737
|
import {
|
|
1128
1738
|
useAsset,
|
|
@@ -1135,16 +1745,16 @@ import {
|
|
|
1135
1745
|
memoGeneric,
|
|
1136
1746
|
useControlledOrUncontrolled
|
|
1137
1747
|
} from "@noya-app/react-utils";
|
|
1138
|
-
import { fileOpen } from "browser-fs-access";
|
|
1748
|
+
import { fileOpen as fileOpen2 } from "browser-fs-access";
|
|
1139
1749
|
import {
|
|
1140
|
-
forwardRef,
|
|
1141
|
-
memo,
|
|
1142
|
-
useCallback,
|
|
1143
|
-
useEffect,
|
|
1144
|
-
useImperativeHandle,
|
|
1145
|
-
useMemo,
|
|
1146
|
-
useRef,
|
|
1147
|
-
useState
|
|
1750
|
+
forwardRef as forwardRef2,
|
|
1751
|
+
memo as memo2,
|
|
1752
|
+
useCallback as useCallback4,
|
|
1753
|
+
useEffect as useEffect2,
|
|
1754
|
+
useImperativeHandle as useImperativeHandle2,
|
|
1755
|
+
useMemo as useMemo3,
|
|
1756
|
+
useRef as useRef2,
|
|
1757
|
+
useState as useState4
|
|
1148
1758
|
} from "react";
|
|
1149
1759
|
|
|
1150
1760
|
// src/utils/mediaItemTree.ts
|
|
@@ -1230,7 +1840,7 @@ var createMediaItemTree = (mediaMap) => {
|
|
|
1230
1840
|
|
|
1231
1841
|
// src/MediaCollection.tsx
|
|
1232
1842
|
import { path as path4 } from "imfs";
|
|
1233
|
-
import
|
|
1843
|
+
import React2 from "react";
|
|
1234
1844
|
|
|
1235
1845
|
// src/utils/files.ts
|
|
1236
1846
|
var import_tree_visit3 = __toESM(require_lib());
|
|
@@ -1243,7 +1853,7 @@ import {
|
|
|
1243
1853
|
rootResource
|
|
1244
1854
|
} from "@noya-app/noya-schemas";
|
|
1245
1855
|
import { path as path2 } from "imfs";
|
|
1246
|
-
var
|
|
1856
|
+
var getVisibleItems2 = ({
|
|
1247
1857
|
expandedMap,
|
|
1248
1858
|
fileKindFilter,
|
|
1249
1859
|
rootItemId,
|
|
@@ -1718,8 +2328,8 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1718
2328
|
}
|
|
1719
2329
|
const fileName = pathProp ? path4.basename(pathProp) : void 0;
|
|
1720
2330
|
const dimensions = width && height ? { width, height } : void 0;
|
|
1721
|
-
return /* @__PURE__ */
|
|
1722
|
-
|
|
2331
|
+
return /* @__PURE__ */ React2.createElement(
|
|
2332
|
+
MediaThumbnail2,
|
|
1723
2333
|
{
|
|
1724
2334
|
contentType,
|
|
1725
2335
|
iconName: isRoot ? "HomeIcon" : isFolder ? "FolderIcon" : void 0,
|
|
@@ -1733,8 +2343,8 @@ var MediaThumbnailInternal = memoGeneric(
|
|
|
1733
2343
|
);
|
|
1734
2344
|
}
|
|
1735
2345
|
);
|
|
1736
|
-
var MediaCollection =
|
|
1737
|
-
|
|
2346
|
+
var MediaCollection = memo2(
|
|
2347
|
+
forwardRef2(function MediaCollection2({
|
|
1738
2348
|
sortableId,
|
|
1739
2349
|
onSelectionChange,
|
|
1740
2350
|
selectedIds: selectedIdsProp,
|
|
@@ -1765,28 +2375,28 @@ var MediaCollection = memo(
|
|
|
1765
2375
|
onDidDeleteItems,
|
|
1766
2376
|
onAssetsUploaded
|
|
1767
2377
|
}, ref) {
|
|
1768
|
-
const setMedia =
|
|
2378
|
+
const setMedia = useCallback4(
|
|
1769
2379
|
(...args) => {
|
|
1770
2380
|
setMediaProp?.(...args);
|
|
1771
2381
|
},
|
|
1772
2382
|
[setMediaProp]
|
|
1773
2383
|
);
|
|
1774
|
-
const tree =
|
|
1775
|
-
const [tempItem, setTempItem] =
|
|
2384
|
+
const tree = useMemo3(() => createMediaItemTree(media), [media]);
|
|
2385
|
+
const [tempItem, setTempItem] = useState4(
|
|
1776
2386
|
void 0
|
|
1777
2387
|
);
|
|
1778
|
-
const mediaWithTempItem =
|
|
2388
|
+
const mediaWithTempItem = useMemo3(
|
|
1779
2389
|
() => ({
|
|
1780
2390
|
...media,
|
|
1781
2391
|
...tempItem ? { [tempItem[0]]: tempItem[1] } : {}
|
|
1782
2392
|
}),
|
|
1783
2393
|
[media, tempItem]
|
|
1784
2394
|
);
|
|
1785
|
-
const treeWithTempItem =
|
|
2395
|
+
const treeWithTempItem = useMemo3(
|
|
1786
2396
|
() => createMediaItemTree(mediaWithTempItem),
|
|
1787
2397
|
[mediaWithTempItem]
|
|
1788
2398
|
);
|
|
1789
|
-
const temp =
|
|
2399
|
+
const temp = useMemo3(
|
|
1790
2400
|
() => ({
|
|
1791
2401
|
media: mediaWithTempItem,
|
|
1792
2402
|
tree: treeWithTempItem
|
|
@@ -1802,8 +2412,8 @@ var MediaCollection = memo(
|
|
|
1802
2412
|
);
|
|
1803
2413
|
const assetManager = useAssetManager();
|
|
1804
2414
|
const assets = useAssets();
|
|
1805
|
-
const [expandedMap, setExpandedMap] =
|
|
1806
|
-
const visibleItems =
|
|
2415
|
+
const [expandedMap, setExpandedMap] = useState4({});
|
|
2416
|
+
const visibleItems = useMemo3(
|
|
1807
2417
|
() => mediaGetVisibleItems({
|
|
1808
2418
|
expandedMap,
|
|
1809
2419
|
fileKindFilter,
|
|
@@ -1821,12 +2431,12 @@ var MediaCollection = memo(
|
|
|
1821
2431
|
showRootItem
|
|
1822
2432
|
]
|
|
1823
2433
|
);
|
|
1824
|
-
const depthMap =
|
|
2434
|
+
const depthMap = useMemo3(
|
|
1825
2435
|
() => mediaGetDepthMap(rootMediaItem, treeWithTempItem, showAllDescendants),
|
|
1826
2436
|
[treeWithTempItem, showAllDescendants]
|
|
1827
2437
|
);
|
|
1828
|
-
const collectionRef =
|
|
1829
|
-
const selectedMediaItems =
|
|
2438
|
+
const collectionRef = useRef2(null);
|
|
2439
|
+
const selectedMediaItems = useMemo3(
|
|
1830
2440
|
() => treeWithTempItem.mediaItemsWithRoot.filter(
|
|
1831
2441
|
(item) => selectedIds.includes(item.id)
|
|
1832
2442
|
),
|
|
@@ -1847,12 +2457,12 @@ var MediaCollection = memo(
|
|
|
1847
2457
|
if (!itemPath || !firstSelectedPath) return false;
|
|
1848
2458
|
return itemPath.startsWith(path4.dirname(firstSelectedPath));
|
|
1849
2459
|
});
|
|
1850
|
-
|
|
2460
|
+
useEffect2(() => {
|
|
1851
2461
|
if (initialExpanded) {
|
|
1852
2462
|
setExpandedMap(initialExpanded);
|
|
1853
2463
|
}
|
|
1854
2464
|
}, [initialExpanded]);
|
|
1855
|
-
const getExpanded =
|
|
2465
|
+
const getExpanded = useCallback4(
|
|
1856
2466
|
(item) => {
|
|
1857
2467
|
if (!expandable) return void 0;
|
|
1858
2468
|
if (item.kind !== "folder") return void 0;
|
|
@@ -1861,8 +2471,8 @@ var MediaCollection = memo(
|
|
|
1861
2471
|
},
|
|
1862
2472
|
[expandedMap, expandable]
|
|
1863
2473
|
);
|
|
1864
|
-
const openConfirmationDialog =
|
|
1865
|
-
const handleDelete =
|
|
2474
|
+
const openConfirmationDialog = useOpenConfirmationDialog2();
|
|
2475
|
+
const handleDelete = useCallback4(
|
|
1866
2476
|
async (selectedIds2) => {
|
|
1867
2477
|
const ok = await openConfirmationDialog({
|
|
1868
2478
|
title: "Delete items",
|
|
@@ -1895,7 +2505,7 @@ var MediaCollection = memo(
|
|
|
1895
2505
|
openConfirmationDialog
|
|
1896
2506
|
]
|
|
1897
2507
|
);
|
|
1898
|
-
const onRename =
|
|
2508
|
+
const onRename = useCallback4(
|
|
1899
2509
|
(selectedItem, newName) => {
|
|
1900
2510
|
if (!renamable) return;
|
|
1901
2511
|
const selectedItemPath = treeWithTempItem.idToPathMap.get(
|
|
@@ -1925,7 +2535,7 @@ var MediaCollection = memo(
|
|
|
1925
2535
|
},
|
|
1926
2536
|
[renamable, setMedia, temp.media, temp.tree, treeWithTempItem.idToPathMap]
|
|
1927
2537
|
);
|
|
1928
|
-
const handleAddFolder =
|
|
2538
|
+
const handleAddFolder = useCallback4(
|
|
1929
2539
|
(currentFolderId) => {
|
|
1930
2540
|
const newFolder = createMediaFolder();
|
|
1931
2541
|
const currentFolderPath = tree.idToPathMap.get(currentFolderId);
|
|
@@ -1940,7 +2550,7 @@ var MediaCollection = memo(
|
|
|
1940
2550
|
},
|
|
1941
2551
|
[tree]
|
|
1942
2552
|
);
|
|
1943
|
-
const handleAddFile =
|
|
2553
|
+
const handleAddFile = useCallback4(
|
|
1944
2554
|
(currentFolderId) => {
|
|
1945
2555
|
const newFile = createMediaFile({
|
|
1946
2556
|
content: "",
|
|
@@ -1960,7 +2570,7 @@ var MediaCollection = memo(
|
|
|
1960
2570
|
},
|
|
1961
2571
|
[tree.idToPathMap]
|
|
1962
2572
|
);
|
|
1963
|
-
const handleMoveUpAFolder =
|
|
2573
|
+
const handleMoveUpAFolder = useCallback4(
|
|
1964
2574
|
(selectedIds2) => {
|
|
1965
2575
|
const newMedia = mediaMoveUpAFolder({
|
|
1966
2576
|
tree,
|
|
@@ -1972,11 +2582,11 @@ var MediaCollection = memo(
|
|
|
1972
2582
|
},
|
|
1973
2583
|
[media, tree, setMedia]
|
|
1974
2584
|
);
|
|
1975
|
-
const [isUploading, setIsUploading] =
|
|
1976
|
-
const handleUpload =
|
|
2585
|
+
const [isUploading, setIsUploading] = useState4(false);
|
|
2586
|
+
const handleUpload = useCallback4(
|
|
1977
2587
|
async (selectedId) => {
|
|
1978
2588
|
try {
|
|
1979
|
-
const files = await
|
|
2589
|
+
const files = await fileOpen2({ multiple: true });
|
|
1980
2590
|
if (!files || !Array.isArray(files) || files.length === 0) return;
|
|
1981
2591
|
const parentPath = tree.idToPathMap.get(selectedId);
|
|
1982
2592
|
if (!parentPath) return;
|
|
@@ -2013,7 +2623,7 @@ var MediaCollection = memo(
|
|
|
2013
2623
|
},
|
|
2014
2624
|
[tree.idToPathMap, setMedia, media, assetManager, onAssetsUploaded]
|
|
2015
2625
|
);
|
|
2016
|
-
const handleDownload =
|
|
2626
|
+
const handleDownload = useCallback4(
|
|
2017
2627
|
async (selectedItems) => {
|
|
2018
2628
|
const downloadPromises = selectedItems.filter((item) => item.kind === "asset").map(async (item) => {
|
|
2019
2629
|
const asset = assets.find((a) => a.stableId === item.assetId) ?? assets.find((a) => a.id === item.assetId);
|
|
@@ -2024,7 +2634,7 @@ var MediaCollection = memo(
|
|
|
2024
2634
|
},
|
|
2025
2635
|
[assets, tree]
|
|
2026
2636
|
);
|
|
2027
|
-
const handlePreview =
|
|
2637
|
+
const handlePreview = useCallback4(
|
|
2028
2638
|
async (selectedItems) => {
|
|
2029
2639
|
const previewPromises = selectedItems.filter((item) => item.kind === "asset").map(async (item) => {
|
|
2030
2640
|
const asset = assets.find((a) => a.stableId === item.assetId) ?? assets.find((a) => a.id === item.assetId);
|
|
@@ -2035,10 +2645,10 @@ var MediaCollection = memo(
|
|
|
2035
2645
|
},
|
|
2036
2646
|
[assets]
|
|
2037
2647
|
);
|
|
2038
|
-
const handleReplace =
|
|
2648
|
+
const handleReplace = useCallback4(
|
|
2039
2649
|
async (selectedItem) => {
|
|
2040
2650
|
try {
|
|
2041
|
-
const file = await
|
|
2651
|
+
const file = await fileOpen2();
|
|
2042
2652
|
if (!file) return;
|
|
2043
2653
|
const created = await assetManager.create(file);
|
|
2044
2654
|
const assetStableId = created.id;
|
|
@@ -2064,13 +2674,13 @@ var MediaCollection = memo(
|
|
|
2064
2674
|
},
|
|
2065
2675
|
[media, setMedia, assetManager, tree]
|
|
2066
2676
|
);
|
|
2067
|
-
const handleRename =
|
|
2677
|
+
const handleRename = useCallback4(
|
|
2068
2678
|
(selectedItemId) => {
|
|
2069
2679
|
collectionRef.current?.editName(selectedItemId);
|
|
2070
2680
|
},
|
|
2071
2681
|
[collectionRef]
|
|
2072
2682
|
);
|
|
2073
|
-
const handleMoveMediaInsideFolder =
|
|
2683
|
+
const handleMoveMediaInsideFolder = useCallback4(
|
|
2074
2684
|
(sourceItem, targetItem) => {
|
|
2075
2685
|
const newMedia = mediaMoveMediaInsideFolder({
|
|
2076
2686
|
sourceItemIds: [sourceItem.id],
|
|
@@ -2088,52 +2698,52 @@ var MediaCollection = memo(
|
|
|
2088
2698
|
},
|
|
2089
2699
|
[media, setMedia, tree]
|
|
2090
2700
|
);
|
|
2091
|
-
const assetContextMenuItems =
|
|
2092
|
-
return
|
|
2701
|
+
const assetContextMenuItems = useMemo3(() => {
|
|
2702
|
+
return createSectionedMenu2(
|
|
2093
2703
|
[
|
|
2094
2704
|
!rootSelected && singleItemSelected && {
|
|
2095
2705
|
title: "Rename",
|
|
2096
2706
|
value: "rename",
|
|
2097
|
-
icon: /* @__PURE__ */
|
|
2707
|
+
icon: /* @__PURE__ */ React2.createElement(InputIcon2, null)
|
|
2098
2708
|
},
|
|
2099
2709
|
onlySingleAssetSelected && {
|
|
2100
2710
|
title: "Replace",
|
|
2101
2711
|
value: "replace",
|
|
2102
|
-
icon: /* @__PURE__ */
|
|
2712
|
+
icon: /* @__PURE__ */ React2.createElement(UpdateIcon, null)
|
|
2103
2713
|
},
|
|
2104
2714
|
!rootSelected && {
|
|
2105
2715
|
title: "Delete",
|
|
2106
2716
|
value: "delete",
|
|
2107
|
-
icon: /* @__PURE__ */
|
|
2717
|
+
icon: /* @__PURE__ */ React2.createElement(TrashIcon2, null)
|
|
2108
2718
|
}
|
|
2109
2719
|
],
|
|
2110
2720
|
[
|
|
2111
2721
|
onlySingleFolderSelected && {
|
|
2112
2722
|
title: "Upload Files",
|
|
2113
2723
|
value: "upload",
|
|
2114
|
-
icon: /* @__PURE__ */
|
|
2724
|
+
icon: /* @__PURE__ */ React2.createElement(UploadIcon2, null)
|
|
2115
2725
|
},
|
|
2116
2726
|
onlySingleFolderSelected && {
|
|
2117
2727
|
title: "Add Folder",
|
|
2118
2728
|
value: "addFolder",
|
|
2119
|
-
icon: /* @__PURE__ */
|
|
2729
|
+
icon: /* @__PURE__ */ React2.createElement(FolderIcon, null)
|
|
2120
2730
|
},
|
|
2121
2731
|
onlyAssetsSelected && tree.mediaItemsWithRoot.length > 0 && {
|
|
2122
2732
|
title: "Download",
|
|
2123
2733
|
value: "download",
|
|
2124
|
-
icon: /* @__PURE__ */
|
|
2734
|
+
icon: /* @__PURE__ */ React2.createElement(DownloadIcon, null)
|
|
2125
2735
|
},
|
|
2126
2736
|
onlySingleAssetSelected && {
|
|
2127
2737
|
title: "Preview",
|
|
2128
2738
|
value: "preview",
|
|
2129
|
-
icon: /* @__PURE__ */
|
|
2739
|
+
icon: /* @__PURE__ */ React2.createElement(OpenInNewWindowIcon, null)
|
|
2130
2740
|
}
|
|
2131
2741
|
],
|
|
2132
2742
|
[
|
|
2133
2743
|
!rootSelected && sameParentSelected && {
|
|
2134
2744
|
title: "Move up a folder",
|
|
2135
2745
|
value: "move",
|
|
2136
|
-
icon: /* @__PURE__ */
|
|
2746
|
+
icon: /* @__PURE__ */ React2.createElement(ResetIcon, null)
|
|
2137
2747
|
}
|
|
2138
2748
|
]
|
|
2139
2749
|
);
|
|
@@ -2146,7 +2756,7 @@ var MediaCollection = memo(
|
|
|
2146
2756
|
tree.mediaItemsWithRoot.length,
|
|
2147
2757
|
sameParentSelected
|
|
2148
2758
|
]);
|
|
2149
|
-
const handleMenuAction =
|
|
2759
|
+
const handleMenuAction = useCallback4(
|
|
2150
2760
|
async (action, selectedItems) => {
|
|
2151
2761
|
if (selectedItems.length === 0) return;
|
|
2152
2762
|
switch (action) {
|
|
@@ -2188,7 +2798,7 @@ var MediaCollection = memo(
|
|
|
2188
2798
|
handleMoveUpAFolder
|
|
2189
2799
|
]
|
|
2190
2800
|
);
|
|
2191
|
-
const handleSetExpanded =
|
|
2801
|
+
const handleSetExpanded = useCallback4(
|
|
2192
2802
|
(item, expanded) => {
|
|
2193
2803
|
setExpandedMap(
|
|
2194
2804
|
(prev) => mediaUpdateExpandedMap({
|
|
@@ -2202,12 +2812,12 @@ var MediaCollection = memo(
|
|
|
2202
2812
|
},
|
|
2203
2813
|
[expandable, tree]
|
|
2204
2814
|
);
|
|
2205
|
-
const renderAction =
|
|
2815
|
+
const renderAction = useMemo3(() => {
|
|
2206
2816
|
if (renderActionProp) return renderActionProp;
|
|
2207
2817
|
return ({
|
|
2208
2818
|
selected,
|
|
2209
2819
|
onOpenChange
|
|
2210
|
-
}) => /* @__PURE__ */
|
|
2820
|
+
}) => /* @__PURE__ */ React2.createElement(
|
|
2211
2821
|
ActionMenu,
|
|
2212
2822
|
{
|
|
2213
2823
|
menuItems: assetContextMenuItems,
|
|
@@ -2228,7 +2838,7 @@ var MediaCollection = memo(
|
|
|
2228
2838
|
selectedMediaItems,
|
|
2229
2839
|
viewType
|
|
2230
2840
|
]);
|
|
2231
|
-
|
|
2841
|
+
useImperativeHandle2(ref, () => ({
|
|
2232
2842
|
upload: (selectedId) => handleUpload(selectedId),
|
|
2233
2843
|
delete: handleDelete,
|
|
2234
2844
|
download: handleDownload,
|
|
@@ -2241,11 +2851,11 @@ var MediaCollection = memo(
|
|
|
2241
2851
|
moveMediaInsideFolder: handleMoveMediaInsideFolder,
|
|
2242
2852
|
getItemAtIndex: (index) => visibleItems[index]
|
|
2243
2853
|
}));
|
|
2244
|
-
return /* @__PURE__ */
|
|
2854
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
|
|
2245
2855
|
FileExplorerLayout,
|
|
2246
2856
|
{
|
|
2247
2857
|
title: title ?? rootMediaItemName,
|
|
2248
|
-
right: !readOnly && /* @__PURE__ */
|
|
2858
|
+
right: !readOnly && /* @__PURE__ */ React2.createElement(
|
|
2249
2859
|
FileExplorerUploadButton,
|
|
2250
2860
|
{
|
|
2251
2861
|
showUploadButton,
|
|
@@ -2256,7 +2866,7 @@ var MediaCollection = memo(
|
|
|
2256
2866
|
),
|
|
2257
2867
|
className
|
|
2258
2868
|
},
|
|
2259
|
-
/* @__PURE__ */
|
|
2869
|
+
/* @__PURE__ */ React2.createElement(
|
|
2260
2870
|
FileExplorerCollection,
|
|
2261
2871
|
{
|
|
2262
2872
|
ref: collectionRef,
|
|
@@ -2300,7 +2910,7 @@ var MediaCollection = memo(
|
|
|
2300
2910
|
onRename,
|
|
2301
2911
|
renamable,
|
|
2302
2912
|
selectedIds,
|
|
2303
|
-
renderThumbnail: (props) => /* @__PURE__ */
|
|
2913
|
+
renderThumbnail: (props) => /* @__PURE__ */ React2.createElement(
|
|
2304
2914
|
MediaThumbnailInternal,
|
|
2305
2915
|
{
|
|
2306
2916
|
...props,
|
|
@@ -2313,9 +2923,9 @@ var MediaCollection = memo(
|
|
|
2313
2923
|
if (file.kind !== "asset") return null;
|
|
2314
2924
|
const asset = assets.find((a) => a.stableId === file.assetId) ?? assets.find((a) => a.id === file.assetId);
|
|
2315
2925
|
if (!asset) return null;
|
|
2316
|
-
return /* @__PURE__ */
|
|
2926
|
+
return /* @__PURE__ */ React2.createElement(FileExplorerDetail, { selected, size }, formatByteSize(asset.size));
|
|
2317
2927
|
},
|
|
2318
|
-
renderEmptyState: () => renderEmptyState?.() ?? /* @__PURE__ */
|
|
2928
|
+
renderEmptyState: () => renderEmptyState?.() ?? /* @__PURE__ */ React2.createElement(FileExplorerEmptyState, null),
|
|
2319
2929
|
itemRoleDescription: "clickable file item",
|
|
2320
2930
|
getDropTargetParentIndex: (overIndex) => {
|
|
2321
2931
|
const item = visibleItems[overIndex];
|
|
@@ -2391,7 +3001,7 @@ function acceptsMediaItemDrop(parameters) {
|
|
|
2391
3001
|
import {
|
|
2392
3002
|
ActionMenu as ActionMenu2,
|
|
2393
3003
|
Chip,
|
|
2394
|
-
createSectionedMenu as
|
|
3004
|
+
createSectionedMenu as createSectionedMenu3,
|
|
2395
3005
|
cssVars as cssVars2,
|
|
2396
3006
|
FileExplorerCollection as FileExplorerCollection2,
|
|
2397
3007
|
FileExplorerDetail as FileExplorerDetail2,
|
|
@@ -2399,18 +3009,18 @@ import {
|
|
|
2399
3009
|
FileExplorerLayout as FileExplorerLayout2,
|
|
2400
3010
|
FileExplorerUploadButton as FileExplorerUploadButton2,
|
|
2401
3011
|
formatByteSize as formatByteSize2,
|
|
2402
|
-
MediaThumbnail as
|
|
2403
|
-
useOpenConfirmationDialog as
|
|
3012
|
+
MediaThumbnail as MediaThumbnail3,
|
|
3013
|
+
useOpenConfirmationDialog as useOpenConfirmationDialog3
|
|
2404
3014
|
} from "@noya-app/noya-designsystem";
|
|
2405
3015
|
import {
|
|
2406
3016
|
DownloadIcon as DownloadIcon2,
|
|
2407
3017
|
FolderIcon as FolderIcon2,
|
|
2408
|
-
InputIcon as
|
|
3018
|
+
InputIcon as InputIcon3,
|
|
2409
3019
|
OpenInNewWindowIcon as OpenInNewWindowIcon2,
|
|
2410
3020
|
ResetIcon as ResetIcon2,
|
|
2411
|
-
TrashIcon as
|
|
3021
|
+
TrashIcon as TrashIcon3,
|
|
2412
3022
|
UpdateIcon as UpdateIcon2,
|
|
2413
|
-
UploadIcon as
|
|
3023
|
+
UploadIcon as UploadIcon3
|
|
2414
3024
|
} from "@noya-app/noya-icons";
|
|
2415
3025
|
import {
|
|
2416
3026
|
useAsset as useAsset2,
|
|
@@ -2433,19 +3043,19 @@ import {
|
|
|
2433
3043
|
SingleDimensionAutoSizer,
|
|
2434
3044
|
useControlledOrUncontrolled as useControlledOrUncontrolled2
|
|
2435
3045
|
} from "@noya-app/react-utils";
|
|
2436
|
-
import { fileOpen as
|
|
3046
|
+
import { fileOpen as fileOpen3 } from "browser-fs-access";
|
|
2437
3047
|
import {
|
|
2438
|
-
forwardRef as
|
|
2439
|
-
memo as
|
|
2440
|
-
useCallback as
|
|
2441
|
-
useEffect as
|
|
2442
|
-
useImperativeHandle as
|
|
2443
|
-
useMemo as
|
|
2444
|
-
useRef as
|
|
2445
|
-
useState as
|
|
3048
|
+
forwardRef as forwardRef3,
|
|
3049
|
+
memo as memo3,
|
|
3050
|
+
useCallback as useCallback5,
|
|
3051
|
+
useEffect as useEffect3,
|
|
3052
|
+
useImperativeHandle as useImperativeHandle3,
|
|
3053
|
+
useMemo as useMemo4,
|
|
3054
|
+
useRef as useRef3,
|
|
3055
|
+
useState as useState5
|
|
2446
3056
|
} from "react";
|
|
2447
3057
|
import { path as path6 } from "imfs";
|
|
2448
|
-
import
|
|
3058
|
+
import React3 from "react";
|
|
2449
3059
|
|
|
2450
3060
|
// src/utils/contentType.ts
|
|
2451
3061
|
function getContentTypeFromFile(file) {
|
|
@@ -2529,13 +3139,8 @@ import {
|
|
|
2529
3139
|
createDirectoryResource
|
|
2530
3140
|
} from "@noya-app/noya-schemas";
|
|
2531
3141
|
import { Base64, uuid as uuid2 } from "@noya-app/noya-utils";
|
|
3142
|
+
import { collectDroppedFiles as collectDroppedFiles2 } from "@noya-app/react-utils";
|
|
2532
3143
|
import { path as path5 } from "imfs";
|
|
2533
|
-
function isDirectoryEntry(entry) {
|
|
2534
|
-
return entry.isDirectory;
|
|
2535
|
-
}
|
|
2536
|
-
function isFileEntry(entry) {
|
|
2537
|
-
return entry.isFile;
|
|
2538
|
-
}
|
|
2539
3144
|
async function handleDataTransfer({
|
|
2540
3145
|
accessibleByFileId,
|
|
2541
3146
|
dataTransfer,
|
|
@@ -2543,66 +3148,7 @@ async function handleDataTransfer({
|
|
|
2543
3148
|
resourceMap
|
|
2544
3149
|
}) {
|
|
2545
3150
|
try {
|
|
2546
|
-
const
|
|
2547
|
-
const supportsEntries = dataTransferItems.some(
|
|
2548
|
-
(item) => typeof item?.webkitGetAsEntry === "function"
|
|
2549
|
-
);
|
|
2550
|
-
const collectFromEntry = async (entry, basePath) => {
|
|
2551
|
-
if (!entry) return [];
|
|
2552
|
-
if (isFileEntry(entry)) {
|
|
2553
|
-
const file = await new Promise(
|
|
2554
|
-
(resolve) => entry.file((f) => resolve(f))
|
|
2555
|
-
);
|
|
2556
|
-
return [
|
|
2557
|
-
{
|
|
2558
|
-
file,
|
|
2559
|
-
relativePath: path5.join(basePath, file.name)
|
|
2560
|
-
}
|
|
2561
|
-
];
|
|
2562
|
-
}
|
|
2563
|
-
if (isDirectoryEntry(entry)) {
|
|
2564
|
-
const reader = entry.createReader();
|
|
2565
|
-
const readAll = async () => {
|
|
2566
|
-
const all = [];
|
|
2567
|
-
while (true) {
|
|
2568
|
-
const entries = await new Promise(
|
|
2569
|
-
(resolve) => reader.readEntries((ents) => resolve(ents))
|
|
2570
|
-
);
|
|
2571
|
-
if (!entries.length) break;
|
|
2572
|
-
all.push(...entries);
|
|
2573
|
-
}
|
|
2574
|
-
return all;
|
|
2575
|
-
};
|
|
2576
|
-
const children = await readAll();
|
|
2577
|
-
const results = await Promise.all(
|
|
2578
|
-
children.map(
|
|
2579
|
-
(child) => collectFromEntry(child, path5.join(basePath, entry.name))
|
|
2580
|
-
)
|
|
2581
|
-
);
|
|
2582
|
-
return results.flat();
|
|
2583
|
-
}
|
|
2584
|
-
return [];
|
|
2585
|
-
};
|
|
2586
|
-
let dropped = [];
|
|
2587
|
-
if (supportsEntries) {
|
|
2588
|
-
const topLevelEntries = dataTransferItems.flatMap((item) => {
|
|
2589
|
-
const entry = item.webkitGetAsEntry?.();
|
|
2590
|
-
if (!entry) return [];
|
|
2591
|
-
return [entry];
|
|
2592
|
-
});
|
|
2593
|
-
const nested = await Promise.all(
|
|
2594
|
-
topLevelEntries.map((entry) => collectFromEntry(entry, ""))
|
|
2595
|
-
);
|
|
2596
|
-
dropped = nested.flat();
|
|
2597
|
-
} else {
|
|
2598
|
-
const files = Array.from(dataTransfer.files);
|
|
2599
|
-
if (files.length === 0) return;
|
|
2600
|
-
dropped = files.map((file) => ({
|
|
2601
|
-
file,
|
|
2602
|
-
// Best effort: try webkitRelativePath; fall back to name
|
|
2603
|
-
relativePath: file.webkitRelativePath && file.webkitRelativePath.length > 0 ? file.webkitRelativePath : file.name
|
|
2604
|
-
}));
|
|
2605
|
-
}
|
|
3151
|
+
const dropped = await collectDroppedFiles2(dataTransfer);
|
|
2606
3152
|
if (dropped.length === 0) return;
|
|
2607
3153
|
const folderRelativePaths = /* @__PURE__ */ new Set();
|
|
2608
3154
|
for (const { relativePath } of dropped) {
|
|
@@ -2684,8 +3230,8 @@ var ResourceThumbnail = memoGeneric2(
|
|
|
2684
3230
|
contentType = contentTypeProp;
|
|
2685
3231
|
}
|
|
2686
3232
|
const fileName = pathProp ? path6.basename(pathProp) : void 0;
|
|
2687
|
-
return /* @__PURE__ */
|
|
2688
|
-
|
|
3233
|
+
return /* @__PURE__ */ React3.createElement(
|
|
3234
|
+
MediaThumbnail3,
|
|
2689
3235
|
{
|
|
2690
3236
|
contentType,
|
|
2691
3237
|
iconName: isRoot ? "HomeIcon" : isFolder ? "FolderIcon" : void 0,
|
|
@@ -2700,8 +3246,8 @@ var ResourceThumbnail = memoGeneric2(
|
|
|
2700
3246
|
);
|
|
2701
3247
|
}
|
|
2702
3248
|
);
|
|
2703
|
-
var ResourceExplorer =
|
|
2704
|
-
|
|
3249
|
+
var ResourceExplorer = memo3(
|
|
3250
|
+
forwardRef3(
|
|
2705
3251
|
function ResourceExplorer2({
|
|
2706
3252
|
parentFileId,
|
|
2707
3253
|
sortableId,
|
|
@@ -2740,28 +3286,28 @@ var ResourceExplorer = memo2(
|
|
|
2740
3286
|
renderUser,
|
|
2741
3287
|
showFileSizes = true
|
|
2742
3288
|
}, ref) {
|
|
2743
|
-
const setMedia =
|
|
3289
|
+
const setMedia = useCallback5(
|
|
2744
3290
|
(...args) => {
|
|
2745
3291
|
setMediaProp?.(...args);
|
|
2746
3292
|
},
|
|
2747
3293
|
[setMediaProp]
|
|
2748
3294
|
);
|
|
2749
|
-
const tree =
|
|
2750
|
-
const [tempItem, setTempItem] =
|
|
3295
|
+
const tree = useMemo4(() => createResourceTree2(media), [media]);
|
|
3296
|
+
const [tempItem, setTempItem] = useState5(
|
|
2751
3297
|
void 0
|
|
2752
3298
|
);
|
|
2753
|
-
const mediaWithTempItem =
|
|
3299
|
+
const mediaWithTempItem = useMemo4(
|
|
2754
3300
|
() => ({
|
|
2755
3301
|
...media,
|
|
2756
3302
|
...tempItem ? { [tempItem[0]]: tempItem[1] } : {}
|
|
2757
3303
|
}),
|
|
2758
3304
|
[media, tempItem]
|
|
2759
3305
|
);
|
|
2760
|
-
const treeWithTempItem =
|
|
3306
|
+
const treeWithTempItem = useMemo4(
|
|
2761
3307
|
() => createResourceTree2(mediaWithTempItem),
|
|
2762
3308
|
[mediaWithTempItem]
|
|
2763
3309
|
);
|
|
2764
|
-
const temp =
|
|
3310
|
+
const temp = useMemo4(
|
|
2765
3311
|
() => ({
|
|
2766
3312
|
media: mediaWithTempItem,
|
|
2767
3313
|
tree: treeWithTempItem
|
|
@@ -2775,9 +3321,9 @@ var ResourceExplorer = memo2(
|
|
|
2775
3321
|
});
|
|
2776
3322
|
const assetManager = useAssetManager2();
|
|
2777
3323
|
const assets = useAssets2();
|
|
2778
|
-
const [expandedMap, setExpandedMap] =
|
|
2779
|
-
const visibleItems =
|
|
2780
|
-
() =>
|
|
3324
|
+
const [expandedMap, setExpandedMap] = useState5({});
|
|
3325
|
+
const visibleItems = useMemo4(
|
|
3326
|
+
() => getVisibleItems2({
|
|
2781
3327
|
expandedMap,
|
|
2782
3328
|
fileKindFilter,
|
|
2783
3329
|
rootItemId,
|
|
@@ -2794,12 +3340,12 @@ var ResourceExplorer = memo2(
|
|
|
2794
3340
|
showRootItem
|
|
2795
3341
|
]
|
|
2796
3342
|
);
|
|
2797
|
-
const depthMap =
|
|
3343
|
+
const depthMap = useMemo4(
|
|
2798
3344
|
() => getDepthMap(rootResource2, treeWithTempItem, showAllDescendants),
|
|
2799
3345
|
[treeWithTempItem, showAllDescendants]
|
|
2800
3346
|
);
|
|
2801
|
-
const collectionRef =
|
|
2802
|
-
const selectedResources =
|
|
3347
|
+
const collectionRef = useRef3(null);
|
|
3348
|
+
const selectedResources = useMemo4(
|
|
2803
3349
|
() => treeWithTempItem.resourcesWithRoot.filter(
|
|
2804
3350
|
(item) => selectedIds.includes(item.id)
|
|
2805
3351
|
),
|
|
@@ -2820,12 +3366,12 @@ var ResourceExplorer = memo2(
|
|
|
2820
3366
|
if (!itemPath || !firstSelectedPath) return false;
|
|
2821
3367
|
return itemPath.startsWith(path6.dirname(firstSelectedPath));
|
|
2822
3368
|
});
|
|
2823
|
-
|
|
3369
|
+
useEffect3(() => {
|
|
2824
3370
|
if (initialExpanded) {
|
|
2825
3371
|
setExpandedMap(initialExpanded);
|
|
2826
3372
|
}
|
|
2827
3373
|
}, [initialExpanded]);
|
|
2828
|
-
const getExpanded =
|
|
3374
|
+
const getExpanded = useCallback5(
|
|
2829
3375
|
(item) => {
|
|
2830
3376
|
if (!expandable) return void 0;
|
|
2831
3377
|
if (item.type !== "directory") return void 0;
|
|
@@ -2834,8 +3380,8 @@ var ResourceExplorer = memo2(
|
|
|
2834
3380
|
},
|
|
2835
3381
|
[expandedMap, expandable]
|
|
2836
3382
|
);
|
|
2837
|
-
const openConfirmationDialog =
|
|
2838
|
-
const handleDelete =
|
|
3383
|
+
const openConfirmationDialog = useOpenConfirmationDialog3();
|
|
3384
|
+
const handleDelete = useCallback5(
|
|
2839
3385
|
async (selectedIds2) => {
|
|
2840
3386
|
const ok = await openConfirmationDialog({
|
|
2841
3387
|
title: "Delete items",
|
|
@@ -2868,7 +3414,7 @@ var ResourceExplorer = memo2(
|
|
|
2868
3414
|
openConfirmationDialog
|
|
2869
3415
|
]
|
|
2870
3416
|
);
|
|
2871
|
-
const onRename =
|
|
3417
|
+
const onRename = useCallback5(
|
|
2872
3418
|
(selectedItem, newName) => {
|
|
2873
3419
|
if (!renamable) return;
|
|
2874
3420
|
const selectedItemPath = treeWithTempItem.idToPathMap.get(
|
|
@@ -2904,7 +3450,7 @@ var ResourceExplorer = memo2(
|
|
|
2904
3450
|
treeWithTempItem.idToPathMap
|
|
2905
3451
|
]
|
|
2906
3452
|
);
|
|
2907
|
-
const handleAddFolder =
|
|
3453
|
+
const handleAddFolder = useCallback5(
|
|
2908
3454
|
(currentFolderId) => {
|
|
2909
3455
|
const currentFolderPath = tree.idToPathMap.get(currentFolderId);
|
|
2910
3456
|
if (!currentFolderPath) return;
|
|
@@ -2925,7 +3471,7 @@ var ResourceExplorer = memo2(
|
|
|
2925
3471
|
},
|
|
2926
3472
|
[parentFileId, tree]
|
|
2927
3473
|
);
|
|
2928
|
-
const handleMoveUpAFolder =
|
|
3474
|
+
const handleMoveUpAFolder = useCallback5(
|
|
2929
3475
|
(selectedIds2) => {
|
|
2930
3476
|
const newMedia = moveUpAFolder({
|
|
2931
3477
|
tree,
|
|
@@ -2937,11 +3483,11 @@ var ResourceExplorer = memo2(
|
|
|
2937
3483
|
},
|
|
2938
3484
|
[media, tree, setMedia]
|
|
2939
3485
|
);
|
|
2940
|
-
const [isUploading, setIsUploading] =
|
|
2941
|
-
const handleUpload =
|
|
3486
|
+
const [isUploading, setIsUploading] = useState5(false);
|
|
3487
|
+
const handleUpload = useCallback5(
|
|
2942
3488
|
async (selectedId) => {
|
|
2943
3489
|
try {
|
|
2944
|
-
const files = await
|
|
3490
|
+
const files = await fileOpen3({ multiple: true });
|
|
2945
3491
|
if (!files || !Array.isArray(files) || files.length === 0) return;
|
|
2946
3492
|
const parentPath = tree.idToPathMap.get(selectedId);
|
|
2947
3493
|
if (!parentPath) return;
|
|
@@ -2986,7 +3532,7 @@ var ResourceExplorer = memo2(
|
|
|
2986
3532
|
},
|
|
2987
3533
|
[tree, setMedia, media, onAssetsUploaded, parentFileId]
|
|
2988
3534
|
);
|
|
2989
|
-
const handleDownload =
|
|
3535
|
+
const handleDownload = useCallback5(
|
|
2990
3536
|
async (selectedItems) => {
|
|
2991
3537
|
const downloadPromises = selectedItems.filter((item) => item.type === "asset").map(async (item) => {
|
|
2992
3538
|
const asset = assets.find((a) => a.stableId === item.assetId) ?? assets.find((a) => a.id === item.assetId);
|
|
@@ -2997,7 +3543,7 @@ var ResourceExplorer = memo2(
|
|
|
2997
3543
|
},
|
|
2998
3544
|
[assets, tree]
|
|
2999
3545
|
);
|
|
3000
|
-
const handlePreview =
|
|
3546
|
+
const handlePreview = useCallback5(
|
|
3001
3547
|
async (selectedItems) => {
|
|
3002
3548
|
const previewPromises = selectedItems.filter((item) => item.type === "asset").map(async (item) => {
|
|
3003
3549
|
const asset = assets.find((a) => a.stableId === item.assetId) ?? assets.find((a) => a.id === item.assetId);
|
|
@@ -3008,10 +3554,10 @@ var ResourceExplorer = memo2(
|
|
|
3008
3554
|
},
|
|
3009
3555
|
[assets]
|
|
3010
3556
|
);
|
|
3011
|
-
const handleReplace =
|
|
3557
|
+
const handleReplace = useCallback5(
|
|
3012
3558
|
async (selectedItem) => {
|
|
3013
3559
|
try {
|
|
3014
|
-
const file = await
|
|
3560
|
+
const file = await fileOpen3();
|
|
3015
3561
|
if (!file) return;
|
|
3016
3562
|
const created = await assetManager.create(file);
|
|
3017
3563
|
const assetStableId = created.id;
|
|
@@ -3037,13 +3583,13 @@ var ResourceExplorer = memo2(
|
|
|
3037
3583
|
},
|
|
3038
3584
|
[media, setMedia, assetManager, tree]
|
|
3039
3585
|
);
|
|
3040
|
-
const handleRename =
|
|
3586
|
+
const handleRename = useCallback5(
|
|
3041
3587
|
(selectedItemId) => {
|
|
3042
3588
|
collectionRef.current?.editName(selectedItemId);
|
|
3043
3589
|
},
|
|
3044
3590
|
[collectionRef]
|
|
3045
3591
|
);
|
|
3046
|
-
const handleMoveMediaInsideFolder =
|
|
3592
|
+
const handleMoveMediaInsideFolder = useCallback5(
|
|
3047
3593
|
(sourceItems, targetItem) => {
|
|
3048
3594
|
const newMedia = moveMediaInsideFolder({
|
|
3049
3595
|
sourceItemIds: sourceItems.map((item) => item.id),
|
|
@@ -3061,52 +3607,52 @@ var ResourceExplorer = memo2(
|
|
|
3061
3607
|
},
|
|
3062
3608
|
[media, setMedia, tree]
|
|
3063
3609
|
);
|
|
3064
|
-
const assetContextMenuItems =
|
|
3065
|
-
return
|
|
3610
|
+
const assetContextMenuItems = useMemo4(() => {
|
|
3611
|
+
return createSectionedMenu3(
|
|
3066
3612
|
[
|
|
3067
3613
|
!rootSelected && singleItemSelected && {
|
|
3068
3614
|
title: "Rename",
|
|
3069
3615
|
value: "rename",
|
|
3070
|
-
icon: /* @__PURE__ */
|
|
3616
|
+
icon: /* @__PURE__ */ React3.createElement(InputIcon3, null)
|
|
3071
3617
|
},
|
|
3072
3618
|
onlySingleAssetSelected && {
|
|
3073
3619
|
title: "Replace",
|
|
3074
3620
|
value: "replace",
|
|
3075
|
-
icon: /* @__PURE__ */
|
|
3621
|
+
icon: /* @__PURE__ */ React3.createElement(UpdateIcon2, null)
|
|
3076
3622
|
},
|
|
3077
3623
|
!rootSelected && {
|
|
3078
3624
|
title: "Delete",
|
|
3079
3625
|
value: "delete",
|
|
3080
|
-
icon: /* @__PURE__ */
|
|
3626
|
+
icon: /* @__PURE__ */ React3.createElement(TrashIcon3, null)
|
|
3081
3627
|
}
|
|
3082
3628
|
],
|
|
3083
3629
|
[
|
|
3084
3630
|
onlySingleFolderSelected && {
|
|
3085
3631
|
title: "Upload Files",
|
|
3086
3632
|
value: "upload",
|
|
3087
|
-
icon: /* @__PURE__ */
|
|
3633
|
+
icon: /* @__PURE__ */ React3.createElement(UploadIcon3, null)
|
|
3088
3634
|
},
|
|
3089
3635
|
onlySingleFolderSelected && {
|
|
3090
3636
|
title: "Add Folder",
|
|
3091
3637
|
value: "addFolder",
|
|
3092
|
-
icon: /* @__PURE__ */
|
|
3638
|
+
icon: /* @__PURE__ */ React3.createElement(FolderIcon2, null)
|
|
3093
3639
|
},
|
|
3094
3640
|
onlyAssetsSelected && tree.resourcesWithRoot.length > 0 && {
|
|
3095
3641
|
title: "Download",
|
|
3096
3642
|
value: "download",
|
|
3097
|
-
icon: /* @__PURE__ */
|
|
3643
|
+
icon: /* @__PURE__ */ React3.createElement(DownloadIcon2, null)
|
|
3098
3644
|
},
|
|
3099
3645
|
onlySingleAssetSelected && {
|
|
3100
3646
|
title: "Preview",
|
|
3101
3647
|
value: "preview",
|
|
3102
|
-
icon: /* @__PURE__ */
|
|
3648
|
+
icon: /* @__PURE__ */ React3.createElement(OpenInNewWindowIcon2, null)
|
|
3103
3649
|
}
|
|
3104
3650
|
],
|
|
3105
3651
|
[
|
|
3106
3652
|
!rootSelected && sameParentSelected && {
|
|
3107
3653
|
title: "Move up a folder",
|
|
3108
3654
|
value: "move",
|
|
3109
|
-
icon: /* @__PURE__ */
|
|
3655
|
+
icon: /* @__PURE__ */ React3.createElement(ResetIcon2, null)
|
|
3110
3656
|
}
|
|
3111
3657
|
]
|
|
3112
3658
|
);
|
|
@@ -3119,7 +3665,7 @@ var ResourceExplorer = memo2(
|
|
|
3119
3665
|
tree.resourcesWithRoot.length,
|
|
3120
3666
|
sameParentSelected
|
|
3121
3667
|
]);
|
|
3122
|
-
const handleMenuAction =
|
|
3668
|
+
const handleMenuAction = useCallback5(
|
|
3123
3669
|
async (action, selectedItems) => {
|
|
3124
3670
|
if (selectedItems.length === 0) return;
|
|
3125
3671
|
switch (action) {
|
|
@@ -3161,7 +3707,7 @@ var ResourceExplorer = memo2(
|
|
|
3161
3707
|
handleMoveUpAFolder
|
|
3162
3708
|
]
|
|
3163
3709
|
);
|
|
3164
|
-
const handleSetExpanded =
|
|
3710
|
+
const handleSetExpanded = useCallback5(
|
|
3165
3711
|
(item, expanded) => {
|
|
3166
3712
|
setExpandedMap(
|
|
3167
3713
|
(prev) => updateExpandedMap({
|
|
@@ -3175,12 +3721,12 @@ var ResourceExplorer = memo2(
|
|
|
3175
3721
|
},
|
|
3176
3722
|
[expandable, tree]
|
|
3177
3723
|
);
|
|
3178
|
-
const renderAction =
|
|
3724
|
+
const renderAction = useMemo4(() => {
|
|
3179
3725
|
if (renderActionProp) return renderActionProp;
|
|
3180
3726
|
return ({
|
|
3181
3727
|
selected,
|
|
3182
3728
|
onOpenChange
|
|
3183
|
-
}) => /* @__PURE__ */
|
|
3729
|
+
}) => /* @__PURE__ */ React3.createElement(
|
|
3184
3730
|
"div",
|
|
3185
3731
|
{
|
|
3186
3732
|
style: {
|
|
@@ -3189,7 +3735,7 @@ var ResourceExplorer = memo2(
|
|
|
3189
3735
|
justifyContent: "flex-end"
|
|
3190
3736
|
}
|
|
3191
3737
|
},
|
|
3192
|
-
/* @__PURE__ */
|
|
3738
|
+
/* @__PURE__ */ React3.createElement(
|
|
3193
3739
|
ActionMenu2,
|
|
3194
3740
|
{
|
|
3195
3741
|
menuItems: assetContextMenuItems,
|
|
@@ -3211,7 +3757,7 @@ var ResourceExplorer = memo2(
|
|
|
3211
3757
|
selectedResources,
|
|
3212
3758
|
viewType
|
|
3213
3759
|
]);
|
|
3214
|
-
|
|
3760
|
+
useImperativeHandle3(ref, () => ({
|
|
3215
3761
|
upload: (selectedId) => handleUpload(selectedId),
|
|
3216
3762
|
delete: handleDelete,
|
|
3217
3763
|
download: handleDownload,
|
|
@@ -3223,7 +3769,7 @@ var ResourceExplorer = memo2(
|
|
|
3223
3769
|
moveMediaInsideFolder: handleMoveMediaInsideFolder,
|
|
3224
3770
|
getItemAtIndex: (index) => visibleItems[index]
|
|
3225
3771
|
}));
|
|
3226
|
-
const diffResources =
|
|
3772
|
+
const diffResources = useMemo4(() => {
|
|
3227
3773
|
if (!publishedResources) return;
|
|
3228
3774
|
const diff = diffResourceMaps(publishedResources, media, "stableId");
|
|
3229
3775
|
return {
|
|
@@ -3238,8 +3784,8 @@ var ResourceExplorer = memo2(
|
|
|
3238
3784
|
)
|
|
3239
3785
|
};
|
|
3240
3786
|
}, [media, publishedResources]);
|
|
3241
|
-
const keyExtractor =
|
|
3242
|
-
const renderCollection = (virtualizedHeight) => /* @__PURE__ */
|
|
3787
|
+
const keyExtractor = useCallback5((item) => item.id, []);
|
|
3788
|
+
const renderCollection = (virtualizedHeight) => /* @__PURE__ */ React3.createElement(
|
|
3243
3789
|
FileExplorerCollection2,
|
|
3244
3790
|
{
|
|
3245
3791
|
ref: collectionRef,
|
|
@@ -3290,7 +3836,7 @@ var ResourceExplorer = memo2(
|
|
|
3290
3836
|
itemClassName,
|
|
3291
3837
|
itemStyle,
|
|
3292
3838
|
virtualized: virtualizedHeight,
|
|
3293
|
-
renderThumbnail: (props) => /* @__PURE__ */
|
|
3839
|
+
renderThumbnail: (props) => /* @__PURE__ */ React3.createElement(
|
|
3294
3840
|
ResourceThumbnail,
|
|
3295
3841
|
{
|
|
3296
3842
|
...props,
|
|
@@ -3306,12 +3852,12 @@ var ResourceExplorer = memo2(
|
|
|
3306
3852
|
resource: file,
|
|
3307
3853
|
diff: diffResources
|
|
3308
3854
|
});
|
|
3309
|
-
return /* @__PURE__ */
|
|
3855
|
+
return /* @__PURE__ */ React3.createElement(
|
|
3310
3856
|
"div",
|
|
3311
3857
|
{
|
|
3312
3858
|
style: { display: "flex", alignItems: "center", gap: "6px" }
|
|
3313
3859
|
},
|
|
3314
|
-
publishStatus && /* @__PURE__ */
|
|
3860
|
+
publishStatus && /* @__PURE__ */ React3.createElement(
|
|
3315
3861
|
Chip,
|
|
3316
3862
|
{
|
|
3317
3863
|
colorScheme: publishStatus === "Modified" ? "info" : publishStatus === "Added" ? "secondary" : "primary"
|
|
@@ -3326,7 +3872,7 @@ var ResourceExplorer = memo2(
|
|
|
3326
3872
|
if (file.type !== "asset") return null;
|
|
3327
3873
|
const asset = assets.find((a) => a.stableId === file.assetId) ?? assets.find((a) => a.id === file.assetId);
|
|
3328
3874
|
if (!asset) return null;
|
|
3329
|
-
return /* @__PURE__ */
|
|
3875
|
+
return /* @__PURE__ */ React3.createElement(
|
|
3330
3876
|
FileExplorerDetail2,
|
|
3331
3877
|
{
|
|
3332
3878
|
selected,
|
|
@@ -3336,7 +3882,7 @@ var ResourceExplorer = memo2(
|
|
|
3336
3882
|
formatByteSize2(asset.size)
|
|
3337
3883
|
);
|
|
3338
3884
|
},
|
|
3339
|
-
renderEmptyState: () => renderEmptyState?.() ?? /* @__PURE__ */
|
|
3885
|
+
renderEmptyState: () => renderEmptyState?.() ?? /* @__PURE__ */ React3.createElement(FileExplorerEmptyState2, null),
|
|
3340
3886
|
itemRoleDescription: "clickable file item",
|
|
3341
3887
|
getDropTargetParentIndex: (overIndex) => {
|
|
3342
3888
|
const item = visibleItems[overIndex];
|
|
@@ -3403,11 +3949,11 @@ var ResourceExplorer = memo2(
|
|
|
3403
3949
|
}
|
|
3404
3950
|
}
|
|
3405
3951
|
);
|
|
3406
|
-
return /* @__PURE__ */
|
|
3952
|
+
return /* @__PURE__ */ React3.createElement(
|
|
3407
3953
|
FileExplorerLayout2,
|
|
3408
3954
|
{
|
|
3409
3955
|
title: title ?? rootResourceName,
|
|
3410
|
-
right: !readOnly && /* @__PURE__ */
|
|
3956
|
+
right: !readOnly && /* @__PURE__ */ React3.createElement(
|
|
3411
3957
|
FileExplorerUploadButton2,
|
|
3412
3958
|
{
|
|
3413
3959
|
showUploadButton,
|
|
@@ -3418,7 +3964,7 @@ var ResourceExplorer = memo2(
|
|
|
3418
3964
|
),
|
|
3419
3965
|
className
|
|
3420
3966
|
},
|
|
3421
|
-
virtualized ? /* @__PURE__ */
|
|
3967
|
+
virtualized ? /* @__PURE__ */ React3.createElement(SingleDimensionAutoSizer, { dimension: "height" }, (height) => renderCollection(height)) : renderCollection(void 0)
|
|
3422
3968
|
);
|
|
3423
3969
|
}
|
|
3424
3970
|
)
|
|
@@ -3454,6 +4000,7 @@ function getPublishStatus({
|
|
|
3454
4000
|
);
|
|
3455
4001
|
}
|
|
3456
4002
|
export {
|
|
4003
|
+
GitFileExplorer2 as GitFileExplorer,
|
|
3457
4004
|
MediaCollection,
|
|
3458
4005
|
PLACEHOLDER_ITEM_NAME,
|
|
3459
4006
|
ResourceExplorer,
|
|
@@ -3471,7 +4018,7 @@ export {
|
|
|
3471
4018
|
getContentTypeFromFile,
|
|
3472
4019
|
getDepthMap,
|
|
3473
4020
|
getParentDirectories,
|
|
3474
|
-
getVisibleItems,
|
|
4021
|
+
getVisibleItems2 as getVisibleItems,
|
|
3475
4022
|
gridThumbnailDimension,
|
|
3476
4023
|
mediaDeleteMediaItems,
|
|
3477
4024
|
mediaGetDepthMap,
|