Skip to content

Commit 47a275e

Browse files
authored
Merge pull request #66 from 8base/PRODUCT-3088
feat: custosm s3 bucket
2 parents 2552af1 + d27b6d3 commit 47a275e

File tree

14 files changed

+13098
-12169
lines changed

14 files changed

+13098
-12169
lines changed

.github/workflows/checks.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ jobs:
2424
- name: Run linter
2525
run: yarn lint
2626

27-
- name: Run prettier
27+
- name: Run prettierWrite
28+
run: yarn prettier:write
29+
30+
- name: Run prettier
2831
run: yarn prettier:check
2932

3033
- name: Run tests

.github/workflows/publish.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: publish
22

3-
on:
4-
release:
5-
types: [created]
3+
on: workflow_dispatch
64

75
env:
86
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

.github/workflows/publishbeta.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: publish_beta
2+
3+
on: workflow_dispatch
4+
5+
env:
6+
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
7+
NPM_AUTH_TOKEN_ORG: ${{ secrets.NPM_AUTH_TOKEN_ORG }}
8+
9+
jobs:
10+
publish:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v2
15+
16+
- name: Install Dependencies
17+
run: yarn --frozen-lockfile
18+
19+
- name: Build packages
20+
run: yarn build-packages
21+
22+
- name: Run linter
23+
run: yarn lint
24+
25+
- name: Run prettier
26+
run: yarn prettier:check
27+
28+
- name: Run tests
29+
run: yarn test
30+
31+
- name: Publish
32+
run: sh ./bin/publishbeta.sh

bin/publishbeta.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
status=0
4+
5+
(./bin/try-publish-beta.sh "file-input") || status=1
6+
7+
exit $status

bin/try-publish-beta.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
package=$1
4+
5+
status=0
6+
7+
echo -e "\033[0;33mStarting try to publish for \"${package}\"\033[0m\n"
8+
9+
cd ./packages/$package
10+
11+
name=$(cat package.json | grep name | head -n 1 | cut -d'"' -f 4)
12+
version=$(cat package.json | grep version | head -n 1 | cut -d'"' -f 4)
13+
published=$(npm info $name version 2> /dev/null)
14+
15+
if [ -z "$published" ]; then
16+
published="0.0.0"
17+
fi
18+
19+
if [ "$published" != "$version" ]; then
20+
echo "Try to publish $version version of the $name package."
21+
echo "//registry.npmjs.org/:_authToken=\${NPM_AUTH_TOKEN}" > .npmrc
22+
23+
npm publish --tag beta --access public; if [ "$?" != "0" ]; then status=1; fi
24+
else
25+
echo "Current version of the package already published to the NPM."
26+
fi
27+
28+
sleep 2
29+
30+
if [ "$status" != "0" ]; then
31+
echo -e "\n\033[0;31mThe try to publish for \"${package}\" exited with $status\033[0m\n"
32+
else
33+
echo -e "\n\033[0;32mThe try to publish for \"${package}\" exited with 0\033[0m\n"
34+
fi
35+
36+
exit $status

