@lowdefy/plugin-aws 4.0.0-alpha.9 → 4.0.0-rc.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/README.md +332 -0
- package/dist/blocks/S3UploadButton/S3UploadButton.js +48 -8
- package/dist/blocks/S3UploadButton/__snapshots__/S3UploadButton.mock.test.js.snap +1597 -0
- package/dist/blocks/S3UploadButton/__snapshots__/S3UploadButton.test.js.snap +281 -0
- package/dist/blocks/S3UploadButton/examples.yaml +44 -0
- package/dist/blocks/S3UploadButton/style.less +1 -1
- package/dist/blocks/S3UploadPhoto/S3UploadPhoto.js +220 -0
- package/dist/blocks/S3UploadPhoto/schema.json +83 -0
- package/dist/blocks/S3UploadPhoto/style.less +17 -0
- package/dist/blocks.js +16 -0
- package/dist/types.js +14 -2
- package/package.json +33 -28
package/README.md
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# Lowdefy S3 Upload Blocks
|
|
2
|
+
|
|
3
|
+
To securely upload files to S3, the `S3UploadButton` or `S3UploadPhoto` blocks can be used. S3 file downloads can be done by getting a presigned URL using a `AwsS3PresignedGetObject` request and opening the URL in a new tab which will result in the browser starting the file download.
|
|
4
|
+
|
|
5
|
+
To access the [Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html), a `AwsS3Bucket` connection is defined, and a `AwsS3PresignedPostPolicy` or `AwsS3PresignedGetObject` requests can be used to either upload or download files to S3.
|
|
6
|
+
|
|
7
|
+
### AwsS3Bucket Connection
|
|
8
|
+
The `AwsS3Bucket` connenction provides functionality of the [Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html).
|
|
9
|
+
|
|
10
|
+
##### Properties
|
|
11
|
+
- `accessKeyId: string`: AWS IAM access key id with s3 access.
|
|
12
|
+
- `secretAccessKey: string` : AWS IAM secret access key with s3 access.
|
|
13
|
+
- `region: string`: AWS region the bucket is located in
|
|
14
|
+
- `bucket: string`: S3 bucket name.
|
|
15
|
+
- `read: boolean` : Allow reads from the bucket.
|
|
16
|
+
- `write: boolean`: Allow writes to the bucket.
|
|
17
|
+
|
|
18
|
+
### AwsS3PresignedPostPolicy File Upload Request
|
|
19
|
+
To upload files, a request of type `AwsS3PresignedPostPolicy` is used.
|
|
20
|
+
|
|
21
|
+
##### Properties
|
|
22
|
+
- `acl: string`: Access control lists used to grant read and write access.
|
|
23
|
+
- `conditions: array`: Conditions to be enforced on the request.
|
|
24
|
+
- `expires: number`: Number of seconds for which the policy should be valid.
|
|
25
|
+
- `key: string`: Key under which object will be stored.
|
|
26
|
+
|
|
27
|
+
### AwsS3PresignedGetObject File Download Request
|
|
28
|
+
To download files, a request of type `AwsS3PresignedGetObject` is used.
|
|
29
|
+
|
|
30
|
+
##### Properties
|
|
31
|
+
- `expires: number`: Number of seconds for which the policy should be valid.
|
|
32
|
+
- `key: string`: Key under which object is stored .
|
|
33
|
+
- `responseContentDisposition: string`: Sets the Content-Disposition header of the response.
|
|
34
|
+
- `responseContentType: string`: Sets the Content-Type header of the response.
|
|
35
|
+
- `versionId: string`: VersionId used to reference a specific version of the object.
|
|
36
|
+
|
|
37
|
+
### S3UploadButton and S3UploadPhoto Blocks
|
|
38
|
+
|
|
39
|
+
##### Properties
|
|
40
|
+
- `accept: string`: File types accepted by the input. See html file type input accept property at [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept).
|
|
41
|
+
- `button: object`: Button block properties.
|
|
42
|
+
- `disabled: boolean`: Disable the file input.
|
|
43
|
+
- `s3PostPolicyRequestId: string`: Id of a request of type AwsS3PresignedPostPolicy that defines to which S3 bucket and how the file should be uploaded.
|
|
44
|
+
- `showUploadList: boolean`: Whether to show default upload list.
|
|
45
|
+
- `singleFile: boolean`: Only allow a single file to be uploaded. Only one file can be selected in the prompt and the upload button is disabled after a file is uploaded.
|
|
46
|
+
|
|
47
|
+
##### Events
|
|
48
|
+
- `onChange`: Triggered when the upload state is changing.
|
|
49
|
+
- `onClick`: Triggered when the upload button is clicked.
|
|
50
|
+
- `onSuccess`: Triggered when the upload is successful, returns `_event` object:
|
|
51
|
+
- `meta`:
|
|
52
|
+
- `bucket`: Name of bucket that the file was stored in.
|
|
53
|
+
- `filename`: Uploaded filename.
|
|
54
|
+
- `key`: Key under which the file is stored.
|
|
55
|
+
- `size`: Size of uploaded file.
|
|
56
|
+
- `type`: Type of uploaded file.
|
|
57
|
+
- `uid`: UID of uploaded file.
|
|
58
|
+
- `onDone`: Triggered when the upload is completed, returns `_event` object:
|
|
59
|
+
- `meta`:
|
|
60
|
+
- `bucket`: Name of bucket that the file was stored in.
|
|
61
|
+
- `filename`: Uploaded filename.
|
|
62
|
+
- `key`: Key under which the file is stored.
|
|
63
|
+
- `size`: Size of uploaded file.
|
|
64
|
+
- `type`: Type of uploaded file.
|
|
65
|
+
- `uid`: UID of uploaded file.
|
|
66
|
+
- `onError`: Triggered when an error occurs, returns `_event` object:
|
|
67
|
+
- `meta`:
|
|
68
|
+
- `bucket`: Name of bucket that the file was stored in.
|
|
69
|
+
- `filename`: Uploaded filename.
|
|
70
|
+
- `key`: Key under which the file is stored.
|
|
71
|
+
- `size`: Size of uploaded file.
|
|
72
|
+
- `type`: Type of uploaded file.
|
|
73
|
+
- `uid`: UID of uploaded file.
|
|
74
|
+
|
|
75
|
+
### Examples
|
|
76
|
+
|
|
77
|
+
1. File Upload and Download:
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
# .env secrets needed
|
|
81
|
+
LOWDEFY_SECRET_UPLOADS_S3_ACCESS_KEY_ID
|
|
82
|
+
LOWDEFY_SECRET_UPLOADS_S3_SECRET_ACCESS_KEY
|
|
83
|
+
LOWDEFY_SECRET_UPLOADS_S3_BUCKET
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
# lowdefy.yaml
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
connections:
|
|
91
|
+
- id: uploads_bucket
|
|
92
|
+
type: AwsS3Bucket
|
|
93
|
+
properties:
|
|
94
|
+
accessKeyId:
|
|
95
|
+
_secret: UPLOADS_S3_ACCESS_KEY_ID
|
|
96
|
+
secretAccessKey:
|
|
97
|
+
_secret: UPLOADS_S3_SECRET_ACCESS_KEY
|
|
98
|
+
region: af-south-1
|
|
99
|
+
bucket:
|
|
100
|
+
_secret: UPLOADS_S3_BUCKET
|
|
101
|
+
write: true
|
|
102
|
+
|
|
103
|
+
pages:
|
|
104
|
+
- id: s3_example_file_upload
|
|
105
|
+
type: PageHeaderMenu
|
|
106
|
+
properties:
|
|
107
|
+
title: S3 Example File Upload
|
|
108
|
+
layout:
|
|
109
|
+
contentGutter: 16
|
|
110
|
+
|
|
111
|
+
events:
|
|
112
|
+
onMount:
|
|
113
|
+
- id: set_state
|
|
114
|
+
type: SetState
|
|
115
|
+
params:
|
|
116
|
+
files: []
|
|
117
|
+
|
|
118
|
+
requests:
|
|
119
|
+
- id: upload_file
|
|
120
|
+
type: AwsS3PresignedPostPolicy
|
|
121
|
+
connectionId: uploads_bucket
|
|
122
|
+
payload:
|
|
123
|
+
key:
|
|
124
|
+
_state: file_uploader.file.name
|
|
125
|
+
properties:
|
|
126
|
+
key:
|
|
127
|
+
_payload: key
|
|
128
|
+
- id: download_file
|
|
129
|
+
type: AwsS3PresignedGetObject
|
|
130
|
+
connectionId: uploads_bucket
|
|
131
|
+
payload:
|
|
132
|
+
key:
|
|
133
|
+
_state: selected.key
|
|
134
|
+
responseContentType:
|
|
135
|
+
_state: selected.type
|
|
136
|
+
properties:
|
|
137
|
+
key:
|
|
138
|
+
_payload: key
|
|
139
|
+
responseContentType:
|
|
140
|
+
_payload: responseContentType
|
|
141
|
+
|
|
142
|
+
blocks:
|
|
143
|
+
- id: file_uploader_card
|
|
144
|
+
type: Card
|
|
145
|
+
properties:
|
|
146
|
+
title: Upload Files
|
|
147
|
+
blocks:
|
|
148
|
+
- id: file_uploader
|
|
149
|
+
type: S3UploadButton
|
|
150
|
+
properties:
|
|
151
|
+
s3PostPolicyRequestId: upload_file
|
|
152
|
+
button:
|
|
153
|
+
title: Upload
|
|
154
|
+
events:
|
|
155
|
+
onSuccess:
|
|
156
|
+
- id: set_state
|
|
157
|
+
type: SetState
|
|
158
|
+
params:
|
|
159
|
+
files:
|
|
160
|
+
_array.concat:
|
|
161
|
+
- _state: files
|
|
162
|
+
- - _event: meta
|
|
163
|
+
|
|
164
|
+
- id: file_card
|
|
165
|
+
type: Card
|
|
166
|
+
properties:
|
|
167
|
+
title: Files
|
|
168
|
+
blocks:
|
|
169
|
+
- id: files_table
|
|
170
|
+
type: AgGridAlpine
|
|
171
|
+
properties:
|
|
172
|
+
enableCellTextSelection: true
|
|
173
|
+
rowData:
|
|
174
|
+
_state: files
|
|
175
|
+
defaultColDef:
|
|
176
|
+
sortable: true
|
|
177
|
+
resizable: true
|
|
178
|
+
filter: true
|
|
179
|
+
columnDefs:
|
|
180
|
+
- headerName: filename
|
|
181
|
+
field: filename
|
|
182
|
+
- headerName: size
|
|
183
|
+
field: size
|
|
184
|
+
- headerName: type
|
|
185
|
+
field: type
|
|
186
|
+
events:
|
|
187
|
+
onRowClick:
|
|
188
|
+
- id: set_selected_id
|
|
189
|
+
type: SetState
|
|
190
|
+
params:
|
|
191
|
+
selected:
|
|
192
|
+
_event: row
|
|
193
|
+
- id: download_file
|
|
194
|
+
type: Request
|
|
195
|
+
params: download_file
|
|
196
|
+
- id: get_download_link
|
|
197
|
+
type: Link
|
|
198
|
+
messages:
|
|
199
|
+
error: Failed to open file. Check if popups are blocked in your browser.
|
|
200
|
+
params:
|
|
201
|
+
url:
|
|
202
|
+
_request: download_file
|
|
203
|
+
newTab: true
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
2. Photo Upload and Download:
|
|
207
|
+
|
|
208
|
+
```yaml
|
|
209
|
+
# .env secrets needed
|
|
210
|
+
LOWDEFY_SECRET_UPLOADS_S3_ACCESS_KEY_ID
|
|
211
|
+
LOWDEFY_SECRET_UPLOADS_S3_SECRET_ACCESS_KEY
|
|
212
|
+
LOWDEFY_SECRET_UPLOADS_S3_BUCKET
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
# lowdefy.yaml
|
|
217
|
+
...
|
|
218
|
+
connections:
|
|
219
|
+
- id: uploads_bucket
|
|
220
|
+
type: AwsS3Bucket
|
|
221
|
+
properties:
|
|
222
|
+
accessKeyId:
|
|
223
|
+
_secret: UPLOADS_S3_ACCESS_KEY_ID
|
|
224
|
+
secretAccessKey:
|
|
225
|
+
_secret: UPLOADS_S3_SECRET_ACCESS_KEY
|
|
226
|
+
region: af-south-1
|
|
227
|
+
bucket:
|
|
228
|
+
_secret: UPLOADS_S3_BUCKET
|
|
229
|
+
write: true
|
|
230
|
+
|
|
231
|
+
pages:
|
|
232
|
+
- id: s3_example_photo_upload
|
|
233
|
+
type: PageHeaderMenu
|
|
234
|
+
properties:
|
|
235
|
+
title: S3 Example Photo Upload
|
|
236
|
+
layout:
|
|
237
|
+
contentGutter: 16
|
|
238
|
+
|
|
239
|
+
events:
|
|
240
|
+
onMount:
|
|
241
|
+
- id: set_state
|
|
242
|
+
type: SetState
|
|
243
|
+
params:
|
|
244
|
+
files: []
|
|
245
|
+
|
|
246
|
+
requests:
|
|
247
|
+
- id: upload_file
|
|
248
|
+
type: AwsS3PresignedPostPolicy
|
|
249
|
+
connectionId: uploads_bucket
|
|
250
|
+
payload:
|
|
251
|
+
key:
|
|
252
|
+
_state: file_uploader.file.name
|
|
253
|
+
properties:
|
|
254
|
+
key:
|
|
255
|
+
_payload: key
|
|
256
|
+
- id: download_file
|
|
257
|
+
type: AwsS3PresignedGetObject
|
|
258
|
+
connectionId: uploads_bucket
|
|
259
|
+
payload:
|
|
260
|
+
key:
|
|
261
|
+
_state: selected.key
|
|
262
|
+
responseContentType:
|
|
263
|
+
_state: selected.type
|
|
264
|
+
properties:
|
|
265
|
+
key:
|
|
266
|
+
_payload: key
|
|
267
|
+
responseContentType:
|
|
268
|
+
_payload: responseContentType
|
|
269
|
+
|
|
270
|
+
blocks:
|
|
271
|
+
- id: file_uploader_card
|
|
272
|
+
type: Card
|
|
273
|
+
properties:
|
|
274
|
+
title: Upload Files
|
|
275
|
+
blocks:
|
|
276
|
+
- id: file_uploader
|
|
277
|
+
type: S3UploadPhoto
|
|
278
|
+
properties:
|
|
279
|
+
s3PostPolicyRequestId: upload_file
|
|
280
|
+
button:
|
|
281
|
+
title: Upload
|
|
282
|
+
events:
|
|
283
|
+
onSuccess:
|
|
284
|
+
- id: set_state
|
|
285
|
+
type: SetState
|
|
286
|
+
params:
|
|
287
|
+
files:
|
|
288
|
+
_array.concat:
|
|
289
|
+
- _state: files
|
|
290
|
+
- - _event: meta
|
|
291
|
+
|
|
292
|
+
- id: file_card
|
|
293
|
+
type: Card
|
|
294
|
+
properties:
|
|
295
|
+
title: Files
|
|
296
|
+
blocks:
|
|
297
|
+
- id: files_table
|
|
298
|
+
type: AgGridAlpine
|
|
299
|
+
properties:
|
|
300
|
+
enableCellTextSelection: true
|
|
301
|
+
rowData:
|
|
302
|
+
_state: files
|
|
303
|
+
defaultColDef:
|
|
304
|
+
sortable: true
|
|
305
|
+
resizable: true
|
|
306
|
+
filter: true
|
|
307
|
+
columnDefs:
|
|
308
|
+
- headerName: filename
|
|
309
|
+
field: filename
|
|
310
|
+
- headerName: size
|
|
311
|
+
field: size
|
|
312
|
+
- headerName: type
|
|
313
|
+
field: type
|
|
314
|
+
events:
|
|
315
|
+
onRowClick:
|
|
316
|
+
- id: set_selected_id
|
|
317
|
+
type: SetState
|
|
318
|
+
params:
|
|
319
|
+
selected:
|
|
320
|
+
_event: row
|
|
321
|
+
- id: download_file
|
|
322
|
+
type: Request
|
|
323
|
+
params: download_file
|
|
324
|
+
- id: get_download_link
|
|
325
|
+
type: Link
|
|
326
|
+
messages:
|
|
327
|
+
error: Failed to open file. Check if popups are blocked in your browser.
|
|
328
|
+
params:
|
|
329
|
+
url:
|
|
330
|
+
_request: download_file
|
|
331
|
+
newTab: true
|
|
332
|
+
```
|
|
@@ -38,8 +38,7 @@ const makeOnChangeValue = (s3Parameters, changeEvent)=>{
|
|
|
38
38
|
const { file , fileList } = changeEvent;
|
|
39
39
|
return {
|
|
40
40
|
file: makeFileValue(file, s3Parameters),
|
|
41
|
-
fileList: fileList.map((fl)=>makeFileValue(fl, s3Parameters)
|
|
42
|
-
)
|
|
41
|
+
fileList: fileList.map((fl)=>makeFileValue(fl, s3Parameters))
|
|
43
42
|
};
|
|
44
43
|
};
|
|
45
44
|
const getDisabled = ({ properties , value })=>{
|
|
@@ -66,6 +65,14 @@ const getCustomRequest = ({ methods , setS3Parameters })=>async ({ file , onErr
|
|
|
66
65
|
}
|
|
67
66
|
const { url , fields } = s3PostPolicyResponse.responses.__getS3PostPolicy.response[0];
|
|
68
67
|
const { bucket , key } = fields;
|
|
68
|
+
const meta = {
|
|
69
|
+
bucket,
|
|
70
|
+
key,
|
|
71
|
+
filename: name,
|
|
72
|
+
size,
|
|
73
|
+
type,
|
|
74
|
+
uid
|
|
75
|
+
};
|
|
69
76
|
setS3Parameters((prevState)=>{
|
|
70
77
|
const ret = {
|
|
71
78
|
...prevState
|
|
@@ -95,16 +102,49 @@ const getCustomRequest = ({ methods , setS3Parameters })=>async ({ file , onErr
|
|
|
95
102
|
});
|
|
96
103
|
}
|
|
97
104
|
};
|
|
98
|
-
xhr.addEventListener('error',
|
|
99
|
-
|
|
105
|
+
xhr.addEventListener('error', async (event)=>{
|
|
106
|
+
await methods.triggerEvent({
|
|
107
|
+
name: 'onError',
|
|
108
|
+
event: {
|
|
109
|
+
meta,
|
|
110
|
+
event
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
onError(event);
|
|
114
|
+
});
|
|
115
|
+
xhr.addEventListener('load', async (event)=>{
|
|
116
|
+
await methods.triggerEvent({
|
|
117
|
+
name: 'onSuccess',
|
|
118
|
+
event: {
|
|
119
|
+
meta,
|
|
120
|
+
event
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
onSuccess(event);
|
|
124
|
+
});
|
|
125
|
+
xhr.addEventListener('loadend', async (event)=>{
|
|
126
|
+
await methods.triggerEvent({
|
|
127
|
+
name: 'onDone',
|
|
128
|
+
event: {
|
|
129
|
+
meta,
|
|
130
|
+
event
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
100
134
|
xhr.open('post', url);
|
|
101
135
|
xhr.send(formData);
|
|
102
136
|
} catch (error) {
|
|
103
137
|
console.error(error);
|
|
138
|
+
await methods.triggerEvent({
|
|
139
|
+
name: 'onError',
|
|
140
|
+
event: {
|
|
141
|
+
meta,
|
|
142
|
+
event
|
|
143
|
+
}
|
|
144
|
+
});
|
|
104
145
|
onError(error);
|
|
105
146
|
}
|
|
106
|
-
}
|
|
107
|
-
;
|
|
147
|
+
};
|
|
108
148
|
const S3UploadButtonBlock = ({ blockId , components , events , methods , properties , value })=>{
|
|
109
149
|
// Use state here because we need to set s3 bucket and key as block value
|
|
110
150
|
// The customRequest function does not have access to the updated block value,
|
|
@@ -137,7 +177,7 @@ const S3UploadButtonBlock = ({ blockId , components , events , methods , propert
|
|
|
137
177
|
properties,
|
|
138
178
|
value
|
|
139
179
|
});
|
|
140
|
-
return
|
|
180
|
+
return /*#__PURE__*/ React.createElement(Upload, {
|
|
141
181
|
accept: properties.accept,
|
|
142
182
|
customRequest: customRequest,
|
|
143
183
|
disabled: disabled,
|
|
@@ -162,7 +202,7 @@ const S3UploadButtonBlock = ({ blockId , components , events , methods , propert
|
|
|
162
202
|
...properties.button
|
|
163
203
|
},
|
|
164
204
|
methods: methods
|
|
165
|
-
}))
|
|
205
|
+
}));
|
|
166
206
|
};
|
|
167
207
|
S3UploadButtonBlock.defaultProps = blockDefaultProps;
|
|
168
208
|
S3UploadButtonBlock.meta = {
|