Skip to content

Commit 601e8e1

Browse files
a2975667mangeshbendre
authored andcommitted
Resolve CORS feature. Complete initial upload feature. (#244)
* resolve CORS issue for local development on port 3000 * fix ReactResumablejs issue and version imcompatability * fix file selection box without css workaround * fix upload feature. Awaiting styling * fix upload styling. Issue with loading on Success * fix reload issue * update on upload feature with reload functions * update on upload feature with reload functions * complete initial upload feature
1 parent e678eb4 commit 601e8e1

15 files changed

Lines changed: 735 additions & 412 deletions

dataspread-ui/package-lock.json

Lines changed: 286 additions & 286 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dataspread-ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
"react-datasheet": "^1.3.8",
1717
"react-dom": "^16.6.0",
1818
"react-draggable": "^3.0.5",
19-
"react-resumable-js": "^1.1.24",
2019
"react-scripts": "1.1.4",
2120
"react-virtualized": "^9.20.1",
2221
"require": "^2.4.20",
22+
"resumablejs": "^1.1.0",
2323
"semantic-ui-css": "^2.3.3",
2424
"semantic-ui-react": "^0.82.2",
2525
"stompjs": "^2.3.3"

dataspread-ui/public/index.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
66
<meta name="theme-color" content="#000000">
7-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
87
<!--
98
manifest.json provides metadata used when your web app is added to the
109
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
1110
-->
1211
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
1312
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
14-
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
1513
<!--
1614
Notice the use of %PUBLIC_URL% in the tags above.
1715
It will be replaced with the URL of the `public` folder during the build.
Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
/**
2+
* Resumable JS for React JS
3+
* @author Gonzalo Rubino gonzalo_rubino@artear.com || gonzalorubino@gmail.com
4+
* @version 1.1.0
5+
*
6+
* Creates an uploader component in React, to use with Resumable JS
7+
* On file added, the upload will begin.
8+
*/
9+
10+
import React from "react";
11+
import Resumablejs from "resumablejs";
12+
import {Button} from 'semantic-ui-react'
13+
14+
export default class ReactResumableJs extends React.Component {
15+
constructor(props) {
16+
super(props);
17+
this.state = {
18+
progressBar: 0,
19+
messageStatus: '',
20+
fileList: {files: []},
21+
isPaused: false,
22+
isUploading: false,
23+
fileName: ""
24+
};
25+
26+
this.resumable = null;
27+
}
28+
29+
componentDidMount = () => {
30+
31+
let ResumableField = new Resumablejs({
32+
target: this.props.service,
33+
query: this.props.query || {},
34+
fileType: this.props.filetypes,
35+
maxFiles: this.props.maxFiles,
36+
maxFileSize: this.props.maxFileSize,
37+
fileTypeErrorCallback: (file, errorCount) => {
38+
if (typeof this.props.onFileAddedError === "function") {
39+
this.props.onFileAddedError(file, errorCount);
40+
}
41+
},
42+
maxFileSizeErrorCallback: (file, errorCount) => {
43+
if (typeof this.props.onMaxFileSizeErrorCallback === "function") {
44+
this.props.onMaxFileSizeErrorCallback(file, errorCount);
45+
}
46+
},
47+
testMethod: this.props.testMethod || 'post',
48+
testChunks: this.props.testChunks || false,
49+
headers: this.props.headerObject || {},
50+
withCredentials: this.props.withCredentials || false,
51+
chunkSize: this.props.chunkSize,
52+
simultaneousUploads: this.props.simultaneousUploads,
53+
fileParameterName: this.props.fileParameterName,
54+
generateUniqueIdentifier: this.props.generateUniqueIdentifier,
55+
forceChunkSize: this.props.forceChunkSize
56+
});
57+
58+
if (typeof this.props.maxFilesErrorCallback === "function") {
59+
ResumableField.opts.maxFilesErrorCallback = this.props.maxFilesErrorCallback;
60+
}
61+
62+
ResumableField.assignBrowse(this.uploader);
63+
64+
//Enable or Disable DragAnd Drop
65+
if (this.props.disableDragAndDrop === false) {
66+
ResumableField.assignDrop(this.dropZone);
67+
}
68+
69+
ResumableField.on('fileAdded', (file, event) => {
70+
this.setState({
71+
messageStatus: this.props.fileAddedMessage || ' Starting upload! '
72+
});
73+
74+
if (typeof this.props.onFileAdded === "function") {
75+
this.props.onFileAdded(file, this.resumable);
76+
this.setState({
77+
fileName : file.file.name
78+
});
79+
} else {
80+
ResumableField.upload();
81+
}
82+
});
83+
84+
ResumableField.on('fileSuccess', (file, fileServer) => {
85+
86+
if (this.props.fileNameServer) {
87+
let objectServer = JSON.parse(fileServer);
88+
file.fileName = objectServer[this.props.fileNameServer];
89+
} else {
90+
file.fileName = fileServer;
91+
}
92+
93+
let currentFiles = this.state.fileList.files;
94+
currentFiles.push(file);
95+
96+
this.setState({
97+
fileList: {files: currentFiles},
98+
messageStatus: this.props.completedMessage + file.fileName || fileServer
99+
}, () => {
100+
if (typeof this.props.onFileSuccess === "function") {
101+
this.props.onFileSuccess(file, fileServer);
102+
}
103+
});
104+
});
105+
106+
ResumableField.on('progress', () => {
107+
108+
109+
this.setState({
110+
isUploading: ResumableField.isUploading()
111+
});
112+
113+
if ((ResumableField.progress() * 100) < 100) {
114+
this.setState({
115+
messageStatus: parseInt(ResumableField.progress() * 100, 10) + '%',
116+
progressBar: ResumableField.progress() * 100
117+
});
118+
} else {
119+
setTimeout(() => {
120+
this.setState({
121+
progressBar: 0
122+
})
123+
}, 1000);
124+
}
125+
126+
});
127+
128+
ResumableField.on('fileError', (file, errorCount) => {
129+
this.props.onUploadErrorCallback(file, errorCount);
130+
});
131+
132+
this.resumable = ResumableField;
133+
};
134+
135+
removeFile = (event, file, index) => {
136+
137+
event.preventDefault();
138+
139+
let currentFileList = this.state.fileList.files;
140+
delete currentFileList[index];
141+
142+
this.setState({
143+
fileList: {files: currentFileList}
144+
});
145+
146+
this.props.onFileRemoved(file);
147+
this.resumable.removeFile(file);
148+
};
149+
150+
createFileList = () => {
151+
152+
let markup = this.state.fileList.files.map((file, index) => {
153+
154+
let uniqID = this.props.uploaderID + '-' + index;
155+
let originFile = file.file;
156+
let media = '';
157+
158+
if (file.file.type.indexOf('video') > -1) {
159+
media = <label className="video">{originFile.name}</label>;
160+
return <li className="thumbnail" key={uniqID}>
161+
<label id={"media_" + uniqID}>{media}</label>
162+
<a onClick={(event) => this.removeFile(event, file, index)} href="#">[X]</a>
163+
</li>;
164+
}
165+
else if (file.file.type.indexOf('image') > -1) if (this.props.tmpDir !== "") {
166+
let src = this.props.tmpDir + file.fileName;
167+
media = <img className="image" width="80" src={src} alt=""/>;
168+
return <li className="thumbnail" key={uniqID}>
169+
<label id={"media_" + uniqID}>{media}</label>
170+
<a onClick={(event) => this.removeFile(event, file, index)} href="#">[X]</a>
171+
</li>;
172+
173+
} else {
174+
let fileReader = new FileReader();
175+
fileReader.readAsDataURL(originFile);
176+
fileReader.onload = (event) => {
177+
media = '<img class="image" width="80" src="' + event.target.result + '"/>';
178+
document.querySelector("#media_" + uniqID).innerHTML = media;
179+
};
180+
return <li className="thumbnail" key={uniqID}>
181+
<label id={"media_" + uniqID}/>
182+
<a onClick={(event) => this.removeFile(event, file, index)} href="#">[X]</a>
183+
</li>;
184+
} else {
185+
media = <label className="document">{originFile.name}</label>;
186+
return <li className="thumbnail" key={uniqID}>
187+
<label id={"media_" + uniqID}>{media}</label>
188+
<a onClick={(event) => this.removeFile(event, file, index)} href="#">[X]</a>
189+
</li>;
190+
}
191+
});
192+
193+
return <ul id={"items-" + this.props.uploaderID}>{markup}</ul>;
194+
};
195+
196+
cancelUpload = () => {
197+
this.resumable.cancel();
198+
199+
this.setState({
200+
fileList: {files: []}
201+
});
202+
203+
this.props.onCancelUpload();
204+
};
205+
206+
pauseUpload = () => {
207+
if (!this.state.isPaused) {
208+
209+
this.resumable.pause();
210+
this.setState({
211+
isPaused: true
212+
});
213+
this.props.onPauseUpload();
214+
} else {
215+
216+
this.resumable.upload();
217+
this.setState({
218+
isPaused: false
219+
});
220+
this.props.onResumeUpload();
221+
}
222+
};
223+
224+
startUpload = () => {
225+
this.resumable.upload();
226+
this.setState({
227+
isPaused: false
228+
});
229+
this.props.onStartUpload();
230+
};
231+
232+
uploadFile_selection = () => {
233+
this.uploader.click();
234+
};
235+
236+
render() {
237+
238+
let fileList = null;
239+
if (this.props.showFileList) {
240+
fileList = <div className="resumable-list">{this.createFileList()}</div>;
241+
}
242+
243+
let previousText = null;
244+
if (this.props.previousText) {
245+
if (typeof this.props.previousText ==="string") previousText = <p>{this.props.previousText}</p>
246+
else previousText = this.props.previousText
247+
}
248+
249+
let textLabel = null;
250+
if (this.props.textLabel) {
251+
textLabel = this.props.textLabel;
252+
253+
}
254+
255+
let startButton = null;
256+
if (this.props.startButton) {
257+
if (typeof this.props.startButton ==="string" || typeof this.props.startButton ==="boolean" ) startButton = <label>
258+
<Button disabled={this.state.isUploading} className="btn start" onClick={this.startUpload}>{this.props.startButton && "upload"}
259+
</Button>
260+
</label>;
261+
else startButton =this.props.startButton
262+
}
263+
264+
let cancelButton = null;
265+
if (this.props.cancelButton) {
266+
if (typeof this.props.cancelButton === "string" || typeof this.props.cancelButton === "boolean")cancelButton = <label>
267+
<Button disabled={!this.state.isUploading} className="btn cancel" onClick={this.cancelUpload}>{this.props.cancelButton && "cancel"}
268+
</Button>
269+
</label>;
270+
else cancelButton = this.props.cancelButton
271+
}
272+
273+
let pauseButton = null;
274+
if (this.props.pauseButton) {
275+
if (typeof this.props.pauseButton === "string" || typeof this.props.pauseButton === "boolean") pauseButton = <label>
276+
<Button disabled={!this.state.isUploading} className="btn pause" onClick={this.pauseUpload}>{this.props.pauseButton && "pause"}
277+
</Button>
278+
</label>;
279+
else pauseButton = this.props.pauseButton
280+
}
281+
282+
return (
283+
<div id={this.props.dropTargetID} ref={node => this.dropZone = node}>
284+
{previousText}
285+
<label className={this.props.disableInput ? 'btn file-upload disabled' : 'btn file-upload'}>{textLabel}
286+
<div className="ui action input importTextBox">
287+
<input type="text" readOnly
288+
value={this.state.fileName}>
289+
</input>
290+
<input
291+
ref={node=> this.uploader = node}
292+
type="file"
293+
id={this.props.uploaderID}
294+
className='btn'
295+
name={this.props.uploaderID + '-upload'}
296+
accept={this.props.fileAccept || '*'}
297+
disabled={this.props.disableInput || false}
298+
style={{display: "none"}}
299+
/>
300+
<div className="ui icon button">
301+
<i className="cloud upload alternate icon"
302+
onClick={this.uploadFile_selection}></i>
303+
</div>
304+
</div>
305+
</label>
306+
307+
<div className="progress" style={{display: this.state.progressBar === 0 ? "none" : "block"}}>
308+
<div className="progress-bar" style={{width: this.state.progressBar + '%'}}></div>
309+
</div>
310+
311+
{/* {fileList}
312+
{startButton}
313+
{pauseButton}
314+
{cancelButton} */}
315+
</div>
316+
);
317+
}
318+
}
319+
320+
ReactResumableJs.defaultProps = {
321+
maxFiles: undefined,
322+
uploaderID: 'default-resumable-uploader',
323+
dropTargetID: 'dropTarget',
324+
filetypes: [],
325+
fileAccept: '*',
326+
maxFileSize: 10240000,
327+
showFileList: true,
328+
onUploadErrorCallback: (file, errorCount) => {
329+
console.log('error', file, errorCount);
330+
},
331+
onFileRemoved: function (file) {
332+
return file;
333+
},
334+
onCancelUpload: function () {
335+
return true;
336+
},
337+
onPauseUpload: function () {
338+
return true;
339+
},
340+
onResumeUpload: function () {
341+
return true;
342+
},
343+
onStartUpload: function () {
344+
return true;
345+
},
346+
disableDragAndDrop: false,
347+
fileNameServer: "",
348+
tmpDir: "",
349+
chunkSize: 1024 * 1024,
350+
simultaneousUploads: 1,
351+
fileParameterName: 'file',
352+
generateUniqueIdentifier: null,
353+
maxFilesErrorCallback: null,
354+
cancelButton: false,
355+
pause: false,
356+
startButton: null,
357+
pauseButton: null,
358+
previousText: "",
359+
headerObject : {},
360+
withCredentials: false,
361+
forceChunkSize: false
362+
};

0 commit comments

Comments
 (0)