@lowdefy/plugin-aws 4.1.0 → 4.2.1
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/blocks/S3Download/S3Download.js +70 -0
- package/dist/blocks/S3Download/schema.json +85 -0
- package/dist/blocks/S3Download/style.less +17 -0
- package/dist/blocks/S3UploadButton/S3UploadButton.js +25 -144
- package/dist/blocks/S3UploadButton/schema.json +5 -1
- package/dist/blocks/S3UploadDragger/S3UploadDragger.js +101 -0
- package/dist/blocks/S3UploadDragger/schema.json +81 -0
- package/dist/blocks/S3UploadDragger/style.less +17 -0
- package/dist/blocks/S3UploadPhoto/S3UploadPhoto.js +35 -142
- package/dist/blocks/S3UploadPhoto/schema.json +21 -5
- package/dist/blocks/utils/getOnPaste.js +48 -0
- package/dist/blocks/utils/getS3Upload.js +81 -0
- package/dist/blocks/utils/useFileList.js +115 -0
- package/dist/blocks.js +3 -1
- package/dist/connections/AwsS3Bucket/AwsS3PresignedPostPolicy/AwsS3PresignedPostPolicy.js +10 -1
- package/package.json +7 -7
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import React, { useEffect } from 'react';
|
|
16
|
+
import { Upload } from 'antd';
|
|
17
|
+
import { blockDefaultProps } from '@lowdefy/block-utils';
|
|
18
|
+
const downloadFile = async ({ file, methods })=>{
|
|
19
|
+
const s3DownloadPolicy = await methods.triggerEvent({
|
|
20
|
+
name: '__getS3DownloadPolicy',
|
|
21
|
+
event: {
|
|
22
|
+
file
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
window.open(s3DownloadPolicy?.responses?.__getS3DownloadPolicy?.response?.[0]);
|
|
26
|
+
};
|
|
27
|
+
const S3Download = ({ blockId, methods, properties })=>{
|
|
28
|
+
useEffect(()=>{
|
|
29
|
+
methods.registerEvent({
|
|
30
|
+
name: '__getS3DownloadPolicy',
|
|
31
|
+
actions: [
|
|
32
|
+
{
|
|
33
|
+
id: '__getS3DownloadPolicy',
|
|
34
|
+
type: 'Request',
|
|
35
|
+
params: [
|
|
36
|
+
properties.s3GetPolicyRequestId
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
}, []);
|
|
42
|
+
return /*#__PURE__*/ React.createElement(Upload, {
|
|
43
|
+
id: blockId,
|
|
44
|
+
className: methods.makeCssClass([
|
|
45
|
+
properties.style
|
|
46
|
+
]),
|
|
47
|
+
fileList: properties.fileList ?? [],
|
|
48
|
+
onPreview: async (file)=>await downloadFile({
|
|
49
|
+
file,
|
|
50
|
+
methods
|
|
51
|
+
}),
|
|
52
|
+
showUploadList: {
|
|
53
|
+
showRemoveIcon: false,
|
|
54
|
+
showDownloadIcon: true
|
|
55
|
+
},
|
|
56
|
+
onDownload: async (file)=>await downloadFile({
|
|
57
|
+
file,
|
|
58
|
+
methods
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
S3Download.defaultProps = blockDefaultProps;
|
|
63
|
+
S3Download.meta = {
|
|
64
|
+
category: 'display',
|
|
65
|
+
icons: [],
|
|
66
|
+
styles: [
|
|
67
|
+
'blocks/S3Download/style.less'
|
|
68
|
+
]
|
|
69
|
+
};
|
|
70
|
+
export default S3Download;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"properties": {
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["s3GetPolicyRequestId"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"fileList": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"description": "List of files to be downloaded. If files were uploaded using an S3Upload block, the fileList value can just be mapped to this field.",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"required": ["key"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"key": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "S3 file key."
|
|
17
|
+
},
|
|
18
|
+
"lastModified": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "File last modified date."
|
|
21
|
+
},
|
|
22
|
+
"name": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "File name."
|
|
25
|
+
},
|
|
26
|
+
"size": {
|
|
27
|
+
"type": "number",
|
|
28
|
+
"description": "File size in bytes."
|
|
29
|
+
},
|
|
30
|
+
"type": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "File MIME type."
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"s3GetPolicyRequestId": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "Id of a request of type s3GetPolicyRequestId that defines to which S3 bucket and what file should be downloaded.",
|
|
40
|
+
"docs": {
|
|
41
|
+
"displayType": "manual",
|
|
42
|
+
"block": {
|
|
43
|
+
"id": "block_properties_s3GetPolicyRequestId",
|
|
44
|
+
"layout": { "_global": "settings_input_layout" },
|
|
45
|
+
"type": "Label",
|
|
46
|
+
"required": true,
|
|
47
|
+
"properties": {
|
|
48
|
+
"title": "s3GetPolicyRequestId",
|
|
49
|
+
"span": 8,
|
|
50
|
+
"align": "right"
|
|
51
|
+
},
|
|
52
|
+
"blocks": [
|
|
53
|
+
{
|
|
54
|
+
"id": "block_properties_s3GetPolicyRequestId_text",
|
|
55
|
+
"type": "Markdown",
|
|
56
|
+
"style": {
|
|
57
|
+
"color": "#8c8c8c"
|
|
58
|
+
},
|
|
59
|
+
"properties": {
|
|
60
|
+
"content": "Id of a request of type AwsS3PresignedGetPolicy that defines to which S3 bucket and what file should be downloaded."
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"style": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"description": "Css style object to applied to download component.",
|
|
70
|
+
"docs": {
|
|
71
|
+
"displayType": "yaml"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"events": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"properties": {
|
|
79
|
+
"onChange": {
|
|
80
|
+
"type": "array",
|
|
81
|
+
"description": "Triggered when the upload state is changing."
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
@import 'antd/lib/upload/style/index.less';
|
|
@@ -12,146 +12,21 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import React, { useEffect
|
|
15
|
+
*/ import React, { useEffect } from 'react';
|
|
16
16
|
import { blockDefaultProps } from '@lowdefy/block-utils';
|
|
17
|
-
import { get } from '@lowdefy/helpers';
|
|
18
17
|
import { Button } from '@lowdefy/blocks-antd/blocks';
|
|
19
18
|
import { Upload } from 'antd';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const { bucket, key } = get(s3Parameters, uid, {
|
|
23
|
-
default: {}
|
|
24
|
-
});
|
|
25
|
-
return {
|
|
26
|
-
bucket,
|
|
27
|
-
key,
|
|
28
|
-
lastModified,
|
|
29
|
-
name,
|
|
30
|
-
percent,
|
|
31
|
-
size,
|
|
32
|
-
status,
|
|
33
|
-
type,
|
|
34
|
-
uid
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
const makeOnChangeValue = (s3Parameters, changeEvent)=>{
|
|
38
|
-
const { file, fileList } = changeEvent;
|
|
39
|
-
return {
|
|
40
|
-
file: makeFileValue(file, s3Parameters),
|
|
41
|
-
fileList: fileList.map((fl)=>makeFileValue(fl, s3Parameters))
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
const getDisabled = ({ properties, value })=>{
|
|
45
|
-
if (properties.disabled) return true;
|
|
46
|
-
return properties.singleFile && value && (value.fileList || []).length >= 1;
|
|
47
|
-
};
|
|
48
|
-
const getCustomRequest = ({ methods, setS3Parameters })=>async ({ file, onError, onProgress, onSuccess })=>{
|
|
49
|
-
let meta;
|
|
50
|
-
try {
|
|
51
|
-
const { name, size, type, uid } = file;
|
|
52
|
-
const s3PostPolicyResponse = await methods.triggerEvent({
|
|
53
|
-
name: '__getS3PostPolicy',
|
|
54
|
-
event: {
|
|
55
|
-
filename: name,
|
|
56
|
-
size,
|
|
57
|
-
type,
|
|
58
|
-
uid
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
if (s3PostPolicyResponse.success !== true) {
|
|
62
|
-
throw new Error('S3 post policy request error.');
|
|
63
|
-
}
|
|
64
|
-
const { url, fields } = s3PostPolicyResponse.responses.__getS3PostPolicy.response[0];
|
|
65
|
-
const { bucket, key } = fields;
|
|
66
|
-
meta = {
|
|
67
|
-
bucket,
|
|
68
|
-
key,
|
|
69
|
-
filename: name,
|
|
70
|
-
size,
|
|
71
|
-
type,
|
|
72
|
-
uid
|
|
73
|
-
};
|
|
74
|
-
setS3Parameters((prevState)=>{
|
|
75
|
-
const ret = {
|
|
76
|
-
...prevState
|
|
77
|
-
};
|
|
78
|
-
ret[uid] = {
|
|
79
|
-
bucket,
|
|
80
|
-
key
|
|
81
|
-
};
|
|
82
|
-
return ret;
|
|
83
|
-
});
|
|
84
|
-
// Set 20 % progress on policy is acquired else user waits to long before progress is reported
|
|
85
|
-
onProgress({
|
|
86
|
-
percent: 20
|
|
87
|
-
});
|
|
88
|
-
// Create FormData with all required fields in S3 policy
|
|
89
|
-
const formData = new FormData();
|
|
90
|
-
Object.keys(fields).forEach((field)=>{
|
|
91
|
-
formData.append(field, fields[field]);
|
|
92
|
-
});
|
|
93
|
-
// file needs to be the last field in the form
|
|
94
|
-
formData.append('file', file);
|
|
95
|
-
const xhr = new XMLHttpRequest();
|
|
96
|
-
xhr.upload.onprogress = (event)=>{
|
|
97
|
-
if (event.lengthComputable) {
|
|
98
|
-
onProgress({
|
|
99
|
-
percent: event.loaded / event.total * 80 + 20
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
xhr.addEventListener('error', async (event)=>{
|
|
104
|
-
await methods.triggerEvent({
|
|
105
|
-
name: 'onError',
|
|
106
|
-
event: {
|
|
107
|
-
meta,
|
|
108
|
-
event
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
onError(event);
|
|
112
|
-
});
|
|
113
|
-
xhr.addEventListener('load', async (event)=>{
|
|
114
|
-
await methods.triggerEvent({
|
|
115
|
-
name: 'onSuccess',
|
|
116
|
-
event: {
|
|
117
|
-
meta,
|
|
118
|
-
event
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
onSuccess(event);
|
|
122
|
-
});
|
|
123
|
-
xhr.addEventListener('loadend', async (event)=>{
|
|
124
|
-
await methods.triggerEvent({
|
|
125
|
-
name: 'onDone',
|
|
126
|
-
event: {
|
|
127
|
-
meta,
|
|
128
|
-
event
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
xhr.open('post', url);
|
|
133
|
-
xhr.send(formData);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error(error);
|
|
136
|
-
await methods.triggerEvent({
|
|
137
|
-
name: 'onError',
|
|
138
|
-
event: {
|
|
139
|
-
meta,
|
|
140
|
-
error
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
onError(error);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
19
|
+
import useFileList from '../utils/useFileList.js';
|
|
20
|
+
import getS3Upload from '../utils/getS3Upload.js';
|
|
146
21
|
const S3UploadButtonBlock = ({ blockId, components, events, methods, properties, value })=>{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
22
|
+
const [state, loadFileList, setFileList, removeFile, setValue] = useFileList({
|
|
23
|
+
properties,
|
|
24
|
+
methods,
|
|
25
|
+
value
|
|
26
|
+
});
|
|
27
|
+
const s3UploadRequest = getS3Upload({
|
|
153
28
|
methods,
|
|
154
|
-
|
|
29
|
+
setFileList
|
|
155
30
|
});
|
|
156
31
|
useEffect(()=>{
|
|
157
32
|
methods.setValue({
|
|
@@ -171,19 +46,25 @@ const S3UploadButtonBlock = ({ blockId, components, events, methods, properties,
|
|
|
171
46
|
]
|
|
172
47
|
});
|
|
173
48
|
}, []);
|
|
174
|
-
|
|
175
|
-
|
|
49
|
+
useEffect(()=>{
|
|
50
|
+
if (JSON.stringify(value) !== JSON.stringify(state)) {
|
|
51
|
+
setValue(value);
|
|
52
|
+
}
|
|
53
|
+
}, [
|
|
176
54
|
value
|
|
177
|
-
|
|
55
|
+
]);
|
|
178
56
|
return /*#__PURE__*/ React.createElement(Upload, {
|
|
179
|
-
accept: properties.accept,
|
|
180
|
-
|
|
181
|
-
|
|
57
|
+
accept: properties.accept ?? '*',
|
|
58
|
+
beforeUpload: loadFileList,
|
|
59
|
+
customRequest: s3UploadRequest,
|
|
60
|
+
disabled: properties.disabled,
|
|
61
|
+
fileList: state.fileList,
|
|
182
62
|
id: blockId,
|
|
63
|
+
maxCount: properties.maxCount,
|
|
183
64
|
multiple: !properties.singleFile,
|
|
65
|
+
onRemove: removeFile,
|
|
184
66
|
showUploadList: properties.showUploadList,
|
|
185
|
-
onChange: (
|
|
186
|
-
methods.setValue(makeOnChangeValue(s3Parameters, event));
|
|
67
|
+
onChange: ()=>{
|
|
187
68
|
methods.triggerEvent({
|
|
188
69
|
name: 'onChange'
|
|
189
70
|
});
|
|
@@ -193,7 +74,7 @@ const S3UploadButtonBlock = ({ blockId, components, events, methods, properties,
|
|
|
193
74
|
components: components,
|
|
194
75
|
events: events,
|
|
195
76
|
properties: {
|
|
196
|
-
disabled,
|
|
77
|
+
disabled: properties.disabled,
|
|
197
78
|
icon: 'AiOutlineUpload',
|
|
198
79
|
title: 'Upload',
|
|
199
80
|
type: 'default',
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"type": "boolean",
|
|
25
25
|
"description": "Disable the file input."
|
|
26
26
|
},
|
|
27
|
+
"maxCount": {
|
|
28
|
+
"type": "number",
|
|
29
|
+
"description": "Maximum number of files that can be uploaded."
|
|
30
|
+
},
|
|
27
31
|
"s3PostPolicyRequestId": {
|
|
28
32
|
"type": "string",
|
|
29
33
|
"description": "Id of a request of type AwsS3PresignedPostPolicy that defines to which S3 bucket and how the file should be uploaded.",
|
|
@@ -63,7 +67,7 @@
|
|
|
63
67
|
"singleFile": {
|
|
64
68
|
"type": "boolean",
|
|
65
69
|
"default": false,
|
|
66
|
-
"description": "Only allow a single file to be uploaded. Only one file can be selected in the prompt
|
|
70
|
+
"description": "Only allow a single file to be uploaded. Only one file can be selected in the prompt."
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
73
|
},
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import React, { useEffect } from 'react';
|
|
16
|
+
import { Upload } from 'antd';
|
|
17
|
+
import { blockDefaultProps, renderHtml } from '@lowdefy/block-utils';
|
|
18
|
+
import useFileList from '../utils/useFileList.js';
|
|
19
|
+
import getS3Upload from '../utils/getS3Upload.js';
|
|
20
|
+
import getOnPaste from '../utils/getOnPaste.js';
|
|
21
|
+
const { Dragger } = Upload;
|
|
22
|
+
const S3UploadDragger = ({ blockId, methods, properties, value })=>{
|
|
23
|
+
const [state, loadFileList, setFileList, removeFile, setValue] = useFileList({
|
|
24
|
+
properties,
|
|
25
|
+
methods,
|
|
26
|
+
value
|
|
27
|
+
});
|
|
28
|
+
const s3UploadRequest = getS3Upload({
|
|
29
|
+
methods,
|
|
30
|
+
setFileList
|
|
31
|
+
});
|
|
32
|
+
const onPaste = getOnPaste({
|
|
33
|
+
s3UploadRequest,
|
|
34
|
+
properties
|
|
35
|
+
});
|
|
36
|
+
useEffect(()=>{
|
|
37
|
+
methods.registerEvent({
|
|
38
|
+
name: '__getS3PostPolicy',
|
|
39
|
+
actions: [
|
|
40
|
+
{
|
|
41
|
+
id: '__getS3PostPolicy',
|
|
42
|
+
type: 'Request',
|
|
43
|
+
params: [
|
|
44
|
+
properties.s3PostPolicyRequestId
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
});
|
|
49
|
+
}, []);
|
|
50
|
+
useEffect(()=>{
|
|
51
|
+
if (JSON.stringify(value) !== JSON.stringify(state)) {
|
|
52
|
+
setValue(value);
|
|
53
|
+
}
|
|
54
|
+
}, [
|
|
55
|
+
value
|
|
56
|
+
]);
|
|
57
|
+
useEffect(()=>{
|
|
58
|
+
methods.registerMethod('uploadFromPaste', async ()=>{
|
|
59
|
+
await onPaste();
|
|
60
|
+
});
|
|
61
|
+
}, [
|
|
62
|
+
onPaste
|
|
63
|
+
]);
|
|
64
|
+
return /*#__PURE__*/ React.createElement("div", {
|
|
65
|
+
id: blockId,
|
|
66
|
+
onPaste: onPaste
|
|
67
|
+
}, /*#__PURE__*/ React.createElement(Dragger, {
|
|
68
|
+
accept: properties.accept ?? '*',
|
|
69
|
+
beforeUpload: loadFileList,
|
|
70
|
+
className: methods.makeCssClass([
|
|
71
|
+
properties.style
|
|
72
|
+
]),
|
|
73
|
+
customRequest: s3UploadRequest,
|
|
74
|
+
disabled: properties.disabled,
|
|
75
|
+
fileList: state.fileList,
|
|
76
|
+
maxCount: properties.maxCount,
|
|
77
|
+
multiple: !properties.singleFile,
|
|
78
|
+
onRemove: removeFile,
|
|
79
|
+
showUploadList: properties.showUploadList,
|
|
80
|
+
onChange: ()=>{
|
|
81
|
+
methods.triggerEvent({
|
|
82
|
+
name: 'onChange'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}, /*#__PURE__*/ React.createElement("div", {
|
|
86
|
+
className: "ant-upload-hint"
|
|
87
|
+
}, renderHtml({
|
|
88
|
+
html: properties.title ?? 'Click or drag to add a file.',
|
|
89
|
+
methods
|
|
90
|
+
}))));
|
|
91
|
+
};
|
|
92
|
+
S3UploadDragger.defaultProps = blockDefaultProps;
|
|
93
|
+
S3UploadDragger.meta = {
|
|
94
|
+
valueType: 'object',
|
|
95
|
+
category: 'input',
|
|
96
|
+
icons: [],
|
|
97
|
+
styles: [
|
|
98
|
+
'blocks/S3UploadDragger/style.less'
|
|
99
|
+
]
|
|
100
|
+
};
|
|
101
|
+
export default S3UploadDragger;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"properties": {
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["s3PostPolicyRequestId"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"title": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Title of the file input to be displayed on the draggable area."
|
|
10
|
+
},
|
|
11
|
+
"accept": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "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."
|
|
14
|
+
},
|
|
15
|
+
"disabled": {
|
|
16
|
+
"type": "boolean",
|
|
17
|
+
"description": "Disable the file input."
|
|
18
|
+
},
|
|
19
|
+
"maxCount": {
|
|
20
|
+
"type": "number",
|
|
21
|
+
"description": "Maximum number of files that can be uploaded."
|
|
22
|
+
},
|
|
23
|
+
"s3PostPolicyRequestId": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Id of a request of type AwsS3PresignedPostPolicy that defines to which S3 bucket and how the file should be uploaded.",
|
|
26
|
+
"docs": {
|
|
27
|
+
"displayType": "manual",
|
|
28
|
+
"block": {
|
|
29
|
+
"id": "block_properties_s3PostPolicyRequestId",
|
|
30
|
+
"layout": { "_global": "settings_input_layout" },
|
|
31
|
+
"type": "Label",
|
|
32
|
+
"required": true,
|
|
33
|
+
"properties": {
|
|
34
|
+
"title": "s3PostPolicyRequestId",
|
|
35
|
+
"span": 8,
|
|
36
|
+
"align": "right"
|
|
37
|
+
},
|
|
38
|
+
"blocks": [
|
|
39
|
+
{
|
|
40
|
+
"id": "block_properties_s3PostPolicyRequestId_text",
|
|
41
|
+
"type": "Markdown",
|
|
42
|
+
"style": {
|
|
43
|
+
"color": "#8c8c8c"
|
|
44
|
+
},
|
|
45
|
+
"properties": {
|
|
46
|
+
"content": "Id of a request of type AwsS3PresignedPostPolicy that defines to which S3 bucket and how the file should be uploaded."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"showUploadList": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"default": true,
|
|
56
|
+
"description": "Whether to show default upload list."
|
|
57
|
+
},
|
|
58
|
+
"singleFile": {
|
|
59
|
+
"type": "boolean",
|
|
60
|
+
"default": false,
|
|
61
|
+
"description": "Only allow a single file to be uploaded. Only one file can be selected in the prompt."
|
|
62
|
+
},
|
|
63
|
+
"style": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"description": "Css style object to applied to draggable area.",
|
|
66
|
+
"docs": {
|
|
67
|
+
"displayType": "yaml"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"events": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {
|
|
75
|
+
"onChange": {
|
|
76
|
+
"type": "array",
|
|
77
|
+
"description": "Triggered when the upload state is changing."
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
@import 'antd/lib/upload/style/index.less';
|
|
@@ -13,144 +13,20 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React, { useEffect, useState } from 'react';
|
|
16
|
-
import { blockDefaultProps } from '@lowdefy/block-utils';
|
|
17
|
-
import { get } from '@lowdefy/helpers';
|
|
16
|
+
import { blockDefaultProps, renderHtml } from '@lowdefy/block-utils';
|
|
18
17
|
import { Upload } from 'antd';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const { bucket, key } = get(s3Parameters, uid, {
|
|
22
|
-
default: {}
|
|
23
|
-
});
|
|
24
|
-
return {
|
|
25
|
-
bucket,
|
|
26
|
-
key,
|
|
27
|
-
lastModified,
|
|
28
|
-
name,
|
|
29
|
-
percent,
|
|
30
|
-
size,
|
|
31
|
-
status,
|
|
32
|
-
type,
|
|
33
|
-
uid
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
const makeOnChangeValue = (s3Parameters, changeEvent)=>{
|
|
37
|
-
const { file, fileList } = changeEvent;
|
|
38
|
-
return {
|
|
39
|
-
file: makeFileValue(file, s3Parameters),
|
|
40
|
-
fileList: fileList.map((fl)=>makeFileValue(fl, s3Parameters))
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
const getCustomRequest = ({ methods, setS3Parameters, setLoading })=>async ({ file, onError, onProgress, onSuccess })=>{
|
|
44
|
-
let meta;
|
|
45
|
-
try {
|
|
46
|
-
setLoading(true);
|
|
47
|
-
const { name, size, type, uid } = file;
|
|
48
|
-
if (size > 1024 * 1024 * 10) throw new Error('File cannot exceed 10mb.');
|
|
49
|
-
const s3PostPolicyResponse = await methods.triggerEvent({
|
|
50
|
-
name: '__getS3PostPolicy',
|
|
51
|
-
event: {
|
|
52
|
-
filename: name,
|
|
53
|
-
size,
|
|
54
|
-
type,
|
|
55
|
-
uid
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
if (s3PostPolicyResponse.success !== true) {
|
|
59
|
-
throw new Error('S3 post policy request error.');
|
|
60
|
-
}
|
|
61
|
-
const { url, fields } = s3PostPolicyResponse.responses.__getS3PostPolicy.response[0];
|
|
62
|
-
const { bucket, key } = fields;
|
|
63
|
-
meta = {
|
|
64
|
-
bucket,
|
|
65
|
-
key,
|
|
66
|
-
filename: name,
|
|
67
|
-
size,
|
|
68
|
-
type,
|
|
69
|
-
uid
|
|
70
|
-
};
|
|
71
|
-
setS3Parameters((prevState)=>{
|
|
72
|
-
const ret = {
|
|
73
|
-
...prevState
|
|
74
|
-
};
|
|
75
|
-
ret[uid] = {
|
|
76
|
-
bucket,
|
|
77
|
-
key
|
|
78
|
-
};
|
|
79
|
-
return ret;
|
|
80
|
-
});
|
|
81
|
-
// Set 20 % progress on policy is acquired else user waits to long before progress is reported
|
|
82
|
-
onProgress({
|
|
83
|
-
percent: 20
|
|
84
|
-
});
|
|
85
|
-
// Create FormData with all required fields in S3 policy
|
|
86
|
-
const formData = new FormData();
|
|
87
|
-
Object.keys(fields).forEach((field)=>{
|
|
88
|
-
formData.append(field, fields[field]);
|
|
89
|
-
});
|
|
90
|
-
// file needs to be the last field in the form
|
|
91
|
-
formData.append('file', file);
|
|
92
|
-
const xhr = new XMLHttpRequest();
|
|
93
|
-
xhr.upload.onprogress = (event)=>{
|
|
94
|
-
if (event.lengthComputable) {
|
|
95
|
-
onProgress({
|
|
96
|
-
percent: event.loaded / event.total * 80 + 20
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
xhr.addEventListener('error', async (event)=>{
|
|
101
|
-
await methods.triggerEvent({
|
|
102
|
-
name: 'onError',
|
|
103
|
-
event: {
|
|
104
|
-
meta,
|
|
105
|
-
event
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
onError(event);
|
|
109
|
-
});
|
|
110
|
-
xhr.addEventListener('load', async (event)=>{
|
|
111
|
-
await methods.triggerEvent({
|
|
112
|
-
name: 'onSuccess',
|
|
113
|
-
event: {
|
|
114
|
-
meta,
|
|
115
|
-
event
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
onSuccess(event);
|
|
119
|
-
});
|
|
120
|
-
xhr.addEventListener('loadend', async (event)=>{
|
|
121
|
-
await methods.triggerEvent({
|
|
122
|
-
name: 'onDone',
|
|
123
|
-
event: {
|
|
124
|
-
meta,
|
|
125
|
-
event
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
setLoading(false);
|
|
129
|
-
});
|
|
130
|
-
xhr.open('post', url);
|
|
131
|
-
xhr.send(formData);
|
|
132
|
-
} catch (error) {
|
|
133
|
-
console.error(error);
|
|
134
|
-
await methods.triggerEvent({
|
|
135
|
-
name: 'onError',
|
|
136
|
-
event: {
|
|
137
|
-
meta,
|
|
138
|
-
error
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
onError(error);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
18
|
+
import useFileList from '../utils/useFileList.js';
|
|
19
|
+
import getS3Upload from '../utils/getS3Upload.js';
|
|
144
20
|
const S3UploadPhoto = ({ blockId, components: { Icon }, events, methods, properties, value })=>{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
21
|
+
const [state, loadFileList, setFileList, removeFile, setValue] = useFileList({
|
|
22
|
+
properties,
|
|
23
|
+
methods,
|
|
24
|
+
value
|
|
25
|
+
});
|
|
150
26
|
const [loading, setLoading] = useState(false);
|
|
151
|
-
const
|
|
27
|
+
const s3UploadRequest = getS3Upload({
|
|
152
28
|
methods,
|
|
153
|
-
|
|
29
|
+
setFileList,
|
|
154
30
|
setLoading
|
|
155
31
|
});
|
|
156
32
|
useEffect(()=>{
|
|
@@ -171,22 +47,36 @@ const S3UploadPhoto = ({ blockId, components: { Icon }, events, methods, propert
|
|
|
171
47
|
]
|
|
172
48
|
});
|
|
173
49
|
}, []);
|
|
50
|
+
useEffect(()=>{
|
|
51
|
+
if (JSON.stringify(value) !== JSON.stringify(state)) {
|
|
52
|
+
setValue(value);
|
|
53
|
+
}
|
|
54
|
+
}, [
|
|
55
|
+
value
|
|
56
|
+
]);
|
|
174
57
|
return /*#__PURE__*/ React.createElement(Upload, {
|
|
175
|
-
listType: "picture-card",
|
|
176
|
-
className: "avatar-uploader",
|
|
177
58
|
accept: "image/*",
|
|
178
|
-
|
|
179
|
-
|
|
59
|
+
beforeUpload: loadFileList,
|
|
60
|
+
className: "avatar-uploader",
|
|
61
|
+
customRequest: s3UploadRequest,
|
|
62
|
+
disabled: properties.disabled,
|
|
63
|
+
fileList: state.fileList,
|
|
180
64
|
id: blockId,
|
|
65
|
+
listType: "picture-card",
|
|
66
|
+
maxCount: properties.maxCount,
|
|
181
67
|
multiple: !properties.singleFile,
|
|
68
|
+
onRemove: removeFile,
|
|
182
69
|
showUploadList: properties.showUploadList,
|
|
183
|
-
onChange: (
|
|
184
|
-
methods.setValue(makeOnChangeValue(s3Parameters, event));
|
|
70
|
+
onChange: ()=>{
|
|
185
71
|
methods.triggerEvent({
|
|
186
72
|
name: 'onChange'
|
|
187
73
|
});
|
|
188
74
|
}
|
|
189
|
-
}, /*#__PURE__*/ React.createElement("div",
|
|
75
|
+
}, /*#__PURE__*/ React.createElement("div", {
|
|
76
|
+
className: methods.makeCssClass([
|
|
77
|
+
properties.style
|
|
78
|
+
])
|
|
79
|
+
}, loading ? /*#__PURE__*/ React.createElement(Icon, {
|
|
190
80
|
blockId: `${blockId}_icon`,
|
|
191
81
|
events: events,
|
|
192
82
|
properties: {
|
|
@@ -204,7 +94,10 @@ const S3UploadPhoto = ({ blockId, components: { Icon }, events, methods, propert
|
|
|
204
94
|
style: {
|
|
205
95
|
marginTop: 8
|
|
206
96
|
}
|
|
207
|
-
},
|
|
97
|
+
}, renderHtml({
|
|
98
|
+
html: properties.title ?? 'Upload image',
|
|
99
|
+
methods
|
|
100
|
+
}))));
|
|
208
101
|
};
|
|
209
102
|
S3UploadPhoto.defaultProps = blockDefaultProps;
|
|
210
103
|
S3UploadPhoto.meta = {
|
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
"type": "object",
|
|
5
5
|
"required": ["s3PostPolicyRequestId"],
|
|
6
6
|
"properties": {
|
|
7
|
+
"title": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Title of the file input to be displayed instead of 'Upload image'.",
|
|
10
|
+
"default": "Upload image"
|
|
11
|
+
},
|
|
12
|
+
"disabled": {
|
|
13
|
+
"type": "boolean",
|
|
14
|
+
"description": "Disable the file input."
|
|
15
|
+
},
|
|
16
|
+
"maxCount": {
|
|
17
|
+
"type": "number",
|
|
18
|
+
"description": "Maximum number of files that can be uploaded."
|
|
19
|
+
},
|
|
7
20
|
"s3PostPolicyRequestId": {
|
|
8
21
|
"type": "string",
|
|
9
22
|
"description": "Id of a request of type AwsS3PresignedPostPolicy that defines to which S3 bucket and how the file should be uploaded.",
|
|
@@ -43,7 +56,14 @@
|
|
|
43
56
|
"singleFile": {
|
|
44
57
|
"type": "boolean",
|
|
45
58
|
"default": false,
|
|
46
|
-
"description": "Only allow a single file to be uploaded. Only one file can be selected in the prompt
|
|
59
|
+
"description": "Only allow a single file to be uploaded. Only one file can be selected in the prompt."
|
|
60
|
+
},
|
|
61
|
+
"style": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"description": "Css style object to applied to draggable area.",
|
|
64
|
+
"docs": {
|
|
65
|
+
"displayType": "yaml"
|
|
66
|
+
}
|
|
47
67
|
}
|
|
48
68
|
}
|
|
49
69
|
},
|
|
@@ -53,10 +73,6 @@
|
|
|
53
73
|
"onChange": {
|
|
54
74
|
"type": "array",
|
|
55
75
|
"description": "Triggered when the upload state is changing."
|
|
56
|
-
},
|
|
57
|
-
"onClick": {
|
|
58
|
-
"type": "array",
|
|
59
|
-
"description": "Triggered when the upload button is clicked."
|
|
60
76
|
}
|
|
61
77
|
}
|
|
62
78
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ const getFileFromEvent = async (event)=>{
|
|
16
|
+
const items = event.clipboardData.items;
|
|
17
|
+
for (const item of items){
|
|
18
|
+
if (item.kind === 'file') {
|
|
19
|
+
return item.getAsFile();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const getFileFromNavigator = async ()=>{
|
|
24
|
+
const items = await navigator.clipboard.read();
|
|
25
|
+
for (const item of items){
|
|
26
|
+
for (const type of item.types){
|
|
27
|
+
if (type === 'image/png' || type === 'image/jpeg') {
|
|
28
|
+
const blob = await item.getType(type);
|
|
29
|
+
return new File([
|
|
30
|
+
blob
|
|
31
|
+
], 'clipboard.png', {
|
|
32
|
+
type: blob.type
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const getOnPaste = ({ s3UploadRequest, properties })=>async (event)=>{
|
|
39
|
+
event?.preventDefault?.();
|
|
40
|
+
if (properties.disabled) return;
|
|
41
|
+
const file = event ? await getFileFromEvent(event) : await getFileFromNavigator();
|
|
42
|
+
if (!file) return;
|
|
43
|
+
file.uid = `${properties.fileName ?? file.name ?? 'clipboard'}-${Date.now()}`;
|
|
44
|
+
await s3UploadRequest({
|
|
45
|
+
file
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
export default getOnPaste;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ const getS3Upload = ({ methods, setFileList, setLoading = ()=>null })=>async ({ file })=>{
|
|
16
|
+
if (!file) {
|
|
17
|
+
console.warn('File is undefined in useS3Upload');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
setLoading(true);
|
|
22
|
+
const { lastModified, name, size, type, uid } = file;
|
|
23
|
+
const s3PostPolicyResponse = await methods.triggerEvent({
|
|
24
|
+
name: '__getS3PostPolicy',
|
|
25
|
+
event: {
|
|
26
|
+
file: {
|
|
27
|
+
name,
|
|
28
|
+
lastModified,
|
|
29
|
+
size,
|
|
30
|
+
type,
|
|
31
|
+
uid
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (s3PostPolicyResponse.success !== true) {
|
|
36
|
+
throw new Error('S3 post policy request error.');
|
|
37
|
+
}
|
|
38
|
+
const { url, fields = {} } = s3PostPolicyResponse.responses.__getS3PostPolicy.response[0];
|
|
39
|
+
const { bucket, key } = fields;
|
|
40
|
+
file.bucket = bucket;
|
|
41
|
+
file.key = key;
|
|
42
|
+
file.percent = 20;
|
|
43
|
+
const formData = new FormData();
|
|
44
|
+
Object.keys(fields).forEach((field)=>{
|
|
45
|
+
formData.append(field, fields[field]);
|
|
46
|
+
});
|
|
47
|
+
formData.append('file', file);
|
|
48
|
+
const xhr = new XMLHttpRequest();
|
|
49
|
+
xhr.upload.onprogress = async (event)=>{
|
|
50
|
+
if (event.lengthComputable) {
|
|
51
|
+
await setFileList({
|
|
52
|
+
event: 'onProgress',
|
|
53
|
+
file,
|
|
54
|
+
percent: event.loaded / event.total * 80 + 20
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
xhr.addEventListener('error', async ()=>{
|
|
59
|
+
await setFileList({
|
|
60
|
+
event: 'onError',
|
|
61
|
+
file
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
xhr.addEventListener('loadend', async ()=>{
|
|
65
|
+
await setFileList({
|
|
66
|
+
event: 'onSuccess',
|
|
67
|
+
file
|
|
68
|
+
});
|
|
69
|
+
setLoading(false);
|
|
70
|
+
});
|
|
71
|
+
xhr.open('post', url);
|
|
72
|
+
xhr.send(formData);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error(error);
|
|
75
|
+
await setFileList({
|
|
76
|
+
event: 'onError',
|
|
77
|
+
file
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
export default getS3Upload;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2024 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { useState } from 'react';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
const useFileList = ({ properties, methods, value = {} })=>{
|
|
18
|
+
const checkedValue = (value)=>{
|
|
19
|
+
let file = type.isObject(value?.file) ? value.file : null;
|
|
20
|
+
if (!file && type.isObject(value?.fileList?.[0])) {
|
|
21
|
+
file = value.fileList[0];
|
|
22
|
+
}
|
|
23
|
+
const fileList = type.isArray(value?.fileList) ? value.fileList : [];
|
|
24
|
+
if (properties.singleFile === true) {
|
|
25
|
+
fileList.splice(1);
|
|
26
|
+
}
|
|
27
|
+
if (type.isInt(properties.maxCount)) {
|
|
28
|
+
fileList.splice(properties.maxCount);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
file,
|
|
32
|
+
fileList
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const [state, setState] = useState(checkedValue(value));
|
|
36
|
+
const setValue = (stateValue)=>{
|
|
37
|
+
setState(()=>{
|
|
38
|
+
return checkedValue(stateValue);
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
const setFileList = async ({ event, file, percent })=>{
|
|
42
|
+
if (!file) {
|
|
43
|
+
throw new Error('File is undefined in useFileList');
|
|
44
|
+
}
|
|
45
|
+
// destruct the file object to avoid the file object being mutated.
|
|
46
|
+
const { bucket, key, lastModified, name, size, status, type, uid } = file;
|
|
47
|
+
const fileObj = {
|
|
48
|
+
bucket,
|
|
49
|
+
key,
|
|
50
|
+
lastModified,
|
|
51
|
+
name,
|
|
52
|
+
percent: percent ?? file.percent ?? 0,
|
|
53
|
+
size,
|
|
54
|
+
status,
|
|
55
|
+
type,
|
|
56
|
+
uid,
|
|
57
|
+
url: file instanceof Blob || file instanceof File ? URL.createObjectURL(file) : null
|
|
58
|
+
};
|
|
59
|
+
switch(event){
|
|
60
|
+
case 'onProgress':
|
|
61
|
+
fileObj.status = 'uploading';
|
|
62
|
+
fileObj.percent = percent ?? fileObj.percent;
|
|
63
|
+
break;
|
|
64
|
+
case 'onSuccess':
|
|
65
|
+
fileObj.status = 'done';
|
|
66
|
+
fileObj.percent = 100;
|
|
67
|
+
break;
|
|
68
|
+
case 'onRemove':
|
|
69
|
+
fileObj.status = 'removed';
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
fileObj.status = 'error';
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
state.fileList.splice(state.fileList.findIndex((f)=>f.uid === fileObj.uid), 1, fileObj);
|
|
76
|
+
const nextState = checkedValue({
|
|
77
|
+
file: fileObj,
|
|
78
|
+
fileList: state.fileList
|
|
79
|
+
});
|
|
80
|
+
await methods.triggerEvent({
|
|
81
|
+
name: event,
|
|
82
|
+
event: nextState
|
|
83
|
+
});
|
|
84
|
+
setValue(nextState);
|
|
85
|
+
methods.setValue(nextState);
|
|
86
|
+
};
|
|
87
|
+
const loadFileList = (file, nextFiles)=>{
|
|
88
|
+
if (properties.singleFile === true && nextFiles.filter((f)=>type.isString(f.uid)).length > 1) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (type.isInt(properties.maxCount) && nextFiles.filter((f)=>type.isString(f.uid)).length > properties.maxCount) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
setValue({
|
|
95
|
+
file,
|
|
96
|
+
fileList: [
|
|
97
|
+
...nextFiles,
|
|
98
|
+
...state.fileList
|
|
99
|
+
]
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
const removeFile = (file)=>{
|
|
103
|
+
state.fileList.splice(state.fileList.findIndex((f)=>f.uid === file.uid), 1);
|
|
104
|
+
setValue(state);
|
|
105
|
+
methods.setValue(state);
|
|
106
|
+
};
|
|
107
|
+
return [
|
|
108
|
+
state,
|
|
109
|
+
loadFileList,
|
|
110
|
+
setFileList,
|
|
111
|
+
removeFile,
|
|
112
|
+
setValue
|
|
113
|
+
];
|
|
114
|
+
};
|
|
115
|
+
export default useFileList;
|
package/dist/blocks.js
CHANGED
|
@@ -12,5 +12,7 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ export { default as
|
|
15
|
+
*/ export { default as S3Download } from './blocks/S3Download/S3Download.js';
|
|
16
|
+
export { default as S3UploadDragger } from './blocks/S3UploadDragger/S3UploadDragger.js';
|
|
17
|
+
export { default as S3UploadButton } from './blocks/S3UploadButton/S3UploadButton.js';
|
|
16
18
|
export { default as S3UploadPhoto } from './blocks/S3UploadPhoto/S3UploadPhoto.js';
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import AWS from 'aws-sdk';
|
|
16
16
|
import schema from './schema.js';
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
17
18
|
function AwsS3PresignedPostPolicy({ request, connection }) {
|
|
18
19
|
const { accessKeyId, secretAccessKey, region, bucket } = connection;
|
|
19
|
-
const { acl, conditions, expires, key } = request;
|
|
20
|
+
const { acl, conditions, expires, key, fields = {} } = request;
|
|
20
21
|
const params = {
|
|
21
22
|
Bucket: bucket,
|
|
22
23
|
Fields: {
|
|
@@ -32,6 +33,14 @@ function AwsS3PresignedPostPolicy({ request, connection }) {
|
|
|
32
33
|
if (acl) {
|
|
33
34
|
params.Fields.acl = acl;
|
|
34
35
|
}
|
|
36
|
+
if (type.isObject(fields) === false) {
|
|
37
|
+
throw new Error('properties.fields must be an object.');
|
|
38
|
+
}
|
|
39
|
+
Object.keys(fields).forEach((field)=>{
|
|
40
|
+
if (fields[field]) {
|
|
41
|
+
params.Fields[field] = fields[field];
|
|
42
|
+
}
|
|
43
|
+
});
|
|
35
44
|
const s3 = new AWS.S3({
|
|
36
45
|
accessKeyId,
|
|
37
46
|
secretAccessKey,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/plugin-aws",
|
|
3
|
-
"version": "4.1
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"dist/*"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@lowdefy/block-utils": "4.1
|
|
44
|
-
"@lowdefy/blocks-antd": "4.1
|
|
45
|
-
"@lowdefy/helpers": "4.1
|
|
43
|
+
"@lowdefy/block-utils": "4.2.1",
|
|
44
|
+
"@lowdefy/blocks-antd": "4.2.1",
|
|
45
|
+
"@lowdefy/helpers": "4.2.1",
|
|
46
46
|
"antd": "4.24.14",
|
|
47
47
|
"aws-sdk": "2.1459.0",
|
|
48
48
|
"react": "18.2.0",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@emotion/jest": "11.10.5",
|
|
53
|
-
"@lowdefy/ajv": "4.1
|
|
54
|
-
"@lowdefy/block-dev": "4.1
|
|
55
|
-
"@lowdefy/jest-yaml-transform": "4.1
|
|
53
|
+
"@lowdefy/ajv": "4.2.1",
|
|
54
|
+
"@lowdefy/block-dev": "4.2.1",
|
|
55
|
+
"@lowdefy/jest-yaml-transform": "4.2.1",
|
|
56
56
|
"@swc/cli": "0.1.63",
|
|
57
57
|
"@swc/core": "1.3.99",
|
|
58
58
|
"@swc/jest": "0.2.29",
|