Skip to content

Commit

Permalink
[Document Repository] Upload multiple files at once (#8289)
Browse files Browse the repository at this point in the history
- <FileElement> now supports the 'multiple' attribute.
- The document_repository module has been modified to support multiple uploaded files.
- Some visual feedback has been added (error reporting + uploading status).

Resolves #8218
  • Loading branch information
jeffersoncasimir committed Apr 5, 2023
1 parent 14ed881 commit 8a70e3e
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 127 deletions.
22 changes: 17 additions & 5 deletions jsx/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -1995,7 +1995,7 @@ NumericElement.defaultProps = {

/**
* File Component
* React wrapper for a simple or 'multiple' <select> element.
* React wrapper for a simple or 'multiple' <input type="file"> element.
*/
class FileElement extends Component {
/**
Expand All @@ -2014,8 +2014,10 @@ class FileElement extends Component {
*/
handleChange(e) {
// Send current file to parent component
const file = e.target.files[0] ? e.target.files[0] : '';
this.props.onUserInput(this.props.name, file);
const files = e.target.files
? (this.props.allowMultiple ? e.target.files : e.target.files[0])
: '';
this.props.onUserInput(this.props.name, files);
}

/**
Expand All @@ -2027,14 +2029,20 @@ class FileElement extends Component {
const required = this.props.required ? 'required' : null;

let fileName = undefined;

if (this.props.value) {
switch (typeof this.props.value) {
case 'string':
fileName = this.props.value;
break;

case 'object':
fileName = this.props.value.name;
if (this.props.value instanceof FileList) {
const files = this.props.value;
fileName = Array.from(files).map((file) => file.name).join(', ');
} else {
fileName = this.props.value.name;
}
break;

default:
Expand Down Expand Up @@ -2106,6 +2114,7 @@ class FileElement extends Component {
} else {
classSz = 'col-sm-12';
}

return (
<div className={elementClass}>
{labelHTML}
Expand All @@ -2127,6 +2136,7 @@ class FileElement extends Component {
name={this.props.name}
onChange={this.handleChange}
required={required}
multiple={this.props.allowMultiple}
/>
</div>
</div>
Expand All @@ -2148,6 +2158,7 @@ FileElement.propTypes = {
id: PropTypes.string,
disabled: PropTypes.bool,
required: PropTypes.bool,
allowMultiple: PropTypes.bool,
hasError: PropTypes.bool,
errorMessage: PropTypes.string,
onUserInput: PropTypes.func,
Expand All @@ -2160,6 +2171,7 @@ FileElement.defaultProps = {
id: null,
disabled: false,
required: false,
allowMultiple: false,
hasError: false,
errorMessage: 'The field is required!',
onUserInput: function() {
Expand Down Expand Up @@ -2468,7 +2480,7 @@ class ButtonElement extends Component {
onClick={this.handleClick}
disabled={this.props.disabled}
>
{this.props.label}
{this.props.disabled ? 'Uploading...' : this.props.label}
</button>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions modules/document_repository/css/document_repository.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
.tool:hover + .tip {
visibility: visible;
}

.upload-response {
max-height: 400px;
overflow-y: scroll;
text-align: left;
}
114 changes: 77 additions & 37 deletions modules/document_repository/jsx/uploadForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Loader from 'Loader';
* Media Upload Form
*
* Fetches data from Loris backend and displays a form allowing
* to upload a document file
* to upload document files
*
* @author Shen Wang
* @version 1.0.0
Expand All @@ -28,10 +28,11 @@ class DocUploadForm extends Component {
uploadResult: null,
errorMessage: null,
isLoaded: false,
uploadInProgress: false,
};

this.setFormData = this.setFormData.bind(this);
this.uploadFile = this.uploadFile.bind(this);
this.uploadFiles = this.uploadFiles.bind(this);
this.fetchData = this.fetchData.bind(this);
}

Expand Down Expand Up @@ -90,10 +91,10 @@ class DocUploadForm extends Component {
<FormElement
name="docUpload"
fileUpload={true}
onSubmit={this.uploadFile}
onSubmit={this.uploadFiles}
method="POST"
>
<h3>Upload a file</h3><br/>
<h3>Upload files</h3><br/>
<SelectElement
name="category"
label="Category"
Expand Down Expand Up @@ -145,14 +146,18 @@ class DocUploadForm extends Component {
value={this.state.formData.comments}
/>
<FileElement
name="file"
name="files"
id="docUploadEl"
onUserInput={this.setFormData}
label="File to upload"
label="File(s) to upload"
required={true}
value={this.state.formData.file}
value={this.state.formData.files}
allowMultiple={true}
/>
<ButtonElement
label="Upload File(s)"
disabled={this.state.uploadInProgress}
/>
<ButtonElement label="Upload File"/>
</FormElement>
</div>
</div>
Expand All @@ -166,46 +171,81 @@ class DocUploadForm extends Component {
*/

/**
* Upload file
* Upload file(s)
*/
uploadFile() {
uploadFiles() {
// Set form data and upload the media file
let formData = this.state.formData;
let formObject = new FormData();
for (let key in formData) {
if (formData[key] !== '') {
formObject.append(key, formData[key]);
try {
this.setState({uploadInProgress: true});
let formData = this.state.formData;
let formObject = new FormData();
for (let key in formData) {
if (formData[key] !== '') {
if (key === 'files' &&
document.querySelector('.fileUpload').multiple) {
Array.from(formData[key]).forEach((file) => {
formObject.append('files[]', file);
});
} else {
formObject.append(key, formData[key]);
}
}
}
}

fetch(this.props.action, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
body: formObject,
})
.then((resp) => {
console.error(resp);
if (resp.ok) {
swal.fire('Upload Successful!', '', 'success').then((result) => {
if (result.value) {
this.setState({formData: {}});
this.props.refreshPage();
fetch(this.props.action, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
body: formObject,
})
.then((resp) => {
if (resp.ok) {
resp.json().then((data) => {
if (data.error_count === 0) {
swal.fire('Upload Successful!', '', 'success')
.then((result) => {
if (result.value) {
this.setState({formData: {}});
this.props.refreshPage();
}
});
} else {
console.error(resp);
swal.fire('Upload Incomplete', data.message, 'warning');
}
}).catch((error) => {
console.error(error);
swal.fire(
'Error reading response',
'Please report the issue or contact your administrator',
'error'
);
});
} else {
resp.json().then((data) => {
console.error(resp);
swal.fire('Could not upload files', data.error, 'error');
}).catch((error) => {
console.error(error);
swal.fire(
'Error reading error response',
'Please report the issue or contact your administrator',
'error'
);
});
}
});
} else {
resp.json().then((data) => {
swal.fire('Could not upload file', data.error, 'error');
}).catch((error) => {
console.error(error);
swal.fire(
'Unknown Error',
'Something went wrong',
'Please report the issue or contact your administrator',
'error'
);
});
}
});
}).finally(() => this.setState({uploadInProgress: false}));
} catch (error) {
console.error(error);
this.setState({uploadInProgress: false});
}
}

/**
Expand Down

0 comments on commit 8a70e3e

Please sign in to comment.