@aws-amplify/ui-react-storage 3.0.17 → 3.1.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/esm/components/StorageImage/StorageImage.mjs +46 -20
- package/dist/esm/components/StorageManager/StorageManager.mjs +23 -10
- package/dist/esm/components/StorageManager/hooks/useStorageManager/actions.mjs +31 -45
- package/dist/esm/components/StorageManager/hooks/useStorageManager/reducer.mjs +1 -1
- package/dist/esm/components/StorageManager/hooks/useUploadFiles/useUploadFiles.mjs +34 -31
- package/dist/esm/components/StorageManager/ui/FileList/FileDetails.mjs +1 -0
- package/dist/esm/components/StorageManager/utils/getInput.mjs +25 -0
- package/dist/esm/components/StorageManager/{hooks/useUploadFiles → utils}/resolveFile.mjs +2 -4
- package/dist/esm/components/StorageManager/utils/uploadFile.mjs +18 -21
- package/dist/esm/version.mjs +1 -1
- package/dist/index.js +264 -222
- package/dist/types/components/StorageImage/StorageImage.d.ts +6 -2
- package/dist/types/components/StorageImage/types.d.ts +30 -0
- package/dist/types/components/StorageManager/StorageManager.d.ts +5 -2
- package/dist/types/components/StorageManager/hooks/useStorageManager/actions.d.ts +2 -5
- package/dist/types/components/StorageManager/hooks/useStorageManager/types.d.ts +2 -2
- package/dist/types/components/StorageManager/hooks/useStorageManager/useStorageManager.d.ts +2 -5
- package/dist/types/components/StorageManager/hooks/useUploadFiles/useUploadFiles.d.ts +4 -1
- package/dist/types/components/StorageManager/types.d.ts +17 -7
- package/dist/types/components/StorageManager/ui/FileList/types.d.ts +4 -14
- package/dist/types/components/StorageManager/utils/getInput.d.ts +13 -0
- package/dist/types/components/StorageManager/utils/index.d.ts +2 -1
- package/dist/types/components/StorageManager/utils/resolveFile.d.ts +9 -0
- package/dist/types/components/StorageManager/utils/uploadFile.d.ts +31 -12
- package/dist/types/version.d.ts +1 -1
- package/package.json +6 -6
- package/dist/types/components/StorageManager/hooks/useUploadFiles/resolveFile.d.ts +0 -10
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ var ui = require('@aws-amplify/ui');
|
|
|
7
7
|
var uiReact = require('@aws-amplify/ui-react');
|
|
8
8
|
var internal = require('@aws-amplify/ui-react/internal');
|
|
9
9
|
var uiReactCore = require('@aws-amplify/ui-react-core');
|
|
10
|
+
var auth = require('aws-amplify/auth');
|
|
10
11
|
var storage = require('aws-amplify/storage');
|
|
11
12
|
|
|
12
13
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -32,29 +33,55 @@ function _interopNamespace(e) {
|
|
|
32
33
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
33
34
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
34
35
|
|
|
35
|
-
const VERSION = '3.0
|
|
36
|
+
const VERSION = '3.1.0';
|
|
36
37
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
38
|
+
const MISSING_REQUIRED_PROP_MESSAGE = '`StorageImage` requires either an `imgKey` or `path` prop.';
|
|
39
|
+
const HAS_DEPRECATED_PROPS_MESSAGE = '`imgKey`, `accessLevel`, and `identityId` will be replaced with `path` in a future major version. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props';
|
|
40
|
+
const HAS_PATH_AND_KEY_MESSAGE = '`imgKey` is ignored when both `imgKey` and `path` props are provided.';
|
|
41
|
+
const HAS_PATH_AND_UNSUPPORTED_OPTIONS_MESSAGE = '`accessLevel` and `identityId` are ignored when the `path` prop is provided.';
|
|
42
|
+
const getDeprecationMessage = ({ hasImgkey, hasPath, hasDeprecatedOptions, }) => {
|
|
43
|
+
let message = '';
|
|
44
|
+
if (hasPath && hasImgkey) {
|
|
45
|
+
message = HAS_PATH_AND_KEY_MESSAGE;
|
|
46
|
+
}
|
|
47
|
+
else if (hasPath && hasDeprecatedOptions) {
|
|
48
|
+
message = HAS_PATH_AND_UNSUPPORTED_OPTIONS_MESSAGE;
|
|
49
|
+
}
|
|
50
|
+
else if (hasImgkey) {
|
|
51
|
+
message = HAS_DEPRECATED_PROPS_MESSAGE;
|
|
52
|
+
}
|
|
53
|
+
return message;
|
|
54
|
+
};
|
|
55
|
+
const StorageImage = ({ accessLevel, className, fallbackSrc, identityId, imgKey, path, onStorageGetError, onGetUrlError, validateObjectExistence = true, ...rest }) => {
|
|
56
|
+
const hasImgkey = !!imgKey;
|
|
57
|
+
const hasPath = !!path;
|
|
58
|
+
const hasDeprecatedOptions = !!accessLevel || !!identityId;
|
|
59
|
+
const message = getDeprecationMessage({
|
|
60
|
+
hasDeprecatedOptions,
|
|
61
|
+
hasImgkey,
|
|
62
|
+
hasPath,
|
|
63
|
+
});
|
|
64
|
+
internal.useDeprecationWarning({ message, shouldWarn: !!message });
|
|
65
|
+
if (!hasImgkey && !hasPath) {
|
|
66
|
+
throw new Error(MISSING_REQUIRED_PROP_MESSAGE);
|
|
67
|
+
}
|
|
46
68
|
uiReactCore.useSetUserAgent({
|
|
47
69
|
componentName: 'StorageImage',
|
|
48
70
|
packageName: 'react-storage',
|
|
49
71
|
version: VERSION,
|
|
50
72
|
});
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
const onError = onGetUrlError ?? onStorageGetError;
|
|
74
|
+
const input = React__namespace.useMemo(() => ({
|
|
75
|
+
...(path ? { path } : { key: imgKey }),
|
|
76
|
+
onError,
|
|
77
|
+
options: {
|
|
78
|
+
accessLevel,
|
|
79
|
+
targetIdentityId: identityId,
|
|
80
|
+
validateObjectExistence,
|
|
81
|
+
},
|
|
82
|
+
}), [accessLevel, imgKey, identityId, onError, path, validateObjectExistence]);
|
|
83
|
+
const { url } = uiReactCore.useGetUrl(input);
|
|
84
|
+
return (React__namespace.createElement(uiReact.Image, { ...rest, className: ui.classNames(ui.ComponentClassName.StorageImage, className), src: url?.toString() ?? fallbackSrc }));
|
|
58
85
|
};
|
|
59
86
|
|
|
60
87
|
var FileStatus;
|
|
@@ -137,7 +164,7 @@ function storageManagerStateReducer(state, action) {
|
|
|
137
164
|
...currentFile,
|
|
138
165
|
status: FileStatus.UPLOADING,
|
|
139
166
|
progress: 0,
|
|
140
|
-
uploadTask
|
|
167
|
+
uploadTask,
|
|
141
168
|
},
|
|
142
169
|
];
|
|
143
170
|
}
|
|
@@ -206,51 +233,37 @@ function storageManagerStateReducer(state, action) {
|
|
|
206
233
|
}
|
|
207
234
|
}
|
|
208
235
|
|
|
209
|
-
const addFilesAction = ({ files, status, getFileErrorMessage, }) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
};
|
|
241
|
-
const setUploadStatusAction = ({ id, status, }) => {
|
|
242
|
-
return {
|
|
243
|
-
type: StorageManagerActionTypes.SET_STATUS,
|
|
244
|
-
id,
|
|
245
|
-
status,
|
|
246
|
-
};
|
|
247
|
-
};
|
|
248
|
-
const removeUploadAction = ({ id }) => {
|
|
249
|
-
return {
|
|
250
|
-
type: StorageManagerActionTypes.REMOVE_UPLOAD,
|
|
251
|
-
id,
|
|
252
|
-
};
|
|
253
|
-
};
|
|
236
|
+
const addFilesAction = ({ files, status, getFileErrorMessage, }) => ({
|
|
237
|
+
type: StorageManagerActionTypes.ADD_FILES,
|
|
238
|
+
files,
|
|
239
|
+
status,
|
|
240
|
+
getFileErrorMessage,
|
|
241
|
+
});
|
|
242
|
+
const clearFilesAction = () => ({
|
|
243
|
+
type: StorageManagerActionTypes.CLEAR_FILES,
|
|
244
|
+
});
|
|
245
|
+
const queueFilesAction = () => ({
|
|
246
|
+
type: StorageManagerActionTypes.QUEUE_FILES,
|
|
247
|
+
});
|
|
248
|
+
const setUploadingFileAction = ({ id, uploadTask, }) => ({
|
|
249
|
+
type: StorageManagerActionTypes.SET_STATUS_UPLOADING,
|
|
250
|
+
id,
|
|
251
|
+
uploadTask,
|
|
252
|
+
});
|
|
253
|
+
const setUploadProgressAction = ({ id, progress, }) => ({
|
|
254
|
+
type: StorageManagerActionTypes.SET_UPLOAD_PROGRESS,
|
|
255
|
+
id,
|
|
256
|
+
progress,
|
|
257
|
+
});
|
|
258
|
+
const setUploadStatusAction = ({ id, status, }) => ({
|
|
259
|
+
type: StorageManagerActionTypes.SET_STATUS,
|
|
260
|
+
id,
|
|
261
|
+
status,
|
|
262
|
+
});
|
|
263
|
+
const removeUploadAction = ({ id }) => ({
|
|
264
|
+
type: StorageManagerActionTypes.REMOVE_UPLOAD,
|
|
265
|
+
id,
|
|
266
|
+
});
|
|
254
267
|
|
|
255
268
|
const isDefaultFile = (file) => !!(ui.isObject(file) && file.key);
|
|
256
269
|
const createFileFromDefault = (file) => isDefaultFile(file)
|
|
@@ -303,157 +316,6 @@ function useStorageManager(defaultFiles = []) {
|
|
|
303
316
|
};
|
|
304
317
|
}
|
|
305
318
|
|
|
306
|
-
function uploadFile({ file, key, level = 'private', progressCallback: onProgress, errorCallback, completeCallback, ...rest }) {
|
|
307
|
-
const contentType = file.type || 'binary/octet-stream';
|
|
308
|
-
const input = {
|
|
309
|
-
key,
|
|
310
|
-
data: file,
|
|
311
|
-
options: {
|
|
312
|
-
accessLevel: level,
|
|
313
|
-
contentType,
|
|
314
|
-
onProgress,
|
|
315
|
-
...rest,
|
|
316
|
-
},
|
|
317
|
-
};
|
|
318
|
-
const output = storage.uploadData(input);
|
|
319
|
-
output.result
|
|
320
|
-
.then(() => {
|
|
321
|
-
if (output.state === 'SUCCESS') {
|
|
322
|
-
completeCallback?.({ key });
|
|
323
|
-
}
|
|
324
|
-
})
|
|
325
|
-
.catch((e) => {
|
|
326
|
-
const error = e;
|
|
327
|
-
errorCallback?.(error.message);
|
|
328
|
-
});
|
|
329
|
-
return output;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Utility function that takes the processFile prop, along with a file a key
|
|
334
|
-
* and returns a Promise that resolves to { file, key, ..rest }
|
|
335
|
-
* regardless if processFile is defined and if it is sync or async
|
|
336
|
-
*/
|
|
337
|
-
const resolveFile = ({ processFile, file, key, }) => {
|
|
338
|
-
return new Promise((resolve, reject) => {
|
|
339
|
-
const result = ui.isFunction(processFile)
|
|
340
|
-
? processFile({ file, key })
|
|
341
|
-
: { file, key };
|
|
342
|
-
if (result instanceof Promise) {
|
|
343
|
-
result.then(resolve).catch(reject);
|
|
344
|
-
}
|
|
345
|
-
else {
|
|
346
|
-
resolve(result);
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
function useUploadFiles({ files, accessLevel, isResumable, setUploadProgress, setUploadingFile, setUploadSuccess, onUploadError, onUploadSuccess, onUploadStart, maxFileCount, processFile, path, }) {
|
|
352
|
-
React__namespace.useEffect(() => {
|
|
353
|
-
const filesReadyToUpload = files.filter((file) => file.status === FileStatus.QUEUED);
|
|
354
|
-
if (filesReadyToUpload.length > maxFileCount) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
for (const { file, key, id } of filesReadyToUpload) {
|
|
358
|
-
const onComplete = (event) => {
|
|
359
|
-
if (ui.isFunction(onUploadSuccess)) {
|
|
360
|
-
onUploadSuccess(event);
|
|
361
|
-
}
|
|
362
|
-
setUploadSuccess({ id });
|
|
363
|
-
};
|
|
364
|
-
const onProgress = (event) => {
|
|
365
|
-
/**
|
|
366
|
-
* When a file is zero bytes, the progress.total will equal zero.
|
|
367
|
-
* Therefore, this will prevent a divide by zero error.
|
|
368
|
-
*/
|
|
369
|
-
const progressPercentage = event.totalBytes === undefined || event.totalBytes === 0
|
|
370
|
-
? 100
|
|
371
|
-
: Math.floor((event.transferredBytes / event.totalBytes) * 100);
|
|
372
|
-
setUploadProgress({ id, progress: progressPercentage });
|
|
373
|
-
};
|
|
374
|
-
if (file) {
|
|
375
|
-
resolveFile({ processFile, file, key }).then(({ key: processedKey, ...rest }) => {
|
|
376
|
-
// prepend `path` to `processedKey`
|
|
377
|
-
const resolvedKey = ui.isString(path)
|
|
378
|
-
? `${path}${processedKey}`
|
|
379
|
-
: processedKey;
|
|
380
|
-
if (ui.isFunction(onUploadStart)) {
|
|
381
|
-
onUploadStart({ key: resolvedKey });
|
|
382
|
-
}
|
|
383
|
-
const uploadTask = uploadFile({
|
|
384
|
-
...rest,
|
|
385
|
-
key: resolvedKey,
|
|
386
|
-
level: accessLevel,
|
|
387
|
-
progressCallback: onProgress,
|
|
388
|
-
errorCallback: (error) => {
|
|
389
|
-
if (ui.isFunction(onUploadError)) {
|
|
390
|
-
onUploadError(error, { key: resolvedKey });
|
|
391
|
-
}
|
|
392
|
-
},
|
|
393
|
-
completeCallback: onComplete,
|
|
394
|
-
});
|
|
395
|
-
setUploadingFile({ id, uploadTask });
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}, [
|
|
400
|
-
files,
|
|
401
|
-
accessLevel,
|
|
402
|
-
isResumable,
|
|
403
|
-
setUploadProgress,
|
|
404
|
-
setUploadingFile,
|
|
405
|
-
onUploadError,
|
|
406
|
-
onUploadSuccess,
|
|
407
|
-
onUploadStart,
|
|
408
|
-
maxFileCount,
|
|
409
|
-
setUploadSuccess,
|
|
410
|
-
processFile,
|
|
411
|
-
path,
|
|
412
|
-
]);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function Container({ children, className, }) {
|
|
416
|
-
return React__default["default"].createElement(uiReact.View, { className: className }, children);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
function DropZone({ children, displayText, inDropZone, onDragEnter, onDragLeave, onDragOver, onDragStart, onDrop, testId, }) {
|
|
420
|
-
const { dropFilesText } = displayText;
|
|
421
|
-
const icons = internal.useIcons('storageManager');
|
|
422
|
-
return (React__default["default"].createElement(uiReact.View, { className: ui.classNames(inDropZone &&
|
|
423
|
-
ui.classNameModifier(ui.ComponentClassName.StorageManagerDropZone, 'active'), ui.ComponentClassName.StorageManagerDropZone), "data-testid": testId, onDragStart: onDragStart, onDragEnter: onDragEnter, onDragLeave: onDragLeave, onDrop: onDrop, onDragOver: onDragOver },
|
|
424
|
-
React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, className: ui.ComponentClassName.StorageManagerDropZoneIcon }, icons?.upload ?? React__default["default"].createElement(internal.IconUpload, null)),
|
|
425
|
-
React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerDropZoneText }, dropFilesText),
|
|
426
|
-
children));
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const FileStatusMessage = ({ errorMessage, getPausedText, getUploadingText, percentage, status, uploadSuccessfulText, }) => {
|
|
430
|
-
const icons = internal.useIcons('storageManager');
|
|
431
|
-
switch (status) {
|
|
432
|
-
case FileStatus.UPLOADING: {
|
|
433
|
-
return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getUploadingText(percentage)));
|
|
434
|
-
}
|
|
435
|
-
case FileStatus.PAUSED:
|
|
436
|
-
return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getPausedText(percentage)));
|
|
437
|
-
case FileStatus.UPLOADED:
|
|
438
|
-
return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'success')) },
|
|
439
|
-
React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.success ?? React__default["default"].createElement(internal.IconCheck, null)),
|
|
440
|
-
uploadSuccessfulText));
|
|
441
|
-
case FileStatus.ERROR:
|
|
442
|
-
return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'error')) },
|
|
443
|
-
React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.error ?? React__default["default"].createElement(internal.IconError, null)),
|
|
444
|
-
errorMessage));
|
|
445
|
-
default:
|
|
446
|
-
return null;
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
const FileRemoveButton = ({ altText, onClick, }) => {
|
|
451
|
-
const icons = internal.useIcons('storageManager');
|
|
452
|
-
return (React__default["default"].createElement(uiReact.Button, { size: "small", onClick: onClick },
|
|
453
|
-
React__default["default"].createElement(uiReact.VisuallyHidden, null, altText),
|
|
454
|
-
React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, fontSize: "medium" }, icons?.remove ?? React__default["default"].createElement(internal.IconClose, null))));
|
|
455
|
-
};
|
|
456
|
-
|
|
457
319
|
/**
|
|
458
320
|
* Format bytes as human-readable text.
|
|
459
321
|
*
|
|
@@ -555,6 +417,174 @@ const filterAllowedFiles = (files, acceptedFileTypes) => {
|
|
|
555
417
|
});
|
|
556
418
|
};
|
|
557
419
|
|
|
420
|
+
/**
|
|
421
|
+
* Utility function that takes the processFile prop, along with a file a key
|
|
422
|
+
* and returns a Promise that resolves to { file, key, ..rest }
|
|
423
|
+
* regardless if processFile is defined and if it is sync or async
|
|
424
|
+
*/
|
|
425
|
+
const resolveFile = ({ processFile, ...input }) => {
|
|
426
|
+
return new Promise((resolve, reject) => {
|
|
427
|
+
const result = ui.isFunction(processFile) ? processFile(input) : input;
|
|
428
|
+
if (result instanceof Promise) {
|
|
429
|
+
result.then(resolve).catch(reject);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
resolve(result);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const getInput = ({ accessLevel, file, key, onProgress, path, processFile, }) => {
|
|
438
|
+
return async () => {
|
|
439
|
+
const hasCallbackPath = ui.isTypedFunction(path);
|
|
440
|
+
const hasStringPath = ui.isString(path);
|
|
441
|
+
const hasKeyInput = !!accessLevel && !hasCallbackPath;
|
|
442
|
+
const { file: data, key: fileKey, ...rest } = await resolveFile({ file, key, processFile });
|
|
443
|
+
const contentType = file.type || 'binary/octet-stream';
|
|
444
|
+
// IMPORTANT: always pass `...rest` here for backwards compatibility
|
|
445
|
+
const options = { contentType, onProgress, ...rest };
|
|
446
|
+
if (hasKeyInput) {
|
|
447
|
+
// legacy handling of `path` is to prefix to `fileKey`
|
|
448
|
+
const resolvedKey = hasStringPath ? `${path}${fileKey}` : fileKey;
|
|
449
|
+
return { data, key: resolvedKey, options: { ...options, accessLevel } };
|
|
450
|
+
}
|
|
451
|
+
const { identityId } = await auth.fetchAuthSession();
|
|
452
|
+
const resolvedPath = `${hasCallbackPath ? path({ identityId }) : path}${fileKey}`;
|
|
453
|
+
return { data: file, path: resolvedPath, options };
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
async function uploadFile({ input, onError, onStart, onComplete, }) {
|
|
458
|
+
const resolvedInput = await input();
|
|
459
|
+
const uploadTask = storage.uploadData(resolvedInput);
|
|
460
|
+
const key = resolvedInput?.key ??
|
|
461
|
+
resolvedInput?.path;
|
|
462
|
+
if (ui.isFunction(onStart)) {
|
|
463
|
+
onStart({ key, uploadTask });
|
|
464
|
+
}
|
|
465
|
+
uploadTask.result
|
|
466
|
+
.then((result) => {
|
|
467
|
+
if (ui.isFunction(onComplete) && uploadTask.state === 'SUCCESS') {
|
|
468
|
+
onComplete(result);
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
.catch((error) => {
|
|
472
|
+
if (ui.isFunction(onError)) {
|
|
473
|
+
onError({ key, error });
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
return uploadTask;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function useUploadFiles({ files, accessLevel, isResumable, setUploadProgress, setUploadingFile, setUploadSuccess, onUploadError, onUploadSuccess, onUploadStart, maxFileCount, processFile, path, }) {
|
|
480
|
+
React__namespace.useEffect(() => {
|
|
481
|
+
const filesReadyToUpload = files.filter((file) => file.status === FileStatus.QUEUED);
|
|
482
|
+
if (filesReadyToUpload.length > maxFileCount) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
for (const { file, key, id } of filesReadyToUpload) {
|
|
486
|
+
const onProgress = (event) => {
|
|
487
|
+
/**
|
|
488
|
+
* When a file is zero bytes, the progress.total will equal zero.
|
|
489
|
+
* Therefore, this will prevent a divide by zero error.
|
|
490
|
+
*/
|
|
491
|
+
const progress = event.totalBytes === undefined || event.totalBytes === 0
|
|
492
|
+
? 100
|
|
493
|
+
: Math.floor((event.transferredBytes / event.totalBytes) * 100);
|
|
494
|
+
setUploadProgress({ id, progress });
|
|
495
|
+
};
|
|
496
|
+
if (file) {
|
|
497
|
+
const input = getInput({
|
|
498
|
+
accessLevel,
|
|
499
|
+
file,
|
|
500
|
+
key,
|
|
501
|
+
onProgress,
|
|
502
|
+
path,
|
|
503
|
+
processFile,
|
|
504
|
+
});
|
|
505
|
+
uploadFile({
|
|
506
|
+
input,
|
|
507
|
+
onComplete: (event) => {
|
|
508
|
+
if (ui.isFunction(onUploadSuccess)) {
|
|
509
|
+
onUploadSuccess({
|
|
510
|
+
key: event.key ??
|
|
511
|
+
event.path,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
setUploadSuccess({ id });
|
|
515
|
+
},
|
|
516
|
+
onError: ({ key, error }) => {
|
|
517
|
+
if (ui.isFunction(onUploadError)) {
|
|
518
|
+
onUploadError(error.message, { key });
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
onStart: ({ key, uploadTask }) => {
|
|
522
|
+
if (ui.isFunction(onUploadStart)) {
|
|
523
|
+
onUploadStart({ key });
|
|
524
|
+
}
|
|
525
|
+
setUploadingFile({ id, uploadTask });
|
|
526
|
+
},
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}, [
|
|
531
|
+
files,
|
|
532
|
+
accessLevel,
|
|
533
|
+
isResumable,
|
|
534
|
+
setUploadProgress,
|
|
535
|
+
setUploadingFile,
|
|
536
|
+
onUploadError,
|
|
537
|
+
onUploadSuccess,
|
|
538
|
+
onUploadStart,
|
|
539
|
+
maxFileCount,
|
|
540
|
+
setUploadSuccess,
|
|
541
|
+
processFile,
|
|
542
|
+
path,
|
|
543
|
+
]);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function Container({ children, className, }) {
|
|
547
|
+
return React__default["default"].createElement(uiReact.View, { className: className }, children);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function DropZone({ children, displayText, inDropZone, onDragEnter, onDragLeave, onDragOver, onDragStart, onDrop, testId, }) {
|
|
551
|
+
const { dropFilesText } = displayText;
|
|
552
|
+
const icons = internal.useIcons('storageManager');
|
|
553
|
+
return (React__default["default"].createElement(uiReact.View, { className: ui.classNames(inDropZone &&
|
|
554
|
+
ui.classNameModifier(ui.ComponentClassName.StorageManagerDropZone, 'active'), ui.ComponentClassName.StorageManagerDropZone), "data-testid": testId, onDragStart: onDragStart, onDragEnter: onDragEnter, onDragLeave: onDragLeave, onDrop: onDrop, onDragOver: onDragOver },
|
|
555
|
+
React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, className: ui.ComponentClassName.StorageManagerDropZoneIcon }, icons?.upload ?? React__default["default"].createElement(internal.IconUpload, null)),
|
|
556
|
+
React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerDropZoneText }, dropFilesText),
|
|
557
|
+
children));
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const FileStatusMessage = ({ errorMessage, getPausedText, getUploadingText, percentage, status, uploadSuccessfulText, }) => {
|
|
561
|
+
const icons = internal.useIcons('storageManager');
|
|
562
|
+
switch (status) {
|
|
563
|
+
case FileStatus.UPLOADING: {
|
|
564
|
+
return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getUploadingText(percentage)));
|
|
565
|
+
}
|
|
566
|
+
case FileStatus.PAUSED:
|
|
567
|
+
return (React__default["default"].createElement(uiReact.Text, { className: ui.ComponentClassName.StorageManagerFileStatus }, getPausedText(percentage)));
|
|
568
|
+
case FileStatus.UPLOADED:
|
|
569
|
+
return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'success')) },
|
|
570
|
+
React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.success ?? React__default["default"].createElement(internal.IconCheck, null)),
|
|
571
|
+
uploadSuccessfulText));
|
|
572
|
+
case FileStatus.ERROR:
|
|
573
|
+
return (React__default["default"].createElement(uiReact.Text, { className: ui.classNames(ui.ComponentClassName.StorageManagerFileStatus, ui.classNameModifier(ui.ComponentClassName.StorageManagerFileStatus, 'error')) },
|
|
574
|
+
React__default["default"].createElement(uiReact.View, { as: "span", fontSize: "xl" }, icons?.error ?? React__default["default"].createElement(internal.IconError, null)),
|
|
575
|
+
errorMessage));
|
|
576
|
+
default:
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
const FileRemoveButton = ({ altText, onClick, }) => {
|
|
582
|
+
const icons = internal.useIcons('storageManager');
|
|
583
|
+
return (React__default["default"].createElement(uiReact.Button, { size: "small", onClick: onClick },
|
|
584
|
+
React__default["default"].createElement(uiReact.VisuallyHidden, null, altText),
|
|
585
|
+
React__default["default"].createElement(uiReact.View, { as: "span", "aria-hidden": true, fontSize: "medium" }, icons?.remove ?? React__default["default"].createElement(internal.IconClose, null))));
|
|
586
|
+
};
|
|
587
|
+
|
|
558
588
|
const UploadDetails = ({ displayName, fileSize, }) => {
|
|
559
589
|
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
560
590
|
React__default["default"].createElement(uiReact.View, { className: ui.ComponentClassName.StorageManagerFileMain },
|
|
@@ -640,10 +670,21 @@ function FilePicker({ children, className = ui.ComponentClassName.StorageManager
|
|
|
640
670
|
}
|
|
641
671
|
|
|
642
672
|
const logger = ui.getLogger('Storage');
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
673
|
+
const MISSING_REQUIRED_PROPS_MESSAGE = '`StorageManager` requires a `maxFileCount` prop to be provided.';
|
|
674
|
+
const ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE = '`StorageManager` does not allow usage of a `path` callback prop with an `accessLevel` prop.';
|
|
675
|
+
const ACCESS_LEVEL_DEPRECATION_MESSAGE = '`accessLevel` has been deprecated and will be removed in a future major version. See migration notes at https://ui.docs.amplify.aws/react/connected-components/storage/storagemanager';
|
|
676
|
+
const StorageManagerBase = React__namespace.forwardRef(function StorageManager({ acceptedFileTypes = [], accessLevel, autoUpload = true, components, defaultFiles, displayText: overrideDisplayText, isResumable = false, maxFileCount, maxFileSize, onFileRemove, onUploadError, onUploadStart, onUploadSuccess, path, processFile, showThumbnails = true, }, ref) {
|
|
677
|
+
if (!maxFileCount) {
|
|
678
|
+
// eslint-disable-next-line no-console
|
|
679
|
+
console.warn(MISSING_REQUIRED_PROPS_MESSAGE);
|
|
680
|
+
}
|
|
681
|
+
if (accessLevel && typeof path === 'function') {
|
|
682
|
+
throw new Error(ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE);
|
|
646
683
|
}
|
|
684
|
+
uiReactCore.useDeprecationWarning({
|
|
685
|
+
message: ACCESS_LEVEL_DEPRECATION_MESSAGE,
|
|
686
|
+
shouldWarn: !!accessLevel,
|
|
687
|
+
});
|
|
647
688
|
const Components = {
|
|
648
689
|
Container,
|
|
649
690
|
DropZone,
|
|
@@ -716,15 +757,15 @@ function StorageManagerBase({ acceptedFileTypes = [], accessLevel, autoUpload =
|
|
|
716
757
|
const onUploadAll = () => {
|
|
717
758
|
queueFiles();
|
|
718
759
|
};
|
|
719
|
-
const onPauseUpload = ({ id, uploadTask
|
|
760
|
+
const onPauseUpload = ({ id, uploadTask }) => {
|
|
720
761
|
uploadTask.pause();
|
|
721
762
|
setUploadPaused({ id });
|
|
722
763
|
};
|
|
723
|
-
const onResumeUpload = ({ id, uploadTask
|
|
764
|
+
const onResumeUpload = ({ id, uploadTask }) => {
|
|
724
765
|
uploadTask.resume();
|
|
725
766
|
setUploadResumed({ id });
|
|
726
767
|
};
|
|
727
|
-
const onCancelUpload = ({ id, uploadTask
|
|
768
|
+
const onCancelUpload = ({ id, uploadTask }) => {
|
|
728
769
|
// At this time we don't know if the delete
|
|
729
770
|
// permissions are enabled (required to cancel upload),
|
|
730
771
|
// so we do a pause instead and remove from files
|
|
@@ -776,8 +817,9 @@ function StorageManagerBase({ acceptedFileTypes = [], accessLevel, autoUpload =
|
|
|
776
817
|
hasFiles ? (React__namespace.createElement(Components.FileListHeader, { allUploadsSuccessful: allUploadsSuccessful, displayText: displayText, fileCount: files.length, remainingFilesCount: remainingFilesCount, selectedFilesCount: selectedFilesCount })) : null,
|
|
777
818
|
React__namespace.createElement(Components.FileList, { displayText: displayText, files: files, isResumable: isResumable, onCancelUpload: onCancelUpload, onDeleteUpload: onDeleteUpload, onResume: onResumeUpload, onPause: onPauseUpload, showThumbnails: showThumbnails, hasMaxFilesError: hasMaxFilesError, maxFileCount: maxFileCount }),
|
|
778
819
|
hasUploadActions ? (React__namespace.createElement(Components.FileListFooter, { displayText: displayText, remainingFilesCount: remainingFilesCount, onClearAll: onClearAll, onUploadAll: onUploadAll })) : null));
|
|
779
|
-
}
|
|
780
|
-
|
|
820
|
+
});
|
|
821
|
+
// pass an empty object as first param to avoid destructive action on `StorageManagerBase`
|
|
822
|
+
const StorageManager = Object.assign({}, StorageManagerBase, {
|
|
781
823
|
Container,
|
|
782
824
|
DropZone,
|
|
783
825
|
FileList,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import type { StorageImageProps } from './types';
|
|
3
|
-
export declare const
|
|
2
|
+
import type { StorageImageProps, StorageImagePathProps } from './types';
|
|
3
|
+
export declare const MISSING_REQUIRED_PROP_MESSAGE = "`StorageImage` requires either an `imgKey` or `path` prop.";
|
|
4
|
+
export declare const HAS_DEPRECATED_PROPS_MESSAGE = "`imgKey`, `accessLevel`, and `identityId` will be replaced with `path` in a future major version. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props";
|
|
5
|
+
export declare const HAS_PATH_AND_KEY_MESSAGE = "`imgKey` is ignored when both `imgKey` and `path` props are provided.";
|
|
6
|
+
export declare const HAS_PATH_AND_UNSUPPORTED_OPTIONS_MESSAGE = "`accessLevel` and `identityId` are ignored when the `path` prop is provided.";
|
|
7
|
+
export declare const StorageImage: ({ accessLevel, className, fallbackSrc, identityId, imgKey, path, onStorageGetError, onGetUrlError, validateObjectExistence, ...rest }: StorageImageProps | StorageImagePathProps) => JSX.Element;
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import { StorageAccessLevel } from '@aws-amplify/core';
|
|
2
2
|
import { ImageProps } from '@aws-amplify/ui-react';
|
|
3
3
|
export interface StorageImageProps extends Omit<ImageProps, 'src'> {
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated
|
|
6
|
+
* `imgKey` will be replaced with `path` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
|
|
7
|
+
*/
|
|
4
8
|
imgKey: string;
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated
|
|
11
|
+
* `accessLevel` will be replaced with `path` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
|
|
12
|
+
*/
|
|
5
13
|
accessLevel: StorageAccessLevel;
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated
|
|
16
|
+
* `identityId` will be replaced with `path` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
|
|
17
|
+
*/
|
|
6
18
|
identityId?: string;
|
|
7
19
|
fallbackSrc?: string;
|
|
8
20
|
validateObjectExistence?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated use `onGetUrlError`
|
|
23
|
+
*
|
|
24
|
+
* `onStorageGetError` will be replaced with `onGetUrlError` in a future major version of Amplify UI. See https://ui.docs.amplify.aws/react/connected-components/storage/storageimage#props
|
|
25
|
+
*/
|
|
9
26
|
onStorageGetError?: (error: Error) => void;
|
|
27
|
+
onGetUrlError?: (error: Error) => void;
|
|
28
|
+
path?: never;
|
|
10
29
|
}
|
|
30
|
+
type OmittedPropKey = 'accessLevel' | 'imgKey' | 'identityId' | 'onStorageGetError' | 'path';
|
|
31
|
+
export interface StorageImagePathProps extends Omit<StorageImageProps, OmittedPropKey> {
|
|
32
|
+
path: string | ((input: {
|
|
33
|
+
identityId?: string;
|
|
34
|
+
}) => string);
|
|
35
|
+
imgKey?: never;
|
|
36
|
+
accessLevel?: never;
|
|
37
|
+
identityId?: never;
|
|
38
|
+
onStorageGetError?: never;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { StorageManagerProps, StorageManagerHandle } from './types';
|
|
2
|
+
import { StorageManagerProps, StorageManagerPathProps, StorageManagerHandle } from './types';
|
|
3
3
|
import { Container, DropZone, FileList, FileListHeader, FileListFooter, FilePicker } from './ui';
|
|
4
|
-
declare const StorageManager
|
|
4
|
+
export declare const MISSING_REQUIRED_PROPS_MESSAGE = "`StorageManager` requires a `maxFileCount` prop to be provided.";
|
|
5
|
+
export declare const ACCESS_LEVEL_WITH_PATH_CALLBACK_MESSAGE = "`StorageManager` does not allow usage of a `path` callback prop with an `accessLevel` prop.";
|
|
6
|
+
export declare const ACCESS_LEVEL_DEPRECATION_MESSAGE = "`accessLevel` has been deprecated and will be removed in a future major version. See migration notes at https://ui.docs.amplify.aws/react/connected-components/storage/storagemanager";
|
|
7
|
+
declare const StorageManager: React.ForwardRefExoticComponent<(StorageManagerProps | StorageManagerPathProps) & React.RefAttributes<StorageManagerHandle>> & {
|
|
5
8
|
Container: typeof Container;
|
|
6
9
|
DropZone: typeof DropZone;
|
|
7
10
|
FileList: typeof FileList;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { UploadDataOutput } from 'aws-amplify/storage';
|
|
2
1
|
import { FileStatus } from '../../types';
|
|
3
2
|
import { Action, AddFilesActionParams } from './types';
|
|
3
|
+
import { TaskEvent } from '../../utils';
|
|
4
4
|
export declare const addFilesAction: ({ files, status, getFileErrorMessage, }: AddFilesActionParams) => Action;
|
|
5
5
|
export declare const clearFilesAction: () => Action;
|
|
6
6
|
export declare const queueFilesAction: () => Action;
|
|
7
|
-
export declare const setUploadingFileAction: ({ id, uploadTask, }:
|
|
8
|
-
id: string;
|
|
9
|
-
uploadTask: UploadDataOutput | undefined;
|
|
10
|
-
}) => Action;
|
|
7
|
+
export declare const setUploadingFileAction: ({ id, uploadTask, }: TaskEvent) => Action;
|
|
11
8
|
export declare const setUploadProgressAction: ({ id, progress, }: {
|
|
12
9
|
id: string;
|
|
13
10
|
progress: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UploadDataOutput } from 'aws-amplify/storage';
|
|
2
1
|
import { FileStatus, StorageFiles } from '../../types';
|
|
2
|
+
import { UploadTask } from '../../utils';
|
|
3
3
|
export interface UseStorageManagerState {
|
|
4
4
|
files: StorageFiles;
|
|
5
5
|
}
|
|
@@ -29,7 +29,7 @@ export type Action = {
|
|
|
29
29
|
} | {
|
|
30
30
|
type: StorageManagerActionTypes.SET_STATUS_UPLOADING;
|
|
31
31
|
id: string;
|
|
32
|
-
uploadTask?:
|
|
32
|
+
uploadTask?: UploadTask;
|
|
33
33
|
} | {
|
|
34
34
|
type: StorageManagerActionTypes.SET_UPLOAD_PROGRESS;
|
|
35
35
|
id: string;
|