@aws-amplify/ui-react-storage 3.15.0 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +1 -1
- package/dist/{createStorageBrowser-CG-6mXiT.js → createStorageBrowser-B-J76Lyp.js} +624 -105
- package/dist/esm/components/StorageBrowser/ErrorBoundary/ErrorBoundary.mjs +0 -4
- package/dist/esm/components/StorageBrowser/actions/configs/defaults.mjs +13 -3
- package/dist/esm/components/StorageBrowser/actions/handlers/delete.mjs +39 -8
- package/dist/esm/components/StorageBrowser/components/ComponentsProvider.mjs +0 -4
- package/dist/esm/components/StorageBrowser/components/base/preview/DownloadButton.mjs +0 -4
- package/dist/esm/components/StorageBrowser/components/composables/ActionConfirmationModal.mjs +34 -0
- package/dist/esm/components/StorageBrowser/components/composables/defaults.mjs +2 -0
- package/dist/esm/components/StorageBrowser/components/elements/definitions.mjs +2 -2
- package/dist/esm/components/StorageBrowser/controls/ActionConfirmationModalControl.mjs +12 -0
- package/dist/esm/components/StorageBrowser/controls/DataTableControl.mjs +0 -4
- package/dist/esm/components/StorageBrowser/controls/hooks/useActionConfirmationModal.mjs +17 -0
- package/dist/esm/components/StorageBrowser/createStorageBrowser/StorageBrowserDefault.mjs +8 -4
- package/dist/esm/components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs +9 -5
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/deleteView.mjs +117 -5
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/locationDetailView.mjs +1 -0
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/shared.mjs +1 -0
- package/dist/esm/components/StorageBrowser/locationItems/context.mjs +17 -14
- package/dist/esm/components/StorageBrowser/locationItems/utils.mjs +38 -0
- package/dist/esm/components/StorageBrowser/store/validateStoreProps.mjs +1 -1
- package/dist/esm/components/StorageBrowser/tasks/useProcessTasks.mjs +7 -4
- package/dist/esm/components/StorageBrowser/useAction/utils.mjs +0 -5
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.mjs +4 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/FoldersMessageControl.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/useCopyView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/useFolders.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/CreateFolderView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/useCreateFolderView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteView.mjs +5 -6
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteViewProvider.mjs +7 -6
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/useDeleteView.mjs +69 -7
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/utils.mjs +87 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/DownloadView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/DownloadViewProvider.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/useDownloadView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadView.mjs +1 -5
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadViewProvider.mjs +3 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/useUploadView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.mjs +2 -1
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.mjs +38 -27
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.mjs +8 -1
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.mjs +10 -9
- package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsView.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsViewProvider.mjs +0 -4
- package/dist/esm/components/StorageBrowser/views/context/actionViews.mjs +7 -4
- package/dist/esm/components/StorageBrowser/views/context/primaryViews.mjs +8 -4
- package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/constants.mjs +10 -1
- package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.mjs +123 -13
- package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/utils.mjs +3 -3
- package/dist/esm/version.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/styles.css +83 -1
- package/dist/types/components/StorageBrowser/actions/handlers/delete.d.ts +5 -3
- package/dist/types/components/StorageBrowser/actions/handlers/types.d.ts +15 -1
- package/dist/types/components/StorageBrowser/components/composables/ActionConfirmationModal.d.ts +12 -0
- package/dist/types/components/StorageBrowser/components/composables/types.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/ActionConfirmationModalControl.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/hooks/useActionConfirmationModal.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/index.d.ts +1 -0
- package/dist/types/components/StorageBrowser/controls/types.d.ts +4 -0
- package/dist/types/components/StorageBrowser/displayText/types.d.ts +7 -0
- package/dist/types/components/StorageBrowser/locationItems/context.d.ts +12 -3
- package/dist/types/components/StorageBrowser/locationItems/index.d.ts +1 -0
- package/dist/types/components/StorageBrowser/locationItems/utils.d.ts +27 -0
- package/dist/types/components/StorageBrowser/tasks/types.d.ts +7 -2
- package/dist/types/components/StorageBrowser/views/LocationActionView/DeleteView/types.d.ts +5 -0
- package/dist/types/components/StorageBrowser/views/LocationActionView/DeleteView/utils.d.ts +26 -0
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.d.ts +4 -1
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.d.ts +3 -2
- package/dist/types/components/StorageBrowser/views/LocationDetailView/types.d.ts +8 -1
- package/dist/types/components/StorageBrowser/views/utils/index.d.ts +1 -1
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/constants.d.ts +1 -0
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.d.ts +5 -2
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/index.d.ts +1 -1
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/types.d.ts +4 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +7 -7
|
@@ -36,7 +36,7 @@ function _interopNamespace(e) {
|
|
|
36
36
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
37
37
|
var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
|
|
38
38
|
|
|
39
|
-
const VERSION = '3.
|
|
39
|
+
const VERSION = '3.16.0';
|
|
40
40
|
|
|
41
41
|
const DEFAULT_CHECKSUM_ALGORITHM = 'crc-32';
|
|
42
42
|
// 5MiB for multipart upload
|
|
@@ -422,27 +422,58 @@ const createFolderHandler = (input) => {
|
|
|
422
422
|
};
|
|
423
423
|
};
|
|
424
424
|
|
|
425
|
-
const deleteHandler = ({ config, data, }) => {
|
|
425
|
+
const deleteHandler = ({ config, data, options, }) => {
|
|
426
426
|
const { key } = data;
|
|
427
427
|
const { accountId, credentials, customEndpoint } = config;
|
|
428
|
-
const
|
|
428
|
+
const { onProgress } = options ?? {};
|
|
429
|
+
let cumulativeSuccessCount = 0;
|
|
430
|
+
let cumulativeFailureCount = 0;
|
|
431
|
+
let operationCancel = () => {
|
|
432
|
+
// noop
|
|
433
|
+
};
|
|
434
|
+
const cancel = () => {
|
|
435
|
+
operationCancel?.();
|
|
436
|
+
};
|
|
437
|
+
const operation = internals.remove({
|
|
429
438
|
path: key,
|
|
430
439
|
options: {
|
|
431
440
|
bucket: constructBucket$1(config),
|
|
432
441
|
locationCredentialsProvider: credentials,
|
|
433
442
|
expectedBucketOwner: accountId,
|
|
434
443
|
customEndpoint,
|
|
444
|
+
onProgress: (progress) => {
|
|
445
|
+
if (!progress) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const batchSuccessCount = progress?.deleted?.length ?? 0;
|
|
449
|
+
const batchFailureCount = progress?.failed?.length ?? 0;
|
|
450
|
+
cumulativeSuccessCount += batchSuccessCount;
|
|
451
|
+
cumulativeFailureCount += batchFailureCount;
|
|
452
|
+
onProgress?.(data, {
|
|
453
|
+
successCount: cumulativeSuccessCount,
|
|
454
|
+
failureCount: cumulativeFailureCount,
|
|
455
|
+
});
|
|
456
|
+
},
|
|
435
457
|
},
|
|
458
|
+
});
|
|
459
|
+
operationCancel = operation?.cancel ? operation?.cancel : () => { };
|
|
460
|
+
const operationPromise = operation?.result ?? operation;
|
|
461
|
+
const result = operationPromise
|
|
462
|
+
?.then?.(({ path }) => {
|
|
463
|
+
return {
|
|
464
|
+
status: 'COMPLETE',
|
|
465
|
+
value: {
|
|
466
|
+
key: path,
|
|
467
|
+
successCount: cumulativeSuccessCount,
|
|
468
|
+
failureCount: cumulativeFailureCount,
|
|
469
|
+
},
|
|
470
|
+
};
|
|
436
471
|
})
|
|
437
|
-
|
|
438
|
-
status: 'COMPLETE',
|
|
439
|
-
value: { key: path },
|
|
440
|
-
}))
|
|
441
|
-
.catch((error) => {
|
|
472
|
+
?.catch?.((error) => {
|
|
442
473
|
const { message } = error;
|
|
443
474
|
return { error, message, status: 'FAILED' };
|
|
444
475
|
});
|
|
445
|
-
return { result };
|
|
476
|
+
return { result, cancel };
|
|
446
477
|
};
|
|
447
478
|
|
|
448
479
|
const zipProgressManager = ({ dataMap, onZipProgress, }) => {
|
|
@@ -792,10 +823,50 @@ const defaultValue$7 = {
|
|
|
792
823
|
};
|
|
793
824
|
const { useActionConfigs, ActionConfigsProvider } = uiReactCore.createContextUtilities({ contextName: 'ActionConfigs', defaultValue: defaultValue$7 });
|
|
794
825
|
|
|
826
|
+
/**
|
|
827
|
+
* Selection utility functions for LocationItems
|
|
828
|
+
*/
|
|
829
|
+
/**
|
|
830
|
+
* Get selected files from dataItems
|
|
831
|
+
*/
|
|
832
|
+
const getSelectedFiles = (dataItems) => {
|
|
833
|
+
return dataItems?.filter((item) => item.type === 'FILE') ?? [];
|
|
834
|
+
};
|
|
835
|
+
/**
|
|
836
|
+
* Get selected folders from dataItems
|
|
837
|
+
*/
|
|
838
|
+
const getSelectedFolders = (dataItems) => {
|
|
839
|
+
return dataItems?.filter((item) => item.type === 'FOLDER') ?? [];
|
|
840
|
+
};
|
|
841
|
+
/**
|
|
842
|
+
* Check if selection contains folders
|
|
843
|
+
*/
|
|
844
|
+
const hasSelectedFolders = (dataItems) => {
|
|
845
|
+
return dataItems?.some((item) => item.type === 'FOLDER') ?? false;
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Get selection summary
|
|
849
|
+
*/
|
|
850
|
+
const getSelectionSummary = (dataItems) => {
|
|
851
|
+
const files = getSelectedFiles(dataItems);
|
|
852
|
+
const folders = getSelectedFolders(dataItems);
|
|
853
|
+
return {
|
|
854
|
+
total: dataItems?.length ?? 0,
|
|
855
|
+
files: files.length,
|
|
856
|
+
folders: folders.length,
|
|
857
|
+
hasFiles: files.length > 0,
|
|
858
|
+
hasFolders: folders.length > 0,
|
|
859
|
+
isMixed: files.length > 0 && folders.length > 0,
|
|
860
|
+
};
|
|
861
|
+
};
|
|
862
|
+
|
|
795
863
|
const copyActionConfig = {
|
|
796
864
|
viewName: 'CopyView',
|
|
797
865
|
actionListItem: {
|
|
798
|
-
disable: (selected) =>
|
|
866
|
+
disable: (selected) => {
|
|
867
|
+
const hasNoSelection = !selected || selected.length === 0;
|
|
868
|
+
return hasNoSelection || hasSelectedFolders(selected);
|
|
869
|
+
},
|
|
799
870
|
hide: (permissions) => !permissions.includes('write'),
|
|
800
871
|
icon: 'copy-file',
|
|
801
872
|
label: 'Copy',
|
|
@@ -805,7 +876,10 @@ const copyActionConfig = {
|
|
|
805
876
|
const deleteActionConfig = {
|
|
806
877
|
viewName: 'DeleteView',
|
|
807
878
|
actionListItem: {
|
|
808
|
-
disable: (selected) =>
|
|
879
|
+
disable: (selected) => {
|
|
880
|
+
const hasNoSelection = !selected || selected.length === 0;
|
|
881
|
+
return hasNoSelection;
|
|
882
|
+
},
|
|
809
883
|
hide: (permissions) => !permissions.includes('delete'),
|
|
810
884
|
icon: 'delete-file',
|
|
811
885
|
label: 'Delete',
|
|
@@ -833,7 +907,10 @@ const uploadActionConfig = {
|
|
|
833
907
|
const downloadActionConfig = {
|
|
834
908
|
viewName: 'DownloadView',
|
|
835
909
|
actionListItem: {
|
|
836
|
-
disable: (selected) =>
|
|
910
|
+
disable: (selected) => {
|
|
911
|
+
const hasNoSelection = !selected || selected.length === 0;
|
|
912
|
+
return hasNoSelection || hasSelectedFolders(selected);
|
|
913
|
+
},
|
|
837
914
|
hide: (permissions) => !permissions.includes('get'),
|
|
838
915
|
icon: 'download',
|
|
839
916
|
label: 'Download',
|
|
@@ -1038,7 +1115,7 @@ const OrderedListElement = elements.defineBaseElement({
|
|
|
1038
1115
|
type: 'ol',
|
|
1039
1116
|
displayName: 'OrderedList',
|
|
1040
1117
|
});
|
|
1041
|
-
elements.defineBaseElement({
|
|
1118
|
+
const UnorderedListElement = elements.defineBaseElement({
|
|
1042
1119
|
type: 'ul',
|
|
1043
1120
|
displayName: 'UnorderedList',
|
|
1044
1121
|
});
|
|
@@ -1178,6 +1255,34 @@ const { useComposables, ComposablesProvider } = uiReactCore.createContextUtiliti
|
|
|
1178
1255
|
|
|
1179
1256
|
const ActionCancel = ({ onCancel, isDisabled, label, }) => (React__namespace["default"].createElement(ButtonElement, { variant: "cancel", className: `${STORAGE_BROWSER_BLOCK}__cancel`, onClick: onCancel, disabled: isDisabled }, label));
|
|
1180
1257
|
|
|
1258
|
+
const ActionConfirmationModal = ({ isOpen = false, title, message, content, onConfirm, onCancel, confirmLabel, cancelLabel, }) => {
|
|
1259
|
+
const modalRef = React__namespace["default"].useRef(null);
|
|
1260
|
+
React__namespace["default"].useEffect(() => {
|
|
1261
|
+
if (isOpen && modalRef.current) {
|
|
1262
|
+
modalRef.current.focus();
|
|
1263
|
+
}
|
|
1264
|
+
}, [isOpen]);
|
|
1265
|
+
const handleKeyDown = (event) => {
|
|
1266
|
+
if (event.key === 'Escape') {
|
|
1267
|
+
onCancel?.();
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
if (!isOpen)
|
|
1271
|
+
return null;
|
|
1272
|
+
return (React__namespace["default"].createElement("div", { ref: modalRef, className: "amplify-modal__overlay", role: "dialog", "aria-modal": "true", tabIndex: -1, onKeyDown: handleKeyDown, onClick: (e) => {
|
|
1273
|
+
if (e.target === e.currentTarget) {
|
|
1274
|
+
onCancel?.();
|
|
1275
|
+
}
|
|
1276
|
+
} },
|
|
1277
|
+
React__namespace["default"].createElement(ViewElement, { className: "amplify-modal__content", role: "document" },
|
|
1278
|
+
React__namespace["default"].createElement(HeadingElement, { className: "amplify-modal__title" }, title),
|
|
1279
|
+
message && (React__namespace["default"].createElement(TextElement, { className: "amplify-modal__body" }, message)),
|
|
1280
|
+
content && (React__namespace["default"].createElement(ViewElement, { className: "amplify-modal__body" }, content)),
|
|
1281
|
+
React__namespace["default"].createElement(ViewElement, { className: "amplify-modal__footer" },
|
|
1282
|
+
React__namespace["default"].createElement(ButtonElement, { className: "amplify-modal__cancel", onClick: onCancel, variant: "cancel" }, cancelLabel),
|
|
1283
|
+
React__namespace["default"].createElement(ButtonElement, { className: "amplify-modal__confirm", onClick: onConfirm, variant: "primary" }, confirmLabel)))));
|
|
1284
|
+
};
|
|
1285
|
+
|
|
1181
1286
|
const ActionDestination$1 = ({ isNavigable, items, label, }) => {
|
|
1182
1287
|
if (!items.length) {
|
|
1183
1288
|
return null;
|
|
@@ -1804,7 +1909,7 @@ const DEPRECATED_PROP_KEYS = ['actionType', 'location', 'path'];
|
|
|
1804
1909
|
const template = (key, index, values) => `\`${key}\`${index < values.length - 1 ? ', ' : ''}`;
|
|
1805
1910
|
const getMissingLocationKeys = (location) => location === null
|
|
1806
1911
|
? []
|
|
1807
|
-
: REQUIRED_LOCATION_KEYS.filter((key) =>
|
|
1912
|
+
: REQUIRED_LOCATION_KEYS.filter((key) => location[key] === undefined || location[key] === null);
|
|
1808
1913
|
let didWarnConflictingBehavior = false;
|
|
1809
1914
|
let didWarnDeprecatedAndConflictingProps = false;
|
|
1810
1915
|
let didWarnDeprecatedProps = false;
|
|
@@ -2065,16 +2170,19 @@ function useProcessTasks(handler, options) {
|
|
|
2065
2170
|
const getTask = () => tasksRef.current.get(data.id);
|
|
2066
2171
|
const { options } = _input;
|
|
2067
2172
|
const { onProgress: _onProgress } = options ?? {};
|
|
2068
|
-
const onProgress = ({ id },
|
|
2173
|
+
const onProgress = ({ id }, progressDetails, status = 'PENDING') => {
|
|
2174
|
+
const isNumber = typeof progressDetails === 'number';
|
|
2069
2175
|
const task = updateTask(id, {
|
|
2070
|
-
progress,
|
|
2176
|
+
progress: isNumber ? progressDetails : progressDetails.progress,
|
|
2177
|
+
failureCount: isNumber ? undefined : progressDetails.failureCount,
|
|
2178
|
+
successCount: isNumber ? undefined : progressDetails.successCount,
|
|
2071
2179
|
status,
|
|
2072
2180
|
});
|
|
2073
2181
|
if (task && ui.isFunction(onTaskProgress)) {
|
|
2074
|
-
onTaskProgress(task,
|
|
2182
|
+
onTaskProgress(task, progressDetails);
|
|
2075
2183
|
}
|
|
2076
2184
|
if (task && ui.isFunction(_onProgress)) {
|
|
2077
|
-
_onProgress(data,
|
|
2185
|
+
_onProgress(data, progressDetails, status);
|
|
2078
2186
|
}
|
|
2079
2187
|
};
|
|
2080
2188
|
const input = { ..._input, data, all, options: { ...options, onProgress } };
|
|
@@ -2284,6 +2392,7 @@ const DEFAULT_ACTION_VIEW_DISPLAY_TEXT = {
|
|
|
2284
2392
|
tableColumnNameHeader: 'Name',
|
|
2285
2393
|
tableColumnTypeHeader: 'Type',
|
|
2286
2394
|
tableColumnSizeHeader: 'Size',
|
|
2395
|
+
tableColumnProgressHeader: 'Progress',
|
|
2287
2396
|
};
|
|
2288
2397
|
const DEFAULT_LIST_VIEW_DISPLAY_TEXT = {
|
|
2289
2398
|
loadingIndicatorLabel: 'Loading',
|
|
@@ -2376,21 +2485,133 @@ const DEFAULT_COPY_VIEW_DISPLAY_TEXT = {
|
|
|
2376
2485
|
searchClearLabel: 'Clear search',
|
|
2377
2486
|
};
|
|
2378
2487
|
|
|
2488
|
+
const pluralize = (count, word) => count === 1 ? word : `${word}s`;
|
|
2489
|
+
const formatCount = (count, word) => `${count === 1 ? '' : 'All '}${count} ${pluralize(count, word)}`;
|
|
2379
2490
|
const DEFAULT_DELETE_VIEW_DISPLAY_TEXT = {
|
|
2380
2491
|
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
2381
2492
|
title: 'Delete',
|
|
2382
2493
|
actionStartLabel: 'Delete',
|
|
2494
|
+
confirmationModalTitle: 'Confirm Deletion',
|
|
2495
|
+
confirmationModalConfirmLabel: 'Delete',
|
|
2496
|
+
confirmationModalCancelLabel: 'Cancel',
|
|
2497
|
+
confirmationModalMessage: 'The items that will be deleted contain {count} folder{plural}',
|
|
2498
|
+
confirmationModalFolderListTitle: 'Folder list:',
|
|
2383
2499
|
getActionCompleteMessage: (data) => {
|
|
2384
|
-
const { counts } = data ?? {};
|
|
2385
|
-
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2500
|
+
const { counts, tasks } = data ?? {};
|
|
2501
|
+
const { COMPLETE = 0, FAILED = 0, TOTAL = 0 } = counts ?? {};
|
|
2502
|
+
if (!TOTAL || TOTAL === 0) {
|
|
2503
|
+
return { content: 'No items to delete.', type: 'info' };
|
|
2504
|
+
}
|
|
2505
|
+
if (tasks && tasks.length > 0) {
|
|
2506
|
+
const folderTasks = tasks.filter((task) => task.data.type === 'FOLDER');
|
|
2507
|
+
const fileTasks = tasks.filter((task) => task.data.type === 'FILE');
|
|
2508
|
+
const completeFolders = folderTasks.filter((task) => task.status === 'COMPLETE').length;
|
|
2509
|
+
const failedFolders = folderTasks.filter((task) => task.status === 'FAILED').length;
|
|
2510
|
+
const completeFiles = fileTasks.filter((task) => task.status === 'COMPLETE').length;
|
|
2511
|
+
const failedFiles = fileTasks.filter((task) => task.status === 'FAILED').length;
|
|
2512
|
+
const hasFolders = folderTasks.length > 0;
|
|
2513
|
+
const hasFiles = fileTasks.length > 0;
|
|
2514
|
+
const isMixed = hasFolders && hasFiles;
|
|
2515
|
+
// All successful
|
|
2516
|
+
if (COMPLETE === TOTAL) {
|
|
2517
|
+
if (isMixed) {
|
|
2518
|
+
return {
|
|
2519
|
+
content: `${formatCount(completeFolders, 'folder')} and ${completeFiles} ${pluralize(completeFiles, 'file')} deleted successfully.`,
|
|
2520
|
+
type: 'success',
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
else if (hasFolders) {
|
|
2524
|
+
return {
|
|
2525
|
+
content: `${formatCount(completeFolders, 'folder')} deleted successfully.`,
|
|
2526
|
+
type: 'success',
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
else {
|
|
2530
|
+
return {
|
|
2531
|
+
content: `${formatCount(completeFiles, 'file')} deleted successfully.`,
|
|
2532
|
+
type: 'success',
|
|
2533
|
+
};
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
// Complete failure
|
|
2537
|
+
if (FAILED === TOTAL) {
|
|
2538
|
+
if (isMixed) {
|
|
2539
|
+
return {
|
|
2540
|
+
content: `Failed to delete ${failedFolders} ${pluralize(failedFolders, 'folder')} and ${failedFiles} ${pluralize(failedFiles, 'file')}. Some contents may have been deleted.`,
|
|
2541
|
+
type: 'error',
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2544
|
+
else if (hasFolders) {
|
|
2545
|
+
return {
|
|
2546
|
+
content: `Failed to delete ${failedFolders} ${pluralize(failedFolders, 'folder')}. Some items may have been deleted.`,
|
|
2547
|
+
type: 'error',
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
else {
|
|
2551
|
+
return {
|
|
2552
|
+
content: `Failed to delete ${failedFiles} ${pluralize(failedFiles, 'file')}.`,
|
|
2553
|
+
type: 'error',
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
// Partial failure
|
|
2558
|
+
if (isMixed) {
|
|
2559
|
+
const messages = [];
|
|
2560
|
+
if (completeFiles > 0) {
|
|
2561
|
+
messages.push(`${completeFiles} ${pluralize(completeFiles, 'file')} deleted`);
|
|
2562
|
+
}
|
|
2563
|
+
if (completeFolders > 0) {
|
|
2564
|
+
messages.push(`${completeFolders} ${pluralize(completeFolders, 'folder')} deleted`);
|
|
2565
|
+
}
|
|
2566
|
+
if (failedFiles > 0) {
|
|
2567
|
+
messages.push(`${failedFiles} ${pluralize(failedFiles, 'file')} failed`);
|
|
2568
|
+
}
|
|
2569
|
+
if (failedFolders > 0) {
|
|
2570
|
+
messages.push(`${failedFolders} ${pluralize(failedFolders, 'folder')} failed`);
|
|
2571
|
+
}
|
|
2572
|
+
return {
|
|
2573
|
+
content: messages.join(', ') + '. Some items may have been deleted.',
|
|
2574
|
+
type: 'error',
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
else if (hasFolders) {
|
|
2578
|
+
// Folders only partial failure
|
|
2579
|
+
if (completeFolders > 0) {
|
|
2580
|
+
return {
|
|
2581
|
+
content: `${completeFolders} ${pluralize(completeFolders, 'folder')} deleted, ${failedFolders} ${pluralize(failedFolders, 'folder')} failed. Some items may have been deleted.`,
|
|
2582
|
+
type: 'error',
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
else {
|
|
2586
|
+
return {
|
|
2587
|
+
content: `Failed to delete ${failedFolders} ${pluralize(failedFolders, 'folder')}. Some items may have been deleted.`,
|
|
2588
|
+
type: 'error',
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
else {
|
|
2593
|
+
// Files only partial failure
|
|
2594
|
+
return {
|
|
2595
|
+
content: `${completeFiles} ${pluralize(completeFiles, 'file')} deleted, ${failedFiles} ${pluralize(failedFiles, 'file')} failed.`,
|
|
2596
|
+
type: 'error',
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
// Fallback to generic messaging if tasks not available
|
|
2386
2601
|
if (COMPLETE === TOTAL) {
|
|
2387
|
-
return {
|
|
2602
|
+
return {
|
|
2603
|
+
content: `${formatCount(TOTAL, 'item')} deleted successfully.`,
|
|
2604
|
+
type: 'success',
|
|
2605
|
+
};
|
|
2388
2606
|
}
|
|
2389
2607
|
if (FAILED === TOTAL) {
|
|
2390
|
-
return {
|
|
2608
|
+
return {
|
|
2609
|
+
content: `Failed to delete ${formatCount(TOTAL, 'item')}.`,
|
|
2610
|
+
type: 'error',
|
|
2611
|
+
};
|
|
2391
2612
|
}
|
|
2392
2613
|
return {
|
|
2393
|
-
content: `${COMPLETE}
|
|
2614
|
+
content: `${COMPLETE} ${pluralize(COMPLETE, 'item')} deleted, ${FAILED} ${pluralize(FAILED, 'item')} failed to delete.`,
|
|
2394
2615
|
type: 'error',
|
|
2395
2616
|
};
|
|
2396
2617
|
},
|
|
@@ -2465,6 +2686,7 @@ const DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT = {
|
|
|
2465
2686
|
tableColumnSizeHeader: 'Size',
|
|
2466
2687
|
tableColumnTypeHeader: 'Type',
|
|
2467
2688
|
selectFileLabel: 'Select file',
|
|
2689
|
+
selectFolderLabel: 'Select folder',
|
|
2468
2690
|
selectAllFilesLabel: 'Select all files',
|
|
2469
2691
|
getActionListItemLabel: (key = '') => {
|
|
2470
2692
|
switch (key) {
|
|
@@ -3287,6 +3509,7 @@ const Title$1 = ({ title }) => (React__namespace["default"].createElement(Headin
|
|
|
3287
3509
|
|
|
3288
3510
|
const DEFAULT_COMPOSABLES = {
|
|
3289
3511
|
ActionCancel,
|
|
3512
|
+
ActionConfirmationModal,
|
|
3290
3513
|
ActionDestination: ActionDestination$1,
|
|
3291
3514
|
ActionExit,
|
|
3292
3515
|
ActionStart,
|
|
@@ -3477,6 +3700,26 @@ const ActionCancelControl = () => {
|
|
|
3477
3700
|
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3478
3701
|
};
|
|
3479
3702
|
|
|
3703
|
+
const useActionConfirmationModal = () => {
|
|
3704
|
+
const { data: { confirmationModal = {} }, onConfirmationModalConfirm = () => { }, onConfirmationModalCancel = () => { }, } = useControlsContext();
|
|
3705
|
+
return {
|
|
3706
|
+
isOpen: false,
|
|
3707
|
+
title: 'Confirm Action',
|
|
3708
|
+
message: '',
|
|
3709
|
+
confirmLabel: 'Confirm',
|
|
3710
|
+
cancelLabel: 'Cancel',
|
|
3711
|
+
...confirmationModal,
|
|
3712
|
+
onConfirm: onConfirmationModalConfirm,
|
|
3713
|
+
onCancel: onConfirmationModalCancel,
|
|
3714
|
+
};
|
|
3715
|
+
};
|
|
3716
|
+
|
|
3717
|
+
const ActionConfirmationModalControl = () => {
|
|
3718
|
+
const props = useActionConfirmationModal();
|
|
3719
|
+
const Resolved = useResolvedComposable(ActionConfirmationModal, 'ActionConfirmationModal');
|
|
3720
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3721
|
+
};
|
|
3722
|
+
|
|
3480
3723
|
const getNavigationItems = ({ destinationParts, location, onNavigate, }) => {
|
|
3481
3724
|
const { bucket, permissions, prefix = '', type } = location;
|
|
3482
3725
|
const destinationSubpaths = [];
|
|
@@ -4011,9 +4254,18 @@ const FILE_DATA_ITEM_TABLE_KEYS = [
|
|
|
4011
4254
|
'status',
|
|
4012
4255
|
'cancel',
|
|
4013
4256
|
];
|
|
4257
|
+
const DELETE_TABLE_KEYS = [
|
|
4258
|
+
'name',
|
|
4259
|
+
'folder',
|
|
4260
|
+
'type',
|
|
4261
|
+
'size',
|
|
4262
|
+
'status',
|
|
4263
|
+
'progress',
|
|
4264
|
+
'cancel',
|
|
4265
|
+
];
|
|
4014
4266
|
|
|
4015
|
-
const getFileType = (value, fallback = '') => value
|
|
4016
|
-
? value
|
|
4267
|
+
const getFileType = (value, fallback = '') => value?.lastIndexOf?.('.') !== -1
|
|
4268
|
+
? value?.slice(value?.lastIndexOf?.('.') + 1)
|
|
4017
4269
|
: fallback;
|
|
4018
4270
|
const getCellName = (value) =>
|
|
4019
4271
|
// `value.split` always returns an array with at least one entry
|
|
@@ -4028,7 +4280,7 @@ const getFileDataCellFolder = (task) => {
|
|
|
4028
4280
|
? task.data.sourceKey
|
|
4029
4281
|
: task.data.key;
|
|
4030
4282
|
const { fileKey } = task.data;
|
|
4031
|
-
return targetKey.slice(0, -fileKey
|
|
4283
|
+
return targetKey.slice(0, -fileKey?.length);
|
|
4032
4284
|
};
|
|
4033
4285
|
const getUploadCellProgress = ({ progress, status, }) => {
|
|
4034
4286
|
// prefer `progress` if available, 1 if status is complete, default 0
|
|
@@ -4073,31 +4325,31 @@ const getFileDataCancelCellContent = (data) => {
|
|
|
4073
4325
|
* Generates a unique key for a table cell based on the key and item id
|
|
4074
4326
|
*/
|
|
4075
4327
|
const getFileDataCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
|
|
4076
|
-
const name$
|
|
4328
|
+
const name$3 = (data) => {
|
|
4077
4329
|
const key = getFileDataCellKey(data);
|
|
4078
4330
|
const { item } = data;
|
|
4079
4331
|
const text = item.data.fileKey;
|
|
4080
4332
|
const icon = STATUS_ICONS[item.status];
|
|
4081
4333
|
return { key, type: 'text', content: { icon, text } };
|
|
4082
4334
|
};
|
|
4083
|
-
const folder$
|
|
4335
|
+
const folder$3 = (data) => {
|
|
4084
4336
|
const key = getFileDataCellKey(data);
|
|
4085
4337
|
const text = getFileDataCellFolder(data.item);
|
|
4086
4338
|
return { key, type: 'text', content: { text } };
|
|
4087
4339
|
};
|
|
4088
|
-
const type$
|
|
4340
|
+
const type$3 = (data) => {
|
|
4089
4341
|
const key = getFileDataCellKey(data);
|
|
4090
4342
|
const { fileKey } = data.item.data;
|
|
4091
4343
|
const text = getFileType(fileKey);
|
|
4092
4344
|
return { key, type: 'text', content: { text } };
|
|
4093
4345
|
};
|
|
4094
|
-
const size$
|
|
4346
|
+
const size$3 = (data) => {
|
|
4095
4347
|
const key = getFileDataCellKey(data);
|
|
4096
4348
|
const { size: value } = data.item.data;
|
|
4097
4349
|
const displayValue = getFileSize(value);
|
|
4098
4350
|
return { key, type: 'number', content: { value, displayValue } };
|
|
4099
4351
|
};
|
|
4100
|
-
const cancel$
|
|
4352
|
+
const cancel$3 = (data) => {
|
|
4101
4353
|
const key = getFileDataCellKey(data);
|
|
4102
4354
|
const content = getFileDataCancelCellContent(data);
|
|
4103
4355
|
return { key, type: 'button', content };
|
|
@@ -4113,12 +4365,12 @@ const status$3 = (data) => {
|
|
|
4113
4365
|
return { key, type: 'text', content: { text } };
|
|
4114
4366
|
};
|
|
4115
4367
|
const COPY_CELL_RESOLVERS = {
|
|
4116
|
-
name: name$
|
|
4117
|
-
folder: folder$
|
|
4118
|
-
type: type$
|
|
4119
|
-
size: size$
|
|
4368
|
+
name: name$3,
|
|
4369
|
+
folder: folder$3,
|
|
4370
|
+
type: type$3,
|
|
4371
|
+
size: size$3,
|
|
4120
4372
|
status: status$3,
|
|
4121
|
-
cancel: cancel$
|
|
4373
|
+
cancel: cancel$3,
|
|
4122
4374
|
/**
|
|
4123
4375
|
* @deprecated
|
|
4124
4376
|
*
|
|
@@ -4140,8 +4392,160 @@ const COPY_TABLE_RESOLVERS = {
|
|
|
4140
4392
|
getRowKey: ({ item }) => item.data.id,
|
|
4141
4393
|
};
|
|
4142
4394
|
|
|
4395
|
+
const getFolderName = (folderKey) => {
|
|
4396
|
+
return folderKey.replace(/\/$/, '').split('/').pop() ?? folderKey;
|
|
4397
|
+
};
|
|
4398
|
+
/**
|
|
4399
|
+
* Creates JSX content showing a list of folders to be deleted
|
|
4400
|
+
*/
|
|
4401
|
+
const createFolderListContent = (folders, folderListTitle) => {
|
|
4402
|
+
return (React__namespace["default"].createElement(React__namespace["default"].Fragment, null,
|
|
4403
|
+
React__namespace["default"].createElement(TextElement, { className: "amplify-modal__list-title" },
|
|
4404
|
+
React__namespace["default"].createElement("strong", null, folderListTitle)),
|
|
4405
|
+
React__namespace["default"].createElement(UnorderedListElement, { className: "amplify-modal__list" }, folders.map((folder) => (React__namespace["default"].createElement(ListItemElement, { key: folder.id, className: "amplify-modal__list-item" }, getFolderName(folder.key)))))));
|
|
4406
|
+
};
|
|
4407
|
+
const createDeleteConfirmationModalProps = ({ items, showConfirmation, displayText, }) => {
|
|
4408
|
+
const folders = getSelectedFolders(items);
|
|
4409
|
+
const folderCount = folders.length;
|
|
4410
|
+
return {
|
|
4411
|
+
isOpen: showConfirmation,
|
|
4412
|
+
title: displayText.confirmationModalTitle,
|
|
4413
|
+
message: displayText.confirmationModalMessage
|
|
4414
|
+
.replace('{count}', folderCount.toString())
|
|
4415
|
+
.replace('{plural}', folderCount !== 1 ? 's' : ''),
|
|
4416
|
+
confirmLabel: displayText.confirmationModalConfirmLabel,
|
|
4417
|
+
cancelLabel: displayText.confirmationModalCancelLabel,
|
|
4418
|
+
content: createFolderListContent(folders, displayText.confirmationModalFolderListTitle),
|
|
4419
|
+
};
|
|
4420
|
+
};
|
|
4421
|
+
/**
|
|
4422
|
+
* Maximum number of files to count before showing "+" notation
|
|
4423
|
+
* This prevents expensive operations on very large folders
|
|
4424
|
+
*/
|
|
4425
|
+
const MAX_FILE_COUNT_LIMIT = 5000;
|
|
4426
|
+
const LIST_PAGE_SIZE = 1000;
|
|
4427
|
+
/**
|
|
4428
|
+
* Count the total number of files in a folder with pagination and limits
|
|
4429
|
+
* @param folderKey - The folder path to count files in
|
|
4430
|
+
* @param config - Storage configuration
|
|
4431
|
+
* @returns Promise<number | string> - File count or "5000+" if exceeds limit
|
|
4432
|
+
*/
|
|
4433
|
+
const countFilesInFolder = async (folderKey, config) => {
|
|
4434
|
+
try {
|
|
4435
|
+
const { accountId, credentials, customEndpoint } = config;
|
|
4436
|
+
const bucket = constructBucket$1(config);
|
|
4437
|
+
let fileCount = 0;
|
|
4438
|
+
let nextToken;
|
|
4439
|
+
let hasMoreItems = true;
|
|
4440
|
+
while (hasMoreItems && fileCount < MAX_FILE_COUNT_LIMIT) {
|
|
4441
|
+
const { items, nextToken: listNextToken } = await internals.list({
|
|
4442
|
+
path: folderKey,
|
|
4443
|
+
options: {
|
|
4444
|
+
bucket,
|
|
4445
|
+
locationCredentialsProvider: credentials,
|
|
4446
|
+
expectedBucketOwner: accountId,
|
|
4447
|
+
customEndpoint,
|
|
4448
|
+
pageSize: LIST_PAGE_SIZE,
|
|
4449
|
+
nextToken,
|
|
4450
|
+
},
|
|
4451
|
+
});
|
|
4452
|
+
const batchFileCount = items.filter((item) => !item.path.endsWith('/')).length;
|
|
4453
|
+
fileCount += batchFileCount;
|
|
4454
|
+
nextToken = listNextToken;
|
|
4455
|
+
hasMoreItems = !!nextToken;
|
|
4456
|
+
if (fileCount >= MAX_FILE_COUNT_LIMIT) {
|
|
4457
|
+
return `${MAX_FILE_COUNT_LIMIT}+`;
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
if (hasMoreItems) {
|
|
4461
|
+
return `${fileCount}+`;
|
|
4462
|
+
}
|
|
4463
|
+
return fileCount;
|
|
4464
|
+
}
|
|
4465
|
+
catch (error) {
|
|
4466
|
+
return 0;
|
|
4467
|
+
}
|
|
4468
|
+
};
|
|
4469
|
+
|
|
4470
|
+
const getDeleteCellKey = (data) => `${data.key}-${data.item.data.id}`;
|
|
4471
|
+
const getCellDataFolder = (data) => {
|
|
4472
|
+
const { type, key } = data;
|
|
4473
|
+
const fileKey = getFileKey(key);
|
|
4474
|
+
const targetKey = data.key;
|
|
4475
|
+
if (type === 'FOLDER') {
|
|
4476
|
+
const pathWithoutTrailingSlash = targetKey.replace(/\/$/, '');
|
|
4477
|
+
const lastSlashIndex = pathWithoutTrailingSlash.lastIndexOf('/');
|
|
4478
|
+
return lastSlashIndex >= 0
|
|
4479
|
+
? pathWithoutTrailingSlash.slice(0, lastSlashIndex + 1)
|
|
4480
|
+
: '';
|
|
4481
|
+
}
|
|
4482
|
+
return targetKey.slice(0, -fileKey?.length);
|
|
4483
|
+
};
|
|
4484
|
+
const name$2 = (data) => {
|
|
4485
|
+
const key = getDeleteCellKey(data);
|
|
4486
|
+
const { item } = data;
|
|
4487
|
+
let text;
|
|
4488
|
+
if (item.data.type === 'FOLDER') {
|
|
4489
|
+
text = `${getFolderName(item.data.key)}/`;
|
|
4490
|
+
}
|
|
4491
|
+
else {
|
|
4492
|
+
text = item.data.fileKey ?? getCellName(item.data.key);
|
|
4493
|
+
}
|
|
4494
|
+
const icon = STATUS_ICONS[item.status];
|
|
4495
|
+
return { key, type: 'text', content: { icon, text } };
|
|
4496
|
+
};
|
|
4497
|
+
const folder$2 = (data) => {
|
|
4498
|
+
const key = getDeleteCellKey(data);
|
|
4499
|
+
const text = getCellDataFolder(data.item.data);
|
|
4500
|
+
return { key, type: 'text', content: { text } };
|
|
4501
|
+
};
|
|
4502
|
+
const type$2 = (data) => {
|
|
4503
|
+
const key = getDeleteCellKey(data);
|
|
4504
|
+
if (data.item.data.type === 'FOLDER') {
|
|
4505
|
+
return { key, type: 'text', content: { text: 'Folder' } };
|
|
4506
|
+
}
|
|
4507
|
+
const text = getFileType(data.item.data.key);
|
|
4508
|
+
return { key, type: 'text', content: { text } };
|
|
4509
|
+
};
|
|
4510
|
+
const size$2 = (data) => {
|
|
4511
|
+
const key = getDeleteCellKey(data);
|
|
4512
|
+
const itemData = data.item.data;
|
|
4513
|
+
if (data.item.data.type === 'FOLDER') {
|
|
4514
|
+
return { key, type: 'text', content: { text: '-' } };
|
|
4515
|
+
}
|
|
4516
|
+
const value = 'size' in itemData ? itemData.size : 0;
|
|
4517
|
+
const displayValue = getFileSize(value);
|
|
4518
|
+
return { key, type: 'number', content: { value, displayValue } };
|
|
4519
|
+
};
|
|
4520
|
+
const getCancelCellContent = (data) => {
|
|
4521
|
+
const { item, props } = data;
|
|
4522
|
+
const { cancel, status } = item;
|
|
4523
|
+
const { isProcessing, onTaskRemove } = props;
|
|
4524
|
+
const isQueued = status === 'QUEUED';
|
|
4525
|
+
const isRemovable = isQueued && !isProcessing;
|
|
4526
|
+
const isCancelable = isProcessing && !!cancel;
|
|
4527
|
+
const itemAriaValue = getCellName(item.data.fileKey ?? item.data.key);
|
|
4528
|
+
const ariaLabel = `${isRemovable ? 'Remove' : 'Cancel'} item: ${itemAriaValue}`;
|
|
4529
|
+
const isDisabled = !isRemovable && !isCancelable;
|
|
4530
|
+
const onClick = !isCancelable && !isRemovable
|
|
4531
|
+
? undefined
|
|
4532
|
+
: () => {
|
|
4533
|
+
if (isRemovable) {
|
|
4534
|
+
onTaskRemove?.(item);
|
|
4535
|
+
return;
|
|
4536
|
+
}
|
|
4537
|
+
if (isCancelable)
|
|
4538
|
+
cancel();
|
|
4539
|
+
};
|
|
4540
|
+
return { ariaLabel, isDisabled, onClick, icon: 'cancel' };
|
|
4541
|
+
};
|
|
4542
|
+
const cancel$2 = (data) => {
|
|
4543
|
+
const key = getDeleteCellKey(data);
|
|
4544
|
+
const content = getCancelCellContent(data);
|
|
4545
|
+
return { key, type: 'button', content };
|
|
4546
|
+
};
|
|
4143
4547
|
const status$2 = (data) => {
|
|
4144
|
-
const key =
|
|
4548
|
+
const key = getDeleteCellKey(data);
|
|
4145
4549
|
const { item: { status }, props: { displayText }, } = data;
|
|
4146
4550
|
const statusLabelKey = STATUS_LABELS[status];
|
|
4147
4551
|
const text = isDeleteViewDisplayTextKey(statusLabelKey)
|
|
@@ -4149,21 +4553,47 @@ const status$2 = (data) => {
|
|
|
4149
4553
|
: '';
|
|
4150
4554
|
return { key, type: 'text', content: { text } };
|
|
4151
4555
|
};
|
|
4556
|
+
const progress$2 = (data) => {
|
|
4557
|
+
const key = getDeleteCellKey(data);
|
|
4558
|
+
const { item } = data;
|
|
4559
|
+
const itemIsFile = item.data.type === 'FILE';
|
|
4560
|
+
if (itemIsFile) {
|
|
4561
|
+
const text = item.status === 'COMPLETE' ? 'Deleted' : '-';
|
|
4562
|
+
return { key, type: 'text', content: { text } };
|
|
4563
|
+
}
|
|
4564
|
+
if ((item.status === 'PENDING' ||
|
|
4565
|
+
item.status === 'FAILED' ||
|
|
4566
|
+
item.status === 'CANCELED') &&
|
|
4567
|
+
item.data.totalCount !== undefined) {
|
|
4568
|
+
const countDisplay = item.data.totalCount ?? '?';
|
|
4569
|
+
const text = `${item.successCount ?? 0}/${countDisplay} files`;
|
|
4570
|
+
return { key, type: 'text', content: { text } };
|
|
4571
|
+
}
|
|
4572
|
+
else if (item.status === 'COMPLETE') {
|
|
4573
|
+
if (item.data.totalCount === null) {
|
|
4574
|
+
const text = `${item.successCount ?? 0} files deleted`;
|
|
4575
|
+
return { key, type: 'text', content: { text } };
|
|
4576
|
+
}
|
|
4577
|
+
const text = `${item.data.totalCount} files deleted`;
|
|
4578
|
+
return { key, type: 'text', content: { text } };
|
|
4579
|
+
}
|
|
4580
|
+
else {
|
|
4581
|
+
const text = item.data.totalCount === null
|
|
4582
|
+
? 'Count failed'
|
|
4583
|
+
: item.data.totalCount !== undefined
|
|
4584
|
+
? `${item.data.totalCount} files`
|
|
4585
|
+
: 'Calculating...';
|
|
4586
|
+
return { key, type: 'text', content: { text } };
|
|
4587
|
+
}
|
|
4588
|
+
};
|
|
4152
4589
|
const DELETE_CELL_RESOLVERS = {
|
|
4153
4590
|
name: name$2,
|
|
4154
4591
|
folder: folder$2,
|
|
4155
4592
|
type: type$2,
|
|
4156
4593
|
size: size$2,
|
|
4157
4594
|
status: status$2,
|
|
4595
|
+
progress: progress$2,
|
|
4158
4596
|
cancel: cancel$2,
|
|
4159
|
-
/**
|
|
4160
|
-
* @deprecated
|
|
4161
|
-
*
|
|
4162
|
-
* non-upload view tables do not include "progress" headers but include here to
|
|
4163
|
-
* keep TS happy as "progress" headers were included in display text interfaces
|
|
4164
|
-
* and cannot be removed from the tables without a breaking change
|
|
4165
|
-
*/
|
|
4166
|
-
progress: ui.noop,
|
|
4167
4597
|
};
|
|
4168
4598
|
const DELETE_TABLE_RESOLVERS = {
|
|
4169
4599
|
getCell: (data) => DELETE_CELL_RESOLVERS[data.key](data),
|
|
@@ -4920,6 +5350,7 @@ function CopyViewProvider({ children, ...props }) {
|
|
|
4920
5350
|
}
|
|
4921
5351
|
|
|
4922
5352
|
const DEFAULT_STATE = {
|
|
5353
|
+
dataItems: undefined,
|
|
4923
5354
|
fileDataItems: undefined,
|
|
4924
5355
|
};
|
|
4925
5356
|
const locationItemsReducer = (prevState, event) => {
|
|
@@ -4928,27 +5359,29 @@ const locationItemsReducer = (prevState, event) => {
|
|
|
4928
5359
|
const { items } = event;
|
|
4929
5360
|
if (!items?.length)
|
|
4930
5361
|
return prevState;
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
const
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
5362
|
+
const nextDataItems = !prevState.dataItems?.length
|
|
5363
|
+
? items
|
|
5364
|
+
: prevState.dataItems.concat(items.filter((data) => !prevState.dataItems?.some(({ id }) => id === data.id)));
|
|
5365
|
+
const fileItems = items.filter((item) => item.type === 'FILE');
|
|
5366
|
+
const nextFileDataItems = !prevState.fileDataItems?.length
|
|
5367
|
+
? fileItems.map(createFileDataItem)
|
|
5368
|
+
: prevState.fileDataItems.concat(fileItems
|
|
5369
|
+
.filter((data) => !prevState.fileDataItems?.some(({ id }) => id === data.id))
|
|
5370
|
+
.map(createFileDataItem));
|
|
4939
5371
|
return {
|
|
4940
|
-
|
|
5372
|
+
dataItems: nextDataItems,
|
|
5373
|
+
fileDataItems: nextFileDataItems,
|
|
4941
5374
|
};
|
|
4942
5375
|
}
|
|
4943
5376
|
case 'REMOVE_LOCATION_ITEM': {
|
|
4944
5377
|
const { id } = event;
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
5378
|
+
const dataItems = prevState.dataItems?.filter((item) => item.id !== id);
|
|
5379
|
+
const fileDataItems = prevState.fileDataItems?.filter((item) => item.id !== id);
|
|
5380
|
+
if (dataItems?.length === prevState.dataItems?.length &&
|
|
5381
|
+
fileDataItems?.length === prevState.fileDataItems?.length) {
|
|
4949
5382
|
return prevState;
|
|
4950
5383
|
}
|
|
4951
|
-
return { fileDataItems };
|
|
5384
|
+
return { dataItems, fileDataItems };
|
|
4952
5385
|
}
|
|
4953
5386
|
case 'RESET_LOCATION_ITEMS': {
|
|
4954
5387
|
return DEFAULT_STATE;
|
|
@@ -5184,12 +5617,12 @@ CopyView.Title = TitleControl;
|
|
|
5184
5617
|
function DeleteViewProvider({ children, ...props }) {
|
|
5185
5618
|
const { DeleteView: displayText } = useDisplayText();
|
|
5186
5619
|
const { actionCancelLabel, actionExitLabel, actionStartLabel, title, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, getActionCompleteMessage, } = displayText;
|
|
5187
|
-
const { isProcessing, isProcessingComplete, statusCounts, tasks
|
|
5620
|
+
const { isProcessing, isProcessingComplete, statusCounts, tasks, confirmationModal, onActionCancel, onActionStart, onActionExit, onTaskRemove, onConfirmDelete, onCancelConfirmation, } = props;
|
|
5188
5621
|
const message = isProcessingComplete
|
|
5189
|
-
? getActionCompleteMessage({ counts: statusCounts })
|
|
5622
|
+
? getActionCompleteMessage({ counts: statusCounts, tasks })
|
|
5190
5623
|
: undefined;
|
|
5191
|
-
const tableData = useResolveTableData(
|
|
5192
|
-
items,
|
|
5624
|
+
const tableData = useResolveTableData(DELETE_TABLE_KEYS, DELETE_TABLE_RESOLVERS, {
|
|
5625
|
+
items: tasks,
|
|
5193
5626
|
props: { displayText, isProcessing, onTaskRemove },
|
|
5194
5627
|
});
|
|
5195
5628
|
return (React__namespace["default"].createElement(ControlsContextProvider, { data: {
|
|
@@ -5207,24 +5640,80 @@ function DeleteViewProvider({ children, ...props }) {
|
|
|
5207
5640
|
tableData,
|
|
5208
5641
|
title,
|
|
5209
5642
|
message,
|
|
5210
|
-
|
|
5643
|
+
confirmationModal,
|
|
5644
|
+
}, onActionStart: onActionStart, onActionExit: onActionExit, onActionCancel: onActionCancel, onConfirmationModalConfirm: onConfirmDelete, onConfirmationModalCancel: onCancelConfirmation }, children));
|
|
5211
5645
|
}
|
|
5212
5646
|
|
|
5213
5647
|
// assign to constant to ensure referential equality
|
|
5214
5648
|
const EMPTY_ITEMS$1 = [];
|
|
5215
5649
|
const useDeleteView = (options) => {
|
|
5216
5650
|
const { onExit: _onExit } = options ?? {};
|
|
5651
|
+
const { DeleteView: displayText } = useDisplayText();
|
|
5217
5652
|
const [{ location }, storeDispatch] = useStore();
|
|
5218
5653
|
const [locationItems, locationItemsDispatch] = useLocationItems();
|
|
5219
5654
|
const { current } = location;
|
|
5220
|
-
const {
|
|
5221
|
-
const
|
|
5655
|
+
const { dataItems = EMPTY_ITEMS$1 } = locationItems;
|
|
5656
|
+
const getConfig = useGetActionInput();
|
|
5657
|
+
const [itemsWithCount, setItemsWithCount] = React__namespace["default"].useState(dataItems);
|
|
5658
|
+
const folderCountsRef = React__namespace["default"].useRef(new Map());
|
|
5659
|
+
// Sync itemsWithCount with dataItems when dataItems changes (e.g., item removal)
|
|
5660
|
+
React__namespace["default"].useEffect(() => {
|
|
5661
|
+
const itemsWithAppliedCounts = dataItems.map((item) => ({
|
|
5662
|
+
...item,
|
|
5663
|
+
totalCount: folderCountsRef.current.get(item.id),
|
|
5664
|
+
}));
|
|
5665
|
+
setItemsWithCount(itemsWithAppliedCounts);
|
|
5666
|
+
}, [dataItems]);
|
|
5667
|
+
const [processState, handleProcess] = useAction('delete', {
|
|
5668
|
+
items: itemsWithCount,
|
|
5669
|
+
});
|
|
5670
|
+
const [showConfirmation, setShowConfirmation] = React__namespace["default"].useState(false);
|
|
5222
5671
|
const { isProcessing, isProcessingComplete, statusCounts, tasks } = processState;
|
|
5672
|
+
const selectionSummary = getSelectionSummary(dataItems);
|
|
5673
|
+
const { hasFolders } = selectionSummary;
|
|
5674
|
+
React__namespace["default"].useEffect(() => {
|
|
5675
|
+
const initializeFolderCounts = async () => {
|
|
5676
|
+
if (!selectionSummary.hasFolders || !current) {
|
|
5677
|
+
return;
|
|
5678
|
+
}
|
|
5679
|
+
const config = getConfig(current);
|
|
5680
|
+
const foldersToCount = dataItems.filter((item) => item.type === 'FOLDER' && !folderCountsRef.current.has(item.id));
|
|
5681
|
+
if (foldersToCount.length === 0) {
|
|
5682
|
+
return;
|
|
5683
|
+
}
|
|
5684
|
+
await Promise.all(foldersToCount.map(async (folder) => {
|
|
5685
|
+
try {
|
|
5686
|
+
const totalCount = await countFilesInFolder(folder.key, config);
|
|
5687
|
+
folderCountsRef.current.set(folder.id, totalCount);
|
|
5688
|
+
}
|
|
5689
|
+
catch (error) {
|
|
5690
|
+
folderCountsRef.current.set(folder.id, null);
|
|
5691
|
+
}
|
|
5692
|
+
}));
|
|
5693
|
+
setItemsWithCount((currentItems) => currentItems.map((item) => ({
|
|
5694
|
+
...item,
|
|
5695
|
+
totalCount: folderCountsRef.current.get(item.id),
|
|
5696
|
+
})));
|
|
5697
|
+
};
|
|
5698
|
+
initializeFolderCounts();
|
|
5699
|
+
}, [current, getConfig, selectionSummary.hasFolders, dataItems]);
|
|
5223
5700
|
const onActionStart = () => {
|
|
5224
5701
|
if (!current)
|
|
5225
5702
|
return;
|
|
5703
|
+
if (hasFolders) {
|
|
5704
|
+
setShowConfirmation(true);
|
|
5705
|
+
}
|
|
5706
|
+
else {
|
|
5707
|
+
handleProcess();
|
|
5708
|
+
}
|
|
5709
|
+
};
|
|
5710
|
+
const onConfirmDelete = () => {
|
|
5711
|
+
setShowConfirmation(false);
|
|
5226
5712
|
handleProcess();
|
|
5227
5713
|
};
|
|
5714
|
+
const onCancelConfirmation = () => {
|
|
5715
|
+
setShowConfirmation(false);
|
|
5716
|
+
};
|
|
5228
5717
|
const onActionCancel = () => {
|
|
5229
5718
|
tasks.forEach((task) => {
|
|
5230
5719
|
// @TODO Fixme, calling cancel on task doesn't currently work
|
|
@@ -5243,6 +5732,11 @@ const useDeleteView = (options) => {
|
|
|
5243
5732
|
const onTaskRemove = React__namespace["default"].useCallback(({ data }) => {
|
|
5244
5733
|
locationItemsDispatch({ type: 'REMOVE_LOCATION_ITEM', id: data.id });
|
|
5245
5734
|
}, [locationItemsDispatch]);
|
|
5735
|
+
const confirmationModal = React__namespace["default"].useMemo(() => createDeleteConfirmationModalProps({
|
|
5736
|
+
items: dataItems,
|
|
5737
|
+
showConfirmation,
|
|
5738
|
+
displayText,
|
|
5739
|
+
}), [dataItems, showConfirmation, displayText]);
|
|
5246
5740
|
return {
|
|
5247
5741
|
isProcessing,
|
|
5248
5742
|
isProcessingComplete,
|
|
@@ -5253,6 +5747,9 @@ const useDeleteView = (options) => {
|
|
|
5253
5747
|
onActionExit,
|
|
5254
5748
|
onActionStart,
|
|
5255
5749
|
onTaskRemove,
|
|
5750
|
+
onConfirmDelete,
|
|
5751
|
+
onCancelConfirmation,
|
|
5752
|
+
confirmationModal,
|
|
5256
5753
|
};
|
|
5257
5754
|
};
|
|
5258
5755
|
|
|
@@ -5271,11 +5768,13 @@ const DeleteView = ({ className, ...props }) => {
|
|
|
5271
5768
|
React__namespace["default"].createElement(MessageControl, null)),
|
|
5272
5769
|
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__buttons` },
|
|
5273
5770
|
React__namespace["default"].createElement(ActionCancelControl, null),
|
|
5274
|
-
React__namespace["default"].createElement(ActionStartControl, null)))
|
|
5771
|
+
React__namespace["default"].createElement(ActionStartControl, null))),
|
|
5772
|
+
React__namespace["default"].createElement(ActionConfirmationModalControl, null))));
|
|
5275
5773
|
};
|
|
5276
5774
|
DeleteView.displayName = 'DeleteView';
|
|
5277
5775
|
DeleteView.Provider = DeleteViewProvider;
|
|
5278
5776
|
DeleteView.Cancel = ActionCancelControl;
|
|
5777
|
+
DeleteView.ConfirmationModal = ActionConfirmationModalControl;
|
|
5279
5778
|
DeleteView.Exit = ActionExitControl;
|
|
5280
5779
|
DeleteView.Message = MessageControl;
|
|
5281
5780
|
DeleteView.Start = ActionStartControl;
|
|
@@ -5489,34 +5988,45 @@ const getFileRowContent = ({ filePreviewEnabled, permissions, isSelected, itemLo
|
|
|
5489
5988
|
}
|
|
5490
5989
|
});
|
|
5491
5990
|
|
|
5492
|
-
const getFolderRowContent = ({ itemSubPath, rowId, onNavigate, }) =>
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5991
|
+
const getFolderRowContent = ({ itemSubPath, rowId, isSelected, selectFolderLabel, onNavigate, onSelect, }) => {
|
|
5992
|
+
return LOCATION_DETAIL_VIEW_HEADERS.map((columnKey) => {
|
|
5993
|
+
const key = `${columnKey}-${rowId}`;
|
|
5994
|
+
switch (columnKey) {
|
|
5995
|
+
case 'checkbox': {
|
|
5996
|
+
return {
|
|
5997
|
+
key,
|
|
5998
|
+
type: 'checkbox',
|
|
5999
|
+
content: {
|
|
6000
|
+
checked: isSelected,
|
|
6001
|
+
id: key,
|
|
6002
|
+
label: `${selectFolderLabel} ${itemSubPath}`,
|
|
6003
|
+
onSelect,
|
|
6004
|
+
},
|
|
6005
|
+
};
|
|
6006
|
+
}
|
|
6007
|
+
case 'name': {
|
|
6008
|
+
return {
|
|
6009
|
+
key,
|
|
6010
|
+
type: 'button',
|
|
6011
|
+
content: {
|
|
6012
|
+
icon: 'folder',
|
|
6013
|
+
ariaLabel: itemSubPath,
|
|
6014
|
+
label: itemSubPath,
|
|
6015
|
+
onClick: onNavigate,
|
|
6016
|
+
},
|
|
6017
|
+
};
|
|
6018
|
+
}
|
|
6019
|
+
case 'type': {
|
|
6020
|
+
return { key, type: 'text', content: { text: 'Folder' } };
|
|
6021
|
+
}
|
|
6022
|
+
case 'last-modified':
|
|
6023
|
+
case 'size':
|
|
6024
|
+
case 'download': {
|
|
6025
|
+
return { key, type: 'text', content: { text: '' } };
|
|
6026
|
+
}
|
|
5517
6027
|
}
|
|
5518
|
-
}
|
|
5519
|
-
}
|
|
6028
|
+
});
|
|
6029
|
+
};
|
|
5520
6030
|
|
|
5521
6031
|
const getHeaders$1 = ({ tableColumnLastModifiedHeader, tableColumnNameHeader, tableColumnSizeHeader, tableColumnTypeHeader, areAllFilesSelected, selectAllFilesLabel, onSelectAll, hasFiles, }) => LOCATION_DETAIL_VIEW_HEADERS.map((key) => {
|
|
5522
6032
|
switch (key) {
|
|
@@ -5583,7 +6093,7 @@ const getHeaders$1 = ({ tableColumnLastModifiedHeader, tableColumnNameHeader, ta
|
|
|
5583
6093
|
}
|
|
5584
6094
|
});
|
|
5585
6095
|
|
|
5586
|
-
const getLocationDetailViewTableData = ({ filePreviewEnabled, activeFile, onSelectActiveFile, areAllFilesSelected, displayText, location, fileDataItems, hasFiles, pageItems, selectFileLabel, selectAllFilesLabel, getDateDisplayValue, onDownload, onNavigate, onSelect, onSelectAll, }) => {
|
|
6096
|
+
const getLocationDetailViewTableData = ({ filePreviewEnabled, activeFile, onSelectActiveFile, areAllFilesSelected, displayText, location, fileDataItems, dataItems, hasFiles, pageItems, selectFileLabel, selectAllFilesLabel, getDateDisplayValue, onDownload, onNavigate, onSelect, onSelectAll, }) => {
|
|
5587
6097
|
const { tableColumnLastModifiedHeader, tableColumnNameHeader, tableColumnSizeHeader, tableColumnTypeHeader, } = displayText;
|
|
5588
6098
|
const headers = getHeaders$1({
|
|
5589
6099
|
areAllFilesSelected,
|
|
@@ -5641,6 +6151,10 @@ const getLocationDetailViewTableData = ({ filePreviewEnabled, activeFile, onSele
|
|
|
5641
6151
|
}
|
|
5642
6152
|
onNavigate({ ...current, id }, itemLocationPath);
|
|
5643
6153
|
};
|
|
6154
|
+
const isSelected = dataItems?.some((item) => item.id === id) ?? false;
|
|
6155
|
+
const onFolderSelect = () => {
|
|
6156
|
+
onSelect(isSelected, locationItem);
|
|
6157
|
+
};
|
|
5644
6158
|
return {
|
|
5645
6159
|
key: id,
|
|
5646
6160
|
active: false,
|
|
@@ -5648,6 +6162,9 @@ const getLocationDetailViewTableData = ({ filePreviewEnabled, activeFile, onSele
|
|
|
5648
6162
|
itemSubPath,
|
|
5649
6163
|
rowId: id,
|
|
5650
6164
|
onNavigate: onFolderNavigate,
|
|
6165
|
+
selectFolderLabel: selectFileLabel,
|
|
6166
|
+
isSelected,
|
|
6167
|
+
onSelect: onFolderSelect,
|
|
5651
6168
|
}),
|
|
5652
6169
|
};
|
|
5653
6170
|
}
|
|
@@ -5659,7 +6176,7 @@ const getLocationDetailViewTableData = ({ filePreviewEnabled, activeFile, onSele
|
|
|
5659
6176
|
function LocationDetailViewProvider({ children, ...props }) {
|
|
5660
6177
|
const { LocationDetailView: displayText } = useDisplayText();
|
|
5661
6178
|
const { LocationDetailView: { loadingIndicatorLabel, searchSubfoldersToggleLabel, selectFileLabel, selectAllFilesLabel, searchPlaceholder, searchSubmitLabel, searchClearLabel, getActionListItemLabel, getDateDisplayValue, getTitle, getListItemsResultMessage, }, } = useDisplayText();
|
|
5662
|
-
const { actionItems, activeFile, activeFileHasNext, activeFileHasPrev, page, pageItems, hasNextPage, highestPageVisited, isLoading, isSearchSubfoldersEnabled, location, fileDataItems, hasError, hasDownloadError, message, downloadErrorMessage, searchQuery, hasExhaustedSearch, onActionSelect, onDropFiles, onRefresh, onPaginate, onDownload, onNavigate, onNavigateHome, onSelect, onSelectActiveFile, onToggleSelectAll, onSearch, onSearchQueryChange, onSearchClear, onToggleSearchSubfolders, filePreviewState, filePreviewEnabled, onRetryFilePreview, } = props;
|
|
6179
|
+
const { actionItems, activeFile, activeFileHasNext, activeFileHasPrev, page, pageItems, hasNextPage, highestPageVisited, isLoading, isSearchSubfoldersEnabled, location, fileDataItems, hasError, hasDownloadError, message, downloadErrorMessage, searchQuery, hasExhaustedSearch, onActionSelect, onDropFiles, onRefresh, onPaginate, onDownload, onNavigate, onNavigateHome, onSelect, onSelectActiveFile, onToggleSelectAll, onSearch, onSearchQueryChange, onSearchClear, onToggleSearchSubfolders, filePreviewState, filePreviewEnabled, onRetryFilePreview, dataItems, } = props;
|
|
5663
6180
|
const actionsWithDisplayText = actionItems.map((item) => ({
|
|
5664
6181
|
...item,
|
|
5665
6182
|
label: getActionListItemLabel(item.label),
|
|
@@ -5716,6 +6233,7 @@ function LocationDetailViewProvider({ children, ...props }) {
|
|
|
5716
6233
|
onNavigate,
|
|
5717
6234
|
onSelect,
|
|
5718
6235
|
onSelectAll: onToggleSelectAll,
|
|
6236
|
+
dataItems,
|
|
5719
6237
|
}),
|
|
5720
6238
|
title: getTitle(location),
|
|
5721
6239
|
message: messageControlContent,
|
|
@@ -5888,7 +6406,7 @@ const useLocationDetailView = (options) => {
|
|
|
5888
6406
|
const [activeFile, setActiveFile] = React__namespace["default"].useState();
|
|
5889
6407
|
const { current, key } = location;
|
|
5890
6408
|
const { permissions, prefix } = current ?? {};
|
|
5891
|
-
const { fileDataItems } = locationItems;
|
|
6409
|
+
const { dataItems, fileDataItems } = locationItems;
|
|
5892
6410
|
const hasInvalidPrefix = ui.isUndefined(prefix);
|
|
5893
6411
|
const [{ task }, handleDownload] = useAction('download');
|
|
5894
6412
|
const [{ value, isLoading, hasError, message }, handleList] = useList('locationItems');
|
|
@@ -6015,13 +6533,13 @@ const useLocationDetailView = (options) => {
|
|
|
6015
6533
|
actionType: type,
|
|
6016
6534
|
icon,
|
|
6017
6535
|
isDisabled: ui.isFunction(disable)
|
|
6018
|
-
? disable(
|
|
6536
|
+
? disable(dataItems)
|
|
6019
6537
|
: disable ?? false,
|
|
6020
6538
|
isHidden: ui.isFunction(hide) ? hide(permissions) : hide,
|
|
6021
6539
|
label,
|
|
6022
6540
|
};
|
|
6023
6541
|
});
|
|
6024
|
-
}, [actionConfigs,
|
|
6542
|
+
}, [actionConfigs, dataItems, permissions]);
|
|
6025
6543
|
return {
|
|
6026
6544
|
actionItems,
|
|
6027
6545
|
actionType,
|
|
@@ -6032,6 +6550,7 @@ const useLocationDetailView = (options) => {
|
|
|
6032
6550
|
page: currentPage,
|
|
6033
6551
|
pageItems,
|
|
6034
6552
|
location,
|
|
6553
|
+
dataItems,
|
|
6035
6554
|
fileDataItems,
|
|
6036
6555
|
hasError,
|
|
6037
6556
|
hasDownloadError: task?.status === 'FAILED',
|
|
@@ -6087,16 +6606,16 @@ const useLocationDetailView = (options) => {
|
|
|
6087
6606
|
storeDispatch({ type: 'RESET_ACTION_TYPE' });
|
|
6088
6607
|
locationItemsDispatch({ type: 'RESET_LOCATION_ITEMS' });
|
|
6089
6608
|
},
|
|
6090
|
-
onSelect: (isSelected,
|
|
6609
|
+
onSelect: (isSelected, item) => {
|
|
6091
6610
|
locationItemsDispatch(isSelected
|
|
6092
|
-
? { type: 'REMOVE_LOCATION_ITEM', id:
|
|
6093
|
-
: { type: 'SET_LOCATION_ITEMS', items: [
|
|
6611
|
+
? { type: 'REMOVE_LOCATION_ITEM', id: item.id }
|
|
6612
|
+
: { type: 'SET_LOCATION_ITEMS', items: [item] });
|
|
6094
6613
|
},
|
|
6095
6614
|
onToggleSelectAll: () => {
|
|
6096
|
-
const
|
|
6097
|
-
locationItemsDispatch(
|
|
6615
|
+
const selectableItems = pageItems;
|
|
6616
|
+
locationItemsDispatch(selectableItems.length === dataItems?.length
|
|
6098
6617
|
? { type: 'RESET_LOCATION_ITEMS' }
|
|
6099
|
-
: { type: 'SET_LOCATION_ITEMS', items:
|
|
6618
|
+
: { type: 'SET_LOCATION_ITEMS', items: selectableItems });
|
|
6100
6619
|
},
|
|
6101
6620
|
onSearch: () => {
|
|
6102
6621
|
setActiveFile(undefined);
|