@aws-amplify/ui-react-storage 3.7.1 → 3.8.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/{createAmplifyAuthAdapter-D6MKiBgI.js → createAmplifyAuthAdapter-BcJMLIum.js} +1203 -1200
- package/dist/esm/components/FileUploader/FileUploader.mjs +2 -1
- package/dist/esm/components/FileUploader/hooks/useUploadFiles/useUploadFiles.mjs +3 -1
- package/dist/esm/components/FileUploader/utils/getInput.mjs +8 -2
- package/dist/esm/components/StorageBrowser/StorageBrowserDefault.mjs +16 -0
- package/dist/esm/components/StorageBrowser/composables/DataTable/DataTable.mjs +40 -38
- package/dist/esm/components/StorageBrowser/controls/hooks/useDataTable.mjs +2 -1
- package/dist/esm/components/StorageBrowser/createStorageBrowser.mjs +3 -3
- package/dist/esm/components/StorageBrowser/views/LocationActionView/getActionViewTableData.mjs +1 -1
- package/dist/esm/components/StorageBrowser/views/useView.mjs +4 -4
- package/dist/esm/components/StorageImage/StorageImage.mjs +11 -2
- package/dist/esm/components/StorageManager/StorageManager.mjs +2 -1
- package/dist/esm/version.mjs +1 -1
- package/dist/index.js +27 -8
- package/dist/types/components/FileUploader/hooks/useUploadFiles/useUploadFiles.d.ts +3 -2
- package/dist/types/components/FileUploader/types.d.ts +8 -1
- package/dist/types/components/FileUploader/utils/getInput.d.ts +3 -2
- package/dist/types/components/StorageBrowser/composables/DataTable/DataTable.d.ts +2 -1
- package/dist/types/components/StorageBrowser/index.d.ts +2 -1
- package/dist/types/components/StorageBrowser/types.d.ts +1 -2
- package/dist/types/components/StorageBrowser/views/index.d.ts +2 -0
- package/dist/types/components/StorageBrowser/views/useView.d.ts +4 -4
- package/dist/types/components/StorageImage/StorageImage.d.ts +1 -1
- package/dist/types/components/StorageImage/types.d.ts +4 -1
- package/dist/types/components/StorageManager/types.d.ts +15 -88
- package/dist/types/version.d.ts +1 -1
- package/package.json +3 -5
- package/dist/storage-browser-styles.css +0 -482
- package/dist/storage-browser-styles.js +0 -2
- package/dist/types/styles/storage-browser-styles.d.ts +0 -1
|
@@ -32,7 +32,7 @@ function _interopNamespace(e) {
|
|
|
32
32
|
|
|
33
33
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
34
|
|
|
35
|
-
const VERSION = '3.
|
|
35
|
+
const VERSION = '3.8.0';
|
|
36
36
|
|
|
37
37
|
const constructBucket = ({ bucket: bucketName, region, }) => ({ bucketName, region });
|
|
38
38
|
const parseAccessGrantLocation = (location) => {
|
|
@@ -845,7 +845,7 @@ const CheckboxHeader = ({ content, }) => {
|
|
|
845
845
|
return (React__namespace["default"].createElement(uiReact.Checkbox, { name: label ?? '', checked: checked, labelHidden: true, label: label, onChange: onSelect, id: id }));
|
|
846
846
|
};
|
|
847
847
|
|
|
848
|
-
const DataTable = ({ headers, rows, }) => {
|
|
848
|
+
const DataTable = ({ headers, isLoading, rows, }) => {
|
|
849
849
|
const mappedHeaders = headers.map(({ key, content, type }) => {
|
|
850
850
|
switch (type) {
|
|
851
851
|
case 'checkbox': {
|
|
@@ -869,44 +869,46 @@ const DataTable = ({ headers, rows, }) => {
|
|
|
869
869
|
}
|
|
870
870
|
}
|
|
871
871
|
});
|
|
872
|
-
const mappedRows =
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
872
|
+
const mappedRows = isLoading
|
|
873
|
+
? []
|
|
874
|
+
: rows.map(({ key, content }) => ({
|
|
875
|
+
key,
|
|
876
|
+
content: content.map(({ key, content, type }) => {
|
|
877
|
+
switch (type) {
|
|
878
|
+
case 'button': {
|
|
879
|
+
return {
|
|
880
|
+
key,
|
|
881
|
+
content: React__namespace["default"].createElement(ButtonDataCell, { content: content }),
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
case 'checkbox': {
|
|
885
|
+
return {
|
|
886
|
+
key,
|
|
887
|
+
content: React__namespace["default"].createElement(CheckboxDataCell, { content: content }),
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
case 'date': {
|
|
891
|
+
return {
|
|
892
|
+
key,
|
|
893
|
+
content: React__namespace["default"].createElement(DateDataCell, { content: content }),
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
case 'number': {
|
|
897
|
+
return {
|
|
898
|
+
key,
|
|
899
|
+
content: React__namespace["default"].createElement(NumberDataCell, { content: content }),
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
case 'text':
|
|
903
|
+
default: {
|
|
904
|
+
return {
|
|
905
|
+
key,
|
|
906
|
+
content: React__namespace["default"].createElement(TextDataCell, { content: content }),
|
|
907
|
+
};
|
|
908
|
+
}
|
|
906
909
|
}
|
|
907
|
-
}
|
|
908
|
-
})
|
|
909
|
-
}));
|
|
910
|
+
}),
|
|
911
|
+
}));
|
|
910
912
|
return React__namespace["default"].createElement(Table, { headers: mappedHeaders, rows: mappedRows });
|
|
911
913
|
};
|
|
912
914
|
|
|
@@ -1184,1282 +1186,1283 @@ const componentsDefault = {
|
|
|
1184
1186
|
Title,
|
|
1185
1187
|
};
|
|
1186
1188
|
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
const CREDENTIALS_STORE_DEFAULT_SIZE = 10;
|
|
1209
|
-
const CREDENTIALS_REFRESH_WINDOW_MS = 30000;
|
|
1210
|
-
|
|
1211
|
-
const serializedPermissions = (permissions) => permissions.sort().join('_');
|
|
1212
|
-
const createCacheKey = (location) => `${location.scope}_${serializedPermissions(location.permissions)}`;
|
|
1213
|
-
const pastTTL = (credentials) => {
|
|
1214
|
-
const { expiration } = credentials;
|
|
1215
|
-
return expiration.getTime() - CREDENTIALS_REFRESH_WINDOW_MS <= Date.now();
|
|
1189
|
+
const DEFAULT_ACTION_VIEW_DISPLAY_TEXT = {
|
|
1190
|
+
actionCancelLabel: 'Cancel',
|
|
1191
|
+
actionExitLabel: 'Exit',
|
|
1192
|
+
actionDestinationLabel: 'Destination',
|
|
1193
|
+
statusDisplayCanceledLabel: 'Canceled',
|
|
1194
|
+
statusDisplayCompletedLabel: 'Completed',
|
|
1195
|
+
statusDisplayFailedLabel: 'Failed',
|
|
1196
|
+
statusDisplayInProgressLabel: 'In progress',
|
|
1197
|
+
statusDisplayTotalLabel: 'Total',
|
|
1198
|
+
statusDisplayQueuedLabel: 'Not started',
|
|
1199
|
+
// empty by default
|
|
1200
|
+
tableColumnCancelHeader: '',
|
|
1201
|
+
tableColumnStatusHeader: 'Status',
|
|
1202
|
+
tableColumnFolderHeader: 'Folder',
|
|
1203
|
+
tableColumnNameHeader: 'Name',
|
|
1204
|
+
tableColumnTypeHeader: 'Type',
|
|
1205
|
+
tableColumnSizeHeader: 'Size',
|
|
1206
|
+
tableColumnProgressHeader: 'Progress',
|
|
1216
1207
|
};
|
|
1217
|
-
const
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1208
|
+
const DEFAULT_LIST_VIEW_DISPLAY_TEXT = {
|
|
1209
|
+
loadingIndicatorLabel: 'Loading',
|
|
1210
|
+
searchSubmitLabel: 'Submit',
|
|
1211
|
+
searchClearLabel: 'Clear search',
|
|
1212
|
+
getDateDisplayValue: (date) => new Intl.DateTimeFormat('en-US', {
|
|
1213
|
+
month: 'short',
|
|
1214
|
+
day: 'numeric',
|
|
1215
|
+
hour: 'numeric',
|
|
1216
|
+
year: 'numeric',
|
|
1217
|
+
minute: 'numeric',
|
|
1218
|
+
hourCycle: 'h12',
|
|
1219
|
+
}).format(date),
|
|
1227
1220
|
};
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1221
|
+
|
|
1222
|
+
const DEFAULT_CREATE_FOLDER_VIEW_DISPLAY_TEXT = {
|
|
1223
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
1224
|
+
title: 'Create folder',
|
|
1225
|
+
actionStartLabel: 'Create folder',
|
|
1226
|
+
folderNameLabel: 'Folder name',
|
|
1227
|
+
folderNamePlaceholder: 'Folder name cannot contain "/", nor end or start with "."',
|
|
1228
|
+
getValidationMessage: () => 'Folder name cannot contain "/", nor end or start with "."',
|
|
1229
|
+
getActionCompleteMessage: (data) => {
|
|
1230
|
+
const { counts } = data ?? {};
|
|
1231
|
+
const { FAILED, OVERWRITE_PREVENTED } = counts ?? {};
|
|
1232
|
+
if (OVERWRITE_PREVENTED) {
|
|
1233
|
+
return {
|
|
1234
|
+
content: 'A folder already exists with the provided name',
|
|
1235
|
+
type: 'warning',
|
|
1236
|
+
};
|
|
1244
1237
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1238
|
+
if (FAILED) {
|
|
1239
|
+
return {
|
|
1240
|
+
content: 'There was an issue creating the folder.',
|
|
1241
|
+
type: 'error',
|
|
1242
|
+
};
|
|
1247
1243
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
};
|
|
1251
|
-
/**
|
|
1252
|
-
* @internal
|
|
1253
|
-
*/
|
|
1254
|
-
const initStore = (refreshHandler, size = CREDENTIALS_STORE_DEFAULT_SIZE) => {
|
|
1255
|
-
internals.assertValidationError(size > 0, internals.StorageValidationErrorCode.InvalidLocationCredentialsCacheSize);
|
|
1256
|
-
return {
|
|
1257
|
-
capacity: size,
|
|
1258
|
-
refreshHandler,
|
|
1259
|
-
values: new Map(),
|
|
1260
|
-
};
|
|
1261
|
-
};
|
|
1262
|
-
const getCacheValue = (store, location) => {
|
|
1263
|
-
const cacheKey = createCacheKey(location);
|
|
1264
|
-
const cachedValue = store.values.get(cacheKey);
|
|
1265
|
-
const cachedCredentials = cachedValue?.credentials;
|
|
1266
|
-
if (!cachedCredentials) {
|
|
1267
|
-
return null;
|
|
1268
|
-
}
|
|
1269
|
-
// Delete and re-insert to key to map to indicate a latest reference in LRU.
|
|
1270
|
-
store.values.delete(cacheKey);
|
|
1271
|
-
if (!pastTTL(cachedCredentials)) {
|
|
1272
|
-
// TODO(@AllanZhengYP): If the credential is still valid but will expire
|
|
1273
|
-
// soon, we should return credentials AND dispatch a refresh.
|
|
1274
|
-
store.values.set(cacheKey, cachedValue);
|
|
1275
|
-
return cachedCredentials;
|
|
1276
|
-
}
|
|
1277
|
-
return null;
|
|
1244
|
+
return { content: 'Folder created.', type: 'success' };
|
|
1245
|
+
},
|
|
1278
1246
|
};
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1247
|
+
|
|
1248
|
+
const DEFAULT_COPY_VIEW_DISPLAY_TEXT = {
|
|
1249
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
1250
|
+
title: 'Copy',
|
|
1251
|
+
actionStartLabel: 'Copy',
|
|
1252
|
+
actionDestinationLabel: 'Copy destination',
|
|
1253
|
+
getListFoldersResultsMessage: ({ folders, query, message, hasError, hasExhaustedSearch, }) => {
|
|
1254
|
+
if (!folders?.length) {
|
|
1255
|
+
return {
|
|
1256
|
+
content: query
|
|
1257
|
+
? `No folders found matching "${query}"`
|
|
1258
|
+
: 'No subfolders found within selected folder.',
|
|
1259
|
+
type: 'info',
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
if (message && !!query) {
|
|
1263
|
+
return { content: 'Error loading folders.', type: 'error' };
|
|
1264
|
+
}
|
|
1265
|
+
if (hasError) {
|
|
1266
|
+
return { content: 'Error loading folders.', type: 'error' };
|
|
1267
|
+
}
|
|
1268
|
+
if (hasExhaustedSearch) {
|
|
1269
|
+
return {
|
|
1270
|
+
content: 'Showing results for up to the first 10,000 items.',
|
|
1271
|
+
type: 'info',
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
},
|
|
1275
|
+
loadingIndicatorLabel: 'Loading',
|
|
1276
|
+
overwriteWarningMessage: 'Copied files will overwrite existing files at selected destination.',
|
|
1277
|
+
searchPlaceholder: 'Search for folders',
|
|
1278
|
+
getActionCompleteMessage: (data) => {
|
|
1279
|
+
const { counts } = data ?? {};
|
|
1280
|
+
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
1281
|
+
if (COMPLETE === TOTAL) {
|
|
1282
|
+
return {
|
|
1283
|
+
content: 'All files copied.',
|
|
1284
|
+
type: 'success',
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
if (FAILED === TOTAL) {
|
|
1288
|
+
return { content: 'All files failed to copy.', type: 'error' };
|
|
1289
|
+
}
|
|
1290
|
+
return {
|
|
1291
|
+
content: `${COMPLETE} files copied, ${FAILED} files failed to copy.`,
|
|
1292
|
+
type: 'error',
|
|
1291
1293
|
};
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
return dispatchRefresh(store.refreshHandler, storeValue, () => {
|
|
1296
|
-
store.values.delete(key);
|
|
1297
|
-
});
|
|
1294
|
+
},
|
|
1295
|
+
searchSubmitLabel: 'Submit',
|
|
1296
|
+
searchClearLabel: 'Clear search',
|
|
1298
1297
|
};
|
|
1299
1298
|
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
const
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
const createStore = (refreshHandler, size) => {
|
|
1310
|
-
const storeSymbol = { value: Symbol('LocationCredentialsStore') };
|
|
1311
|
-
storeRegistry.set(storeSymbol, initStore(refreshHandler, size));
|
|
1312
|
-
return storeSymbol;
|
|
1313
|
-
};
|
|
1314
|
-
const getCredentialsStore = (storeSymbol) => {
|
|
1315
|
-
internals.assertValidationError(storeRegistry.has(storeSymbol), internals.StorageValidationErrorCode.LocationCredentialsStoreDestroyed);
|
|
1316
|
-
return storeRegistry.get(storeSymbol);
|
|
1317
|
-
};
|
|
1318
|
-
/**
|
|
1319
|
-
* @internal
|
|
1320
|
-
*/
|
|
1321
|
-
const getValue = async (input) => {
|
|
1322
|
-
const { storeSymbol: storeReference, location, forceRefresh } = input;
|
|
1323
|
-
const store = getCredentialsStore(storeReference);
|
|
1324
|
-
if (!forceRefresh) {
|
|
1325
|
-
const credentials = getCacheValue(store, location);
|
|
1326
|
-
if (credentials !== null) {
|
|
1327
|
-
return { credentials };
|
|
1299
|
+
const DEFAULT_DELETE_VIEW_DISPLAY_TEXT = {
|
|
1300
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
1301
|
+
title: 'Delete',
|
|
1302
|
+
actionStartLabel: 'Delete',
|
|
1303
|
+
getActionCompleteMessage: (data) => {
|
|
1304
|
+
const { counts } = data ?? {};
|
|
1305
|
+
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
1306
|
+
if (COMPLETE === TOTAL) {
|
|
1307
|
+
return { content: 'All files deleted.', type: 'success' };
|
|
1328
1308
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1309
|
+
if (FAILED === TOTAL) {
|
|
1310
|
+
return { content: 'All files failed to delete.', type: 'error' };
|
|
1311
|
+
}
|
|
1312
|
+
return {
|
|
1313
|
+
content: `${COMPLETE} files deleted, ${FAILED} files failed to delete.`,
|
|
1314
|
+
type: 'error',
|
|
1315
|
+
};
|
|
1316
|
+
},
|
|
1334
1317
|
};
|
|
1335
1318
|
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
storeSymbol,
|
|
1349
|
-
location: { ...providerLocation },
|
|
1350
|
-
forceRefresh,
|
|
1351
|
-
});
|
|
1319
|
+
const DEFAULT_ERROR_MESSAGE$1 = 'There was an error loading items.';
|
|
1320
|
+
const DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT = {
|
|
1321
|
+
...DEFAULT_LIST_VIEW_DISPLAY_TEXT,
|
|
1322
|
+
getListItemsResultMessage: (data) => {
|
|
1323
|
+
const { items, hasExhaustedSearch, hasError = false, message, isLoading, } = data ?? {};
|
|
1324
|
+
if (isLoading) {
|
|
1325
|
+
return undefined;
|
|
1326
|
+
}
|
|
1327
|
+
if (hasError) {
|
|
1328
|
+
return {
|
|
1329
|
+
type: 'error',
|
|
1330
|
+
content: message ?? DEFAULT_ERROR_MESSAGE$1,
|
|
1352
1331
|
};
|
|
1353
|
-
return locationCredentialsProvider;
|
|
1354
|
-
},
|
|
1355
|
-
destroy() {
|
|
1356
|
-
removeStore(storeSymbol);
|
|
1357
|
-
},
|
|
1358
|
-
};
|
|
1359
|
-
return store;
|
|
1360
|
-
};
|
|
1361
|
-
|
|
1362
|
-
const createCredentialsStore = ({ ...input }) => {
|
|
1363
|
-
const { destroy, getProvider } = createLocationCredentialsStore(input);
|
|
1364
|
-
return {
|
|
1365
|
-
destroy,
|
|
1366
|
-
getCredentials: ({ scope, permissions }) => getProvider({
|
|
1367
|
-
scope,
|
|
1368
|
-
permissions,
|
|
1369
|
-
}),
|
|
1370
|
-
};
|
|
1371
|
-
};
|
|
1372
|
-
const isCredentialsStore = (value) => ui.isFunction(value?.getCredentials);
|
|
1373
|
-
function useCredentialsStore({ getLocationCredentials: handler, initialValue, onDestroy, registerAuthListener, }) {
|
|
1374
|
-
const hasExistingStore = isCredentialsStore(initialValue);
|
|
1375
|
-
const [store, setStore] = React__namespace["default"].useState(() => hasExistingStore ? initialValue : createCredentialsStore({ handler }));
|
|
1376
|
-
const { destroy } = store;
|
|
1377
|
-
React__namespace["default"].useEffect(() => {
|
|
1378
|
-
if (hasExistingStore) {
|
|
1379
|
-
return;
|
|
1380
1332
|
}
|
|
1381
|
-
|
|
1382
|
-
destroy();
|
|
1383
|
-
if (ui.isFunction(onDestroy)) {
|
|
1384
|
-
onDestroy();
|
|
1385
|
-
}
|
|
1386
|
-
setStore(createCredentialsStore({ handler }));
|
|
1387
|
-
};
|
|
1388
|
-
// provide `handleAuthStatusChange` to consumer
|
|
1389
|
-
registerAuthListener(handleAuthStatusChange);
|
|
1390
|
-
}, [destroy, handler, hasExistingStore, onDestroy, registerAuthListener]);
|
|
1391
|
-
return store;
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
const ERROR_MESSAGE$3 = '`useCredentials` must be called from within a `CredentialsProvider`.';
|
|
1395
|
-
const { useCredentials, CredentialsContext } = uiReactCore.createContextUtilities({
|
|
1396
|
-
contextName: 'Credentials',
|
|
1397
|
-
errorMessage: ERROR_MESSAGE$3,
|
|
1398
|
-
});
|
|
1399
|
-
function CredentialsProvider({ children, ...props }) {
|
|
1400
|
-
const initialValue = React__namespace["default"].useContext(CredentialsContext);
|
|
1401
|
-
const value = useCredentialsStore({ ...props, initialValue });
|
|
1402
|
-
return (React__namespace["default"].createElement(CredentialsContext.Provider, { value: value }, children));
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
const ERROR_MESSAGE$2 = 'Invalid `location` value provided as initial value to `LocationProvider.';
|
|
1406
|
-
const DEFAULT_STATE$1 = {
|
|
1407
|
-
current: undefined,
|
|
1408
|
-
path: '',
|
|
1409
|
-
key: '',
|
|
1410
|
-
};
|
|
1411
|
-
function handleAction$1(state, action) {
|
|
1412
|
-
switch (action.type) {
|
|
1413
|
-
case 'NAVIGATE': {
|
|
1414
|
-
const { location, path = '' } = action;
|
|
1415
|
-
if (state.current?.id === location.id && state.path === path) {
|
|
1416
|
-
return state;
|
|
1417
|
-
}
|
|
1333
|
+
if (!items?.length && hasExhaustedSearch) {
|
|
1418
1334
|
return {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
key: `${location.prefix ?? ''}${path}`,
|
|
1335
|
+
type: 'info',
|
|
1336
|
+
content: `No results found in the first 10,000 items.`,
|
|
1422
1337
|
};
|
|
1423
1338
|
}
|
|
1424
|
-
|
|
1425
|
-
return
|
|
1339
|
+
if (!items?.length) {
|
|
1340
|
+
return {
|
|
1341
|
+
type: 'info',
|
|
1342
|
+
content: 'No files.',
|
|
1343
|
+
};
|
|
1426
1344
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
defaultValue: defaultValue$7,
|
|
1433
|
-
});
|
|
1434
|
-
function LocationProvider({ children, location, path = '', }) {
|
|
1435
|
-
if (location) {
|
|
1436
|
-
assertLocationData(location, ERROR_MESSAGE$2);
|
|
1437
|
-
}
|
|
1438
|
-
const value = React__namespace["default"].useReducer(handleAction$1, location
|
|
1439
|
-
? {
|
|
1440
|
-
current: location,
|
|
1441
|
-
path,
|
|
1442
|
-
key: `${location.prefix ?? ''}${path}`,
|
|
1345
|
+
if (hasExhaustedSearch) {
|
|
1346
|
+
return {
|
|
1347
|
+
type: 'info',
|
|
1348
|
+
content: `Showing results for up to the first 10,000 items.`,
|
|
1349
|
+
};
|
|
1443
1350
|
}
|
|
1444
|
-
:
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1351
|
+
// TODO: add more cases as needed
|
|
1352
|
+
return undefined;
|
|
1353
|
+
},
|
|
1354
|
+
searchSubfoldersToggleLabel: 'Include subfolders',
|
|
1355
|
+
searchPlaceholder: 'Search current folder',
|
|
1356
|
+
tableColumnLastModifiedHeader: 'Last modified',
|
|
1357
|
+
tableColumnNameHeader: 'Name',
|
|
1358
|
+
tableColumnSizeHeader: 'Size',
|
|
1359
|
+
tableColumnTypeHeader: 'Type',
|
|
1360
|
+
selectFileLabel: 'Select file',
|
|
1361
|
+
selectAllFilesLabel: 'Select all files',
|
|
1362
|
+
getActionListItemLabel: (key = '') => {
|
|
1363
|
+
switch (key) {
|
|
1364
|
+
case 'Copy':
|
|
1365
|
+
return 'Copy';
|
|
1366
|
+
case 'Delete':
|
|
1367
|
+
return 'Delete';
|
|
1368
|
+
case 'Create folder':
|
|
1369
|
+
return 'Create folder';
|
|
1370
|
+
case 'Upload':
|
|
1371
|
+
return 'Upload';
|
|
1372
|
+
default:
|
|
1373
|
+
return key;
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
getTitle: (location) => {
|
|
1377
|
+
const { current, key } = location;
|
|
1378
|
+
const { bucket = '' } = current ?? {};
|
|
1379
|
+
return key || bucket;
|
|
1380
|
+
},
|
|
1470
1381
|
};
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1382
|
+
|
|
1383
|
+
const DEFAULT_ERROR_MESSAGE = 'There was an error loading locations.';
|
|
1384
|
+
const DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT = {
|
|
1385
|
+
...DEFAULT_LIST_VIEW_DISPLAY_TEXT,
|
|
1386
|
+
title: 'Home',
|
|
1387
|
+
searchPlaceholder: 'Filter folders and files',
|
|
1388
|
+
getListLocationsResultMessage: (data) => {
|
|
1389
|
+
const { isLoading, items, hasExhaustedSearch, hasError = false, message, } = data ?? {};
|
|
1390
|
+
if (isLoading) {
|
|
1391
|
+
return undefined;
|
|
1475
1392
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1393
|
+
if (hasError) {
|
|
1394
|
+
return {
|
|
1395
|
+
type: 'error',
|
|
1396
|
+
content: message ?? DEFAULT_ERROR_MESSAGE,
|
|
1397
|
+
};
|
|
1481
1398
|
}
|
|
1482
|
-
|
|
1483
|
-
return
|
|
1399
|
+
if (items?.length === 0 && !hasExhaustedSearch) {
|
|
1400
|
+
return {
|
|
1401
|
+
type: 'info',
|
|
1402
|
+
content: 'No folders or files.',
|
|
1403
|
+
};
|
|
1484
1404
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
return ['FILE', undefined];
|
|
1491
|
-
if (ui.isString(value))
|
|
1492
|
-
return [value, undefined];
|
|
1493
|
-
const [selectType, ...rest] = value;
|
|
1494
|
-
return [selectType, !rest?.length ? undefined : { accept: rest.join() }];
|
|
1495
|
-
};
|
|
1496
|
-
|
|
1497
|
-
const defaultValue$6 = [undefined, ui.noop];
|
|
1498
|
-
const { FilesContext, useFiles } = uiReactCore.createContextUtilities({
|
|
1499
|
-
contextName: 'Files',
|
|
1500
|
-
defaultValue: defaultValue$6,
|
|
1501
|
-
});
|
|
1502
|
-
function FilesProvider({ children, }) {
|
|
1503
|
-
const [items, dispatch] = React__namespace["default"].useReducer(filesReducer, []);
|
|
1504
|
-
const [fileInput, handleFileSelect] = internal.useFileSelect((nextFiles) => {
|
|
1505
|
-
dispatch({ type: 'ADD_FILE_ITEMS', files: nextFiles });
|
|
1506
|
-
});
|
|
1507
|
-
const handleFilesAction = React__namespace["default"].useCallback((action) => {
|
|
1508
|
-
if (action.type === 'SELECT_FILES') {
|
|
1509
|
-
handleFileSelect(...parseFileSelectParams(action.selectionType));
|
|
1405
|
+
if (hasExhaustedSearch) {
|
|
1406
|
+
return {
|
|
1407
|
+
type: 'info',
|
|
1408
|
+
content: `Showing results for up to the first 10,000 items.`,
|
|
1409
|
+
};
|
|
1510
1410
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1411
|
+
// TODO: add more cases as needed
|
|
1412
|
+
return undefined;
|
|
1413
|
+
},
|
|
1414
|
+
getPermissionName: (permissions) => {
|
|
1415
|
+
let text = '';
|
|
1416
|
+
if (permissions.includes('get') || permissions.includes('list')) {
|
|
1417
|
+
text = 'Read';
|
|
1513
1418
|
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
return (React__namespace["default"].createElement(FilesContext.Provider, { value: value },
|
|
1517
|
-
fileInput,
|
|
1518
|
-
children));
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
const handleAction = (event) => {
|
|
1522
|
-
switch (event.type) {
|
|
1523
|
-
case 'SET_ACTION_TYPE': {
|
|
1524
|
-
return event.actionType;
|
|
1419
|
+
if (permissions.includes('write') || permissions.includes('delete')) {
|
|
1420
|
+
text = text ? 'Read/Write' : 'Write';
|
|
1525
1421
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1422
|
+
if (!text) {
|
|
1423
|
+
text = permissions.join('/');
|
|
1528
1424
|
}
|
|
1529
|
-
|
|
1425
|
+
return text;
|
|
1426
|
+
},
|
|
1427
|
+
getDownloadLabel: (fileName) => `Download ${fileName}`,
|
|
1428
|
+
tableColumnBucketHeader: 'Bucket',
|
|
1429
|
+
tableColumnFolderHeader: 'Folder',
|
|
1430
|
+
tableColumnPermissionsHeader: 'Permissions',
|
|
1431
|
+
tableColumnActionsHeader: 'Actions',
|
|
1530
1432
|
};
|
|
1531
|
-
function useActionTypeState(initialState) {
|
|
1532
|
-
const [actionType, setActionType] = React__namespace["default"].useState(initialState);
|
|
1533
|
-
const handler = React__namespace["default"].useCallback((action) => setActionType(handleAction(action)), []);
|
|
1534
|
-
return [actionType, handler];
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
const defaultValue$5 = [undefined, ui.noop];
|
|
1538
|
-
const { ActionTypeContext, useActionType } = uiReactCore.createContextUtilities({
|
|
1539
|
-
contextName: 'ActionType',
|
|
1540
|
-
defaultValue: defaultValue$5,
|
|
1541
|
-
});
|
|
1542
|
-
function ActionTypeProvider({ actionType, children, }) {
|
|
1543
|
-
const value = useActionTypeState(actionType);
|
|
1544
|
-
return (React__namespace["default"].createElement(ActionTypeContext.Provider, { value: value }, children));
|
|
1545
|
-
}
|
|
1546
1433
|
|
|
1547
|
-
const
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1434
|
+
const DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT = {
|
|
1435
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
1436
|
+
title: 'Upload',
|
|
1437
|
+
actionStartLabel: 'Upload',
|
|
1438
|
+
addFilesLabel: 'Add files',
|
|
1439
|
+
addFolderLabel: 'Add folder',
|
|
1440
|
+
getActionCompleteMessage: (data) => {
|
|
1441
|
+
const { counts } = data ?? {};
|
|
1442
|
+
const { COMPLETE, FAILED, OVERWRITE_PREVENTED, CANCELED, TOTAL } = counts ?? {};
|
|
1443
|
+
const hasPreventedOverwrite = !!OVERWRITE_PREVENTED;
|
|
1444
|
+
const hasFailure = !!FAILED;
|
|
1445
|
+
const hasSuccess = !!COMPLETE;
|
|
1446
|
+
const hasCanceled = !!CANCELED;
|
|
1447
|
+
const type = hasFailure
|
|
1448
|
+
? 'error'
|
|
1449
|
+
: hasPreventedOverwrite || hasCanceled
|
|
1450
|
+
? 'warning'
|
|
1451
|
+
: 'success';
|
|
1452
|
+
const preventedOverwriteMessage = hasPreventedOverwrite
|
|
1453
|
+
? [
|
|
1454
|
+
'Overwrite prevented for',
|
|
1455
|
+
OVERWRITE_PREVENTED === TOTAL ? 'all' : String(OVERWRITE_PREVENTED),
|
|
1456
|
+
OVERWRITE_PREVENTED > 1 || OVERWRITE_PREVENTED === TOTAL
|
|
1457
|
+
? `files`
|
|
1458
|
+
: 'file',
|
|
1459
|
+
].join(' ')
|
|
1460
|
+
: undefined;
|
|
1461
|
+
const canceledMessage = hasCanceled
|
|
1462
|
+
? [
|
|
1463
|
+
CANCELED === TOTAL ? 'All' : String(CANCELED),
|
|
1464
|
+
CANCELED > 1 || CANCELED === TOTAL ? `uploads` : 'upload',
|
|
1465
|
+
'canceled',
|
|
1466
|
+
].join(' ')
|
|
1467
|
+
: undefined;
|
|
1468
|
+
const failedMessage = hasFailure
|
|
1469
|
+
? [
|
|
1470
|
+
FAILED === TOTAL ? 'All' : String(FAILED),
|
|
1471
|
+
FAILED > 1 || FAILED === TOTAL ? `files` : 'file',
|
|
1472
|
+
'failed to upload',
|
|
1473
|
+
].join(' ')
|
|
1474
|
+
: undefined;
|
|
1475
|
+
const completedMessage = hasSuccess
|
|
1476
|
+
? [
|
|
1477
|
+
COMPLETE === TOTAL ? 'All' : String(COMPLETE),
|
|
1478
|
+
COMPLETE > 1 || COMPLETE === TOTAL ? `files` : 'file',
|
|
1479
|
+
'uploaded',
|
|
1480
|
+
].join(' ')
|
|
1481
|
+
: undefined;
|
|
1482
|
+
const messages = [
|
|
1483
|
+
preventedOverwriteMessage,
|
|
1484
|
+
failedMessage,
|
|
1485
|
+
canceledMessage,
|
|
1486
|
+
completedMessage,
|
|
1487
|
+
].filter(Boolean);
|
|
1488
|
+
if (messages.length > 0) {
|
|
1564
1489
|
return {
|
|
1565
|
-
|
|
1490
|
+
content: messages.join(', ') + '.',
|
|
1491
|
+
type,
|
|
1566
1492
|
};
|
|
1567
1493
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
if (fileDataItems.length === prevState.fileDataItems.length) {
|
|
1574
|
-
return prevState;
|
|
1575
|
-
}
|
|
1576
|
-
return { fileDataItems };
|
|
1494
|
+
return { content: 'All files uploaded.', type };
|
|
1495
|
+
},
|
|
1496
|
+
getFilesValidationMessage: (data) => {
|
|
1497
|
+
if (!data?.invalidFiles) {
|
|
1498
|
+
return undefined;
|
|
1577
1499
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1500
|
+
const tooBigFileNames = data.invalidFiles
|
|
1501
|
+
.filter(({ file }) => isFileTooBig(file))
|
|
1502
|
+
.map(({ file }) => file.name)
|
|
1503
|
+
.join(', ');
|
|
1504
|
+
if (tooBigFileNames) {
|
|
1505
|
+
return {
|
|
1506
|
+
content: `Files larger than 160GB cannot be added to the upload queue: ${tooBigFileNames}`,
|
|
1507
|
+
type: 'warning',
|
|
1508
|
+
};
|
|
1580
1509
|
}
|
|
1581
|
-
|
|
1510
|
+
return undefined;
|
|
1511
|
+
},
|
|
1512
|
+
statusDisplayOverwritePreventedLabel: 'Overwrite prevented',
|
|
1513
|
+
overwriteToggleLabel: 'Overwrite existing files',
|
|
1582
1514
|
};
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1515
|
+
|
|
1516
|
+
const DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT = {
|
|
1517
|
+
CopyView: DEFAULT_COPY_VIEW_DISPLAY_TEXT,
|
|
1518
|
+
CreateFolderView: DEFAULT_CREATE_FOLDER_VIEW_DISPLAY_TEXT,
|
|
1519
|
+
DeleteView: DEFAULT_DELETE_VIEW_DISPLAY_TEXT,
|
|
1520
|
+
LocationDetailView: DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT,
|
|
1521
|
+
LocationsView: DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT,
|
|
1522
|
+
UploadView: DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT,
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
const { DisplayTextContext, useDisplayText } = uiReactCore.createContextUtilities({
|
|
1526
|
+
contextName: 'DisplayText',
|
|
1527
|
+
errorMessage: '`useDisplayText` must be called inside `DisplayTextProvider`',
|
|
1528
|
+
});
|
|
1529
|
+
function resolveDisplayText(displayText) {
|
|
1530
|
+
if (!displayText)
|
|
1531
|
+
return DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT;
|
|
1532
|
+
// override
|
|
1533
|
+
const { CopyView, CreateFolderView, DeleteView, LocationDetailView, LocationsView, UploadView, } = displayText;
|
|
1534
|
+
return {
|
|
1535
|
+
CopyView: { ...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.CopyView, ...CopyView },
|
|
1536
|
+
CreateFolderView: {
|
|
1537
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.CreateFolderView,
|
|
1538
|
+
...CreateFolderView,
|
|
1539
|
+
},
|
|
1540
|
+
DeleteView: {
|
|
1541
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.DeleteView,
|
|
1542
|
+
...DeleteView,
|
|
1543
|
+
},
|
|
1544
|
+
LocationDetailView: {
|
|
1545
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView,
|
|
1546
|
+
...LocationDetailView,
|
|
1547
|
+
},
|
|
1548
|
+
LocationsView: {
|
|
1549
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView,
|
|
1550
|
+
...LocationsView,
|
|
1551
|
+
},
|
|
1552
|
+
UploadView: {
|
|
1553
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView,
|
|
1554
|
+
...UploadView,
|
|
1555
|
+
},
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
function DisplayTextProvider({ children, displayText: _override, }) {
|
|
1559
|
+
// do deep merge here of default and override here
|
|
1560
|
+
const resolvedDisplayText = React__namespace["default"].useMemo(() => resolveDisplayText(_override), [_override]);
|
|
1561
|
+
return (React__namespace["default"].createElement(DisplayTextContext.Provider, { value: resolvedDisplayText }, children));
|
|
1588
1562
|
}
|
|
1589
1563
|
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1564
|
+
const Fallback = () => (React__namespace["default"].createElement("div", { className: STORAGE_BROWSER_BLOCK_TO_BE_UPDATED },
|
|
1565
|
+
React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__error-boundary` }, "Something went wrong.")));
|
|
1566
|
+
class ErrorBoundary extends React__namespace["default"].Component {
|
|
1567
|
+
constructor(props) {
|
|
1568
|
+
super(props);
|
|
1569
|
+
this.state = { hasError: false };
|
|
1570
|
+
}
|
|
1571
|
+
static getDerivedStateFromError(_error) {
|
|
1572
|
+
// Update state so the next render will show the fallback UI.
|
|
1573
|
+
return { hasError: true };
|
|
1574
|
+
}
|
|
1575
|
+
render() {
|
|
1576
|
+
const { hasError } = this.state;
|
|
1577
|
+
const { children } = this.props;
|
|
1578
|
+
if (hasError) {
|
|
1579
|
+
return React__namespace["default"].createElement(Fallback, null);
|
|
1580
|
+
}
|
|
1581
|
+
return children;
|
|
1582
|
+
}
|
|
1596
1583
|
}
|
|
1597
1584
|
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
const [files, dispatchFilesAction] = useFiles();
|
|
1601
|
-
const [location, dispatchLocationAction] = useLocation();
|
|
1602
|
-
const [locationItems, dispatchLocationItemsAction] = useLocationItems();
|
|
1603
|
-
const dispatchHandler = React__namespace["default"].useCallback((action) => {
|
|
1604
|
-
switch (action.type) {
|
|
1605
|
-
case 'ADD_FILE_ITEMS':
|
|
1606
|
-
case 'REMOVE_FILE_ITEM':
|
|
1607
|
-
case 'SELECT_FILES':
|
|
1608
|
-
case 'RESET_FILE_ITEMS': {
|
|
1609
|
-
dispatchFilesAction(action);
|
|
1610
|
-
break;
|
|
1611
|
-
}
|
|
1612
|
-
case 'NAVIGATE':
|
|
1613
|
-
case 'RESET_LOCATION': {
|
|
1614
|
-
dispatchLocationAction(action);
|
|
1615
|
-
break;
|
|
1616
|
-
}
|
|
1617
|
-
case 'SET_LOCATION_ITEMS':
|
|
1618
|
-
case 'REMOVE_LOCATION_ITEM':
|
|
1619
|
-
case 'RESET_LOCATION_ITEMS': {
|
|
1620
|
-
dispatchLocationItemsAction(action);
|
|
1621
|
-
break;
|
|
1622
|
-
}
|
|
1623
|
-
case 'SET_ACTION_TYPE':
|
|
1624
|
-
case 'RESET_ACTION_TYPE': {
|
|
1625
|
-
dispatchActionType(action);
|
|
1626
|
-
break;
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
}, [
|
|
1630
|
-
dispatchActionType,
|
|
1631
|
-
dispatchFilesAction,
|
|
1632
|
-
dispatchLocationAction,
|
|
1633
|
-
dispatchLocationItemsAction,
|
|
1634
|
-
]);
|
|
1635
|
-
return [{ actionType, files, location, locationItems }, dispatchHandler];
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
const getErrorMessage = (propertyName) => `Unable to resolve credentials due to invalid value of '${propertyName}'`;
|
|
1639
|
-
function useGetActionInputCallback({ accountId, customEndpoint, region, }) {
|
|
1640
|
-
const { getCredentials } = useCredentials();
|
|
1641
|
-
const [{ location }] = useStore();
|
|
1642
|
-
const { current, key } = location;
|
|
1643
|
-
return React__namespace["default"].useCallback((_location) => {
|
|
1644
|
-
// prefer passed in location / prefix over current location in state
|
|
1645
|
-
const location = _location ?? current;
|
|
1646
|
-
// when `location` has been provided as a param, resolve `_prefix` to `location.prefix`.
|
|
1647
|
-
// in the default scenario where `current` is the target `location` use the fully qualified `key`
|
|
1648
|
-
// that includes the default `prefix` and any additional prefixes from navigation
|
|
1649
|
-
const prefix = _location ? _location.prefix : key;
|
|
1650
|
-
assertLocationData(location, getErrorMessage('locationData'));
|
|
1651
|
-
assertPrefix(prefix, getErrorMessage('prefix'));
|
|
1652
|
-
const { bucket, permissions, type } = location;
|
|
1653
|
-
// BUCKET/PREFIX grants end with `*`, but object grants do not.
|
|
1654
|
-
const scope = `s3://${bucket}/${prefix}${type === 'OBJECT' ? '' : '*'}`;
|
|
1655
|
-
return {
|
|
1656
|
-
accountId,
|
|
1657
|
-
bucket,
|
|
1658
|
-
credentials: getCredentials({
|
|
1659
|
-
permissions,
|
|
1660
|
-
scope,
|
|
1661
|
-
}),
|
|
1662
|
-
region,
|
|
1663
|
-
customEndpoint,
|
|
1664
|
-
};
|
|
1665
|
-
}, [accountId, current, customEndpoint, getCredentials, key, region]);
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
const ERROR_MESSAGE$1 = '`useGetActionInput` must be called from within a `ConfigurationProvider`.';
|
|
1669
|
-
const { useGetActionInput, GetActionInputContext } = uiReactCore.createContextUtilities({
|
|
1670
|
-
contextName: 'GetActionInput',
|
|
1671
|
-
errorMessage: ERROR_MESSAGE$1,
|
|
1672
|
-
});
|
|
1673
|
-
function GetActionInputProvider({ accountId, children, customEndpoint, region, }) {
|
|
1674
|
-
const value = useGetActionInputCallback({
|
|
1675
|
-
accountId,
|
|
1676
|
-
customEndpoint,
|
|
1677
|
-
region,
|
|
1678
|
-
});
|
|
1679
|
-
return (React__namespace["default"].createElement(GetActionInputContext.Provider, { value: value }, children));
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
const Passthrough = ({ children }) => (React__namespace["default"].createElement(React__namespace["default"].Fragment, null, children));
|
|
1683
|
-
function createConfigurationProvider(input) {
|
|
1684
|
-
const { accountId, ChildComponent, displayName, region, customEndpoint, ...rest } = input;
|
|
1685
|
-
const Child = elements.isComponent(ChildComponent) ? ChildComponent : Passthrough;
|
|
1686
|
-
const Provider = (props) => (React__namespace["default"].createElement(CredentialsProvider, { ...rest },
|
|
1687
|
-
React__namespace["default"].createElement(GetActionInputProvider, { accountId: accountId, region: region, customEndpoint: customEndpoint },
|
|
1688
|
-
React__namespace["default"].createElement(Child, { ...props }))));
|
|
1689
|
-
Provider.displayName = displayName;
|
|
1690
|
-
return Provider;
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
const defaultValue$3 = { data: {} };
|
|
1694
|
-
const { useControlsContext, ControlsContextProvider } = uiReactCore.createContextUtilities({
|
|
1695
|
-
contextName: 'ControlsContext',
|
|
1696
|
-
defaultValue: defaultValue$3,
|
|
1697
|
-
});
|
|
1585
|
+
const CREDENTIALS_STORE_DEFAULT_SIZE = 10;
|
|
1586
|
+
const CREDENTIALS_REFRESH_WINDOW_MS = 30000;
|
|
1698
1587
|
|
|
1699
|
-
const
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
label: actionCancelLabel,
|
|
1705
|
-
};
|
|
1588
|
+
const serializedPermissions = (permissions) => permissions.sort().join('_');
|
|
1589
|
+
const createCacheKey = (location) => `${location.scope}_${serializedPermissions(location.permissions)}`;
|
|
1590
|
+
const pastTTL = (credentials) => {
|
|
1591
|
+
const { expiration } = credentials;
|
|
1592
|
+
return expiration.getTime() - CREDENTIALS_REFRESH_WINDOW_MS <= Date.now();
|
|
1706
1593
|
};
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
const
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
}, [composables, DefaultComposable, name]);
|
|
1718
|
-
return Composable;
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
const ActionCancelControl = () => {
|
|
1722
|
-
const props = useActionCancel();
|
|
1723
|
-
const Resolved = useResolvedComposable(ActionCancel, 'ActionCancel');
|
|
1724
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
1594
|
+
const setCacheRecord = (store, key, value) => {
|
|
1595
|
+
if (store.capacity === store.values.size) {
|
|
1596
|
+
// Pop least used entry. The Map's key are in insertion order.
|
|
1597
|
+
// So first key is the last recently inserted.
|
|
1598
|
+
const [oldestKey] = store.values.keys();
|
|
1599
|
+
store.values.delete(oldestKey);
|
|
1600
|
+
// TODO(@AllanZhengYP): Add log info when record is evicted.
|
|
1601
|
+
}
|
|
1602
|
+
// Add latest used value to the cache.
|
|
1603
|
+
store.values.set(key, value);
|
|
1725
1604
|
};
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1605
|
+
const dispatchRefresh = (refreshHandler, value, onRefreshFailure) => {
|
|
1606
|
+
if (value.inflightCredentials) {
|
|
1607
|
+
return value.inflightCredentials;
|
|
1608
|
+
}
|
|
1609
|
+
value.inflightCredentials = (async () => {
|
|
1610
|
+
try {
|
|
1611
|
+
const { credentials } = await refreshHandler({
|
|
1612
|
+
scope: value.scope,
|
|
1613
|
+
permissions: value.permissions,
|
|
1614
|
+
});
|
|
1615
|
+
value.credentials = credentials;
|
|
1616
|
+
return { credentials };
|
|
1734
1617
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
type,
|
|
1739
|
-
permissions,
|
|
1740
|
-
bucket,
|
|
1741
|
-
prefix,
|
|
1742
|
-
};
|
|
1743
|
-
return {
|
|
1744
|
-
name: part,
|
|
1745
|
-
...(isCurrent && { isCurrent }),
|
|
1746
|
-
onNavigate: () => {
|
|
1747
|
-
onNavigate?.(destination, destinationPath);
|
|
1748
|
-
},
|
|
1749
|
-
};
|
|
1750
|
-
});
|
|
1751
|
-
};
|
|
1752
|
-
|
|
1753
|
-
const getNavigationParts = ({ location, path, includeBucketInPrefix, }) => {
|
|
1754
|
-
const { bucket, prefix = '', type } = location;
|
|
1755
|
-
const trimmedPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
|
|
1756
|
-
const trimmedPath = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
1757
|
-
const firstPrefixPart = [];
|
|
1758
|
-
if (type !== 'BUCKET') {
|
|
1759
|
-
if (includeBucketInPrefix) {
|
|
1760
|
-
firstPrefixPart.push(bucket);
|
|
1618
|
+
catch (e) {
|
|
1619
|
+
onRefreshFailure();
|
|
1620
|
+
throw e;
|
|
1761
1621
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
firstPrefixPart.push('/');
|
|
1765
|
-
}
|
|
1766
|
-
firstPrefixPart.push(trimmedPrefix);
|
|
1622
|
+
finally {
|
|
1623
|
+
value.inflightCredentials = undefined;
|
|
1767
1624
|
}
|
|
1625
|
+
})();
|
|
1626
|
+
return value.inflightCredentials;
|
|
1627
|
+
};
|
|
1628
|
+
/**
|
|
1629
|
+
* @internal
|
|
1630
|
+
*/
|
|
1631
|
+
const initStore = (refreshHandler, size = CREDENTIALS_STORE_DEFAULT_SIZE) => {
|
|
1632
|
+
internals.assertValidationError(size > 0, internals.StorageValidationErrorCode.InvalidLocationCredentialsCacheSize);
|
|
1633
|
+
return {
|
|
1634
|
+
capacity: size,
|
|
1635
|
+
refreshHandler,
|
|
1636
|
+
values: new Map(),
|
|
1637
|
+
};
|
|
1638
|
+
};
|
|
1639
|
+
const getCacheValue = (store, location) => {
|
|
1640
|
+
const cacheKey = createCacheKey(location);
|
|
1641
|
+
const cachedValue = store.values.get(cacheKey);
|
|
1642
|
+
const cachedCredentials = cachedValue?.credentials;
|
|
1643
|
+
if (!cachedCredentials) {
|
|
1644
|
+
return null;
|
|
1768
1645
|
}
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1646
|
+
// Delete and re-insert to key to map to indicate a latest reference in LRU.
|
|
1647
|
+
store.values.delete(cacheKey);
|
|
1648
|
+
if (!pastTTL(cachedCredentials)) {
|
|
1649
|
+
// TODO(@AllanZhengYP): If the credential is still valid but will expire
|
|
1650
|
+
// soon, we should return credentials AND dispatch a refresh.
|
|
1651
|
+
store.values.set(cacheKey, cachedValue);
|
|
1652
|
+
return cachedCredentials;
|
|
1772
1653
|
}
|
|
1773
|
-
|
|
1774
|
-
return prefixParts.concat(pathParts);
|
|
1654
|
+
return null;
|
|
1775
1655
|
};
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
const
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
path,
|
|
1789
|
-
});
|
|
1790
|
-
return {
|
|
1791
|
-
label: actionDestinationLabel,
|
|
1792
|
-
items: getNavigationItems({
|
|
1793
|
-
location: current,
|
|
1794
|
-
destinationParts,
|
|
1795
|
-
onNavigate: onSelectDestination,
|
|
1796
|
-
}),
|
|
1797
|
-
isNavigable: isActionDestinationNavigable,
|
|
1656
|
+
/**
|
|
1657
|
+
* Fetch new credentials value with refresh handler and cache the result in
|
|
1658
|
+
* LRU cache.
|
|
1659
|
+
* @internal
|
|
1660
|
+
*/
|
|
1661
|
+
const fetchNewValue = async (store, location) => {
|
|
1662
|
+
const storeValues = store.values;
|
|
1663
|
+
const key = createCacheKey(location);
|
|
1664
|
+
if (!storeValues.has(key)) {
|
|
1665
|
+
const newStoreValue = {
|
|
1666
|
+
scope: location.scope,
|
|
1667
|
+
permissions: location.permissions,
|
|
1798
1668
|
};
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1669
|
+
setCacheRecord(store, key, newStoreValue);
|
|
1670
|
+
}
|
|
1671
|
+
const storeValue = storeValues.get(key);
|
|
1672
|
+
return dispatchRefresh(store.refreshHandler, storeValue, () => {
|
|
1673
|
+
store.values.delete(key);
|
|
1674
|
+
});
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Keep all cache records for all instances of credentials store in a singleton
|
|
1679
|
+
* so we can reliably de-reference from the memory when we destroy a store
|
|
1680
|
+
* instance.
|
|
1681
|
+
*/
|
|
1682
|
+
const storeRegistry = new WeakMap();
|
|
1683
|
+
/**
|
|
1684
|
+
* @internal
|
|
1685
|
+
*/
|
|
1686
|
+
const createStore = (refreshHandler, size) => {
|
|
1687
|
+
const storeSymbol = { value: Symbol('LocationCredentialsStore') };
|
|
1688
|
+
storeRegistry.set(storeSymbol, initStore(refreshHandler, size));
|
|
1689
|
+
return storeSymbol;
|
|
1690
|
+
};
|
|
1691
|
+
const getCredentialsStore = (storeSymbol) => {
|
|
1692
|
+
internals.assertValidationError(storeRegistry.has(storeSymbol), internals.StorageValidationErrorCode.LocationCredentialsStoreDestroyed);
|
|
1693
|
+
return storeRegistry.get(storeSymbol);
|
|
1694
|
+
};
|
|
1695
|
+
/**
|
|
1696
|
+
* @internal
|
|
1697
|
+
*/
|
|
1698
|
+
const getValue = async (input) => {
|
|
1699
|
+
const { storeSymbol: storeReference, location, forceRefresh } = input;
|
|
1700
|
+
const store = getCredentialsStore(storeReference);
|
|
1701
|
+
if (!forceRefresh) {
|
|
1702
|
+
const credentials = getCacheValue(store, location);
|
|
1703
|
+
if (credentials !== null) {
|
|
1704
|
+
return { credentials };
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return fetchNewValue(store, location);
|
|
1805
1708
|
};
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
const props = useActionDestination();
|
|
1809
|
-
const Resolved = useResolvedComposable(ActionDestination$1, 'ActionDestination');
|
|
1810
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
1709
|
+
const removeStore = (storeSymbol) => {
|
|
1710
|
+
storeRegistry.delete(storeSymbol);
|
|
1811
1711
|
};
|
|
1812
1712
|
|
|
1813
|
-
const
|
|
1814
|
-
const
|
|
1815
|
-
|
|
1713
|
+
const validateS3Uri = (uri) => {
|
|
1714
|
+
const s3UrlSchemaRegex = /^s3:\/\/[^/]+/;
|
|
1715
|
+
internals.assertValidationError(s3UrlSchemaRegex.test(uri), internals.StorageValidationErrorCode.InvalidS3Uri);
|
|
1816
1716
|
};
|
|
1817
|
-
|
|
1818
|
-
const
|
|
1819
|
-
const
|
|
1820
|
-
|
|
1821
|
-
|
|
1717
|
+
const createLocationCredentialsStore = (input) => {
|
|
1718
|
+
const storeSymbol = createStore(input.handler);
|
|
1719
|
+
const store = {
|
|
1720
|
+
getProvider(providerLocation) {
|
|
1721
|
+
const locationCredentialsProvider = async ({ forceRefresh = false, } = {}) => {
|
|
1722
|
+
validateS3Uri(providerLocation.scope);
|
|
1723
|
+
// TODO(@AllanZhengYP): validate the action bucket and paths matches provider scope.
|
|
1724
|
+
return getValue({
|
|
1725
|
+
storeSymbol,
|
|
1726
|
+
location: { ...providerLocation },
|
|
1727
|
+
forceRefresh,
|
|
1728
|
+
});
|
|
1729
|
+
};
|
|
1730
|
+
return locationCredentialsProvider;
|
|
1731
|
+
},
|
|
1732
|
+
destroy() {
|
|
1733
|
+
removeStore(storeSymbol);
|
|
1734
|
+
},
|
|
1735
|
+
};
|
|
1736
|
+
return store;
|
|
1822
1737
|
};
|
|
1823
1738
|
|
|
1824
|
-
const
|
|
1825
|
-
const {
|
|
1739
|
+
const createCredentialsStore = ({ ...input }) => {
|
|
1740
|
+
const { destroy, getProvider } = createLocationCredentialsStore(input);
|
|
1826
1741
|
return {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1742
|
+
destroy,
|
|
1743
|
+
getCredentials: ({ scope, permissions }) => getProvider({
|
|
1744
|
+
scope,
|
|
1745
|
+
permissions,
|
|
1746
|
+
}),
|
|
1830
1747
|
};
|
|
1831
1748
|
};
|
|
1749
|
+
const isCredentialsStore = (value) => ui.isFunction(value?.getCredentials);
|
|
1750
|
+
function useCredentialsStore({ getLocationCredentials: handler, initialValue, onDestroy, registerAuthListener, }) {
|
|
1751
|
+
const hasExistingStore = isCredentialsStore(initialValue);
|
|
1752
|
+
const [store, setStore] = React__namespace["default"].useState(() => hasExistingStore ? initialValue : createCredentialsStore({ handler }));
|
|
1753
|
+
const { destroy } = store;
|
|
1754
|
+
React__namespace["default"].useEffect(() => {
|
|
1755
|
+
if (hasExistingStore) {
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
const handleAuthStatusChange = () => {
|
|
1759
|
+
destroy();
|
|
1760
|
+
if (ui.isFunction(onDestroy)) {
|
|
1761
|
+
onDestroy();
|
|
1762
|
+
}
|
|
1763
|
+
setStore(createCredentialsStore({ handler }));
|
|
1764
|
+
};
|
|
1765
|
+
// provide `handleAuthStatusChange` to consumer
|
|
1766
|
+
registerAuthListener(handleAuthStatusChange);
|
|
1767
|
+
}, [destroy, handler, hasExistingStore, onDestroy, registerAuthListener]);
|
|
1768
|
+
return store;
|
|
1769
|
+
}
|
|
1832
1770
|
|
|
1833
|
-
const
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
};
|
|
1771
|
+
const ERROR_MESSAGE$3 = '`useCredentials` must be called from within a `CredentialsProvider`.';
|
|
1772
|
+
const { useCredentials, CredentialsContext } = uiReactCore.createContextUtilities({
|
|
1773
|
+
contextName: 'Credentials',
|
|
1774
|
+
errorMessage: ERROR_MESSAGE$3,
|
|
1775
|
+
});
|
|
1776
|
+
function CredentialsProvider({ children, ...props }) {
|
|
1777
|
+
const initialValue = React__namespace["default"].useContext(CredentialsContext);
|
|
1778
|
+
const value = useCredentialsStore({ ...props, initialValue });
|
|
1779
|
+
return (React__namespace["default"].createElement(CredentialsContext.Provider, { value: value }, children));
|
|
1780
|
+
}
|
|
1838
1781
|
|
|
1839
|
-
const
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
onAddFiles,
|
|
1845
|
-
};
|
|
1782
|
+
const ERROR_MESSAGE$2 = 'Invalid `location` value provided as initial value to `LocationProvider.';
|
|
1783
|
+
const DEFAULT_STATE$1 = {
|
|
1784
|
+
current: undefined,
|
|
1785
|
+
path: '',
|
|
1786
|
+
key: '',
|
|
1846
1787
|
};
|
|
1788
|
+
function handleAction$1(state, action) {
|
|
1789
|
+
switch (action.type) {
|
|
1790
|
+
case 'NAVIGATE': {
|
|
1791
|
+
const { location, path = '' } = action;
|
|
1792
|
+
if (state.current?.id === location.id && state.path === path) {
|
|
1793
|
+
return state;
|
|
1794
|
+
}
|
|
1795
|
+
return {
|
|
1796
|
+
current: location,
|
|
1797
|
+
path,
|
|
1798
|
+
key: `${location.prefix ?? ''}${path}`,
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
case 'RESET_LOCATION': {
|
|
1802
|
+
return DEFAULT_STATE$1;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
const defaultValue$7 = [DEFAULT_STATE$1, ui.noop];
|
|
1807
|
+
const { LocationContext, useLocation } = uiReactCore.createContextUtilities({
|
|
1808
|
+
contextName: 'Location',
|
|
1809
|
+
defaultValue: defaultValue$7,
|
|
1810
|
+
});
|
|
1811
|
+
function LocationProvider({ children, location, path = '', }) {
|
|
1812
|
+
if (location) {
|
|
1813
|
+
assertLocationData(location, ERROR_MESSAGE$2);
|
|
1814
|
+
}
|
|
1815
|
+
const value = React__namespace["default"].useReducer(handleAction$1, location
|
|
1816
|
+
? {
|
|
1817
|
+
current: location,
|
|
1818
|
+
path,
|
|
1819
|
+
key: `${location.prefix ?? ''}${path}`,
|
|
1820
|
+
}
|
|
1821
|
+
: DEFAULT_STATE$1);
|
|
1822
|
+
return (React__namespace["default"].createElement(LocationContext.Provider, { value: value }, children));
|
|
1823
|
+
}
|
|
1847
1824
|
|
|
1848
|
-
const
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1825
|
+
const compareFileItems = (prev, next) => prev.key.localeCompare(next.key);
|
|
1826
|
+
const resolveFiles = (prevItems, files) => {
|
|
1827
|
+
if (!files?.length)
|
|
1828
|
+
return prevItems;
|
|
1829
|
+
// construct `nextItems` and filter out existing `file` entries
|
|
1830
|
+
const nextItems = files.reduce((items, file) => {
|
|
1831
|
+
const { name, webkitRelativePath } = file;
|
|
1832
|
+
return prevItems.some(({ file: existing }) => existing.name === name &&
|
|
1833
|
+
existing.webkitRelativePath === webkitRelativePath)
|
|
1834
|
+
? items
|
|
1835
|
+
: items.concat({
|
|
1836
|
+
key: ui.isEmpty(webkitRelativePath) ? name : webkitRelativePath,
|
|
1837
|
+
id: crypto.randomUUID(),
|
|
1838
|
+
file,
|
|
1839
|
+
});
|
|
1840
|
+
}, []);
|
|
1841
|
+
if (!nextItems.length)
|
|
1842
|
+
return prevItems;
|
|
1843
|
+
if (!prevItems.length) {
|
|
1844
|
+
return nextItems.sort(compareFileItems);
|
|
1845
|
+
}
|
|
1846
|
+
return prevItems.concat(nextItems).sort(compareFileItems);
|
|
1852
1847
|
};
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1848
|
+
const filesReducer = (prevItems, input) => {
|
|
1849
|
+
switch (input.type) {
|
|
1850
|
+
case 'ADD_FILE_ITEMS': {
|
|
1851
|
+
return resolveFiles(prevItems, input.files);
|
|
1852
|
+
}
|
|
1853
|
+
case 'REMOVE_FILE_ITEM': {
|
|
1854
|
+
const filteredItems = prevItems.filter(({ id }) => id !== input.id);
|
|
1855
|
+
return filteredItems.length === prevItems.length
|
|
1856
|
+
? prevItems
|
|
1857
|
+
: filteredItems;
|
|
1858
|
+
}
|
|
1859
|
+
case 'RESET_FILE_ITEMS': {
|
|
1860
|
+
return [];
|
|
1861
|
+
}
|
|
1862
|
+
// TODO: clear message
|
|
1863
|
+
}
|
|
1861
1864
|
};
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1865
|
+
const parseFileSelectParams = (value) => {
|
|
1866
|
+
if (ui.isUndefined(value))
|
|
1867
|
+
return ['FILE', undefined];
|
|
1868
|
+
if (ui.isString(value))
|
|
1869
|
+
return [value, undefined];
|
|
1870
|
+
const [selectType, ...rest] = value;
|
|
1871
|
+
return [selectType, !rest?.length ? undefined : { accept: rest.join() }];
|
|
1867
1872
|
};
|
|
1868
1873
|
|
|
1869
|
-
const
|
|
1870
|
-
|
|
1871
|
-
|
|
1874
|
+
const defaultValue$6 = [undefined, ui.noop];
|
|
1875
|
+
const { FilesContext, useFiles } = uiReactCore.createContextUtilities({
|
|
1876
|
+
contextName: 'Files',
|
|
1877
|
+
defaultValue: defaultValue$6,
|
|
1878
|
+
});
|
|
1879
|
+
function FilesProvider({ children, }) {
|
|
1880
|
+
const [items, dispatch] = React__namespace["default"].useReducer(filesReducer, []);
|
|
1881
|
+
const [fileInput, handleFileSelect] = internal.useFileSelect((nextFiles) => {
|
|
1882
|
+
dispatch({ type: 'ADD_FILE_ITEMS', files: nextFiles });
|
|
1883
|
+
});
|
|
1884
|
+
const handleFilesAction = React__namespace["default"].useCallback((action) => {
|
|
1885
|
+
if (action.type === 'SELECT_FILES') {
|
|
1886
|
+
handleFileSelect(...parseFileSelectParams(action.selectionType));
|
|
1887
|
+
}
|
|
1888
|
+
else {
|
|
1889
|
+
dispatch(action);
|
|
1890
|
+
}
|
|
1891
|
+
}, [handleFileSelect]);
|
|
1892
|
+
const value = React__namespace["default"].useMemo(() => [items, handleFilesAction], [items, handleFilesAction]);
|
|
1893
|
+
return (React__namespace["default"].createElement(FilesContext.Provider, { value: value },
|
|
1894
|
+
fileInput,
|
|
1895
|
+
children));
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
const handleAction = (event) => {
|
|
1899
|
+
switch (event.type) {
|
|
1900
|
+
case 'SET_ACTION_TYPE': {
|
|
1901
|
+
return event.actionType;
|
|
1902
|
+
}
|
|
1903
|
+
case 'RESET_ACTION_TYPE': {
|
|
1904
|
+
return undefined;
|
|
1905
|
+
}
|
|
1872
1906
|
}
|
|
1873
|
-
return b === undefined ? -1 : a.localeCompare(b);
|
|
1874
1907
|
};
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1908
|
+
function useActionTypeState(initialState) {
|
|
1909
|
+
const [actionType, setActionType] = React__namespace["default"].useState(initialState);
|
|
1910
|
+
const handler = React__namespace["default"].useCallback((action) => setActionType(handleAction(action)), []);
|
|
1911
|
+
return [actionType, handler];
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
const defaultValue$5 = [undefined, ui.noop];
|
|
1915
|
+
const { ActionTypeContext, useActionType } = uiReactCore.createContextUtilities({
|
|
1916
|
+
contextName: 'ActionType',
|
|
1917
|
+
defaultValue: defaultValue$5,
|
|
1918
|
+
});
|
|
1919
|
+
function ActionTypeProvider({ actionType, children, }) {
|
|
1920
|
+
const value = useActionTypeState(actionType);
|
|
1921
|
+
return (React__namespace["default"].createElement(ActionTypeContext.Provider, { value: value }, children));
|
|
1922
|
+
}
|
|
1878
1923
|
|
|
1879
|
-
const
|
|
1880
|
-
|
|
1881
|
-
return b === undefined ? 0 : 1;
|
|
1882
|
-
}
|
|
1883
|
-
return b === undefined ? -1 : a.getTime() - b.getTime();
|
|
1924
|
+
const DEFAULT_STATE = {
|
|
1925
|
+
fileDataItems: undefined,
|
|
1884
1926
|
};
|
|
1885
|
-
const
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1927
|
+
const locationItemsReducer = (prevState, event) => {
|
|
1928
|
+
switch (event.type) {
|
|
1929
|
+
case 'SET_LOCATION_ITEMS': {
|
|
1930
|
+
const { items } = event;
|
|
1931
|
+
if (!items?.length)
|
|
1932
|
+
return prevState;
|
|
1933
|
+
if (!prevState.fileDataItems?.length) {
|
|
1934
|
+
return { fileDataItems: items.map(createFileDataItem) };
|
|
1935
|
+
}
|
|
1936
|
+
const nextFileDataItems = items?.reduce((fileDataItems, data) => prevState.fileDataItems?.some(({ id }) => id === data.id)
|
|
1937
|
+
? fileDataItems
|
|
1938
|
+
: fileDataItems.concat(createFileDataItem(data)), []);
|
|
1939
|
+
if (!nextFileDataItems?.length)
|
|
1940
|
+
return prevState;
|
|
1941
|
+
return {
|
|
1942
|
+
fileDataItems: prevState.fileDataItems.concat(nextFileDataItems),
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
case 'REMOVE_LOCATION_ITEM': {
|
|
1946
|
+
const { id } = event;
|
|
1947
|
+
if (!prevState.fileDataItems)
|
|
1948
|
+
return prevState;
|
|
1949
|
+
const fileDataItems = prevState.fileDataItems.filter((item) => item.id !== id);
|
|
1950
|
+
if (fileDataItems.length === prevState.fileDataItems.length) {
|
|
1951
|
+
return prevState;
|
|
1952
|
+
}
|
|
1953
|
+
return { fileDataItems };
|
|
1954
|
+
}
|
|
1955
|
+
case 'RESET_LOCATION_ITEMS': {
|
|
1956
|
+
return DEFAULT_STATE;
|
|
1957
|
+
}
|
|
1892
1958
|
}
|
|
1893
|
-
return b === undefined ? -1 : a - b;
|
|
1894
1959
|
};
|
|
1895
|
-
const
|
|
1896
|
-
|
|
1897
|
-
|
|
1960
|
+
const defaultValue$4 = [DEFAULT_STATE, ui.noop];
|
|
1961
|
+
const { LocationItemsContext, useLocationItems } = uiReactCore.createContextUtilities({ contextName: 'LocationItems', defaultValue: defaultValue$4 });
|
|
1962
|
+
function LocationItemsProvider({ children, }) {
|
|
1963
|
+
const value = React__namespace["default"].useReducer(locationItemsReducer, DEFAULT_STATE);
|
|
1964
|
+
return (React__namespace["default"].createElement(LocationItemsContext.Provider, { value: value }, children));
|
|
1965
|
+
}
|
|
1898
1966
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
};
|
|
1905
|
-
|
|
1906
|
-
? compareContent(a.content, b.content)
|
|
1907
|
-
: compareContent(b.content, a.content);
|
|
1967
|
+
function StoreProvider(props) {
|
|
1968
|
+
const { actionType, children, location, path } = props;
|
|
1969
|
+
return (React__namespace["default"].createElement(FilesProvider, null,
|
|
1970
|
+
React__namespace["default"].createElement(LocationProvider, { location: location, path: path },
|
|
1971
|
+
React__namespace["default"].createElement(LocationItemsProvider, null,
|
|
1972
|
+
React__namespace["default"].createElement(ActionTypeProvider, { actionType: actionType }, children)))));
|
|
1973
|
+
}
|
|
1908
1974
|
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
index: defaultSortIndex,
|
|
1923
|
-
direction: 'ascending',
|
|
1924
|
-
});
|
|
1925
|
-
const mappedHeaders = React__namespace["default"].useMemo(() => tableData?.headers.map((header, index) => {
|
|
1926
|
-
const { type } = header;
|
|
1927
|
-
switch (type) {
|
|
1928
|
-
case 'sort': {
|
|
1929
|
-
return {
|
|
1930
|
-
...header,
|
|
1931
|
-
content: {
|
|
1932
|
-
...header.content,
|
|
1933
|
-
onSort: () => {
|
|
1934
|
-
setSortState({
|
|
1935
|
-
index,
|
|
1936
|
-
direction: sortState.index === index
|
|
1937
|
-
? sortState.direction === 'ascending'
|
|
1938
|
-
? 'descending'
|
|
1939
|
-
: 'ascending'
|
|
1940
|
-
: 'ascending',
|
|
1941
|
-
});
|
|
1942
|
-
},
|
|
1943
|
-
sortDirection: sortState.index === index ? sortState.direction : undefined,
|
|
1944
|
-
},
|
|
1945
|
-
};
|
|
1975
|
+
function useStore() {
|
|
1976
|
+
const [actionType, dispatchActionType] = useActionType();
|
|
1977
|
+
const [files, dispatchFilesAction] = useFiles();
|
|
1978
|
+
const [location, dispatchLocationAction] = useLocation();
|
|
1979
|
+
const [locationItems, dispatchLocationItemsAction] = useLocationItems();
|
|
1980
|
+
const dispatchHandler = React__namespace["default"].useCallback((action) => {
|
|
1981
|
+
switch (action.type) {
|
|
1982
|
+
case 'ADD_FILE_ITEMS':
|
|
1983
|
+
case 'REMOVE_FILE_ITEM':
|
|
1984
|
+
case 'SELECT_FILES':
|
|
1985
|
+
case 'RESET_FILE_ITEMS': {
|
|
1986
|
+
dispatchFilesAction(action);
|
|
1987
|
+
break;
|
|
1946
1988
|
}
|
|
1947
|
-
case '
|
|
1948
|
-
case '
|
|
1949
|
-
|
|
1950
|
-
|
|
1989
|
+
case 'NAVIGATE':
|
|
1990
|
+
case 'RESET_LOCATION': {
|
|
1991
|
+
dispatchLocationAction(action);
|
|
1992
|
+
break;
|
|
1993
|
+
}
|
|
1994
|
+
case 'SET_LOCATION_ITEMS':
|
|
1995
|
+
case 'REMOVE_LOCATION_ITEM':
|
|
1996
|
+
case 'RESET_LOCATION_ITEMS': {
|
|
1997
|
+
dispatchLocationItemsAction(action);
|
|
1998
|
+
break;
|
|
1999
|
+
}
|
|
2000
|
+
case 'SET_ACTION_TYPE':
|
|
2001
|
+
case 'RESET_ACTION_TYPE': {
|
|
2002
|
+
dispatchActionType(action);
|
|
2003
|
+
break;
|
|
1951
2004
|
}
|
|
1952
2005
|
}
|
|
1953
|
-
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2006
|
+
}, [
|
|
2007
|
+
dispatchActionType,
|
|
2008
|
+
dispatchFilesAction,
|
|
2009
|
+
dispatchLocationAction,
|
|
2010
|
+
dispatchLocationItemsAction,
|
|
2011
|
+
]);
|
|
2012
|
+
return [{ actionType, files, location, locationItems }, dispatchHandler];
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
const getErrorMessage = (propertyName) => `Unable to resolve credentials due to invalid value of '${propertyName}'`;
|
|
2016
|
+
function useGetActionInputCallback({ accountId, customEndpoint, region, }) {
|
|
2017
|
+
const { getCredentials } = useCredentials();
|
|
2018
|
+
const [{ location }] = useStore();
|
|
2019
|
+
const { current, key } = location;
|
|
2020
|
+
return React__namespace["default"].useCallback((_location) => {
|
|
2021
|
+
// prefer passed in location / prefix over current location in state
|
|
2022
|
+
const location = _location ?? current;
|
|
2023
|
+
// when `location` has been provided as a param, resolve `_prefix` to `location.prefix`.
|
|
2024
|
+
// in the default scenario where `current` is the target `location` use the fully qualified `key`
|
|
2025
|
+
// that includes the default `prefix` and any additional prefixes from navigation
|
|
2026
|
+
const prefix = _location ? _location.prefix : key;
|
|
2027
|
+
assertLocationData(location, getErrorMessage('locationData'));
|
|
2028
|
+
assertPrefix(prefix, getErrorMessage('prefix'));
|
|
2029
|
+
const { bucket, permissions, type } = location;
|
|
2030
|
+
// BUCKET/PREFIX grants end with `*`, but object grants do not.
|
|
2031
|
+
const scope = `s3://${bucket}/${prefix}${type === 'OBJECT' ? '' : '*'}`;
|
|
2032
|
+
return {
|
|
2033
|
+
accountId,
|
|
2034
|
+
bucket,
|
|
2035
|
+
credentials: getCredentials({
|
|
2036
|
+
permissions,
|
|
2037
|
+
scope,
|
|
2038
|
+
}),
|
|
2039
|
+
region,
|
|
2040
|
+
customEndpoint,
|
|
1970
2041
|
};
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2042
|
+
}, [accountId, current, customEndpoint, getCredentials, key, region]);
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
const ERROR_MESSAGE$1 = '`useGetActionInput` must be called from within a `ConfigurationProvider`.';
|
|
2046
|
+
const { useGetActionInput, GetActionInputContext } = uiReactCore.createContextUtilities({
|
|
2047
|
+
contextName: 'GetActionInput',
|
|
2048
|
+
errorMessage: ERROR_MESSAGE$1,
|
|
2049
|
+
});
|
|
2050
|
+
function GetActionInputProvider({ accountId, children, customEndpoint, region, }) {
|
|
2051
|
+
const value = useGetActionInputCallback({
|
|
2052
|
+
accountId,
|
|
2053
|
+
customEndpoint,
|
|
2054
|
+
region,
|
|
2055
|
+
});
|
|
2056
|
+
return (React__namespace["default"].createElement(GetActionInputContext.Provider, { value: value }, children));
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
const Passthrough = ({ children }) => (React__namespace["default"].createElement(React__namespace["default"].Fragment, null, children));
|
|
2060
|
+
function createConfigurationProvider(input) {
|
|
2061
|
+
const { accountId, ChildComponent, displayName, region, customEndpoint, ...rest } = input;
|
|
2062
|
+
const Child = elements.isComponent(ChildComponent) ? ChildComponent : Passthrough;
|
|
2063
|
+
const Provider = (props) => (React__namespace["default"].createElement(CredentialsProvider, { ...rest },
|
|
2064
|
+
React__namespace["default"].createElement(GetActionInputProvider, { accountId: accountId, region: region, customEndpoint: customEndpoint },
|
|
2065
|
+
React__namespace["default"].createElement(Child, { ...props }))));
|
|
2066
|
+
Provider.displayName = displayName;
|
|
2067
|
+
return Provider;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
const defaultValue$3 = { data: {} };
|
|
2071
|
+
const { useControlsContext, ControlsContextProvider } = uiReactCore.createContextUtilities({
|
|
2072
|
+
contextName: 'ControlsContext',
|
|
2073
|
+
defaultValue: defaultValue$3,
|
|
2074
|
+
});
|
|
2075
|
+
|
|
2076
|
+
const useActionCancel = () => {
|
|
2077
|
+
const { data: { actionCancelLabel, isActionCancelDisabled }, onActionCancel, } = useControlsContext();
|
|
2001
2078
|
return {
|
|
2002
|
-
|
|
2003
|
-
|
|
2079
|
+
onCancel: onActionCancel,
|
|
2080
|
+
isDisabled: isActionCancelDisabled,
|
|
2081
|
+
label: actionCancelLabel,
|
|
2004
2082
|
};
|
|
2005
2083
|
};
|
|
2006
2084
|
|
|
2007
|
-
|
|
2008
|
-
const
|
|
2009
|
-
const
|
|
2085
|
+
function useResolvedComposable(DefaultComposable, name) {
|
|
2086
|
+
const { composables } = useComposables();
|
|
2087
|
+
const Composable = React__namespace["default"].useMemo(() => {
|
|
2088
|
+
const ResolvedComposable = (props) => {
|
|
2089
|
+
const Resolved = composables?.[name] ?? DefaultComposable;
|
|
2090
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2091
|
+
};
|
|
2092
|
+
ResolvedComposable.displayName = name;
|
|
2093
|
+
return ResolvedComposable;
|
|
2094
|
+
}, [composables, DefaultComposable, name]);
|
|
2095
|
+
return Composable;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
const ActionCancelControl = () => {
|
|
2099
|
+
const props = useActionCancel();
|
|
2100
|
+
const Resolved = useResolvedComposable(ActionCancel, 'ActionCancel');
|
|
2010
2101
|
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2011
2102
|
};
|
|
2012
2103
|
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2104
|
+
const getNavigationItems = ({ destinationParts, location, onNavigate, }) => {
|
|
2105
|
+
const { bucket, permissions, prefix = '', type } = location;
|
|
2106
|
+
const destinationSubpaths = [];
|
|
2107
|
+
return destinationParts.map((part, index) => {
|
|
2108
|
+
const isCurrent = index === destinationParts.length - 1;
|
|
2109
|
+
if (index !== 0) {
|
|
2110
|
+
destinationSubpaths.push(part);
|
|
2111
|
+
}
|
|
2112
|
+
const destinationPath = `${destinationSubpaths.concat('').join('/')}`;
|
|
2113
|
+
const destination = {
|
|
2114
|
+
id: crypto.randomUUID(),
|
|
2115
|
+
type,
|
|
2116
|
+
permissions,
|
|
2117
|
+
bucket,
|
|
2118
|
+
prefix,
|
|
2119
|
+
};
|
|
2120
|
+
return {
|
|
2121
|
+
name: part,
|
|
2122
|
+
...(isCurrent && { isCurrent }),
|
|
2123
|
+
onNavigate: () => {
|
|
2124
|
+
onNavigate?.(destination, destinationPath);
|
|
2125
|
+
},
|
|
2126
|
+
};
|
|
2127
|
+
});
|
|
2020
2128
|
};
|
|
2021
2129
|
|
|
2022
|
-
const
|
|
2023
|
-
const
|
|
2024
|
-
const
|
|
2025
|
-
|
|
2130
|
+
const getNavigationParts = ({ location, path, includeBucketInPrefix, }) => {
|
|
2131
|
+
const { bucket, prefix = '', type } = location;
|
|
2132
|
+
const trimmedPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
|
|
2133
|
+
const trimmedPath = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
2134
|
+
const firstPrefixPart = [];
|
|
2135
|
+
if (type !== 'BUCKET') {
|
|
2136
|
+
if (includeBucketInPrefix) {
|
|
2137
|
+
firstPrefixPart.push(bucket);
|
|
2138
|
+
}
|
|
2139
|
+
if (trimmedPrefix) {
|
|
2140
|
+
if (includeBucketInPrefix) {
|
|
2141
|
+
firstPrefixPart.push('/');
|
|
2142
|
+
}
|
|
2143
|
+
firstPrefixPart.push(trimmedPrefix);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
const prefixParts = type === 'BUCKET' ? [bucket] : [firstPrefixPart.join('')];
|
|
2147
|
+
if (type === 'BUCKET' && trimmedPrefix) {
|
|
2148
|
+
prefixParts.push(trimmedPrefix);
|
|
2149
|
+
}
|
|
2150
|
+
const pathParts = trimmedPath ? trimmedPath.split('/') : [];
|
|
2151
|
+
return prefixParts.concat(pathParts);
|
|
2026
2152
|
};
|
|
2027
2153
|
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2154
|
+
// import { ActionDestinationProps } from '../../composables/ActionDestination';
|
|
2155
|
+
const useActionDestination = () => {
|
|
2156
|
+
const { data, onSelectDestination } = useControlsContext();
|
|
2157
|
+
const { actionDestinationLabel, isActionDestinationNavigable, destination } = data;
|
|
2158
|
+
return React__namespace["default"].useMemo(() => {
|
|
2159
|
+
if (!destination?.current) {
|
|
2160
|
+
return { items: [] };
|
|
2161
|
+
}
|
|
2162
|
+
const { current, path } = destination;
|
|
2163
|
+
const destinationParts = getNavigationParts({
|
|
2164
|
+
location: current,
|
|
2165
|
+
path,
|
|
2166
|
+
});
|
|
2167
|
+
return {
|
|
2168
|
+
label: actionDestinationLabel,
|
|
2169
|
+
items: getNavigationItems({
|
|
2170
|
+
location: current,
|
|
2171
|
+
destinationParts,
|
|
2172
|
+
onNavigate: onSelectDestination,
|
|
2173
|
+
}),
|
|
2174
|
+
isNavigable: isActionDestinationNavigable,
|
|
2175
|
+
};
|
|
2176
|
+
}, [
|
|
2177
|
+
actionDestinationLabel,
|
|
2178
|
+
isActionDestinationNavigable,
|
|
2179
|
+
destination,
|
|
2180
|
+
onSelectDestination,
|
|
2181
|
+
]);
|
|
2036
2182
|
};
|
|
2037
2183
|
|
|
2038
|
-
const
|
|
2039
|
-
const props =
|
|
2040
|
-
const Resolved = useResolvedComposable(
|
|
2184
|
+
const ActionDestinationControl = () => {
|
|
2185
|
+
const props = useActionDestination();
|
|
2186
|
+
const Resolved = useResolvedComposable(ActionDestination$1, 'ActionDestination');
|
|
2041
2187
|
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2042
2188
|
};
|
|
2043
2189
|
|
|
2044
|
-
const
|
|
2045
|
-
const { data: {
|
|
2046
|
-
return
|
|
2190
|
+
const useActionExit = () => {
|
|
2191
|
+
const { data: { actionExitLabel: label, isActionExitDisabled: isDisabled }, onActionExit: onExit, } = useControlsContext();
|
|
2192
|
+
return { label, isDisabled, onExit };
|
|
2047
2193
|
};
|
|
2048
2194
|
|
|
2049
|
-
const
|
|
2050
|
-
const props =
|
|
2051
|
-
const Resolved = useResolvedComposable(
|
|
2195
|
+
const ActionExitControl = () => {
|
|
2196
|
+
const props = useActionExit();
|
|
2197
|
+
const Resolved = useResolvedComposable(ActionExit, 'ActionExit');
|
|
2052
2198
|
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2053
2199
|
};
|
|
2054
2200
|
|
|
2055
|
-
const
|
|
2056
|
-
const { data } = useControlsContext();
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
{ name: statusDisplayCompletedLabel ?? '', count: statusCounts.COMPLETE },
|
|
2063
|
-
{ name: statusDisplayFailedLabel ?? '', count: statusCounts.FAILED },
|
|
2064
|
-
{ name: statusDisplayCanceledLabel ?? '', count: statusCounts.CANCELED },
|
|
2065
|
-
{ name: statusDisplayQueuedLabel ?? '', count: statusCounts.QUEUED },
|
|
2066
|
-
];
|
|
2067
|
-
return { statuses, total: statusCounts.TOTAL };
|
|
2201
|
+
const useActionStart = () => {
|
|
2202
|
+
const { data: { actionStartLabel, isActionStartDisabled }, onActionStart, } = useControlsContext();
|
|
2203
|
+
return {
|
|
2204
|
+
label: actionStartLabel,
|
|
2205
|
+
isDisabled: isActionStartDisabled,
|
|
2206
|
+
onStart: onActionStart,
|
|
2207
|
+
};
|
|
2068
2208
|
};
|
|
2069
2209
|
|
|
2070
|
-
const
|
|
2071
|
-
const props =
|
|
2072
|
-
const Resolved = useResolvedComposable(
|
|
2210
|
+
const ActionStartControl = () => {
|
|
2211
|
+
const props = useActionStart();
|
|
2212
|
+
const Resolved = useResolvedComposable(ActionStart, 'ActionStart');
|
|
2073
2213
|
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2074
2214
|
};
|
|
2075
2215
|
|
|
2076
|
-
const
|
|
2077
|
-
const { data } = useControlsContext();
|
|
2216
|
+
const useAddFiles = () => {
|
|
2217
|
+
const { data: { addFilesLabel, isAddFilesDisabled }, onAddFiles, } = useControlsContext();
|
|
2078
2218
|
return {
|
|
2079
|
-
|
|
2219
|
+
isDisabled: isAddFilesDisabled,
|
|
2220
|
+
label: addFilesLabel,
|
|
2221
|
+
onAddFiles,
|
|
2080
2222
|
};
|
|
2081
2223
|
};
|
|
2082
2224
|
|
|
2083
|
-
const
|
|
2084
|
-
const props =
|
|
2085
|
-
const Resolved = useResolvedComposable(
|
|
2225
|
+
const AddFilesControl = () => {
|
|
2226
|
+
const props = useAddFiles();
|
|
2227
|
+
const Resolved = useResolvedComposable(AddFiles, 'AddFiles');
|
|
2086
2228
|
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2087
2229
|
};
|
|
2088
2230
|
|
|
2089
|
-
const
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
statusDisplayInProgressLabel: 'In progress',
|
|
2097
|
-
statusDisplayTotalLabel: 'Total',
|
|
2098
|
-
statusDisplayQueuedLabel: 'Not started',
|
|
2099
|
-
// empty by default
|
|
2100
|
-
tableColumnCancelHeader: '',
|
|
2101
|
-
tableColumnStatusHeader: 'Status',
|
|
2102
|
-
tableColumnFolderHeader: 'Folder',
|
|
2103
|
-
tableColumnNameHeader: 'Name',
|
|
2104
|
-
tableColumnTypeHeader: 'Type',
|
|
2105
|
-
tableColumnSizeHeader: 'Size',
|
|
2106
|
-
tableColumnProgressHeader: 'Progress',
|
|
2231
|
+
const useAddFolder = () => {
|
|
2232
|
+
const { data: { addFolderLabel, isAddFolderDisabled }, onAddFolder, } = useControlsContext();
|
|
2233
|
+
return {
|
|
2234
|
+
isDisabled: isAddFolderDisabled,
|
|
2235
|
+
label: addFolderLabel,
|
|
2236
|
+
onAddFolder,
|
|
2237
|
+
};
|
|
2107
2238
|
};
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
month: 'short',
|
|
2114
|
-
day: 'numeric',
|
|
2115
|
-
hour: 'numeric',
|
|
2116
|
-
year: 'numeric',
|
|
2117
|
-
minute: 'numeric',
|
|
2118
|
-
hourCycle: 'h12',
|
|
2119
|
-
}).format(date),
|
|
2239
|
+
|
|
2240
|
+
const AddFolderControl = () => {
|
|
2241
|
+
const props = useAddFolder();
|
|
2242
|
+
const Resolved = useResolvedComposable(AddFolder, 'AddFolder');
|
|
2243
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2120
2244
|
};
|
|
2121
2245
|
|
|
2122
|
-
const
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
}
|
|
2138
|
-
if (FAILED) {
|
|
2139
|
-
return {
|
|
2140
|
-
content: 'There was an issue creating the folder.',
|
|
2141
|
-
type: 'error',
|
|
2142
|
-
};
|
|
2143
|
-
}
|
|
2144
|
-
return { content: 'Folder created.', type: 'success' };
|
|
2145
|
-
},
|
|
2246
|
+
const compareContent$3 = ({ label: a }, { label: b }) => {
|
|
2247
|
+
if (a === undefined) {
|
|
2248
|
+
return b === undefined ? 0 : 1;
|
|
2249
|
+
}
|
|
2250
|
+
return b === undefined ? -1 : a.localeCompare(b);
|
|
2251
|
+
};
|
|
2252
|
+
const compareButtonData = (a, b, direction) => direction === 'ascending'
|
|
2253
|
+
? compareContent$3(a.content, b.content)
|
|
2254
|
+
: compareContent$3(b.content, a.content);
|
|
2255
|
+
|
|
2256
|
+
const compareContent$2 = ({ value: a }, { value: b }) => {
|
|
2257
|
+
if (a === undefined) {
|
|
2258
|
+
return b === undefined ? 0 : 1;
|
|
2259
|
+
}
|
|
2260
|
+
return b === undefined ? -1 : a.getTime() - b.getTime();
|
|
2146
2261
|
};
|
|
2262
|
+
const compareDateData = (a, b, direction) => direction === 'ascending'
|
|
2263
|
+
? compareContent$2(a.content, b.content)
|
|
2264
|
+
: compareContent$2(b.content, a.content);
|
|
2147
2265
|
|
|
2148
|
-
const
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2266
|
+
const compareContent$1 = ({ value: a }, { value: b }) => {
|
|
2267
|
+
if (a === undefined) {
|
|
2268
|
+
return b === undefined ? 0 : 1;
|
|
2269
|
+
}
|
|
2270
|
+
return b === undefined ? -1 : a - b;
|
|
2271
|
+
};
|
|
2272
|
+
const compareNumberData = (a, b, direction) => direction === 'ascending'
|
|
2273
|
+
? compareContent$1(a.content, b.content)
|
|
2274
|
+
: compareContent$1(b.content, a.content);
|
|
2275
|
+
|
|
2276
|
+
const compareContent = ({ text: a }, { text: b }) => {
|
|
2277
|
+
if (a === undefined) {
|
|
2278
|
+
return b === undefined ? 0 : 1;
|
|
2279
|
+
}
|
|
2280
|
+
return b === undefined ? -1 : a.localeCompare(b);
|
|
2281
|
+
};
|
|
2282
|
+
const compareTextData = (a, b, direction) => direction === 'ascending'
|
|
2283
|
+
? compareContent(a.content, b.content)
|
|
2284
|
+
: compareContent(b.content, a.content);
|
|
2285
|
+
|
|
2286
|
+
const GROUP_ORDER = [
|
|
2287
|
+
'checkbox',
|
|
2288
|
+
'button',
|
|
2289
|
+
'date',
|
|
2290
|
+
'number',
|
|
2291
|
+
'text',
|
|
2292
|
+
];
|
|
2293
|
+
const UNSORTABLE_GROUPS = ['checkbox'];
|
|
2294
|
+
const useDataTable = () => {
|
|
2295
|
+
const { data } = useControlsContext();
|
|
2296
|
+
const { isLoading, tableData } = data;
|
|
2297
|
+
const defaultSortIndex = React__namespace["default"].useMemo(() => tableData?.headers?.findIndex(({ type }) => type === 'sort') ?? -1, [tableData]);
|
|
2298
|
+
const [sortState, setSortState] = React__namespace["default"].useState({
|
|
2299
|
+
index: defaultSortIndex,
|
|
2300
|
+
direction: 'ascending',
|
|
2301
|
+
});
|
|
2302
|
+
const mappedHeaders = React__namespace["default"].useMemo(() => tableData?.headers.map((header, index) => {
|
|
2303
|
+
const { type } = header;
|
|
2304
|
+
switch (type) {
|
|
2305
|
+
case 'sort': {
|
|
2306
|
+
return {
|
|
2307
|
+
...header,
|
|
2308
|
+
content: {
|
|
2309
|
+
...header.content,
|
|
2310
|
+
onSort: () => {
|
|
2311
|
+
setSortState({
|
|
2312
|
+
index,
|
|
2313
|
+
direction: sortState.index === index
|
|
2314
|
+
? sortState.direction === 'ascending'
|
|
2315
|
+
? 'descending'
|
|
2316
|
+
: 'ascending'
|
|
2317
|
+
: 'ascending',
|
|
2318
|
+
});
|
|
2319
|
+
},
|
|
2320
|
+
sortDirection: sortState.index === index ? sortState.direction : undefined,
|
|
2321
|
+
},
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
case 'checkbox':
|
|
2325
|
+
case 'text':
|
|
2326
|
+
default: {
|
|
2327
|
+
return header;
|
|
2328
|
+
}
|
|
2173
2329
|
}
|
|
2174
|
-
},
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
const { counts } = data ?? {};
|
|
2180
|
-
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2181
|
-
if (COMPLETE === TOTAL) {
|
|
2182
|
-
return {
|
|
2183
|
-
content: 'All files copied.',
|
|
2184
|
-
type: 'success',
|
|
2185
|
-
};
|
|
2330
|
+
}), [sortState, tableData]);
|
|
2331
|
+
const sortedRows = React__namespace["default"].useMemo(() => {
|
|
2332
|
+
// Early return if there is no table data
|
|
2333
|
+
if (!tableData) {
|
|
2334
|
+
return;
|
|
2186
2335
|
}
|
|
2187
|
-
if
|
|
2188
|
-
|
|
2336
|
+
// Return rows as is if there are no sortable columns
|
|
2337
|
+
if (sortState.index < 0) {
|
|
2338
|
+
return tableData.rows;
|
|
2189
2339
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2340
|
+
const { index, direction } = sortState;
|
|
2341
|
+
const groupedRows = {
|
|
2342
|
+
button: [],
|
|
2343
|
+
checkbox: [],
|
|
2344
|
+
date: [],
|
|
2345
|
+
number: [],
|
|
2346
|
+
text: [],
|
|
2193
2347
|
};
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2348
|
+
tableData.rows.forEach((row) => {
|
|
2349
|
+
const { type } = row.content[index];
|
|
2350
|
+
groupedRows[type].push(row);
|
|
2351
|
+
});
|
|
2352
|
+
const groupOrder = direction === 'ascending' ? GROUP_ORDER : [...GROUP_ORDER].reverse();
|
|
2353
|
+
return groupOrder
|
|
2354
|
+
.map((groupType) => {
|
|
2355
|
+
if (UNSORTABLE_GROUPS.includes(groupType)) {
|
|
2356
|
+
return groupedRows[groupType];
|
|
2357
|
+
}
|
|
2358
|
+
return groupedRows[groupType].sort((rowA, rowB) => {
|
|
2359
|
+
switch (groupType) {
|
|
2360
|
+
case 'button': {
|
|
2361
|
+
return compareButtonData(rowA.content[index], rowB.content[index], direction);
|
|
2362
|
+
}
|
|
2363
|
+
case 'date': {
|
|
2364
|
+
return compareDateData(rowA.content[index], rowB.content[index], direction);
|
|
2365
|
+
}
|
|
2366
|
+
case 'number': {
|
|
2367
|
+
return compareNumberData(rowA.content[index], rowB.content[index], direction);
|
|
2368
|
+
}
|
|
2369
|
+
case 'text':
|
|
2370
|
+
default: {
|
|
2371
|
+
return compareTextData(rowA.content[index], rowB.content[index], direction);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
});
|
|
2375
|
+
})
|
|
2376
|
+
.flat();
|
|
2377
|
+
}, [sortState, tableData]);
|
|
2378
|
+
return {
|
|
2379
|
+
headers: mappedHeaders ?? [],
|
|
2380
|
+
isLoading,
|
|
2381
|
+
rows: sortedRows ?? [],
|
|
2382
|
+
};
|
|
2197
2383
|
};
|
|
2198
2384
|
|
|
2199
|
-
const
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
getActionCompleteMessage: (data) => {
|
|
2204
|
-
const { counts } = data ?? {};
|
|
2205
|
-
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2206
|
-
if (COMPLETE === TOTAL) {
|
|
2207
|
-
return { content: 'All files deleted.', type: 'success' };
|
|
2208
|
-
}
|
|
2209
|
-
if (FAILED === TOTAL) {
|
|
2210
|
-
return { content: 'All files failed to delete.', type: 'error' };
|
|
2211
|
-
}
|
|
2212
|
-
return {
|
|
2213
|
-
content: `${COMPLETE} files deleted, ${FAILED} files failed to delete.`,
|
|
2214
|
-
type: 'error',
|
|
2215
|
-
};
|
|
2216
|
-
},
|
|
2385
|
+
const DataTableControl = () => {
|
|
2386
|
+
const props = useDataTable();
|
|
2387
|
+
const Resolved = useResolvedComposable(DataTable, 'DataTable');
|
|
2388
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2217
2389
|
};
|
|
2218
2390
|
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
}
|
|
2233
|
-
if (!items?.length && hasExhaustedSearch) {
|
|
2234
|
-
return {
|
|
2235
|
-
type: 'info',
|
|
2236
|
-
content: `No results found in the first 10,000 items.`,
|
|
2237
|
-
};
|
|
2238
|
-
}
|
|
2239
|
-
if (!items?.length) {
|
|
2240
|
-
return {
|
|
2241
|
-
type: 'info',
|
|
2242
|
-
content: 'No files.',
|
|
2243
|
-
};
|
|
2244
|
-
}
|
|
2245
|
-
if (hasExhaustedSearch) {
|
|
2246
|
-
return {
|
|
2247
|
-
type: 'info',
|
|
2248
|
-
content: `Showing results for up to the first 10,000 items.`,
|
|
2249
|
-
};
|
|
2250
|
-
}
|
|
2251
|
-
// TODO: add more cases as needed
|
|
2252
|
-
return undefined;
|
|
2253
|
-
},
|
|
2254
|
-
searchSubfoldersToggleLabel: 'Include subfolders',
|
|
2255
|
-
searchPlaceholder: 'Search current folder',
|
|
2256
|
-
tableColumnLastModifiedHeader: 'Last modified',
|
|
2257
|
-
tableColumnNameHeader: 'Name',
|
|
2258
|
-
tableColumnSizeHeader: 'Size',
|
|
2259
|
-
tableColumnTypeHeader: 'Type',
|
|
2260
|
-
selectFileLabel: 'Select file',
|
|
2261
|
-
selectAllFilesLabel: 'Select all files',
|
|
2262
|
-
getActionListItemLabel: (key = '') => {
|
|
2263
|
-
switch (key) {
|
|
2264
|
-
case 'Copy':
|
|
2265
|
-
return 'Copy';
|
|
2266
|
-
case 'Delete':
|
|
2267
|
-
return 'Delete';
|
|
2268
|
-
case 'Create folder':
|
|
2269
|
-
return 'Create folder';
|
|
2270
|
-
case 'Upload':
|
|
2271
|
-
return 'Upload';
|
|
2272
|
-
default:
|
|
2273
|
-
return key;
|
|
2274
|
-
}
|
|
2275
|
-
},
|
|
2276
|
-
getTitle: (location) => {
|
|
2277
|
-
const { current, key } = location;
|
|
2278
|
-
const { bucket = '' } = current ?? {};
|
|
2279
|
-
return key || bucket;
|
|
2280
|
-
},
|
|
2391
|
+
/**
|
|
2392
|
+
* This hook, not to be confused with the useDropZone vended from @aws-amplify/ui-react-core, is only intended for use
|
|
2393
|
+
* with its corresponding DropZone control.
|
|
2394
|
+
*/
|
|
2395
|
+
const useDropZone = () => {
|
|
2396
|
+
const { onDropFiles } = useControlsContext();
|
|
2397
|
+
return { onDropFiles };
|
|
2398
|
+
};
|
|
2399
|
+
|
|
2400
|
+
const DropZoneControl = ({ children, }) => {
|
|
2401
|
+
const props = useDropZone();
|
|
2402
|
+
const Resolved = useResolvedComposable(DropZone, 'DropZone');
|
|
2403
|
+
return React__namespace["default"].createElement(Resolved, { ...props }, children);
|
|
2281
2404
|
};
|
|
2282
2405
|
|
|
2283
|
-
const
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
return undefined;
|
|
2292
|
-
}
|
|
2293
|
-
if (hasError) {
|
|
2294
|
-
return {
|
|
2295
|
-
type: 'error',
|
|
2296
|
-
content: message ?? DEFAULT_ERROR_MESSAGE,
|
|
2297
|
-
};
|
|
2298
|
-
}
|
|
2299
|
-
if (items?.length === 0 && !hasExhaustedSearch) {
|
|
2300
|
-
return {
|
|
2301
|
-
type: 'info',
|
|
2302
|
-
content: 'No folders or files.',
|
|
2303
|
-
};
|
|
2304
|
-
}
|
|
2305
|
-
if (hasExhaustedSearch) {
|
|
2306
|
-
return {
|
|
2307
|
-
type: 'info',
|
|
2308
|
-
content: `Showing results for up to the first 10,000 items.`,
|
|
2309
|
-
};
|
|
2310
|
-
}
|
|
2311
|
-
// TODO: add more cases as needed
|
|
2312
|
-
return undefined;
|
|
2313
|
-
},
|
|
2314
|
-
getPermissionName: (permissions) => {
|
|
2315
|
-
let text = '';
|
|
2316
|
-
if (permissions.includes('get') || permissions.includes('list')) {
|
|
2317
|
-
text = 'Read';
|
|
2318
|
-
}
|
|
2319
|
-
if (permissions.includes('write') || permissions.includes('delete')) {
|
|
2320
|
-
text = text ? 'Read/Write' : 'Write';
|
|
2321
|
-
}
|
|
2322
|
-
if (!text) {
|
|
2323
|
-
text = permissions.join('/');
|
|
2324
|
-
}
|
|
2325
|
-
return text;
|
|
2326
|
-
},
|
|
2327
|
-
getDownloadLabel: (fileName) => `Download ${fileName}`,
|
|
2328
|
-
tableColumnBucketHeader: 'Bucket',
|
|
2329
|
-
tableColumnFolderHeader: 'Folder',
|
|
2330
|
-
tableColumnPermissionsHeader: 'Permissions',
|
|
2331
|
-
tableColumnActionsHeader: 'Actions',
|
|
2406
|
+
const useOverwriteToggle = () => {
|
|
2407
|
+
const { data: { isOverwritingEnabled, isOverwriteToggleDisabled, overwriteToggleLabel, }, onToggleOverwrite, } = useControlsContext();
|
|
2408
|
+
return {
|
|
2409
|
+
isDisabled: isOverwriteToggleDisabled,
|
|
2410
|
+
isOverwritingEnabled,
|
|
2411
|
+
label: overwriteToggleLabel,
|
|
2412
|
+
onToggle: onToggleOverwrite,
|
|
2413
|
+
};
|
|
2332
2414
|
};
|
|
2333
2415
|
|
|
2334
|
-
const
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
addFilesLabel: 'Add files',
|
|
2339
|
-
addFolderLabel: 'Add folder',
|
|
2340
|
-
getActionCompleteMessage: (data) => {
|
|
2341
|
-
const { counts } = data ?? {};
|
|
2342
|
-
const { COMPLETE, FAILED, OVERWRITE_PREVENTED, CANCELED, TOTAL } = counts ?? {};
|
|
2343
|
-
const hasPreventedOverwrite = !!OVERWRITE_PREVENTED;
|
|
2344
|
-
const hasFailure = !!FAILED;
|
|
2345
|
-
const hasSuccess = !!COMPLETE;
|
|
2346
|
-
const hasCanceled = !!CANCELED;
|
|
2347
|
-
const type = hasFailure
|
|
2348
|
-
? 'error'
|
|
2349
|
-
: hasPreventedOverwrite || hasCanceled
|
|
2350
|
-
? 'warning'
|
|
2351
|
-
: 'success';
|
|
2352
|
-
const preventedOverwriteMessage = hasPreventedOverwrite
|
|
2353
|
-
? [
|
|
2354
|
-
'Overwrite prevented for',
|
|
2355
|
-
OVERWRITE_PREVENTED === TOTAL ? 'all' : String(OVERWRITE_PREVENTED),
|
|
2356
|
-
OVERWRITE_PREVENTED > 1 || OVERWRITE_PREVENTED === TOTAL
|
|
2357
|
-
? `files`
|
|
2358
|
-
: 'file',
|
|
2359
|
-
].join(' ')
|
|
2360
|
-
: undefined;
|
|
2361
|
-
const canceledMessage = hasCanceled
|
|
2362
|
-
? [
|
|
2363
|
-
CANCELED === TOTAL ? 'All' : String(CANCELED),
|
|
2364
|
-
CANCELED > 1 || CANCELED === TOTAL ? `uploads` : 'upload',
|
|
2365
|
-
'canceled',
|
|
2366
|
-
].join(' ')
|
|
2367
|
-
: undefined;
|
|
2368
|
-
const failedMessage = hasFailure
|
|
2369
|
-
? [
|
|
2370
|
-
FAILED === TOTAL ? 'All' : String(FAILED),
|
|
2371
|
-
FAILED > 1 || FAILED === TOTAL ? `files` : 'file',
|
|
2372
|
-
'failed to upload',
|
|
2373
|
-
].join(' ')
|
|
2374
|
-
: undefined;
|
|
2375
|
-
const completedMessage = hasSuccess
|
|
2376
|
-
? [
|
|
2377
|
-
COMPLETE === TOTAL ? 'All' : String(COMPLETE),
|
|
2378
|
-
COMPLETE > 1 || COMPLETE === TOTAL ? `files` : 'file',
|
|
2379
|
-
'uploaded',
|
|
2380
|
-
].join(' ')
|
|
2381
|
-
: undefined;
|
|
2382
|
-
const messages = [
|
|
2383
|
-
preventedOverwriteMessage,
|
|
2384
|
-
failedMessage,
|
|
2385
|
-
canceledMessage,
|
|
2386
|
-
completedMessage,
|
|
2387
|
-
].filter(Boolean);
|
|
2388
|
-
if (messages.length > 0) {
|
|
2389
|
-
return {
|
|
2390
|
-
content: messages.join(', ') + '.',
|
|
2391
|
-
type,
|
|
2392
|
-
};
|
|
2393
|
-
}
|
|
2394
|
-
return { content: 'All files uploaded.', type };
|
|
2395
|
-
},
|
|
2396
|
-
getFilesValidationMessage: (data) => {
|
|
2397
|
-
if (!data?.invalidFiles) {
|
|
2398
|
-
return undefined;
|
|
2399
|
-
}
|
|
2400
|
-
const tooBigFileNames = data.invalidFiles
|
|
2401
|
-
.filter(({ file }) => isFileTooBig(file))
|
|
2402
|
-
.map(({ file }) => file.name)
|
|
2403
|
-
.join(', ');
|
|
2404
|
-
if (tooBigFileNames) {
|
|
2405
|
-
return {
|
|
2406
|
-
content: `Files larger than 160GB cannot be added to the upload queue: ${tooBigFileNames}`,
|
|
2407
|
-
type: 'warning',
|
|
2408
|
-
};
|
|
2409
|
-
}
|
|
2410
|
-
return undefined;
|
|
2411
|
-
},
|
|
2412
|
-
statusDisplayOverwritePreventedLabel: 'Overwrite prevented',
|
|
2413
|
-
overwriteToggleLabel: 'Overwrite existing files',
|
|
2416
|
+
const OverwriteToggleControl = () => {
|
|
2417
|
+
const props = useOverwriteToggle();
|
|
2418
|
+
const Resolved = useResolvedComposable(OverwriteToggle$1, 'OverwriteToggle');
|
|
2419
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2414
2420
|
};
|
|
2415
2421
|
|
|
2416
|
-
const
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
DeleteView: DEFAULT_DELETE_VIEW_DISPLAY_TEXT,
|
|
2420
|
-
LocationDetailView: DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT,
|
|
2421
|
-
LocationsView: DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT,
|
|
2422
|
-
UploadView: DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT,
|
|
2422
|
+
const useMessage = () => {
|
|
2423
|
+
const { data: { message = {} }, } = useControlsContext();
|
|
2424
|
+
return message;
|
|
2423
2425
|
};
|
|
2424
2426
|
|
|
2425
|
-
const
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
});
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
const {
|
|
2427
|
+
const MessageControl = () => {
|
|
2428
|
+
const props = useMessage();
|
|
2429
|
+
const Resolved = useResolvedComposable(Message, 'Message');
|
|
2430
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2431
|
+
};
|
|
2432
|
+
|
|
2433
|
+
const useStatusDisplay = () => {
|
|
2434
|
+
const { data } = useControlsContext();
|
|
2435
|
+
const { statusCounts, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, } = data;
|
|
2436
|
+
if (!statusCounts?.TOTAL) {
|
|
2437
|
+
return { statuses: [], total: 0 };
|
|
2438
|
+
}
|
|
2439
|
+
const statuses = [
|
|
2440
|
+
{ name: statusDisplayCompletedLabel ?? '', count: statusCounts.COMPLETE },
|
|
2441
|
+
{ name: statusDisplayFailedLabel ?? '', count: statusCounts.FAILED },
|
|
2442
|
+
{ name: statusDisplayCanceledLabel ?? '', count: statusCounts.CANCELED },
|
|
2443
|
+
{ name: statusDisplayQueuedLabel ?? '', count: statusCounts.QUEUED },
|
|
2444
|
+
];
|
|
2445
|
+
return { statuses, total: statusCounts.TOTAL };
|
|
2446
|
+
};
|
|
2447
|
+
|
|
2448
|
+
const StatusDisplayControl = () => {
|
|
2449
|
+
const props = useStatusDisplay();
|
|
2450
|
+
const Resolved = useResolvedComposable(StatusDisplay$1, 'StatusDisplay');
|
|
2451
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2452
|
+
};
|
|
2453
|
+
|
|
2454
|
+
const useTitle = () => {
|
|
2455
|
+
const { data } = useControlsContext();
|
|
2434
2456
|
return {
|
|
2435
|
-
|
|
2436
|
-
CreateFolderView: {
|
|
2437
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.CreateFolderView,
|
|
2438
|
-
...CreateFolderView,
|
|
2439
|
-
},
|
|
2440
|
-
DeleteView: {
|
|
2441
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.DeleteView,
|
|
2442
|
-
...DeleteView,
|
|
2443
|
-
},
|
|
2444
|
-
LocationDetailView: {
|
|
2445
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView,
|
|
2446
|
-
...LocationDetailView,
|
|
2447
|
-
},
|
|
2448
|
-
LocationsView: {
|
|
2449
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView,
|
|
2450
|
-
...LocationsView,
|
|
2451
|
-
},
|
|
2452
|
-
UploadView: {
|
|
2453
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView,
|
|
2454
|
-
...UploadView,
|
|
2455
|
-
},
|
|
2457
|
+
title: data?.title,
|
|
2456
2458
|
};
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
const
|
|
2461
|
-
|
|
2462
|
-
}
|
|
2459
|
+
};
|
|
2460
|
+
|
|
2461
|
+
const TitleControl = () => {
|
|
2462
|
+
const props = useTitle();
|
|
2463
|
+
const Resolved = useResolvedComposable(Title$1, 'Title');
|
|
2464
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2465
|
+
};
|
|
2463
2466
|
|
|
2464
2467
|
const getActionIcon = (status) => {
|
|
2465
2468
|
switch (status) {
|
|
@@ -2624,7 +2627,7 @@ const getActionViewTableData = ({ tasks, displayText, isProcessing, locationKey,
|
|
|
2624
2627
|
value: progress,
|
|
2625
2628
|
displayValue: `${getPercentValue(
|
|
2626
2629
|
// Default progress to 100% if progress value is unavailable but status is recognized as complete
|
|
2627
|
-
progress ?? status === 'COMPLETE' ? 1 : 0)}%`,
|
|
2630
|
+
progress ?? (status === 'COMPLETE' ? 1 : 0))}%`,
|
|
2628
2631
|
},
|
|
2629
2632
|
};
|
|
2630
2633
|
}
|
|
@@ -4765,6 +4768,23 @@ function useViews() {
|
|
|
4765
4768
|
};
|
|
4766
4769
|
}
|
|
4767
4770
|
|
|
4771
|
+
const DEFAULT_VIEW_HOOKS = {
|
|
4772
|
+
Copy: useCopyView,
|
|
4773
|
+
CreateFolder: useCreateFolderView,
|
|
4774
|
+
Delete: useDeleteView,
|
|
4775
|
+
LocationDetail: useLocationDetailView,
|
|
4776
|
+
Locations: useLocationsView,
|
|
4777
|
+
Upload: useUploadView,
|
|
4778
|
+
};
|
|
4779
|
+
const isUseViewType = (value) => !!DEFAULT_VIEW_HOOKS?.[value];
|
|
4780
|
+
// @ts-expect-error
|
|
4781
|
+
const useView = (type) => {
|
|
4782
|
+
if (!isUseViewType(type)) {
|
|
4783
|
+
throw new Error(`Value of \`${type}\` cannot be used to index \`useView\``);
|
|
4784
|
+
}
|
|
4785
|
+
return DEFAULT_VIEW_HOOKS[type]();
|
|
4786
|
+
};
|
|
4787
|
+
|
|
4768
4788
|
/**
|
|
4769
4789
|
* Handles default `StorageBrowser` behavior:
|
|
4770
4790
|
* - render `LocationsView` on init
|
|
@@ -4785,23 +4805,6 @@ function StorageBrowserDefault() {
|
|
|
4785
4805
|
return React__namespace["default"].createElement(LocationsView, null);
|
|
4786
4806
|
}
|
|
4787
4807
|
|
|
4788
|
-
const USE_VIEW_HOOKS = {
|
|
4789
|
-
Copy: useCopyView,
|
|
4790
|
-
CreateFolder: useCreateFolderView,
|
|
4791
|
-
Delete: useDeleteView,
|
|
4792
|
-
LocationDetail: useLocationDetailView,
|
|
4793
|
-
Locations: useLocationsView,
|
|
4794
|
-
Upload: useUploadView,
|
|
4795
|
-
};
|
|
4796
|
-
const isUseViewType = (value) => !!USE_VIEW_HOOKS?.[value];
|
|
4797
|
-
// @ts-expect-error
|
|
4798
|
-
const useView = (type) => {
|
|
4799
|
-
if (!isUseViewType(type)) {
|
|
4800
|
-
throw new Error(`Value of \`${type}\` cannot be used to index \`useView\``);
|
|
4801
|
-
}
|
|
4802
|
-
return USE_VIEW_HOOKS[type]();
|
|
4803
|
-
};
|
|
4804
|
-
|
|
4805
4808
|
function createStorageBrowser(input) {
|
|
4806
4809
|
assertRegisterAuthListener(input.config.registerAuthListener);
|
|
4807
4810
|
const { accountId, customEndpoint, registerAuthListener, getLocationCredentials, region, } = input.config;
|