1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 17:33:14 +01:00

Implement lazy blob creation routine and increase robustness of upload button template for react-fineuploader

This commit is contained in:
Tim Daubenschütz 2015-11-09 16:58:35 +01:00
parent 3e22ad1d9d
commit deceb61c60
3 changed files with 135 additions and 83 deletions

View File

@ -2,6 +2,8 @@
import React from 'react';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
@ -29,24 +31,41 @@ const UploadFileButton = React.createClass({
fileClassToUpload: shape({
singular: string,
plural: string
}).isRequired
}).isRequired,
createBlobRoutine: shape({
url: string,
pieceId: number
})
},
submitFile(file) {
console.log(file);
getInitialState() {
return {
file: null
};
},
handleSubmitFile(file) {
this.setState({
file
});
},
createBlobRoutine() {
const { fineuploader } = this.refs;
const { file } = this.state;
fineuploader.createBlob(file);
},
render() {
const { fileClassToUpload, validation, keyRoutine } = this.props;
const { fileClassToUpload, validation, keyRoutine, createBlobRoutine } = this.props;
return (
<ReactS3FineUploader
ref="fineuploader"
fileInputElement={UploadButton}
keyRoutine={keyRoutine}
createBlobRoutine={{
url: ApiUrls.blob_contracts
}}
createBlobRoutine={createBlobRoutine}
validation={validation}
setIsUploadReady={() =>{/* So that ReactS3FineUploader is not complaining */}}
signature={{
@ -65,9 +84,9 @@ const UploadFileButton = React.createClass({
}}
fileClassToUpload={fileClassToUpload}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
submitFile={this.submitFile}
submitFile={this.handleSubmitFile}
location={this.props.location}/>
);
);
}
});

View File

