1
0
mirror of https://github.com/ascribe/onion.git synced 2025-02-14 21:10:27 +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 React from 'react';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader'; import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button'; import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
@ -29,24 +31,41 @@ const UploadFileButton = React.createClass({
fileClassToUpload: shape({ fileClassToUpload: shape({
singular: string, singular: string,
plural: string plural: string
}).isRequired }).isRequired,
createBlobRoutine: shape({
url: string,
pieceId: number
})
}, },
submitFile(file) { getInitialState() {
console.log(file); return {
file: null
};
},
handleSubmitFile(file) {
this.setState({
file
});
},
createBlobRoutine() {
const { fineuploader } = this.refs;
const { file } = this.state;
fineuploader.createBlob(file);
}, },
render() { render() {
const { fileClassToUpload, validation, keyRoutine, createBlobRoutine } = this.props;
const { fileClassToUpload, validation, keyRoutine } = this.props;
return ( return (
<ReactS3FineUploader <ReactS3FineUploader
ref="fineuploader"
fileInputElement={UploadButton} fileInputElement={UploadButton}
keyRoutine={keyRoutine} keyRoutine={keyRoutine}
createBlobRoutine={{ createBlobRoutine={createBlobRoutine}
url: ApiUrls.blob_contracts
}}
validation={validation} validation={validation}
setIsUploadReady={() =>{/* So that ReactS3FineUploader is not complaining */}} setIsUploadReady={() =>{/* So that ReactS3FineUploader is not complaining */}}
signature={{ signature={{
@ -65,9 +84,9 @@ const UploadFileButton = React.createClass({
}} }}
fileClassToUpload={fileClassToUpload} fileClassToUpload={fileClassToUpload}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
submitFile={this.submitFile} submitFile={this.handleSubmitFile}
location={this.props.location}/> location={this.props.location}/>
); );
} }
}); });

View File

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

View File

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