@aws-amplify/ui-react-storage 3.9.0 → 3.9.2

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.
Files changed (118) hide show
  1. package/dist/browser.js +3 -1
  2. package/dist/{createAmplifyAuthAdapter-BcuxpEzi.js → createAmplifyAuthAdapter-BJjOYxQA.js} +541 -394
  3. package/dist/esm/browser.mjs +6 -0
  4. package/dist/esm/components/StorageBrowser/StorageBrowserAmplify.mjs +1 -0
  5. package/dist/esm/components/StorageBrowser/StorageBrowserDefault.mjs +3 -2
  6. package/dist/esm/components/StorageBrowser/actions/configs/defaults.mjs +10 -12
  7. package/dist/esm/components/StorageBrowser/actions/handlers/constants.mjs +4 -1
  8. package/dist/esm/components/StorageBrowser/actions/handlers/copy.mjs +4 -1
  9. package/dist/esm/components/StorageBrowser/actions/handlers/createFolder.mjs +4 -3
  10. package/dist/esm/components/StorageBrowser/actions/handlers/defaults.mjs +17 -0
  11. package/dist/esm/components/StorageBrowser/actions/handlers/delete.mjs +4 -1
  12. package/dist/esm/components/StorageBrowser/actions/handlers/download.mjs +4 -1
  13. package/dist/esm/components/StorageBrowser/actions/handlers/upload.mjs +6 -11
  14. package/dist/esm/components/StorageBrowser/actions/handlers/utils.mjs +4 -3
  15. package/dist/esm/components/StorageBrowser/adapters/createManagedAuthAdapter/createManagedAuthAdapter.mjs +2 -1
  16. package/dist/esm/components/StorageBrowser/componentsDefault.mjs +4 -4
  17. package/dist/esm/components/StorageBrowser/createStorageBrowser.mjs +7 -1
  18. package/dist/esm/components/StorageBrowser/displayText/libraries/en/shared.mjs +0 -1
  19. package/dist/esm/components/StorageBrowser/displayText/libraries/en/uploadView.mjs +3 -2
  20. package/dist/esm/components/StorageBrowser/displayText/utils.mjs +7 -0
  21. package/dist/esm/components/StorageBrowser/providers/store/locationItems/context.mjs +1 -0
  22. package/dist/esm/components/StorageBrowser/tasks/useProcessTasks.mjs +20 -22
  23. package/dist/esm/components/StorageBrowser/useAction/useAction.mjs +14 -7
  24. package/dist/esm/components/StorageBrowser/useAction/useHandler.mjs +26 -32
  25. package/dist/esm/components/StorageBrowser/useAction/useList.mjs +0 -1
  26. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.mjs +8 -10
  27. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/useCopyView.mjs +1 -0
  28. package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/useFolders.mjs +11 -13
  29. package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/useCreateFolderView.mjs +1 -0
  30. package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteViewProvider.mjs +6 -8
  31. package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/useDeleteView.mjs +6 -9
  32. package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadViewProvider.mjs +14 -10
  33. package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/useUploadView.mjs +2 -1
  34. package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.mjs +1 -0
  35. package/dist/esm/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.mjs +7 -11
  36. package/dist/esm/components/StorageBrowser/views/LocationsView/useLocationsView.mjs +5 -5
  37. package/dist/esm/components/StorageBrowser/views/context/actionViews.mjs +3 -2
  38. package/dist/esm/components/StorageBrowser/views/context/getViews.mjs +4 -1
  39. package/dist/esm/components/StorageBrowser/views/context/primaryViews.mjs +3 -2
  40. package/dist/esm/components/StorageBrowser/views/hooks/usePaginate.mjs +19 -21
  41. package/dist/esm/components/StorageBrowser/views/hooks/useResolveTableData/useResolveTableData.mjs +15 -0
  42. package/dist/esm/components/StorageBrowser/views/useView.mjs +6 -7
  43. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/constants.mjs +18 -0
  44. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/copyResolvers.mjs +82 -0
  45. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.mjs +82 -0
  46. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/uploadResolvers.mjs +112 -0
  47. package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/utils.mjs +49 -0
  48. package/dist/esm/version.mjs +1 -1
  49. package/dist/index.js +1 -1
  50. package/dist/types/components/StorageBrowser/ComponentsProvider.d.ts +4 -1
  51. package/dist/types/components/StorageBrowser/actions/configs/types.d.ts +41 -2
  52. package/dist/types/components/StorageBrowser/actions/handlers/constants.d.ts +1 -0
  53. package/dist/types/components/StorageBrowser/actions/handlers/copy.d.ts +4 -7
  54. package/dist/types/components/StorageBrowser/actions/handlers/createFolder.d.ts +1 -3
  55. package/dist/types/components/StorageBrowser/actions/handlers/defaults.d.ts +15 -0
  56. package/dist/types/components/StorageBrowser/actions/handlers/delete.d.ts +2 -2
  57. package/dist/types/components/StorageBrowser/actions/handlers/index.d.ts +1 -0
  58. package/dist/types/components/StorageBrowser/actions/handlers/listLocations.d.ts +4 -12
  59. package/dist/types/components/StorageBrowser/actions/handlers/types.d.ts +26 -17
  60. package/dist/types/components/StorageBrowser/actions/handlers/upload.d.ts +1 -4
  61. package/dist/types/components/StorageBrowser/actions/handlers/utils.d.ts +2 -2
  62. package/dist/types/components/StorageBrowser/actions/index.d.ts +1 -1
  63. package/dist/types/components/StorageBrowser/componentsDefault.d.ts +2 -2
  64. package/dist/types/components/StorageBrowser/createStorageBrowser.d.ts +6 -0
  65. package/dist/types/components/StorageBrowser/displayText/index.d.ts +1 -0
  66. package/dist/types/components/StorageBrowser/displayText/types.d.ts +16 -5
  67. package/dist/types/components/StorageBrowser/displayText/utils.d.ts +3 -0
  68. package/dist/types/components/StorageBrowser/index.d.ts +4 -3
  69. package/dist/types/components/StorageBrowser/providers/configuration/createConfigurationProvider.d.ts +1 -1
  70. package/dist/types/components/StorageBrowser/providers/configuration/types.d.ts +3 -3
  71. package/dist/types/components/StorageBrowser/providers/index.d.ts +1 -1
  72. package/dist/types/components/StorageBrowser/providers/store/actionType/types.d.ts +4 -0
  73. package/dist/types/components/StorageBrowser/providers/store/files/types.d.ts +1 -4
  74. package/dist/types/components/StorageBrowser/providers/store/index.d.ts +1 -1
  75. package/dist/types/components/StorageBrowser/providers/store/location/context.d.ts +6 -0
  76. package/dist/types/components/StorageBrowser/storage-internal.d.ts +1 -1
  77. package/dist/types/components/StorageBrowser/tasks/index.d.ts +1 -1
  78. package/dist/types/components/StorageBrowser/tasks/types.d.ts +41 -23
  79. package/dist/types/components/StorageBrowser/tasks/useProcessTasks.d.ts +3 -3
  80. package/dist/types/components/StorageBrowser/types.d.ts +191 -15
  81. package/dist/types/components/StorageBrowser/useAction/types.d.ts +60 -32
  82. package/dist/types/components/StorageBrowser/useAction/useHandler.d.ts +4 -3
  83. package/dist/types/components/StorageBrowser/useAction/useList.d.ts +10 -7
  84. package/dist/types/components/StorageBrowser/views/LocationActionView/CopyView/types.d.ts +5 -0
  85. package/dist/types/components/StorageBrowser/views/LocationActionView/UploadView/types.d.ts +2 -2
  86. package/dist/types/components/StorageBrowser/views/LocationActionView/types.d.ts +4 -4
  87. package/dist/types/components/StorageBrowser/views/LocationDetailView/index.d.ts +1 -1
  88. package/dist/types/components/StorageBrowser/views/LocationsView/index.d.ts +1 -1
  89. package/dist/types/components/StorageBrowser/views/context/getViews.d.ts +2 -2
  90. package/dist/types/components/StorageBrowser/views/context/views.d.ts +2 -2
  91. package/dist/types/components/StorageBrowser/views/hooks/usePaginate.d.ts +8 -8
  92. package/dist/types/components/StorageBrowser/views/hooks/useResolveTableData/index.d.ts +2 -0
  93. package/dist/types/components/StorageBrowser/views/hooks/useResolveTableData/types.d.ts +26 -0
  94. package/dist/types/components/StorageBrowser/views/hooks/useResolveTableData/useResolveTableData.d.ts +6 -0
  95. package/dist/types/components/StorageBrowser/views/types.d.ts +1 -1
  96. package/dist/types/components/StorageBrowser/views/useView.d.ts +16 -13
  97. package/dist/types/components/StorageBrowser/views/utils/index.d.ts +1 -0
  98. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/__testUtils__/tasks.d.ts +23 -0
  99. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/constants.d.ts +16 -0
  100. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/copyResolvers.d.ts +3 -0
  101. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.d.ts +3 -0
  102. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/index.d.ts +3 -0
  103. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/types.d.ts +36 -0
  104. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/uploadResolvers.d.ts +3 -0
  105. package/dist/types/components/StorageBrowser/views/utils/tableResolvers/utils.d.ts +12 -0
  106. package/dist/types/version.d.ts +1 -1
  107. package/package.json +5 -5
  108. package/dist/esm/components/StorageBrowser/views/LocationActionView/getActionIcon.mjs +0 -25
  109. package/dist/esm/components/StorageBrowser/views/LocationActionView/getActionViewTableData.mjs +0 -155
  110. package/dist/esm/components/StorageBrowser/views/LocationActionView/getDefaultActionViewHeaders.mjs +0 -24
  111. package/dist/esm/components/StorageBrowser/views/LocationActionView/getFileTypeDisplayValue.mjs +0 -5
  112. package/dist/esm/components/StorageBrowser/views/LocationActionView/getPercentValue.mjs +0 -3
  113. package/dist/types/components/StorageBrowser/displayText/en.d.ts +0 -9
  114. package/dist/types/components/StorageBrowser/views/LocationActionView/getActionIcon.d.ts +0 -3
  115. package/dist/types/components/StorageBrowser/views/LocationActionView/getActionViewTableData.d.ts +0 -14
  116. package/dist/types/components/StorageBrowser/views/LocationActionView/getDefaultActionViewHeaders.d.ts +0 -5
  117. package/dist/types/components/StorageBrowser/views/LocationActionView/getFileTypeDisplayValue.d.ts +0 -1
  118. package/dist/types/components/StorageBrowser/views/LocationActionView/getPercentValue.d.ts +0 -1
