Skip to content

Commit ba17d38

Browse files
authored
feat(storagemanager): add useAccelerateEndpoint (#5501)
1 parent 0919e55 commit ba17d38

File tree

11 files changed

+200
-17
lines changed

11 files changed

+200
-17
lines changed

.changeset/healthy-baboons-film.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@aws-amplify/ui-react-storage": minor
3+
---
4+
5+
feat(storagemanager): add useAccelerateEndpoint
6+
7+
```jsx
8+
<StorageManager
9+
acceptedFileTypes={['image/*']}
10+
path="public/"
11+
useAccelerateEndpoint
12+
/>
13+
```

docs/src/pages/[platform]/connected-components/storage/storagemanager/props.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ export const STORAGE_MANAGER = [
9595
description: 'Text to override in the component.',
9696
type: 'StorageManagerDisplayText',
9797
},
98+
{
99+
name: `useAccelerateEndpoint?`,
100+
description: 'Use the accelerated S3 endpoint to upload files.',
101+
type: 'boolean',
102+
},
98103
{
99104
name: `components?.Container?`,
100105
description: 'The container the StorageManager is wrapped in.',

docs/src/pages/[platform]/connected-components/storage/storagemanager/react.mdx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,44 @@ You can add metadata by adding a `metadata` object in the return object of `proc
229229
</ExampleCode>
230230
</Example>
231231

232+
## Accelerate Endpoint
233+
234+
Amazon S3 transfer acceleration optimizes transfer speeds from around the world into S3 buckets. When you use Transfer Acceleration, additional data transfer charges might apply. For more information about pricing, see [Amazon S3 pricing](https://aws.amazon.com/s3/pricing/).
235+
236+
To use transfer acceleration you first need to [enable it on your S3 bucket](https://docs.amplify.aws/react/build-a-backend/storage/extend-s3-resources/#example---enable-transfer-acceleration). Then add `useAccelerateEndpoint` on the `<StorageManager />` component. By default transfer acceleration is off.
237+
238+
<ExampleCode>
239+
240+
```jsx
241+
<StorageManager
242+
acceptedFileTypes={['image/*']}
243+
maxFileCount={10}
244+
useAccelerateEndpoint
245+
/>
246+
```
247+
248+
</ExampleCode>
249+
250+
You can also choose whether or not to use transfer acceleration at the file level by returning `useAccelerateEndpoint` from the `processFile` function.
251+
252+
<ExampleCode>
253+
254+
```jsx
255+
<StorageManager
256+
acceptedFileTypes={['image/*']}
257+
maxFileCount={10}
258+
processFile={({ file, key }) => {
259+
return {
260+
file,
261+
key,
262+
useAccelerateEndpoint: file.size > 10000 ? true : false,
263+
};
264+
}}
265+
/>
266+
```
267+
268+
</ExampleCode>
269+
232270
## Customization
233271

234272
### Text and labels
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import amplifyOutputs from '@environments/storage/gen2/amplify_outputs';
2+
export default amplifyOutputs;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Amplify } from 'aws-amplify';
2+
import { StorageManager } from '@aws-amplify/ui-react-storage';
3+
import '@aws-amplify/ui-react/styles.css';
4+
import amplifyOutputs from './amplify_outputs';
5+
Amplify.configure(amplifyOutputs);
6+
7+
const processFile = ({ file, key }) => {
8+
return {
9+
file,
10+
key,
11+
useAccelerateEndpoint: file.size > 10000 ? true : false,
12+
};
13+
};
14+
15+
export function StorageManagerExample() {
16+
return (
17+
<StorageManager
18+
acceptedFileTypes={['image/*']}
19+
path="public/"
20+
maxFileCount={10}
21+
showThumbnails
22+
autoUpload={false}
23+
useAccelerateEndpoint
24+
processFile={processFile}
25+
/>
26+
);
27+
}
28+
export default StorageManagerExample;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Feature: Storage Manager with accelerate endpoint
2+
3+
Background:
4+
Given I'm running the example "ui/components/storage/storage-manager/use-accelerate-endpoint"
5+
6+
@react
7+
Scenario: I select a file and upload it on click
8+
Then I see "Browse files"
9+
Then I select a file with file name "test.jpg"
10+
Then I see "test.jpg"
11+
Then I see "Upload 1 file"
12+
Then I see "Clear all"
13+
Given I intercept '{ "method": "POST", "url": "**/test.jpg?uploads" }' with fixture "Storage.public-uploads.xml"
14+
Given I intercept '{ "method": "PUT", "url": "**/test.jpg?partNumber=1**" }' with fixture "Storage.public-upload-part.xml" and add header "Etag" with value "&quot;abc123&quot;"
15+
Given I intercept '{ "method": "POST", "url": "**/test.jpg?uploadId**" }' with fixture "Storage.public-upload-complete-multipart.xml"
16+
Given I intercept '{ "method": "GET", "url": "**/?list-type=2**" }' with fixture "Storage.public-uploads-list.xml"
17+
Then I see "1 file selected"
18+
Then I click the "Upload 1 file" button
19+
Then I see "Uploaded"
20+
Then I see "1 file uploaded"
21+
22+
@react
23+
Scenario: I can clear all selected files
24+
Then I see "Browse files"
25+
Then I select a file with file name "test.jpg"
26+
Then I see "test.jpg"
27+
Then I see "Upload 1 file"
28+
Then I see "Clear all"
29+
Given I intercept '{ "method": "POST", "url": "**/test.jpg?uploads" }' with fixture "Storage.public-uploads.xml"
30+
Given I intercept '{ "method": "PUT", "url": "**/test.jpg?partNumber=1**" }' with fixture "Storage.public-upload-part.xml" and add header "Etag" with value "&quot;abc123&quot;"
31+
Given I intercept '{ "method": "POST", "url": "**/test.jpg?uploadId**" }' with fixture "Storage.public-upload-complete-multipart.xml"
32+
Given I intercept '{ "method": "GET", "url": "**/?list-type=2**" }' with fixture "Storage.public-uploads-list.xml"
33+
Then I click the "Clear all" button
34+
Then I see "Browse files"
35+
Then I don't see "Uploaded"

packages/react-storage/src/components/StorageManager/StorageManager.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const StorageManagerBase = React.forwardRef(function StorageManager(
5858
path,
5959
processFile,
6060
showThumbnails = true,
61+
useAccelerateEndpoint,
6162
}: StorageManagerPathProps | StorageManagerProps,
6263
ref: React.ForwardedRef<StorageManagerHandle>
6364
): JSX.Element {
@@ -154,6 +155,7 @@ const StorageManagerBase = React.forwardRef(function StorageManager(
154155
setUploadSuccess,
155156
processFile,
156157
path,
158+
useAccelerateEndpoint,
157159
});
158160

159161
const onFilePickerChange = (event: React.ChangeEvent<HTMLInputElement>) => {

packages/react-storage/src/components/StorageManager/hooks/useUploadFiles/useUploadFiles.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface UseUploadFilesProps
1818
| 'onUploadStart'
1919
| 'maxFileCount'
2020
| 'processFile'
21+
| 'useAccelerateEndpoint'
2122
>,
2223
Pick<
2324
UseStorageManager,
@@ -42,6 +43,7 @@ export function useUploadFiles({
4243
setUploadingFile,
4344
setUploadProgress,
4445
setUploadSuccess,
46+
useAccelerateEndpoint,
4547
}: UseUploadFilesProps): void {
4648
React.useEffect(() => {
4749
const filesReadyToUpload = files.filter(
@@ -77,6 +79,7 @@ export function useUploadFiles({
7779
onProgress,
7880
path,
7981
processFile,
82+
useAccelerateEndpoint,
8083
});
8184

8285
uploadFile({
@@ -119,5 +122,6 @@ export function useUploadFiles({
119122
setUploadSuccess,
120123
processFile,
121124
path,
125+
useAccelerateEndpoint,
122126
]);
123127
}

packages/react-storage/src/components/StorageManager/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export type DefaultFile = Pick<StorageFile, 'key'>;
4141
export interface ProcessFileParams extends Record<string, any> {
4242
file: File;
4343
key: string;
44+
useAccelerateEndpoint?: boolean;
4445
}
4546

4647
export type ProcessFile = (
@@ -126,6 +127,8 @@ export interface StorageManagerProps {
126127
* Provided value is prefixed to the file `key` for each file
127128
*/
128129
path?: string;
130+
131+
useAccelerateEndpoint?: boolean;
129132
}
130133

131134
export interface StorageManagerPathProps
@@ -138,4 +141,5 @@ export interface StorageManagerPathProps
138141
*/
139142
path: string | PathCallback;
140143
accessLevel?: never;
144+
useAccelerateEndpoint?: boolean;
141145
}

packages/react-storage/src/components/StorageManager/utils/__tests__/getInput.spec.ts

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ describe('getInput', () => {
6262
it('resolves an UploadDataWithPathInput with a string `path` as expected', async () => {
6363
const expected: UploadDataWithPathInput = {
6464
data: file,
65-
options: { contentType: file.type, onProgress },
65+
options: {
66+
contentType: file.type,
67+
useAccelerateEndpoint: undefined,
68+
onProgress,
69+
},
6670
path: `${stringPath}${key}`,
6771
};
6872

@@ -76,7 +80,11 @@ describe('getInput', () => {
7680
it('resolves an UploadDataWithPathInput with a callback `path` as expected', async () => {
7781
const expected: UploadDataWithPathInput = {
7882
data: file,
79-
options: { contentType: file.type, onProgress },
83+
options: {
84+
contentType: file.type,
85+
useAccelerateEndpoint: undefined,
86+
onProgress,
87+
},
8088
path: `${stringPath}${identityId}${key}`,
8189
};
8290

@@ -90,7 +98,12 @@ describe('getInput', () => {
9098
it('resolves an UploadDataInput without a `path` as expected', async () => {
9199
const expected: UploadDataInput = {
92100
data: file,
93-
options: { accessLevel, contentType: file.type, onProgress },
101+
options: {
102+
accessLevel,
103+
contentType: file.type,
104+
useAccelerateEndpoint: undefined,
105+
onProgress,
106+
},
94107
key,
95108
};
96109

@@ -104,7 +117,12 @@ describe('getInput', () => {
104117
it('resolves an UploadDataInput with a `path` as expected', async () => {
105118
const expected: UploadDataInput = {
106119
data: file,
107-
options: { accessLevel, contentType: file.type, onProgress },
120+
options: {
121+
accessLevel,
122+
contentType: file.type,
123+
useAccelerateEndpoint: undefined,
124+
onProgress,
125+
},
108126
key: `${stringPath}${key}`,
109127
};
110128

@@ -118,7 +136,11 @@ describe('getInput', () => {
118136
it('handles a `processFile` param expected', async () => {
119137
const expected: UploadDataWithPathInput = {
120138
data: file,
121-
options: { contentType: file.type, onProgress },
139+
options: {
140+
contentType: file.type,
141+
useAccelerateEndpoint: undefined,
142+
onProgress,
143+
},
122144
path: `${stringPath}${identityId}${processFilePrefix}${key}`,
123145
};
124146

@@ -167,6 +189,7 @@ describe('getInput', () => {
167189
contentType: file.type,
168190
metadata,
169191
onProgress,
192+
useAccelerateEndpoint: undefined,
170193
},
171194
path: `${stringPath}${processFilePrefix}${key}`,
172195
};
@@ -216,19 +239,46 @@ describe('getInput', () => {
216239
processedKey,
217240
});
218241
});
219-
});
220242

221-
it('defaults `options.contentType` to "binary/octet-stream" when no file type is provided', async () => {
222-
const data = new File(['hello'], 'hello.png');
223-
const expected: UploadDataWithPathInput = {
224-
data,
225-
options: { contentType: 'binary/octet-stream', onProgress },
226-
path: `${stringPath}${key}`,
227-
};
243+
it('defaults `options.contentType` to "binary/octet-stream" when no file type is provided', async () => {
244+
const data = new File(['hello'], 'hello.png');
245+
const expected: UploadDataWithPathInput = {
246+
data,
247+
options: {
248+
contentType: 'binary/octet-stream',
249+
useAccelerateEndpoint: undefined,
250+
onProgress,
251+
},
252+
path: `${stringPath}${key}`,
253+
};
254+
255+
const input = getInput({ ...pathStringInput, file: data });
228256

229-
const input = getInput({ ...pathStringInput, file: data });
257+
const output = await input();
230258

231-
const output = await input();
259+
expect(output).toStrictEqual(expected);
260+
});
232261

233-
expect(output).toStrictEqual(expected);
262+
it('accepts useAccelerateEndpoint', async () => {
263+
const data = new File(['hello'], 'hello.png');
264+
const expected: UploadDataWithPathInput = {
265+
data,
266+
options: {
267+
contentType: 'binary/octet-stream',
268+
useAccelerateEndpoint: true,
269+
onProgress,
270+
},
271+
path: `${stringPath}${key}`,
272+
};
273+
274+
const input = getInput({
275+
...pathStringInput,
276+
file: data,
277+
useAccelerateEndpoint: true,
278+
});
279+
280+
const output = await input();
281+
282+
expect(output).toStrictEqual(expected);
283+
});
234284
});

0 commit comments

Comments
 (0)