@ -2,8 +2,11 @@
import React from 'react';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils';
import { getLangText } from '../../../utils/lang_utils';
import { truncateTextAtCharIndex } from '../../../utils/general_utils';
let UploadButton = React.createClass({
@ -37,6 +40,10 @@ let UploadButton = React.createClass({
return this.props.filesToUpload.filter((file) => file.status === 'uploading');
},
getUploadedFile() {
return this.props.filesToUpload.filter((file) => file.status === 'upload successful')[0];
},
handleOnClick() {
let uploadingFiles = this.getUploadingFiles();
@ -57,14 +64,22 @@ let UploadButton = React.createClass({
},
getButtonLabel() {
const uploadedFile = this.getUploadedFile();
let { filesToUpload, fileClassToUpload } = this.props;
// filter invalid files that might have been deleted or canceled...
filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter);
// Depending on wether there is an upload going on or not we
// display the progress
if(filesToUpload.length > 0) {
// Depending on whether there is an upload going on or not we
// display the progress or the successfully uploaded file's name
if(uploadedFile) {
return (
<span>
<Glyphicon glyph="ok" />
{' ' + truncateTextAtCharIndex(uploadedFile.name, 20)}
</span>
);
} else if(filesToUpload.length > 0) {
return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
} else {
return fileClassToUpload.singular;
@ -74,7 +89,6 @@ let UploadButton = React.createClass({
render() {
let {
multiple,
fileClassToUpload,
allowedExtensions
} = this.props;
@ -82,7 +96,7 @@ let UploadButton = React.createClass({
<button
onClick={this.handleOnClick}
className="btn btn-default btn-sm margin-left-2px"
disabled={this.getUploadingFiles().length !== 0}>
disabled={this.getUploadingFiles().length !== 0 || !!this.getUploadedFile()}>
{this.getButtonLabel()}
<input
multiple={multiple}

View File

@ -308,47 +308,58 @@ let ReactS3FineUploader = React.createClass({
},
createBlob(file) {
return Q.Promise((resolve, reject) => {
window.fetch(this.props.createBlobRoutine.url, {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': getCookie(AppConstants.csrftoken)
},
credentials: 'include',
body: JSON.stringify({
'filename': file.name,
'key': file.key,
'piece_id': this.props.createBlobRoutine.pieceId
const { createBlobRoutine } = this.props;
// returning here without doing anything enables us to
// lazy create the blob at any time after the upload
if(!createBlobRoutine) {
return null;
} else {
return Q.Promise((resolve, reject) => {
window.fetch(createBlobRoutine.url, {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': getCookie(AppConstants.csrftoken)
},
credentials: 'include',
body: JSON.stringify({
'filename': file.name,
'key': file.key,
'piece_id': createBlobRoutine.pieceId
})
})
})
.then((res) => {
return res.json();
})
.then((res) => {
if(res.otherdata) {
file.s3Url = res.otherdata.url_safe;
file.s3UrlSafe = res.otherdata.url_safe;
} else if(res.digitalwork) {
file.s3Url = res.digitalwork.url_safe;
file.s3UrlSafe = res.digitalwork.url_safe;
} else if(res.contractblob) {
file.s3Url = res.contractblob.url_safe;
file.s3UrlSafe = res.contractblob.url_safe;
} else {
throw new Error(getLangText('Could not find a url to download.'));
}
resolve(res);
})
.catch((err) => {
console.logGlobal(err, false, {
files: this.state.filesToUpload,
chunks: this.state.chunks
.then((res) => {
return res.json();
})
.then((res) => {
if(res.otherdata) {
file.s3Url = res.otherdata.url_safe;
file.s3UrlSafe = res.otherdata.url_safe;
} else if(res.digitalwork) {
file.s3Url = res.digitalwork.url_safe;
file.s3UrlSafe = res.digitalwork.url_safe;
} else if(res.contractblob) {
file.s3Url = res.contractblob.url_safe;
file.s3UrlSafe = res.contractblob.url_safe;
} else if(res.thumbnail) {
file.s3Url = res.thumbnail.url_safe;
file.s3UrlSafe = res.thumbnail.url_safe;
} else {
throw new Error(getLangText('Could not find a url to download.'));
}
resolve(res);
})
.catch((err) => {
console.logGlobal(err, false, {
files: this.state.filesToUpload,
chunks: this.state.chunks
});
reject(err);
});
reject(err);
});
});
}
},
/* FineUploader specific callback function handlers */
@ -404,39 +415,47 @@ let ReactS3FineUploader = React.createClass({
let filesToUpload = React.addons.update(this.state.filesToUpload, { $set: files });
this.setState({ filesToUpload });
// Only after the blob has been created server-side, we can make the form submittable.
this.createBlob(files[id])
.then(() => {
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitFile
// are optional, we'll only trigger them when they're actually defined
if(this.props.submitFile) {
this.props.submitFile(files[id]);
} else {
console.warn('You didn\'t define submitFile in as a prop in react-s3-fine-uploader');
}
// for explanation, check comment of if statement above
if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) {
// also, lets check if after the completion of this upload,
// the form is ready for submission or not
if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
// if so, set uploadstatus to true
this.props.setIsUploadReady(true);
const createBlobResult = this.createBlob(files[id]);
if(!createBlobResult) {
if(this.props.submitFile) {
this.props.submitFile(files[id]);
} else {
console.warn('You didn\'t define submitFile in as a prop in react-s3-fine-uploader');
}
} else {
// Only after the blob has been created server-side, we can make the form submittable.
this.createBlob(files[id])
.then(() => {
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitFile
// are optional, we'll only trigger them when they're actually defined
if(this.props.submitFile) {
this.props.submitFile(files[id]);
} else {
this.props.setIsUploadReady(false);
console.warn('You didn\'t define submitFile in as a prop in react-s3-fine-uploader');
}
} else {
console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader');
}
})
.catch((err) => {
console.logGlobal(err, false, {
files: this.state.filesToUpload,
chunks: this.state.chunks
// for explanation, check comment of if statement above
if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) {
// also, lets check if after the completion of this upload,
// the form is ready for submission or not
if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
// if so, set uploadstatus to true
this.props.setIsUploadReady(true);
} else {
this.props.setIsUploadReady(false);
}
} else {
console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader');
}
})
.catch((err) => {
console.logGlobal(err, false, {
files: this.state.filesToUpload,
chunks: this.state.chunks
});
let notification = new GlobalNotificationModel(err.message, 'danger', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
});
let notification = new GlobalNotificationModel(err.message, 'danger', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
});
}
}
},