@@ -32,7 +32,12 @@ function _interopNamespace(e) {
32
32
 
33
33
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
34
34
 
35
- const VERSION = '3.9.0';
35
+ const VERSION = '3.9.2';
36
+
37
+ const DEFAULT_CHECKSUM_ALGORITHM = 'crc-32';
38
+ // 5MiB for multipart upload
39
+ // https://github.com/aws-amplify/amplify-js/blob/1a5366d113c9af4ce994168653df3aadb142c581/packages/storage/src/providers/s3/utils/constants.ts#L16
40
+ const MULTIPART_UPLOAD_THRESHOLD_BYTES = 5 * 1024 * 1024;
36
41
 
37
42
  const constructBucket = ({ bucket: bucketName, region, }) => ({ bucketName, region });
38
43
  const parseAccessGrantLocation = (location) => {
@@ -118,9 +123,8 @@ const createFileDataItem = (data) => ({
118
123
  ...data,
119
124
  fileKey: getFileKey(data.key),
120
125
  });
121
- const isFileItem = (value) => !!value.file;
122
- const isFileDataItem = (item) => !!item.fileKey;
123
126
  const getProgress = ({ totalBytes, transferredBytes, }) => totalBytes ? transferredBytes / totalBytes : undefined;
127
+ const isMultipartUpload = (file) => file.size > MULTIPART_UPLOAD_THRESHOLD_BYTES;
124
128
 
125
129
  const copyHandler = (input) => {
126
130
  const { config, data } = input;
@@ -155,12 +159,13 @@ const copyHandler = (input) => {
155
159
  status: 'COMPLETE',
156
160
  value: { key: path },
157
161
  }))
158
- .catch(({ message }) => ({ message, status: 'FAILED' })),
162
+ .catch((error) => {
163
+ const { message } = error;
164
+ return { error, message, status: 'FAILED' };
165
+ }),
159
166
  };
160
167
  };
161
168
 
162
- const DEFAULT_CHECKSUM_ALGORITHM = 'crc-32';
163
-
164
169
  const createFolderHandler = (input) => {
165
170
  const { config, data, options } = input;
166
171
  const { accountId, credentials, customEndpoint } = config;
@@ -189,11 +194,12 @@ const createFolderHandler = (input) => {
189
194
  status: 'COMPLETE',
190
195
  value: { key: path },
191
196
  }))
192
- .catch(({ message, name }) => {
197
+ .catch((error) => {
198
+ const { message, name } = error;
193
199
  if (name === 'PreconditionFailed') {
194
- return { message, status: 'OVERWRITE_PREVENTED' };
200
+ return { error, message, status: 'OVERWRITE_PREVENTED' };
195
201
  }
196
- return { message, status: 'FAILED' };
202
+ return { error, message, status: 'FAILED' };
197
203
  }),
198
204
  };
199
205
  };
@@ -214,7 +220,10 @@ const deleteHandler = ({ config, data, }) => {
214
220
  status: 'COMPLETE',
215
221
  value: { key: path },
216
222
  }))
217
- .catch(({ message }) => ({ message, status: 'FAILED' }));
223
+ .catch((error) => {
224
+ const { message } = error;
225
+ return { error, message, status: 'FAILED' };
226
+ });
218
227
  return { result };
219
228
  };
220
229
 
@@ -244,11 +253,14 @@ const downloadHandler = ({ config, data: { key }, }) => {
244
253
  downloadFromUrl(key, url.toString());
245
254
  return { status: 'COMPLETE', value: { url } };
246
255
  })
247
- .catch(({ message }) => ({ message, status: 'FAILED' }));
256
+ .catch((error) => {
257
+ const { message } = error;
258
+ return { error, message, status: 'FAILED' };
259
+ });
248
260
  return { result };
249
261
  };
250
262
 
251
- const DEFAULT_PAGE_SIZE$3 = 1000;
263
+ const DEFAULT_PAGE_SIZE$4 = 1000;
252
264
  const parseItems = (items, excludedPath) => items
253
265
  // remove root `key` from results
254
266
  .filter(({ path }) => path !== excludedPath)
@@ -281,7 +293,7 @@ const parseResult = ({ excludedSubpaths, items }, prefix) => filterDotItems([...
281
293
  const listLocationItemsHandler = async (input) => {
282
294
  const { config, prefix, options } = input;
283
295
  const { bucket: _bucket, credentials, customEndpoint, region, accountId, } = config;
284
- const { exclude, delimiter, nextToken, pageSize: _pageSize = DEFAULT_PAGE_SIZE$3, ..._options } = options ?? {};
296
+ const { exclude, delimiter, nextToken, pageSize: _pageSize = DEFAULT_PAGE_SIZE$4, ..._options } = options ?? {};
285
297
  const bucket = { bucketName: _bucket, region };
286
298
  const subpathStrategy = {
287
299
  delimiter,
@@ -318,39 +330,6 @@ const listLocationItemsHandler = async (input) => {
318
330
  return { items: result, nextToken: nextNextToken };
319
331
  };
320
332
 
321
- function assertLocationPermissions(value, message) {
322
- if (!Array.isArray(value) ||
323
- value.some((inputPermissionEntry) => typeof inputPermissionEntry !== 'string' ||
324
- !['list', 'get', 'write', 'delete'].includes(inputPermissionEntry))) {
325
- throw new Error(message);
326
- }
327
- }
328
- function assertLocationData(value, message = 'Invalid value provided as `location`.') {
329
- const locationStringDataKeys = ['bucket', 'id', 'prefix', 'type'];
330
- if (!ui.isObject(value) ||
331
- locationStringDataKeys.some((key) => !ui.isString(value[key]))) {
332
- throw new Error(message);
333
- }
334
- assertLocationPermissions(value?.permissions, message);
335
- }
336
- function assertPrefix(value, message) {
337
- if (!ui.isString(value)) {
338
- throw new Error(message ?? 'Invalid value provided as `prefix`.');
339
- }
340
- }
341
-
342
- function assertRegisterAuthListener(value) {
343
- if (!ui.isFunction(value)) {
344
- throw new Error('StorageBrowser: `registerAuthListener` must be a function.');
345
- }
346
- }
347
-
348
- const UPLOAD_FILE_SIZE_LIMIT = 160 * 1000 * 1000 * 1000;
349
- const isFileTooBig = (file) => file.size > UPLOAD_FILE_SIZE_LIMIT;
350
-
351
- // 5MB for multipart upload
352
- // https://github.com/aws-amplify/amplify-js/blob/1a5366d113c9af4ce994168653df3aadb142c581/packages/storage/src/providers/s3/utils/constants.ts#L16
353
- const MULTIPART_UPLOAD_THRESHOLD_BYTES = 5 * 1024 * 1024;
354
333
  const UNDEFINED_CALLBACKS = {
355
334
  cancel: undefined,
356
335
  pause: undefined,
@@ -378,7 +357,7 @@ const uploadHandler = ({ config, data, options }) => {
378
357
  };
379
358
  const { cancel, pause, resume, result } = internals.uploadData(input);
380
359
  return {
381
- ...(file.size > MULTIPART_UPLOAD_THRESHOLD_BYTES
360
+ ...(isMultipartUpload(file)
382
361
  ? { cancel, pause, resume }
383
362
  : UNDEFINED_CALLBACKS),
384
363
  result: result
@@ -389,16 +368,53 @@ const uploadHandler = ({ config, data, options }) => {
389
368
  .catch((error) => {
390
369
  const { message } = error;
391
370
  if (error.name === 'PreconditionFailed') {
392
- return { message, status: 'OVERWRITE_PREVENTED' };
371
+ return { error, message, status: 'OVERWRITE_PREVENTED' };
393
372
  }
394
- return {
395
- message,
396
- status: storage.isCancelError(error) ? 'CANCELED' : 'FAILED',
397
- };
373
+ const status = storage.isCancelError(error) ? 'CANCELED' : 'FAILED';
374
+ return { error, message, status };
398
375
  }),
399
376
  };
400
377
  };
401
378
 
379
+ const defaultHandlers = {
380
+ copy: copyHandler,
381
+ createFolder: createFolderHandler,
382
+ delete: deleteHandler,
383
+ download: downloadHandler,
384
+ listLocationItems: listLocationItemsHandler,
385
+ upload: uploadHandler,
386
+ };
387
+
388
+ function assertLocationPermissions(value, message) {
389
+ if (!Array.isArray(value) ||
390
+ value.some((inputPermissionEntry) => typeof inputPermissionEntry !== 'string' ||
391
+ !['list', 'get', 'write', 'delete'].includes(inputPermissionEntry))) {
392
+ throw new Error(message);
393
+ }
394
+ }
395
+ function assertLocationData(value, message = 'Invalid value provided as `location`.') {
396
+ const locationStringDataKeys = ['bucket', 'id', 'prefix', 'type'];
397
+ if (!ui.isObject(value) ||
398
+ locationStringDataKeys.some((key) => !ui.isString(value[key]))) {
399
+ throw new Error(message);
400
+ }
401
+ assertLocationPermissions(value?.permissions, message);
402
+ }
403
+ function assertPrefix(value, message) {
404
+ if (!ui.isString(value)) {
405
+ throw new Error(message ?? 'Invalid value provided as `prefix`.');
406
+ }
407
+ }
408
+
409
+ function assertRegisterAuthListener(value) {
410
+ if (!ui.isFunction(value)) {
411
+ throw new Error('StorageBrowser: `registerAuthListener` must be a function.');
412
+ }
413
+ }
414
+
415
+ const UPLOAD_FILE_SIZE_LIMIT = 160 * 1000 * 1000 * 1000;
416
+ const isFileTooBig = (file) => file.size > UPLOAD_FILE_SIZE_LIMIT;
417
+
402
418
  const defaultValue$9 = {
403
419
  actionConfigs: undefined,
404
420
  };
@@ -412,7 +428,7 @@ const copyActionConfig = {
412
428
  icon: 'copy-file',
413
429
  label: 'Copy',
414
430
  },
415
- handler: copyHandler,
431
+ handler: defaultHandlers.copy,
416
432
  };
417
433
  const deleteActionConfig = {
418
434
  viewName: 'DeleteView',
@@ -422,7 +438,7 @@ const deleteActionConfig = {
422
438
  icon: 'delete-file',
423
439
  label: 'Delete',
424
440
  },
425
- handler: deleteHandler,
441
+ handler: defaultHandlers.delete,
426
442
  };
427
443
  const createFolderActionConfig = {
428
444
  viewName: 'CreateFolderView',
@@ -431,7 +447,7 @@ const createFolderActionConfig = {
431
447
  icon: 'create-folder',
432
448
  label: 'Create folder',
433
449
  },
434
- handler: createFolderHandler,
450
+ handler: defaultHandlers.createFolder,
435
451
  };
436
452
  const uploadActionConfig = {
437
453
  viewName: 'UploadView',
@@ -440,12 +456,14 @@ const uploadActionConfig = {
440
456
  icon: 'upload-file',
441
457
  label: 'Upload',
442
458
  },
443
- handler: uploadHandler,
459
+ handler: defaultHandlers.upload,
444
460
  };
461
+ // Action view configs only, does not include `listLocationItems`
445
462
  const defaultActionViewConfigs = {
446
463
  copy: copyActionConfig,
447
464
  createFolder: createFolderActionConfig,
448
- download: downloadHandler,
465
+ // provide `download` handler only; `download` does not have a dedicated view/config
466
+ download: defaultHandlers.download,
449
467
  delete: deleteActionConfig,
450
468
  upload: uploadActionConfig,
451
469
  };
@@ -453,7 +471,7 @@ const DEFAULT_ACTION_VIEW_TYPES = Object.keys(defaultActionViewConfigs);
453
471
  const isDefaultActionViewType = (value) => DEFAULT_ACTION_VIEW_TYPES.some((type) => type === value);
454
472
  const defaultActionConfigs = {
455
473
  ...defaultActionViewConfigs,
456
- listLocationItems: listLocationItemsHandler,
474
+ listLocationItems: defaultHandlers.listLocationItems,
457
475
  };
458
476
 
459
477
  const isActionConfig = (value) => ui.isObject(value);
@@ -1084,7 +1102,7 @@ const OverwriteToggle = ({ isDisabled, isOverwritingEnabled, label = '', onToggl
1084
1102
  onToggle?.();
1085
1103
  } }));
1086
1104
  };
1087
- const SearchSubfoldersToggle = ({ isSearchingSubfolders, label = '', onToggle, }) => {
1105
+ const SearchSubfoldersToggle = ({ isSearchingSubfolders, label = '', onToggle }) => {
1088
1106
  return (React__namespace.createElement(uiReact.CheckboxField, { name: label, label: label, labelPosition: "end", checked: isSearchingSubfolders, onChange: () => {
1089
1107
  onToggle?.();
1090
1108
  } }));
@@ -1114,7 +1132,7 @@ const Navigation = ({ items }) => {
1114
1132
  item.isCurrent ? null : React__namespace.createElement(uiReact.Breadcrumbs.Separator, null)));
1115
1133
  })));