packages/file-input/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
},
2121
"dependencies": {
2222
"filestack-js": "3.7.0",
23-
"graphql-tag": "^2.10.0"
23+
"graphql-tag": "^2.10.0",
24+
"react-dropzone": "^14.2.3"
2425
},
2526
"devDependencies": {
2627
"@babel/core": "^7.4.3",
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
import React, { useState, useEffect, useMemo } from 'react';
2+
import { Accept, useDropzone } from 'react-dropzone';
3+
import { withApollo, WithApolloClient } from 'react-apollo';
4+
import gql from 'graphql-tag';
5+
import { FileInputValue, OriginalFileInputValue } from './types';
6+
7+
interface IFileChooserProps {
8+
maxFiles?: number;
9+
onUploadDone?: (value: FileInputValue, originalFile: OriginalFileInputValue) => Promise<FileInputValue>;
10+
onChange: (value: any, originalFile: File[]) => void;
11+
client: WithApolloClient<any>;
12+
value: any;
13+
workspace?: string;
14+
apiKey?: string;
15+
uploadHost?: string | 'http://localhost:3007';
16+
}
17+
18+
const FILE_UPLOAD_INFO_QUERY = gql`
19+
query FileUploadInfo {
20+
fileUploadInfo {
21+
policy
22+
signature
23+
apiKey
24+
path
25+
}
26+
}
27+
`;
28+
29+
const FileChooser: React.FC<IFileChooserProps> = ({
30+
maxFiles,
31+
onUploadDone,
32+
onChange,
33+
client,
34+
value,
35+
workspace,
36+
apiKey,
37+
uploadHost,
38+
}) => {
39+
const [files, setFiles] = useState<File[]>([]);
40+
const [path, setPath] = useState<string>('');
41+
const [uploading, setUploading] = useState(false);
42+
const [uploadProgress, setUploadProgress] = useState<number>(0);
43+
44+
const cardsContainerStyle: React.CSSProperties = {
45+
display: 'flex',
46+
flexWrap: 'wrap',
47+
};
48+
49+
const cardStyle: React.CSSProperties = {
50+
width: '120px',
51+
height: '150px',
52+
border: '1px solid #e0e0e0',
53+
borderRadius: '8px',
54+
margin: '10px',
55+
overflow: 'hidden',
56+
display: 'flex',
57+
flexDirection: 'column',
58+
};
59+
60+
const cardBodyStyle: React.CSSProperties = {
61+
padding: '8px',
62+
flex: 1,
63+
display: 'flex',
64+
height: '100%',
65+
flexDirection: 'column',
66+
alignItems: 'center',
67+
justifyContent: 'center',
68+
};
69+
70+
const imageStyle: React.CSSProperties = {
71+
objectFit: 'cover',
72+
height: 'auto',
73+
marginBottom: '8px',
74+
borderRadius: '4px',
75+
};
76+
77+
const fileNameStyle: React.CSSProperties = {
78+
fontSize: '12px',
79+
fontWeight: 'bold',
80+
textAlign: 'center',
81+
overflow: 'hidden',
82+
textOverflow: 'ellipsis',
83+
whiteSpace: 'nowrap',
84+
};
85+
86+
const dropzoneStyle: React.CSSProperties = {
87+
border: '2px dashed #cccccc',
88+
borderRadius: '4px',
89+
padding: '20px',
90+
textAlign: 'center',
91+
cursor: 'pointer',
92+
};
93+
94+
const [error, setError] = useState<Error | null>(null);
95+
96+
const { loading, error: queryError } = client.query({
97+
query: FILE_UPLOAD_INFO_QUERY,
98+
});
99+
100+
useEffect(() => {
101+
const fetchData = async () => {
102+
try {
103+
const result = await client.query({
104+
query: FILE_UPLOAD_INFO_QUERY,
105+
});
106+
if (result.data) {
107+
const { path } = result.data.fileUploadInfo;
108+
setPath(path);
109+
}
110+
} catch (error) {
111+
setError(queryError);
112+
}
113+
};
114+
115+
fetchData();
116+
}, []);
117+
118+
const onDrop = (acceptedFiles: File[]) => {
119+
if (maxFiles && maxFiles > 1) {
120+
setFiles(prevFiles => [...prevFiles, ...acceptedFiles]);
121+
} else {
122+
setFiles([acceptedFiles[0]]);
123+
}
124+
};
125+
126+
const removeFile = (index: number) => {
127+
setFiles(prevFiles => {
128+
const updatedFiles = [...prevFiles];
129+
updatedFiles.splice(index, 1);
130+
return updatedFiles;
131+
});
132+
};
133+
134+
const uploadToS3 = async (files: File[]) => {
135+
const myHeaders = new Headers();
136+
setUploading(true);
137+
myHeaders.append('storage-provider', 'S3');
138+
if (apiKey) {
139+
myHeaders.append('authorization', apiKey);
140+
}
141+
if (workspace) {
142+
myHeaders.append('workspace', workspace);
143+
}
144+
145+
const formdata = new FormData();
146+
147+
files.forEach(file => {
148+
formdata.append('files', file, file.name);
149+
});
150+
151+
formdata.append('bucketName', 'test-dyron');
152+
153+
const requestOptions: RequestInit = {
154+
method: 'POST',
155+
headers: myHeaders,
156+
body: formdata,
157+
redirect: 'follow' as RequestRedirect,
158+
};
159+
160+
try {
161+
const response = await fetch(uploadHost + '/upload', requestOptions);
162+
if (!response.ok) {
163+
throw new Error(`HTTP error! Status: ${response.status}`);
164+
}
165+
166+
const result = await response.json();
167+
168+
setUploadProgress(100);
169+
170+
return result.data;
171+
} catch (error) {
172+
throw error;
173+
} finally {
174+
setUploading(false);
175+
setUploadProgress(0);
176+
}
177+
};
178+
179+
const handleUpload = async () => {
180+
setUploadProgress(1);
181+
let value = await uploadToS3(files);
182+
const originalFile = files.map(item => item);
183+
if (maxFiles === 1) {
184+
value = value[0];
185+
}
186+
if (typeof onChange === 'function') {
187+
onChange(value, originalFile);
188+
}
189+
190+
if (maxFiles === 1) {
191+
// setFiles([value[0]]);
192+
}
193+
194+
if (typeof onUploadDone === 'function') {
195+
onUploadDone(value, originalFile);
196+
}
197+
};
198+
199+
const { getRootProps, getInputProps, isDragActive } = useDropzone({
200+
onDrop,
201+
accept: ('image/*' as unknown) as Accept,
202+
});
203+
204+
const renderTableFields = () => {
205+
return (
206+
<div style={cardsContainerStyle}>
207+
{files.length > 0 &&
208+
files.map((file, index) => (
209+
<div key={index} style={cardStyle}>
210+
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
211+
<button
212+
onClick={() => removeFile(index)}
213+
style={{
214+
position: 'absolute',
215+
top: '0',
216+
right: '0',
217+
padding: '4px',
218+
cursor: 'pointer',
219+
zIndex: 1,
220+
background: 'transparent',
221+
border: 'none',
222+
transition: 'color 0.3s ease',
223+
}}
224+
onMouseOver={(e: React.MouseEvent<HTMLButtonElement>) => (e.currentTarget.style.color = 'blue')}
225+
onMouseOut={(e: React.MouseEvent<HTMLButtonElement>) => (e.currentTarget.style.color = 'gray')}
226+
>
227+
X
228+
</button>
229+
<div style={cardBodyStyle}>
230+
<img src={URL.createObjectURL(file)} alt={`Preview ${index}`} style={imageStyle} />
231+
<p style={fileNameStyle}>{file.name}</p>
232+
</div>
233+
</div>
234+
</div>
235+
))}
236+
</div>
237+
);
238+
};
239+
240+
const memoizedRenderTableFields = useMemo(() => renderTableFields(), [files]);
241+
242+
if (loading) {
243+
return <div>Loading...</div>;
244+
}
245+
246+
if (error) {
247+
return <div>Error: {error.message}</div>;
248+
}
249+
250+
return (
251+
<div>
252+
<div {...getRootProps()} style={dropzoneStyle}>
253+
<input {...getInputProps()} />
254+
{isDragActive ? <p>Drop the files here...</p> : <p>Drag and drop some files here, or click to select files</p>}
255+
</div>
256+
257+
{files.length > 0 && memoizedRenderTableFields}
258+
259+
{uploadProgress > 0 && <p>Uploading... {uploadProgress}%</p>}
260+
261+
<button
262+
type="button"
263+
onClick={handleUpload}
264+
disabled={uploading || files.length === 0}
265+
style={{
266+
marginTop: '10px',
267+
padding: '8px',
268+
background: uploading || files.length === 0 ? '#dcdcdc' : '#0874F9',
269+
color: uploading || files.length === 0 ? '#808080' : '#fff',
270+
border: 'none',
271+
borderRadius: '4px',
272+
cursor: 'pointer',
273+
}}
274+
>
275+
Upload
276+
</button>
277+
</div>
278+
);
279+
};
280+
281+
const FileChooserWithApollo = withApollo<IFileChooserProps>(FileChooser);
282+
283+
export default FileChooserWithApollo;

0 commit comments

Comments
 (0)