1116
1134
  };
1117
- const LoadingIndicator = ({ isLoading }) => {
1135
+ const LoadingIndicator = ({ isLoading, }) => {
1118
1136
  if (isLoading) {
1119
1137
  return (React__namespace.createElement(uiReact.Loader, { className: "amplify-storage-browser__loader", variation: "linear", size: "small" }));
1120
1138
  }
@@ -1129,7 +1147,7 @@ const FolderNameField = ({ onChange, label, placeholder, validationMessage, onVa
1129
1147
  onChange?.(value);
1130
1148
  } }));
1131
1149
  };
1132
- const DataRefresh = ({ onRefresh }) => {
1150
+ const DataRefresh = ({ onRefresh, }) => {
1133
1151
  return (React__namespace.createElement(uiReact.Button, { onClick: () => {
1134
1152
  onRefresh?.();
1135
1153
  }, "aria-label": "Refresh data" },
@@ -1147,7 +1165,7 @@ const ActionsList = ({ items, onActionSelect, isDisabled, }) => {
1147
1165
  label));
1148
1166
  })));
1149
1167
  };
1150
- const StatusDisplay = ({ statuses, total }) => {
1168
+ const StatusDisplay = ({ statuses, total, }) => {
1151
1169
  if (!statuses?.length) {
1152
1170
  return null;
1153
1171
  }
@@ -1203,7 +1221,6 @@ const DEFAULT_ACTION_VIEW_DISPLAY_TEXT = {
1203
1221
  tableColumnNameHeader: 'Name',
1204
1222
  tableColumnTypeHeader: 'Type',
1205
1223
  tableColumnSizeHeader: 'Size',
1206
- tableColumnProgressHeader: 'Progress',
1207
1224
  };
1208
1225
  const DEFAULT_LIST_VIEW_DISPLAY_TEXT = {
1209
1226
  loadingIndicatorLabel: 'Loading',
@@ -1433,7 +1450,6 @@ const DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT = {
1433
1450
 
1434
1451
  const DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT = {
1435
1452
  ...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
1436
- title: 'Upload',
1437
1453
  actionStartLabel: 'Upload',
1438
1454
  addFilesLabel: 'Add files',
1439
1455
  addFolderLabel: 'Add folder',
@@ -1509,8 +1525,10 @@ const DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT = {
1509
1525
  }
1510
1526
  return undefined;
1511
1527
  },
1512
- statusDisplayOverwritePreventedLabel: 'Overwrite prevented',
1513
1528
  overwriteToggleLabel: 'Overwrite existing files',
1529
+ statusDisplayOverwritePreventedLabel: 'Overwrite prevented',
1530
+ tableColumnProgressHeader: 'Progress',
1531
+ title: 'Upload',
1514
1532
  };
1515
1533
 
1516
1534
  const DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT = {
@@ -1561,6 +1579,9 @@ function DisplayTextProvider({ children, displayText: _override, }) {
1561
1579
  return (React__namespace["default"].createElement(DisplayTextContext.Provider, { value: resolvedDisplayText }, children));
1562
1580
  }
1563
1581
 
1582
+ const isCopyViewDisplayTextKey = (value) => !!DEFAULT_COPY_VIEW_DISPLAY_TEXT[value];
1583
+ const isDeleteViewDisplayTextKey = (value) => !!DEFAULT_DELETE_VIEW_DISPLAY_TEXT[value];
1584
+
1564
1585
  const Fallback = () => (React__namespace["default"].createElement("div", { className: STORAGE_BROWSER_BLOCK_TO_BE_UPDATED },
1565
1586
  React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__error-boundary` }, "Something went wrong.")));
1566
1587
  class ErrorBoundary extends React__namespace["default"].Component {
@@ -2464,207 +2485,342 @@ const TitleControl = () => {
2464
2485
  return React__namespace["default"].createElement(Resolved, { ...props });
2465
2486
  };
2466
2487
 
2467
- const getActionIcon = (status) => {
2468
- switch (status) {
2469
- case 'PENDING': {
2470
- return 'action-progress';
2471
- }
2472
- case 'COMPLETE': {
2473
- return 'action-success';
2474
- }
2475
- case 'FAILED': {
2476
- return 'action-error';
2477
- }
2478
- case 'OVERWRITE_PREVENTED': {
2479
- return 'action-info';
2480
- }
2481
- case 'CANCELED': {
2482
- return 'action-canceled';
2483
- }
2484
- case 'QUEUED':
2485
- default: {
2486
- return 'action-queued';
2487
- }
2488
- }
2489
- };
2490
-
2491
- const getFileTypeDisplayValue = (fileName) => fileName.lastIndexOf('.') !== -1
2492
- ? fileName.slice(fileName.lastIndexOf('.') + 1)
2493
- : '';
2488
+ function useResolveDataTable(keys, { getCell, getHeader, getRowKey }, { items, props }) {
2489
+ return React__namespace["default"].useMemo(() => {
2490
+ const getRow = (item) => ({
2491
+ key: getRowKey({ item, props }),
2492
+ content: keys.map((key) => getCell({ key, item, props })),
2493
+ });
2494
+ const headers = keys.map((key) => getHeader({ key, props }));
2495
+ const rows = (items ?? []).map(getRow);
2496
+ return { headers, rows };
2497
+ }, [getCell, getHeader, getRowKey, keys, items, props]);
2498
+ }
2494
2499
 
2495
- const getPercentValue = (value) => Math.round(value * 100);
2500
+ const STATUS_LABELS = {
2501
+ PENDING: 'statusDisplayInProgressLabel',
2502
+ CANCELED: 'statusDisplayCanceledLabel',
2503
+ COMPLETE: 'statusDisplayCompletedLabel',
2504
+ FAILED: 'statusDisplayFailedLabel',
2505
+ QUEUED: 'statusDisplayQueuedLabel',
2506
+ OVERWRITE_PREVENTED: 'statusDisplayOverwritePreventedLabel',
2507
+ };
2508
+ const STATUS_ICONS = {
2509
+ PENDING: 'action-progress',
2510
+ COMPLETE: 'action-success',
2511
+ FAILED: 'action-error',
2512
+ OVERWRITE_PREVENTED: 'action-info',
2513
+ CANCELED: 'action-canceled',
2514
+ QUEUED: 'action-queued',
2515
+ };
2516
+
2517
+ const getFileType = (value, fallback = '') => value.lastIndexOf('.') !== -1
2518
+ ? value.slice(value.lastIndexOf('.') + 1)
2519
+ : fallback;
2520
+ const getCellName = (value) =>
2521
+ // `value.split` always returns an array with at least one entry
2522
+ // ensruing `.pop()` will always return a string
2523
+ value.split('/').pop();
2524
+ const getUploadCellFolder = ({ data: { file: { webkitRelativePath }, }, }, fallback = '-') => webkitRelativePath
2525
+ ? webkitRelativePath.slice(0, webkitRelativePath.lastIndexOf('/') + 1)
2526
+ : fallback;
2527
+ const getCopyCellFolder = ({ data: { fileKey, sourceKey }, }) => sourceKey.slice(0, -fileKey.length);
2528
+ const getDeleteCellFolder = ({ data: { fileKey, key }, }) => key.slice(0, -fileKey.length);
2529
+ const getUploadCellProgress = ({ progress, status, }) => {
2530
+ // prefer `progress` if available, 1 if status is complete, default 0
2531
+ const value = progress ?? (status === 'COMPLETE' ? 1 : 0);
2532
+ const displayValue = `${Math.round(value * 100)}%`;
2533
+ return { displayValue, value };
2534
+ };
2535
+ const getFileSize = (value, fallback = '-') => (!value ? fallback : ui.humanFileSize(value, true));
2536
+ const getCopyOrDeleteCancelCellContent = (data) => {
2537
+ const { item, props } = data;
2538
+ const { cancel, status } = item;
2539
+ const { isProcessing, onTaskRemove } = props;
2540
+ const isQueued = status === 'QUEUED';
2541
+ // a task is removable prior to processing start. Including `isQueued` ensures
2542
+ // that `isRemovable` is `false` on all tasks processing complete
2543
+ const isRemovable = isQueued && !isProcessing;
2544
+ // a task is cancelable while processing is true, and the task has a cancel handler
2545
+ const isCancelable = isProcessing && !!cancel;
2546
+ const ariaLabel = `${isRemovable ? 'Remove' : 'Cancel'} item: ${getCellName(item.data.fileKey)}`;
2547
+ const isDisabled = !isRemovable && !isCancelable;
2548
+ // resolve to `undefined` if not cancelable or removable
2549
+ const onClick = !isCancelable && !isRemovable
2550
+ ? undefined
2551
+ : () => {
2552
+ if (isRemovable) {
2553
+ onTaskRemove?.(item);
2554
+ // do not run cancel handler on remove
2555
+ return;
2556
+ }
2557
+ if (isCancelable)
2558
+ cancel();
2559
+ };
2560
+ return { ariaLabel, isDisabled, onClick, icon: 'cancel' };
2561
+ };
2496
2562
 
2497
- const getDefaultActionViewHeaders = ({ displayText: { tableColumnNameHeader, tableColumnTypeHeader, tableColumnSizeHeader, tableColumnStatusHeader, tableColumnCancelHeader, tableColumnFolderHeader, }, }) => {
2498
- return [
2499
- {
2500
- key: 'name',
2501
- type: 'sort',
2502
- content: { label: tableColumnNameHeader },
2503
- },
2504
- {
2505
- key: 'folder',
2506
- type: 'sort',
2507
- content: { label: tableColumnFolderHeader },
2508
- },
2509
- { key: 'type', type: 'sort', content: { label: tableColumnTypeHeader } },
2510
- { key: 'size', type: 'sort', content: { label: tableColumnSizeHeader } },
2511
- {
2512
- key: 'status',
2513
- type: 'sort',
2514
- content: { label: tableColumnStatusHeader },
2515
- },
2516
- { key: 'cancel', type: 'text', content: { text: tableColumnCancelHeader } },
2517
- ];
2563
+ const COPY_TABLE_KEYS = [
2564
+ 'name',
2565
+ 'folder',
2566
+ 'type',
2567
+ 'size',
2568
+ 'status',
2569
+ 'cancel',
2570
+ ];
2571
+ const getCopyCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
2572
+ const name$2 = (data) => {
2573
+ const key = getCopyCellKey(data);
2574
+ const { item } = data;
2575
+ const text = item.data.fileKey;
2576
+ const icon = STATUS_ICONS[item.status];
2577
+ return { key, type: 'text', content: { icon, text } };
2578
+ };
2579
+ const folder$2 = (data) => {
2580
+ const key = getCopyCellKey(data);
2581
+ const text = getCopyCellFolder(data.item);
2582
+ return { key, type: 'text', content: { text } };
2583
+ };
2584
+ const type$2 = (data) => {
2585
+ const key = getCopyCellKey(data);
2586
+ const { fileKey } = data.item.data;
2587
+ const text = getFileType(fileKey);
2588
+ return { key, type: 'text', content: { text } };
2589
+ };
2590
+ const size$2 = (data) => {
2591
+ const key = getCopyCellKey(data);
2592
+ const { size: value } = data.item.data;
2593
+ const displayValue = getFileSize(value);
2594
+ return { key, type: 'number', content: { value, displayValue } };
2595
+ };
2596
+ const status$2 = (data) => {
2597
+ const key = getCopyCellKey(data);
2598
+ const { item: { status }, props: { displayText }, } = data;
2599
+ const statusLabelKey = STATUS_LABELS[status];
2600
+ const text = isCopyViewDisplayTextKey(statusLabelKey)
2601
+ ? displayText[statusLabelKey]
2602
+ : '';
2603
+ return { key, type: 'text', content: { text } };
2604
+ };
2605
+ const cancel$2 = (data) => {
2606
+ const key = getCopyCellKey(data);
2607
+ const content = getCopyOrDeleteCancelCellContent(data);
2608
+ return { key, type: 'button', content };
2609
+ };
2610
+ const COPY_CELL_RESOLVERS = {
2611
+ name: name$2,
2612
+ folder: folder$2,
2613
+ type: type$2,
2614
+ size: size$2,
2615
+ status: status$2,
2616
+ cancel: cancel$2,
2617
+ /**
2618
+ * @deprecated
2619
+ *
2620
+ * non-upload view tables do not include "progress" headers but include here to
2621
+ * keep TS happy as "progress" headers were included in display text interfaces
2622
+ * and cannot be removed from the tables without a breaking change
2623
+ */
2624
+ progress: ui.noop,
2625
+ };
2626
+ const COPY_TABLE_RESOLVERS = {
2627
+ getCell: (data) => COPY_CELL_RESOLVERS[data.key](data),
2628
+ getHeader: ({ key, props: { displayText } }) => {
2629
+ const text = displayText[`tableColumn${ui.capitalize(key)}Header`];
2630
+ if (key === 'cancel') {
2631
+ return { key, type: 'text', content: { text } };
2632
+ }
2633
+ return { key, type: 'sort', content: { label: text } };
2634
+ },
2635
+ getRowKey: ({ item }) => item.data.id,
2518
2636
  };
2519
2637
 
2520
- const getTaskStatusDisplayLabel = ({ status, displayText: { statusDisplayInProgressLabel, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, statusDisplayOverwritePreventedLabel, }, }) => {
2521
- switch (status) {
2522
- case 'PENDING':
2523
- return statusDisplayInProgressLabel;
2524
- case 'CANCELED':
2525
- return statusDisplayCanceledLabel;
2526
- case 'COMPLETE':
2527
- return statusDisplayCompletedLabel;
2528
- case 'FAILED':
2529
- return statusDisplayFailedLabel;
2530
- case 'QUEUED':
2531
- return statusDisplayQueuedLabel;
2532
- case 'OVERWRITE_PREVENTED':
2533
- return statusDisplayOverwritePreventedLabel;
2534
- default:
2535
- return statusDisplayQueuedLabel;
2638
+ const UPLOAD_TABLE_KEYS = [
2639
+ 'name',
2640
+ 'folder',
2641
+ 'type',
2642
+ 'size',
2643
+ 'status',
2644
+ 'progress',
2645
+ 'cancel',
2646
+ ];
2647
+ const getUploadCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
2648
+ const name$1 = (data) => {
2649
+ const key = getUploadCellKey(data);
2650
+ const { item } = data;
2651
+ const icon = STATUS_ICONS[item.status];
2652
+ const text = getCellName(item.data.key);
2653
+ return { key, type: 'text', content: { icon, text } };
2654
+ };
2655
+ const folder$1 = (data) => {
2656
+ const key = getUploadCellKey(data);
2657
+ const text = getUploadCellFolder(data.item);
2658
+ return { key, type: 'text', content: { text } };
2659
+ };
2660
+ const type$1 = (data) => {
2661
+ const key = getUploadCellKey(data);
2662
+ const { item } = data;
2663
+ const text = getFileType(getCellName(item.data.key));
2664
+ return { key, type: 'text', content: { text } };
2665
+ };
2666
+ const size$1 = (data) => {
2667
+ const key = getUploadCellKey(data);
2668
+ const { size: value } = data.item.data.file;
2669
+ const displayValue = getFileSize(value);
2670
+ return { key, type: 'number', content: { value, displayValue } };
2671
+ };
2672
+ const status$1 = (data) => {
2673
+ const key = getUploadCellKey(data);
2674
+ const { item: { status }, props: { displayText }, } = data;
2675
+ const text = displayText[STATUS_LABELS[status]];
2676
+ return { key, type: 'text', content: { text } };
2677
+ };
2678
+ const progress = (data) => {
2679
+ const key = getUploadCellKey(data);
2680
+ const content = getUploadCellProgress(data.item);
2681
+ return { key, type: 'number', content };
2682
+ };
2683
+ const cancel$1 = (data) => {
2684
+ const key = getUploadCellKey(data);
2685
+ const { item, props } = data;
2686
+ const { cancel, data: taskData, status, progress } = item;
2687
+ const { isMultipartUpload, isProcessing, onTaskRemove } = props;
2688
+ const isQueued = status === 'QUEUED';
2689
+ const isPending = status === 'PENDING';
2690
+ // cancelability is dependent on differing conditions for multipart and single part uploads
2691
+ let isCancelable;
2692
+ if (isMultipartUpload(taskData.file)) {
2693
+ // signals MPU complete has been reached
2694
+ const hasUploadedAllBytes = progress === 1;
2695
+ // MPU allows cancel when tasks processing has begun and task is queued or
2696
+ // pending but not yet reached MPU complete
2697
+ isCancelable =
2698
+ isProcessing && (isQueued || isPending) && !hasUploadedAllBytes;
2536
2699
  }
2537
- };
2538
- const getProgressHeader = (label) => ({
2539
- key: 'progress',
2540
- type: 'sort',
2541
- content: { label },
2542
- });
2543
- const getActionViewTableData = ({ tasks, displayText, isProcessing, locationKey, shouldDisplayProgress = false, onTaskRemove, }) => {
2544
- const headers = [
2545
- ...getDefaultActionViewHeaders({
2546
- displayText,
2547
- }),
2548
- ];
2549
- if (shouldDisplayProgress) {
2550
- headers.splice(-1, 0, getProgressHeader(displayText.tableColumnProgressHeader));
2700
+ else {
2701
+ // single part upload allows cancel when processing has begun and task is queued
2702
+ isCancelable = isProcessing && isQueued;
2551
2703
  }
2552
- const rows = tasks.map((task) => {
2553
- const { cancel, data, progress, status } = task;
2554
- const { id } = data;
2555
- const displayKey = isFileDataItem(data)
2556
- ? data.fileKey
2557
- : data.key.split('/').pop() ?? '';
2558
- return {
2559
- key: id,
2560
- content: headers.map(({ key: columnKey }) => {
2561
- const key = `${columnKey}-${id}`;
2562
- switch (columnKey) {
2563
- case 'name': {
2564
- return {
2565
- key,
2566
- type: 'text',
2567
- content: {
2568
- icon: getActionIcon(status),
2569
- text: displayKey,
2570
- },
2571
- };
2572
- }
2573
- case 'folder': {
2574
- if (locationKey) {
2575
- return { key, type: 'text', content: { text: locationKey } };
2576
- }
2577
- if (isFileItem(data)) {
2578
- const { webkitRelativePath } = data.file;
2579
- return {
2580
- key,
2581
- type: 'text',
2582
- content: {
2583
- text: webkitRelativePath
2584
- ? webkitRelativePath.slice(0, webkitRelativePath.lastIndexOf('/') + 1)
2585
- : '-',
2586
- },
2587
- };
2588
- }
2589
- return { key, type: 'text', content: { text: '/' } };
2590
- }
2591
- case 'type': {
2592
- return {
2593
- key,
2594
- type: 'text',
2595
- content: { text: getFileTypeDisplayValue(displayKey) },
2596
- };
2597
- }
2598
- case 'size': {
2599
- const value = isFileItem(data)
2600
- ? data.file.size
2601
- : isFileDataItem(data)
2602
- ? data.size
2603
- : undefined;
2604
- return {
2605
- key,
2606
- type: 'number',
2607
- content: {
2608
- value,
2609
- displayValue: value ? ui.humanFileSize(value, true) : '-',
2610
- },
2611
- };
2612
- }
2613
- case 'status': {
2614
- return {
2615
- key,
2616
- type: 'text',
2617
- content: {
2618
- text: getTaskStatusDisplayLabel({ status, displayText }),
2619
- },
2620
- };
2621
- }
2622
- case 'progress': {
2623
- return {
2624
- key,
2625
- type: 'number',
2626
- content: {
2627
- value: progress,
2628
- displayValue: `${getPercentValue(
2629
- // Default progress to 100% if progress value is unavailable but status is recognized as complete
2630
- progress ?? (status === 'COMPLETE' ? 1 : 0))}%`,
2631
- },
2632
- };
2633
- }
2634
- case 'cancel': {
2635
- const isPending = status === 'PENDING';
2636
- const isQueued = status === 'QUEUED';
2637
- const isDisabled = (!isPending && !isQueued) || !cancel || progress === 1;
2638
- const ariaLabel = `${isProcessing ? 'Cancel' : 'Remove'} item: ${displayKey}`;
2639
- return {
2640
- key,
2641
- type: 'button',
2642
- content: {
2643
- isDisabled,
2644
- onClick: () => {
2645
- if (!isProcessing) {
2646
- onTaskRemove?.(task);
2647
- }
2648
- cancel?.();
2649
- },
2650
- ariaLabel,
2651
- icon: 'cancel',
2652
- },
2653
- };
2654
- }
2655
- default:
2656
- return { key, type: 'text', content: {} };
2657
- }
2658
- }),
2704
+ // all uploads are removable prior to processing start. Including `isQueued`
2705
+ // ensures that `isRemovable` is `false` on all tasks processing complete
2706
+ const isRemovable = !isProcessing && isQueued;
2707
+ const isDisabled = !isRemovable && !isCancelable;
2708
+ const ariaLabel = `${isRemovable ? 'Remove' : 'Cancel'} item: ${getCellName(item.data.key)}`;
2709
+ // resolve to `undefined` if not cancelable or removable
2710
+ const onClick = !isCancelable && !isRemovable
2711
+ ? undefined
2712
+ : () => {
2713
+ if (isRemovable) {
2714
+ onTaskRemove?.(item);
2715
+ // do not run cancel handler on remove
2716
+ return;
2717
+ }
2718
+ if (!!cancel && isCancelable)
2719
+ cancel();
2659
2720
  };
2660
- });
2661
- return { headers, rows };
2721
+ const content = { ariaLabel, isDisabled, onClick, icon: 'cancel' };
2722
+ return { key, type: 'button', content };
2723
+ };
2724
+ const UPLOAD_CELL_RESOLVERS = {
2725
+ cancel: cancel$1,
2726
+ folder: folder$1,
2727
+ name: name$1,
2728
+ progress,
2729
+ size: size$1,
2730
+ status: status$1,
2731
+ type: type$1,
2732
+ };
2733
+ const UPLOAD_TABLE_RESOLVERS = {
2734
+ getCell: (data) => UPLOAD_CELL_RESOLVERS[data.key](data),
2735
+ getHeader: ({ key, props: { displayText } }) => {
2736
+ const text = displayText[`tableColumn${ui.capitalize(key)}Header`];
2737
+ if (key === 'cancel') {
2738
+ return { key, type: 'text', content: { text } };
2739
+ }
2740
+ return { key, type: 'sort', content: { label: text } };
2741
+ },
2742
+ getRowKey: ({ item }) => item.data.id,
2743
+ };
2744
+
2745
+ const DELETE_TABLE_KEYS = [
2746
+ 'name',
2747
+ 'folder',
2748
+ 'type',
2749
+ 'size',
2750
+ 'status',
2751
+ 'cancel',
2752
+ ];
2753
+ const getDeleteCellKey = ({ key, item, }) => `${key}-${item.data.id}`;
2754
+ const name = (data) => {
2755
+ const key = getDeleteCellKey(data);
2756
+ const { item } = data;
2757
+ const text = item.data.fileKey;
2758
+ const icon = STATUS_ICONS[item.status];
2759
+ return { key, type: 'text', content: { icon, text } };
2760
+ };
2761
+ const folder = (data) => {
2762
+ const key = getDeleteCellKey(data);
2763
+ const text = getDeleteCellFolder(data.item);
2764
+ return { key, type: 'text', content: { text } };
2765
+ };
2766
+ const type = (data) => {
2767
+ const key = getDeleteCellKey(data);
2768
+ const { fileKey } = data.item.data;
2769
+ const text = getFileType(fileKey);
2770
+ return { key, type: 'text', content: { text } };
2771
+ };
2772
+ const size = (data) => {
2773
+ const key = getDeleteCellKey(data);
2774
+ const { size: value } = data.item.data;
2775
+ const displayValue = getFileSize(value);
2776
+ return { key, type: 'number', content: { value, displayValue } };
2777
+ };
2778
+ const status = (data) => {
2779
+ const key = getDeleteCellKey(data);
2780
+ const { item: { status }, props: { displayText }, } = data;
2781
+ const statusLabelKey = STATUS_LABELS[status];
2782
+ const text = isDeleteViewDisplayTextKey(statusLabelKey)
2783
+ ? displayText[statusLabelKey]
2784
+ : '';
2785
+ return { key, type: 'text', content: { text } };
2786
+ };
2787
+ const cancel = (data) => {
2788
+ const key = getDeleteCellKey(data);
2789
+ const content = getCopyOrDeleteCancelCellContent(data);
2790
+ return { key, type: 'button', content };
2791
+ };
2792
+ const DELETE_CELL_RESOLVERS = {
2793
+ name,
2794
+ folder,
2795
+ type,
2796
+ size,
2797
+ status,
2798
+ cancel,
2799
+ /**
2800
+ * @deprecated
2801
+ *
2802
+ * non-upload view tables do not include "progress" headers but include here to
2803
+ * keep TS happy as "progress" headers were included in display text interfaces
2804
+ * and cannot be removed from the tables without a breaking change
2805
+ */
2806
+ progress: ui.noop,
2807
+ };
2808
+ const DELETE_TABLE_RESOLVERS = {
2809
+ getCell: (data) => DELETE_CELL_RESOLVERS[data.key](data),
2810
+ getHeader: ({ key, props: { displayText } }) => {
2811
+ const text = displayText[`tableColumn${ui.capitalize(key)}Header`];
2812
+ if (key === 'cancel') {
2813
+ return { key, type: 'text', content: { text } };
2814
+ }
2815
+ return { key, type: 'sort', content: { label: text } };
2816
+ },
2817
+ getRowKey: ({ item }) => item.data.id,
2662
2818
  };
2663
2819
 
2664
2820
  function UploadViewProvider({ children, ...props }) {
2665
2821
  const { UploadView: displayText } = useDisplayText();
2666
2822
  const { actionCancelLabel, actionDestinationLabel, actionExitLabel, actionStartLabel, addFilesLabel, addFolderLabel, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, overwriteToggleLabel, title, getActionCompleteMessage, getFilesValidationMessage, } = displayText;
2667
- const { isOverwritingEnabled, isProcessing, isProcessingComplete, location, tasks, statusCounts, invalidFiles, onActionStart, onActionCancel, onDropFiles, onActionExit, onTaskRemove, onSelectFiles, onToggleOverwrite, } = props;
2823
+ const { isOverwritingEnabled, isProcessing, isProcessingComplete, location, tasks: items, statusCounts, invalidFiles, onActionStart, onActionCancel, onDropFiles, onActionExit, onTaskRemove, onSelectFiles, onToggleOverwrite, } = props;
2668
2824
  const isActionStartDisabled = isProcessing || isProcessingComplete || statusCounts.TOTAL === 0;
2669
2825
  const isActionCancelDisabled = !isProcessing || isProcessingComplete;
2670
2826
  const isAddFilesDisabled = isProcessing || isProcessingComplete;
@@ -2678,6 +2834,10 @@ function UploadViewProvider({ children, ...props }) {
2678
2834
  const filesValidationMessage = invalidFiles && !isProcessing
2679
2835
  ? getFilesValidationMessage({ invalidFiles })
2680
2836
  : undefined;
2837
+ const tableData = useResolveDataTable(UPLOAD_TABLE_KEYS, UPLOAD_TABLE_RESOLVERS, {
2838
+ items,
2839
+ props: { displayText, isProcessing, isMultipartUpload, onTaskRemove },
2840
+ });
2681
2841
  return (React__namespace["default"].createElement(ControlsContextProvider, { data: {
2682
2842
  actionCancelLabel,
2683
2843
  actionDestinationLabel,
@@ -2701,13 +2861,7 @@ function UploadViewProvider({ children, ...props }) {
2701
2861
  statusDisplayCompletedLabel,
2702
2862
  statusDisplayFailedLabel,
2703
2863
  statusDisplayQueuedLabel,
2704
- tableData: getActionViewTableData({
2705
- tasks,
2706
- shouldDisplayProgress: true,
2707
- displayText,
2708
- isProcessing,
2709
- onTaskRemove,
2710
- }),
2864
+ tableData,
2711
2865
  title,
2712
2866
  }, onActionCancel: onActionCancel, onActionExit: onActionExit, onActionStart: onActionStart, onAddFiles: () => {
2713
2867
  onSelectFiles('FILE');
@@ -2843,6 +2997,9 @@ const createEnhancedListHandler = (action) => {
2843
2997
  };
2844
2998
  };
2845
2999
 
3000
+ const DEFAULT_ACTION_CONCURRENCY = 4;
3001
+ const USE_LIST_ERROR_MESSAGE = '`useList` must be called from within `StorageBrowser.Provider`';
3002
+
2846
3003
  const INITIAL_STATUS_COUNTS = {
2847
3004
  CANCELED: 0,
2848
3005
  COMPLETE: 0,
@@ -2873,8 +3030,8 @@ const QUEUED_TASK_BASE = {
2873
3030
  status: 'QUEUED',
2874
3031
  };
2875
3032
  const isTaskHandlerInput = (input) => !!input.data;
2876
- const useProcessTasks = (handler, items, options) => {
2877
- const { concurrency, ...callbacks } = options ?? {};
3033
+ function useProcessTasks(handler, options) {
3034
+ const { concurrency, items, ...callbacks } = options ?? {};
2878
3035
  const callbacksRef = React__namespace["default"].useRef(callbacks);
2879
3036
  if (callbacks) {
2880
3037
  callbacksRef.current = callbacks;
@@ -2900,6 +3057,7 @@ const useProcessTasks = (handler, items, options) => {
2900
3057
  tasksRef.current.set(id, { ...task, ...next });
2901
3058
  }
2902
3059
  flush();
3060
+ return !next ? undefined : tasksRef.current.get(id);
2903
3061
  }, [flush]);
2904
3062
  const createTask = React__namespace["default"].useCallback((data) => {
2905
3063
  const getTask = () => tasksRef.current.get(data.id);
@@ -2908,9 +3066,12 @@ const useProcessTasks = (handler, items, options) => {
2908
3066
  const task = getTask();
2909
3067
  if (!task || task?.status !== 'QUEUED')
2910
3068
  return;
2911
- if (task && ui.isFunction(onTaskCancel))
2912
- onTaskCancel(task);
2913
- updateTask(data.id, { cancel: undefined, status: 'CANCELED' });
3069
+ const canceledTask = updateTask(data.id, {
3070
+ cancel: undefined,
3071
+ status: 'CANCELED',
3072
+ });
3073
+ if (canceledTask && ui.isFunction(onTaskCancel))
3074
+ onTaskCancel(canceledTask);
2914
3075
  }
2915
3076
  const task = { ...QUEUED_TASK_BASE, cancel, data };
2916
3077
  tasksRef.current.set(data.id, task);
@@ -2955,16 +3116,15 @@ const useProcessTasks = (handler, items, options) => {
2955
3116
  const { onTaskCancel, onTaskComplete, onTaskError, onTaskProgress, onTaskSuccess, } = callbacksRef.current;
2956
3117
  const getTask = () => tasksRef.current.get(data.id);
2957
3118
  const { options } = _input;
2958
- const { onProgress: _onProgress, onSuccess, onError } = options ?? {};
3119
+ const { onProgress: _onProgress } = options ?? {};
2959
3120
  const onProgress = ({ id }, progress) => {
2960
- const task = getTask();
3121
+ const task = updateTask(id, { progress });
2961
3122
  if (task && ui.isFunction(onTaskProgress)) {
2962
3123
  onTaskProgress(task, progress);
2963
3124
  }
2964
3125
  if (task && ui.isFunction(_onProgress)) {
2965
3126
  _onProgress(data, progress);
2966
3127
  }
2967
- updateTask(id, { progress });
2968
3128
  };
2969
3129
  const input = { ..._input, data, options: { ...options, onProgress } };
2970
3130
  const { cancel: _cancel, result } = handler(input);
@@ -2978,21 +3138,16 @@ const useProcessTasks = (handler, items, options) => {
2978
3138
  };
2979
3139
  result
2980
3140
  .then((output) => {
2981
- const task = getTask();
2982
- if (task && ui.isFunction(onTaskSuccess)) {
2983
- onTaskSuccess(task, output?.value);
2984
- }
2985
- if (task && ui.isFunction(onSuccess))
2986
- onSuccess(data, output?.value);
2987
- updateTask(data.id, output);
3141
+ const task = updateTask(data.id, output);
3142
+ const { value } = output;
3143
+ if (task && ui.isFunction(onTaskSuccess))
3144
+ onTaskSuccess(task, value);
2988
3145
  })
2989
- .catch((e) => {
2990
- const task = getTask();
3146
+ .catch((error) => {
3147
+ const { message } = error;
3148
+ const task = updateTask(data.id, { message, status: 'FAILED' });
2991
3149
  if (task && ui.isFunction(onTaskError))
2992
- onTaskError(task, e);
2993
- if (task && ui.isFunction(onError))
2994
- onError(data, e?.message);
2995
- updateTask(data.id, { message: e.message, status: 'FAILED' });
3150
+ onTaskError(task, error);
2996
3151
  })
2997
3152
  .finally(() => {
2998
3153
  const task = getTask();
@@ -3030,52 +3185,54 @@ const useProcessTasks = (handler, items, options) => {
3030
3185
  { isProcessing, isProcessingComplete, reset, statusCounts, tasks },
3031
3186
  handleProcessTasks,
3032
3187
  ];
3033
- };
3034
-
3035
- const DEFAULT_ACTION_CONCURRENCY = 4;
3036
- const USE_LIST_ERROR_MESSAGE = '`useList` must be called from within `StorageBrowser.Provider`';
3188
+ }
3037
3189
 
3038
- const isTasksOptions = (value) => ui.isObject(value);
3039
- const useHandler = (action, options) => {
3040
- const hasOptions = isTasksOptions(options);
3041
- const { items, onTaskSuccess } = options ?? {};
3042
- const getConfig = useGetActionInput();
3043
- const { location: { current }, } = useStore()[0];
3044
- const [state, processTask] = useProcessTasks(action, items, {
3045
- onTaskSuccess,
3046
- ...(items ? { concurrency: DEFAULT_ACTION_CONCURRENCY } : undefined),
3190
+ const isOptionsWithItems = (options) => !!options?.items;
3191
+ const isHandleTaskInput = (value) => !!value?.data;
3192
+ function useHandler(handler, options) {
3193
+ const [state, handleProcessing] = useProcessTasks(handler, {
3194
+ ...options,
3195
+ concurrency: DEFAULT_ACTION_CONCURRENCY,
3047
3196
  });
3048
- const { reset, isProcessing, tasks } = state;
3049
- const handler = React__namespace["default"].useCallback((input) => {
3050
- const { location } = input ?? {};
3051
- const config = getConfig(location ?? current);
3052
- if (!hasOptions) {
3053
- // clean up previous state
3197
+ const getConfig = useGetActionInput();
3198
+ const { reset, isProcessing, tasks, ...rest } = state;
3199
+ const handleDispatch = React__namespace["default"].useCallback((input) => {
3200
+ const config = getConfig(input?.location);
3201
+ const hasData = isHandleTaskInput(input);
3202
+ // clean up previous state for atomic handler
3203
+ if (hasData)
3054
3204
  reset();
3055
- processTask({ ...input, config });
3056
- return;
3057
- }
3058
- processTask({ config });
3059
- }, [current, getConfig, hasOptions, processTask, reset]);
3060
- return [
3061
- hasOptions ? state : { isProcessing, task: tasks?.[0] },
3062
- handler,
3063
- ];
3064
- };
3205
+ handleProcessing({
3206
+ config,
3207
+ ...(hasData ? { data: input.data } : undefined),
3208
+ });
3209
+ }, [getConfig, handleProcessing, reset]);
3210
+ if (isOptionsWithItems(options)) {
3211
+ return [{ ...rest, isProcessing, reset, tasks }, handleDispatch];
3212
+ }
3213
+ return [{ isProcessing, task: tasks?.[0] }, handleDispatch];
3214
+ }
3065
3215
 
3066
3216
  const ERROR_MESSAGE = '`useAction` must be called from within `StorageBrowser.Provider`';
3067
- const useAction = (key, options) => {
3068
- if (key === 'listLocations' ||
3069
- key === 'listLocationItems') {
3217
+ function assertActionHandlerKey(key) {
3218
+ if (key === 'listLocations' || key === 'listLocationItems') {
3070
3219
  throw new Error(`Value of \`${key}\` cannot be provided to \`useAction\``);
3071
3220
  }
3072
- const { handlers } = useActionHandlers({ errorMessage: ERROR_MESSAGE });
3073
- const handler = handlers?.[key];
3074
- if (!handler) {
3221
+ }
3222
+ function assertActionHandler(handler, key) {
3223
+ if (typeof handler !== 'function') {
3075
3224
  throw new Error(`No handler found for value of \`${key}\` provided to \`useAction\``);
3076
3225
  }
3226
+ }
3227
+ const useAction = ((key, options) => {
3228
+ assertActionHandlerKey(key);
3229
+ const { handlers } = useActionHandlers({ errorMessage: ERROR_MESSAGE });
3230
+ const handler = handlers?.[key];
3231
+ assertActionHandler(handler, key);
3077
3232
  return useHandler(handler, options);
3078
- };
3233
+ // casting to allow usage of `UseAction` interface which ensures that
3234
+ // the `options` param receives the correct typing
3235
+ });
3079
3236
 
3080
3237
  const useListLocations = () => {
3081
3238
  const { handlers } = useActionHandlers({
@@ -3121,7 +3278,6 @@ const LIST_ACTION_HOOKS = {
3121
3278
  locations: useListLocations,
3122
3279
  };
3123
3280
  const isListActionViewType = (value) => Object.keys(LIST_ACTION_HOOKS).includes(value);
3124
- // @ts-expect-error
3125
3281
  const useList = (type) => {
3126
3282
  if (!isListActionViewType(type)) {
3127
3283
  throw new Error(`Value of \`${type}\` cannot be used to index \`useList\``);
@@ -3487,16 +3643,12 @@ FoldersTableControl.displayName = 'FoldersTable';
3487
3643
 
3488
3644
  function CopyViewProvider({ children, ...props }) {
3489
3645
  const { CopyView: displayText } = useDisplayText();
3490
- const { actionCancelLabel, actionDestinationLabel, actionExitLabel, actionStartLabel, getActionCompleteMessage, overwriteWarningMessage, searchPlaceholder, searchSubmitLabel, searchClearLabel, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, } = displayText;
3491
- const { destination, folders, isProcessing, isProcessingComplete, location, statusCounts, tasks, onActionCancel, onActionExit, onActionStart, onSelectDestination, onTaskRemove, } = props;
3646
+ const { actionCancelLabel, actionDestinationLabel, actionExitLabel, actionStartLabel, getActionCompleteMessage, overwriteWarningMessage, searchPlaceholder, searchSubmitLabel, searchClearLabel, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, title, } = displayText;
3647
+ const { destination, folders, isProcessing, isProcessingComplete, statusCounts, tasks: items, onActionCancel, onActionExit, onActionStart, onSelectDestination, onTaskRemove, } = props;
3492
3648
  const { hasNextPage, highestPageVisited, hasError: hasFoldersError, message: foldersErrorMessage, query, hasExhaustedSearch, isLoading, page, pageItems, onPaginate, onQuery, onSearchClear, onSearch, onSelectFolder, } = folders;
3493
- const { key: locationKey } = location ?? {};
3494
- const tableData = getActionViewTableData({
3495
- tasks,
3496
- locationKey,
3497
- isProcessing,
3498
- displayText,
3499
- onTaskRemove,
3649
+ const tableData = useResolveDataTable(COPY_TABLE_KEYS, COPY_TABLE_RESOLVERS, {
3650
+ items,
3651
+ props: { displayText, isProcessing, onTaskRemove },
3500
3652
  });
3501
3653
  const isActionStartDisabled = isProcessing || isProcessingComplete || !destination?.current;
3502
3654
  const isActionCancelDisabled = !isProcessing || isProcessingComplete;
@@ -3528,46 +3680,45 @@ function CopyViewProvider({ children, ...props }) {
3528
3680
  statusDisplayFailedLabel,
3529
3681
  statusDisplayQueuedLabel,
3530
3682
  tableData,
3683
+ title,
3531
3684
  }, onActionCancel: onActionCancel, onActionExit: onActionExit, onActionStart: onActionStart, onSearch: onSearch, onSearchClear: onSearchClear, onSearchQueryChange: onQuery, onSelectDestination: onSelectDestination },
3532
3685
  React__namespace["default"].createElement(FoldersPaginationProvider, { hasNextPage: hasNextPage, highestPageVisited: highestPageVisited, page: page, onPaginate: onPaginate },
3533
3686
  React__namespace["default"].createElement(FoldersTableProvider, { destination: destination, folders: pageItems, onSelectFolder: onSelectFolder },
3534
3687
  React__namespace["default"].createElement(FoldersMessageProvider, { folders: folders.pageItems, hasError: hasFoldersError, message: foldersErrorMessage, query: query, hasExhaustedSearch: hasExhaustedSearch }, children)))));
3535
3688
  }
3536
3689
 
3537
- const usePaginate = ({ hasNextToken, items, paginateCallback, pageSize, }) => {
3538
- const [currentPage, setCurrentPage] = React__namespace["default"].useState(1);
3690
+ const DEFAULT_PAGE_SIZE$3 = 100;
3691
+ const usePaginate = ({ items, onPaginate, page = 1, pageSize = DEFAULT_PAGE_SIZE$3, }) => {
3692
+ const [currentPage, setCurrentPage] = React__namespace["default"].useState(page);
3693
+ const visitedRef = React__namespace["default"].useRef(page);
3539
3694
  const handleReset = React__namespace["default"].useRef(() => {
3540
- setCurrentPage(1);
3695
+ setCurrentPage(page);
3696
+ // set `visitedRef` to initially provided `page`
3697
+ visitedRef.current = page;
3541
3698
  }).current;
3542
3699
  return React__namespace["default"].useMemo(() => {
3543
- const resultCount = Array.isArray(items) ? items.length : 0;
3544
- const highestPageVisited = Math.ceil(resultCount / pageSize);
3700
+ const hasItems = Array.isArray(items);
3701
+ const highestPageVisited = visitedRef.current;
3545
3702
  const isFirstPage = currentPage === 1;
3546
3703
  const start = isFirstPage ? 0 : (currentPage - 1) * pageSize;
3547
3704
  const end = isFirstPage ? pageSize : currentPage * pageSize;
3548
- const pageItems = Array.isArray(items) ? items.slice(start, end) : [];
3705
+ const pageItems = hasItems ? items.slice(start, end) : [];
3549
3706
  return {
3550
3707
  currentPage,
3551
- onPaginate: (page) => {
3552
- const shouldPaginate = page >= 1 && (page <= highestPageVisited || hasNextToken);
3553
- if (shouldPaginate) {
3554
- if (ui.isFunction(paginateCallback))
3555
- paginateCallback();
3556
- setCurrentPage(page);
3557
- }
3708
+ handlePaginate: (page) => {
3709
+ if (page < 1)
3710
+ return;
3711
+ if (ui.isFunction(onPaginate))
3712
+ onPaginate(page);
3713
+ if (page > currentPage)
3714
+ visitedRef.current = page;
3715
+ setCurrentPage(page);
3558
3716
  },
3559
3717
  handleReset,
3560
3718
  highestPageVisited,
3561
3719
  pageItems,
3562
3720
  };
3563
- }, [
3564
- currentPage,
3565
- handleReset,
3566
- hasNextToken,
3567
- items,
3568
- paginateCallback,
3569
- pageSize,
3570
- ]);
3721
+ }, [currentPage, handleReset, items, onPaginate, pageSize]);
3571
3722
  };
3572
3723
 
3573
3724
  function useSearch(props) {
@@ -3612,20 +3763,19 @@ const useFolders = ({ destination, setDestination, }) => {
3612
3763
  options: { ...DEFAULT_REFRESH_OPTIONS },
3613
3764
  });
3614
3765
  }, [handleList, key]);
3615
- const hasNextToken = !!nextToken;
3616
- const paginateCallback = () => {
3617
- if (!nextToken)
3766
+ const hasNextPage = !!nextToken;
3767
+ const onPaginate = () => {
3768
+ if (!hasNextPage)
3618
3769
  return;
3619
3770
  handleList({
3620
3771
  prefix: key,
3621
3772
  options: { ...DEFAULT_LIST_OPTIONS$2, nextToken },
3622
3773
  });
3623
3774
  };
3624
- const { currentPage: page, onPaginate, highestPageVisited, pageItems, handleReset, } = usePaginate({
3775
+ const { currentPage: page, handlePaginate, highestPageVisited, pageItems, handleReset, } = usePaginate({
3625
3776
  items,
3626
- paginateCallback,
3777
+ onPaginate,
3627
3778
  pageSize: DEFAULT_PAGE_SIZE$2,
3628
- hasNextToken,
3629
3779
  });
3630
3780
  const onSearch = (query) => {
3631
3781
  handleReset();
@@ -3651,7 +3801,7 @@ const useFolders = ({ destination, setDestination, }) => {
3651
3801
  };
3652
3802
  return {
3653
3803
  hasError,
3654
- hasNextPage: hasNextToken,
3804
+ hasNextPage,
3655
3805
  highestPageVisited,
3656
3806
  isLoading,
3657
3807
  message,
@@ -3660,7 +3810,7 @@ const useFolders = ({ destination, setDestination, }) => {
3660
3810
  pageItems,
3661
3811
  query,
3662
3812
  hasExhaustedSearch,
3663
- onPaginate,
3813
+ onPaginate: handlePaginate,
3664
3814
  onQuery,
3665
3815
  onSearch: onSearchSubmit,
3666
3816
  onSearchClear: () => {
@@ -3796,16 +3946,13 @@ CopyView.Title = TitleControl;
3796
3946
  function DeleteViewProvider({ children, ...props }) {
3797
3947
  const { DeleteView: displayText } = useDisplayText();
3798
3948
  const { actionCancelLabel, actionExitLabel, actionStartLabel, title, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, getActionCompleteMessage, } = displayText;
3799
- const { isProcessing, isProcessingComplete, location, statusCounts, tasks, onActionCancel, onActionStart, onActionExit, onTaskRemove, } = props;
3949
+ const { isProcessing, isProcessingComplete, statusCounts, tasks: items, onActionCancel, onActionStart, onActionExit, onTaskRemove, } = props;
3800
3950
  const message = isProcessingComplete
3801
3951
  ? getActionCompleteMessage({ counts: statusCounts })
3802
3952
  : undefined;
3803
- const tableData = getActionViewTableData({
3804
- tasks,
3805
- locationKey: location.key,
3806
- isProcessing,
3807
- displayText,
3808
- onTaskRemove,
3953
+ const tableData = useResolveDataTable(DELETE_TABLE_KEYS, DELETE_TABLE_RESOLVERS, {
3954
+ items,
3955
+ props: { displayText, isProcessing, onTaskRemove },
3809
3956
  });
3810
3957
  return (React__namespace["default"].createElement(ControlsContextProvider, { data: {
3811
3958
  actionCancelLabel,
@@ -3825,18 +3972,14 @@ function DeleteViewProvider({ children, ...props }) {
3825
3972
  }, onActionStart: onActionStart, onActionExit: onActionExit, onActionCancel: onActionCancel }, children));
3826
3973
  }
3827
3974
 
3975
+ // assign to constant to ensure referential equality
3976
+ const EMPTY_ITEMS = [];
3828
3977
  const useDeleteView = (options) => {
3829
3978
  const { onExit: _onExit } = options ?? {};
3830
3979
  const [{ location, locationItems }, dispatchStoreAction] = useStore();
3831
- const { fileDataItems } = locationItems;
3832
- const { current, key } = location;
3833
- const data = React__namespace["default"].useMemo(() => !fileDataItems
3834
- ? []
3835
- : fileDataItems.map((item) => ({
3836
- ...item,
3837
- key: `${key}${item.fileKey}`,
3838
- })), [fileDataItems, key]);
3839
- const [processState, handleProcess] = useAction('delete', { items: data });
3980
+ const { current } = location;
3981
+ const { fileDataItems: items = EMPTY_ITEMS } = locationItems;
3982
+ const [processState, handleProcess] = useAction('delete', { items });
3840
3983
  const { isProcessing, isProcessingComplete, statusCounts, tasks } = processState;
3841
3984
  const onActionStart = () => {
3842
3985
  if (!current)
@@ -4034,8 +4177,7 @@ const useLocationDetailView = (options) => {
4034
4177
  // set up pagination
4035
4178
  const { items, nextToken, search } = data;
4036
4179
  const { hasExhaustedSearch = false } = search ?? {};
4037
- const hasNextToken = !!nextToken;
4038
- const paginateCallback = () => {
4180
+ const onPaginate = () => {
4039
4181
  if (hasInvalidPrefix || !nextToken)
4040
4182
  return;
4041
4183
  dispatchStoreAction({ type: 'RESET_LOCATION_ITEMS' });
@@ -4044,11 +4186,10 @@ const useLocationDetailView = (options) => {
4044
4186
  options: { ...listOptions, nextToken },
4045
4187
  });
4046
4188
  };
4047
- const { currentPage, onPaginate, handleReset, highestPageVisited, pageItems, } = usePaginate({
4189
+ const { currentPage, handlePaginate, handleReset, highestPageVisited, pageItems, } = usePaginate({
4048
4190
  items,
4049
- paginateCallback,
4191
+ onPaginate,
4050
4192
  pageSize: listOptions.pageSize,
4051
- hasNextToken,
4052
4193
  });
4053
4194
  const onSearch = (query, includeSubfolders) => {
4054
4195
  if (hasInvalidPrefix)
@@ -4116,13 +4257,13 @@ const useLocationDetailView = (options) => {
4116
4257
  fileDataItems,
4117
4258
  hasError,
4118
4259
  hasDownloadError: task?.status === 'FAILED',
4119
- hasNextPage: hasNextToken,
4260
+ hasNextPage: !!nextToken,
4120
4261
  highestPageVisited,
4121
4262
  message,
4122
4263
  downloadErrorMessage: getDownloadErrorMessageFromFailedDownloadTask(task),
4123
4264
  isLoading,
4124
4265
  isSearchSubfoldersEnabled,
4125
- onPaginate,
4266
+ onPaginate: handlePaginate,
4126
4267
  searchQuery,
4127
4268
  hasExhaustedSearch,
4128
4269
  onRefresh,
@@ -4178,10 +4319,7 @@ const useLocationDetailView = (options) => {
4178
4319
  resetSearch();
4179
4320
  if (hasInvalidPrefix)
4180
4321
  return;
4181
- handleList({
4182
- prefix: key,
4183
- options: { ...listOptions, refresh: true },
4184
- });
4322
+ handleList({ prefix: key, options: { ...listOptions, refresh: true } });
4185
4323
  handleReset();
4186
4324
  },
4187
4325
  onSearchQueryChange,
@@ -4688,16 +4826,15 @@ const useLocationsView = (options) => {
4688
4826
  handleList({ options: { ...listOptions, refresh: true } });
4689
4827
  }, [handleList, listOptions]);
4690
4828
  // set up pagination
4691
- const paginateCallback = () => {
4829
+ const onPaginate = () => {
4692
4830
  if (!nextToken)
4693
4831
  return;
4694
4832
  handleList({ options: { ...listOptions, nextToken } });
4695
4833
  };
4696
- const { currentPage, onPaginate, handleReset, highestPageVisited, pageItems, } = usePaginate({
4834
+ const { currentPage, handlePaginate, handleReset, highestPageVisited, pageItems, } = usePaginate({
4697
4835
  items,
4698
- paginateCallback,
4836
+ onPaginate,
4699
4837
  pageSize: listOptions.pageSize,
4700
- hasNextToken,
4701
4838
  });
4702
4839
  const onSearch = (query) => {
4703
4840
  handleReset();
@@ -4744,7 +4881,7 @@ const useLocationsView = (options) => {
4744
4881
  handleReset();
4745
4882
  handleList({ options: { ...listOptions, refresh: true } });
4746
4883
  },
4747
- onPaginate,
4884
+ onPaginate: handlePaginate,
4748
4885
  onSearch: onSearchSubmit,
4749
4886
  onSearchQueryChange,
4750
4887
  onSearchClear: () => {
@@ -4808,7 +4945,10 @@ const getViews = (views, customConfigs) => {
4808
4945
  // ignore custom actions that are only handlers
4809
4946
  return !ui.isObject(config) || ui.isFunction(config)
4810
4947
  ? acc
4811
- : { ...acc, [key]: views?.[config.viewName] };
4948
+ : {
4949
+ ...acc,
4950
+ [key]: views?.[config.viewName],
4951
+ };
4812
4952
  }, {});
4813
4953
  return {
4814
4954
  action: { ...resolvedDefaultActionViews, ...customActionViews },
@@ -4833,7 +4973,7 @@ function useViews() {
4833
4973
  };
4834
4974
  }
4835
4975
 
4836
- const DEFAULT_VIEW_HOOKS = {
4976
+ const USE_VIEW_HOOKS = {
4837
4977
  Copy: useCopyView,
4838
4978
  CreateFolder: useCreateFolderView,
4839
4979
  Delete: useDeleteView,
@@ -4841,13 +4981,12 @@ const DEFAULT_VIEW_HOOKS = {
4841
4981
  Locations: useLocationsView,
4842
4982
  Upload: useUploadView,
4843
4983
  };
4844
- const isUseViewType = (value) => !!DEFAULT_VIEW_HOOKS?.[value];
4845
- // @ts-expect-error
4984
+ const isUseViewType = (value) => !!USE_VIEW_HOOKS?.[value];
4846
4985
  const useView = (type) => {
4847
4986
  if (!isUseViewType(type)) {
4848
4987
  throw new Error(`Value of \`${type}\` cannot be used to index \`useView\``);
4849
4988
  }
4850
- return DEFAULT_VIEW_HOOKS[type]();
4989
+ return USE_VIEW_HOOKS[type]();
4851
4990
  };
4852
4991
 
4853
4992
  /**
@@ -4870,6 +5009,12 @@ function StorageBrowserDefault() {
4870
5009
  return React__namespace["default"].createElement(LocationsView, null);
4871
5010
  }
4872
5011
 
5012
+ /**
5013
+ * Creates a `StorageBrowser` component and utility hooks from provided configuration `input`.
5014
+ *
5015
+ * @param input - `StorageBrowser` auth, actions and ui configuration values
5016
+ * @returns `StorageBrowser` component, `useAction` and `useView` hooks
5017
+ */
4873
5018
  function createStorageBrowser(input) {
4874
5019
  assertRegisterAuthListener(input.config.registerAuthListener);
4875
5020
  const { accountId, customEndpoint, registerAuthListener, getLocationCredentials, region, } = input.config;
@@ -5071,5 +5216,7 @@ exports.VERSION = VERSION;
5071
5216
  exports.componentsDefault = componentsDefault;
5072
5217
  exports.createAmplifyAuthAdapter = createAmplifyAuthAdapter;
5073
5218
  exports.createStorageBrowser = createStorageBrowser;
5219
+ exports.defaultActionConfigs = defaultActionConfigs;
5220
+ exports.defaultHandlers = defaultHandlers;
5074
5221
  exports.getFilteredLocations = getFilteredLocations;
5075
5222
  exports.toAccessGrantPermission = toAccessGrantPermission;