mirror of
https://github.com/ascribe/onion.git
synced 2025-01-03 18:35:09 +01:00
Merged in AD-957-custom-upload-button-for-contract (pull request #58)
Ad 957 custom upload button for contract
This commit is contained in:
commit
9336903470
@ -30,7 +30,7 @@ class ContractListActions {
|
||||
|
||||
changeContract(contract){
|
||||
return Q.Promise((resolve, reject) => {
|
||||
OwnershipFetcher.makeContractPublic(contract)
|
||||
OwnershipFetcher.changeContract(contract)
|
||||
.then((res) => {
|
||||
resolve(res);
|
||||
})
|
||||
|
@ -38,9 +38,9 @@ let FurtherDetails = React.createClass({
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
submitKey(key){
|
||||
submitFile(file){
|
||||
this.setState({
|
||||
otherDataKey: key
|
||||
otherDataKey: file.key
|
||||
});
|
||||
},
|
||||
|
||||
@ -78,7 +78,7 @@ let FurtherDetails = React.createClass({
|
||||
extraData={this.props.extraData} />
|
||||
<Form>
|
||||
<FurtherDetailsFileuploader
|
||||
submitKey={this.submitKey}
|
||||
submitFile={this.submitFile}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||
editable={this.props.editable}
|
||||
|
@ -17,7 +17,7 @@ let FurtherDetailsFileuploader = React.createClass({
|
||||
pieceId: React.PropTypes.number,
|
||||
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
submitFile: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
editable: React.PropTypes.bool,
|
||||
multiple: React.PropTypes.bool
|
||||
@ -55,11 +55,8 @@ let FurtherDetailsFileuploader = React.createClass({
|
||||
url: ApiUrls.blob_otherdatas,
|
||||
pieceId: this.props.pieceId
|
||||
}}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '50000000'
|
||||
}}
|
||||
submitKey={this.props.submitKey}
|
||||
validation={AppConstants.fineUploader.validation.additionalData}
|
||||
submitFile={this.props.submitFile}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
session={{
|
||||
|
@ -4,45 +4,40 @@ import React from 'react';
|
||||
|
||||
import Form from '../ascribe_forms/form';
|
||||
import Property from '../ascribe_forms/property';
|
||||
import InputCheckbox from '../ascribe_forms/input_checkbox';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import ContractListActions from '../../actions/contract_list_actions';
|
||||
|
||||
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
|
||||
|
||||
import InputFineUploader from './input_fineuploader';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
|
||||
|
||||
|
||||
let CreateContractForm = React.createClass({
|
||||
propTypes: {
|
||||
isPublic: React.PropTypes.bool,
|
||||
|
||||
// A class of a file the user has to upload
|
||||
// Needs to be defined both in singular as well as in plural
|
||||
fileClassToUpload: React.PropTypes.shape({
|
||||
singular: React.PropTypes.string,
|
||||
plural: React.PropTypes.string
|
||||
})
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
contractKey: null,
|
||||
isUploadReady: false
|
||||
isUploadReady: false,
|
||||
contractName: ''
|
||||
};
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return {
|
||||
blob: this.state.contractKey
|
||||
};
|
||||
},
|
||||
|
||||
submitKey(key) {
|
||||
this.setState({
|
||||
contractKey: key
|
||||
});
|
||||
},
|
||||
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
isUploadReady: isReady
|
||||
@ -56,31 +51,25 @@ let CreateContractForm = React.createClass({
|
||||
this.refs.form.reset();
|
||||
},
|
||||
|
||||
submitFileName(fileName) {
|
||||
this.setState({
|
||||
contractName: fileName
|
||||
});
|
||||
|
||||
this.refs.form.submit();
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form
|
||||
ref='form'
|
||||
url={ApiUrls.ownership_contract_list}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.handleCreateSuccess}
|
||||
buttons={
|
||||
<button
|
||||
type="submit"
|
||||
className="btn ascribe-btn ascribe-btn-login"
|
||||
disabled={!this.state.isUploadReady}>
|
||||
{getLangText('Create new contract')}
|
||||
</button>
|
||||
}
|
||||
spinner={
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</span>
|
||||
}>
|
||||
handleSuccess={this.handleCreateSuccess}>
|
||||
<Property
|
||||
label="Contract file">
|
||||
<ReactS3FineUploader
|
||||
ref='uploader'
|
||||
name="blob"
|
||||
label={getLangText('Contract file (*.pdf only, max. 50MB per contract)')}>
|
||||
<InputFineUploader
|
||||
submitFileName={this.submitFileName}
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'contract'
|
||||
@ -89,46 +78,30 @@ let CreateContractForm = React.createClass({
|
||||
url: ApiUrls.blob_contracts
|
||||
}}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '50000000'
|
||||
}}
|
||||
signature={{
|
||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie(AppConstants.csrftoken)
|
||||
}
|
||||
}}
|
||||
deleteFile={{
|
||||
enabled: true,
|
||||
method: 'DELETE',
|
||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie(AppConstants.csrftoken)
|
||||
}
|
||||
itemLimit: AppConstants.fineUploader.validation.additionalData.itemLimit,
|
||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
|
||||
allowedExtensions: ['pdf']
|
||||
}}
|
||||
areAssetsDownloadable={true}
|
||||
areAssetsEditable={true}
|
||||
submitKey={this.submitKey}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}/>
|
||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||
fileClassToUpload={this.props.fileClassToUpload}/>
|
||||
</Property>
|
||||
<Property
|
||||
name='name'
|
||||
label={getLangText('Contract name')}>
|
||||
label={getLangText('Contract name')}
|
||||
hidden={true}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="(e.g. Contract - Loan agreement #1)"
|
||||
required/>
|
||||
value={this.state.contractName}/>
|
||||
</Property>
|
||||
<Property
|
||||
name="is_public"
|
||||
className="ascribe-settings-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputCheckbox>
|
||||
<span>
|
||||
Make contract public (this will replace the current public contract)
|
||||
</span>
|
||||
</InputCheckbox>
|
||||
hidden={true}>
|
||||
<input
|
||||
type="checkbox"
|
||||
value={this.props.isPublic} />
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
|
@ -10,6 +10,7 @@ import Property from './property';
|
||||
import InputFineUploader from './input_fineuploader';
|
||||
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
@ -99,6 +100,14 @@ let RegisterPieceForm = React.createClass({
|
||||
name="digital_work_key"
|
||||
ignoreFocus={true}>
|
||||
<InputFineUploader
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'digitalwork'
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: ApiUrls.blob_digitalworks
|
||||
}}
|
||||
validation={AppConstants.fineUploader.validation.registerWork}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||
isFineUploaderActive={this.props.isFineUploaderActive}
|
||||
|
@ -5,7 +5,6 @@ import React from 'react';
|
||||
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
|
||||
@ -13,7 +12,21 @@ let InputFileUploader = React.createClass({
|
||||
propTypes: {
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
submitFileName: React.PropTypes.func,
|
||||
|
||||
onClick: React.PropTypes.func,
|
||||
keyRoutine: React.PropTypes.shape({
|
||||
url: React.PropTypes.string,
|
||||
fileClass: React.PropTypes.string
|
||||
}),
|
||||
createBlobRoutine: React.PropTypes.shape({
|
||||
url: React.PropTypes.string
|
||||
}),
|
||||
validation: React.PropTypes.shape({
|
||||
itemLimit: React.PropTypes.number,
|
||||
sizeLimit: React.PropTypes.string,
|
||||
allowedExtensions: React.PropTypes.arrayOf(React.PropTypes.string)
|
||||
}),
|
||||
|
||||
// isFineUploaderActive is used to lock react fine uploader in case
|
||||
// a user is actually not logged in already to prevent him from droping files
|
||||
@ -24,7 +37,14 @@ let InputFileUploader = React.createClass({
|
||||
enableLocalHashing: React.PropTypes.bool,
|
||||
|
||||
// provided by Property
|
||||
disabled: React.PropTypes.bool
|
||||
disabled: React.PropTypes.bool,
|
||||
|
||||
// A class of a file the user has to upload
|
||||
// Needs to be defined both in singular as well as in plural
|
||||
fileClassToUpload: React.PropTypes.shape({
|
||||
singular: React.PropTypes.string,
|
||||
plural: React.PropTypes.string
|
||||
})
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
@ -33,10 +53,14 @@ let InputFileUploader = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
submitKey(key){
|
||||
submitFile(file){
|
||||
this.setState({
|
||||
value: key
|
||||
value: file.key
|
||||
});
|
||||
|
||||
if(typeof this.props.submitFileName === 'function') {
|
||||
this.props.submitFileName(file.originalName);
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
@ -56,18 +80,10 @@ let InputFileUploader = React.createClass({
|
||||
<ReactS3FineUploader
|
||||
ref="fineuploader"
|
||||
onClick={this.props.onClick}
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'digitalwork'
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: ApiUrls.blob_digitalworks
|
||||
}}
|
||||
submitKey={this.submitKey}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '25000000000'
|
||||
}}
|
||||
keyRoutine={this.props.keyRoutine}
|
||||
createBlobRoutine={this.props.createBlobRoutine}
|
||||
validation={this.props.validation}
|
||||
submitFile={this.submitFile}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
areAssetsDownloadable={false}
|
||||
@ -87,7 +103,8 @@ let InputFileUploader = React.createClass({
|
||||
}
|
||||
}}
|
||||
onInactive={this.props.onLoggedOut}
|
||||
enableLocalHashing={this.props.enableLocalHashing} />
|
||||
enableLocalHashing={this.props.enableLocalHashing}
|
||||
fileClassToUpload={this.props.fileClassToUpload}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -70,7 +70,7 @@ let Property = React.createClass({
|
||||
// In order to set this.state.value from another component
|
||||
// the state of value should only be set if its not undefined and
|
||||
// actually references something
|
||||
if(typeof childInput.getDOMNode().value !== 'undefined') {
|
||||
if(childInput && typeof childInput.getDOMNode().value !== 'undefined') {
|
||||
this.setState({
|
||||
value: childInput.getDOMNode().value
|
||||
});
|
||||
|
@ -9,12 +9,14 @@ import ContractListStore from '../../stores/contract_list_store';
|
||||
import ContractListActions from '../../actions/contract_list_actions';
|
||||
|
||||
import ActionPanel from '../ascribe_panel/action_panel';
|
||||
import ContractSettingsUpdateButton from './contract_settings_update_button';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
|
||||
let ContractSettings = React.createClass({
|
||||
propTypes: {
|
||||
defaultExpanded: React.PropTypes.bool
|
||||
@ -37,23 +39,6 @@ let ContractSettings = React.createClass({
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
makeContractPublic(contract) {
|
||||
return () => {
|
||||
contract.is_public = true;
|
||||
ContractListActions.changeContract(contract)
|
||||
.then(() => {
|
||||
ContractListActions.fetchContractList(true);
|
||||
let notification = getLangText('Contract %s is now public', contract.name);
|
||||
notification = new GlobalNotificationModel(notification, 'success', 4000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
})
|
||||
.catch((err) => {
|
||||
let notification = new GlobalNotificationModel(err, 'danger', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
removeContract(contract) {
|
||||
return () => {
|
||||
ContractListActions.removeContract(contract.id)
|
||||
@ -80,81 +65,92 @@ let ContractSettings = React.createClass({
|
||||
render() {
|
||||
let publicContracts = this.getPublicContracts();
|
||||
let privateContracts = this.getPrivateContracts();
|
||||
let createPublicContractForm = null;
|
||||
|
||||
if(publicContracts.length === 0) {
|
||||
createPublicContractForm = (
|
||||
<CreateContractForm
|
||||
isPublic={true}
|
||||
fileClassToUpload={{
|
||||
singular: 'new public contract',
|
||||
plural: 'new public contracts'
|
||||
}}/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Contract Settings')}
|
||||
title={getLangText('Contracts')}
|
||||
show={true}
|
||||
defaultExpanded={true}>
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('List Contracts')}
|
||||
title={getLangText('Public Contracts')}
|
||||
show={true}
|
||||
defaultExpanded={true}>
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Public Contracts')}
|
||||
show={true}
|
||||
defaultExpanded={true}>
|
||||
{publicContracts.map((contract, i) => {
|
||||
return (
|
||||
<ActionPanel
|
||||
key={i}
|
||||
title={contract.name}
|
||||
content={contract.name}
|
||||
buttons={
|
||||
<div className="pull-right">
|
||||
<button className="btn btn-default btn-sm margin-left-2px">
|
||||
UPDATE
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
onClick={this.removeContract(contract)}>
|
||||
REMOVE
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
leftColumnWidth="40%"
|
||||
rightColumnWidth="60%"/>
|
||||
);
|
||||
})}
|
||||
</CollapsibleParagraph>
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Private Contracts')}
|
||||
show={true}
|
||||
defaultExpanded={true}>
|
||||
{privateContracts.map((contract, i) => {
|
||||
return (
|
||||
<ActionPanel
|
||||
key={i}
|
||||
title={contract.name}
|
||||
content={contract.name}
|
||||
buttons={
|
||||
<div className="pull-right">
|
||||
<button className="btn btn-default btn-sm margin-left-2px">
|
||||
UPDATE
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
onClick={this.removeContract(contract)}>
|
||||
REMOVE
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
onClick={this.makeContractPublic(contract)}>
|
||||
MAKE PUBLIC
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
leftColumnWidth="40%"
|
||||
rightColumnWidth="60%"/>
|
||||
);
|
||||
})}
|
||||
</CollapsibleParagraph>
|
||||
{createPublicContractForm}
|
||||
{publicContracts.map((contract, i) => {
|
||||
return (
|
||||
<ActionPanel
|
||||
key={i}
|
||||
title={contract.name}
|
||||
content={contract.name}
|
||||
buttons={
|
||||
<div className="pull-right">
|
||||
<ContractSettingsUpdateButton contract={contract}/>
|
||||
<a
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
href={contract.blob.url_safe}
|
||||
target="_blank">
|
||||
{getLangText('PREVIEW')}
|
||||
</a>
|
||||
<button
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
onClick={this.removeContract(contract)}>
|
||||
{getLangText('REMOVE')}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
leftColumnWidth="40%"
|
||||
rightColumnWidth="60%"/>
|
||||
);
|
||||
})}
|
||||
</CollapsibleParagraph>
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Create Contract')}
|
||||
title={getLangText('Private Contracts')}
|
||||
show={true}
|
||||
defaultExpanded={true}>
|
||||
<CreateContractForm />
|
||||
<CreateContractForm
|
||||
isPublic={false}
|
||||
fileClassToUpload={{
|
||||
singular: getLangText('new private contract'),
|
||||
plural: getLangText('new private contracts')
|
||||
}}/>
|
||||
{privateContracts.map((contract, i) => {
|
||||
return (
|
||||
<ActionPanel
|
||||
key={i}
|
||||
title={contract.name}
|
||||
content={contract.name}
|
||||
buttons={
|
||||
<div className="pull-right">
|
||||
<ContractSettingsUpdateButton contract={contract} />
|
||||
<a
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
href={contract.blob.url_safe}
|
||||
target="_blank">
|
||||
{getLangText('PREVIEW')}
|
||||
</a>
|
||||
<button
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
onClick={this.removeContract(contract)}>
|
||||
{getLangText('REMOVE')}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
leftColumnWidth="40%"
|
||||
rightColumnWidth="60%"/>
|
||||
);
|
||||
})}
|
||||
</CollapsibleParagraph>
|
||||
</CollapsibleParagraph>
|
||||
);
|
||||
|
@ -0,0 +1,98 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
||||
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
|
||||
import ContractListActions from '../../actions/contract_list_actions';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
|
||||
let ContractSettingsUpdateButton = React.createClass({
|
||||
propTypes: {
|
||||
contract: React.PropTypes.object
|
||||
},
|
||||
|
||||
submitFile(file) {
|
||||
let contract = this.props.contract;
|
||||
|
||||
// override the blob with the key's value
|
||||
contract.blob = file.key;
|
||||
|
||||
// send it to the server
|
||||
ContractListActions
|
||||
.changeContract(contract)
|
||||
.then((res) => {
|
||||
|
||||
// Display feedback to the user
|
||||
let notification = new GlobalNotificationModel(getLangText('Contract %s successfully updated', res.name), 'success', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
// and refresh the contract list to get the updated contracs
|
||||
return ContractListActions.fetchContractList(true);
|
||||
})
|
||||
.then(() => {
|
||||
// Also, reset the fineuploader component so that the user can again 'update' his contract
|
||||
this.refs.fineuploader.reset();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.logGlobal(err);
|
||||
let notification = new GlobalNotificationModel(getLangText('Contract could not be updated'), 'success', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ReactS3FineUploader
|
||||
ref="fineuploader"
|
||||
fileInputElement={UploadButton}
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'contract'
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: ApiUrls.blob_contracts
|
||||
}}
|
||||
validation={{
|
||||
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
|
||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
|
||||
allowedExtensions: ['pdf']
|
||||
}}
|
||||
setIsUploadReady={() =>{/* So that ReactS3FineUploader is not complaining */}}
|
||||
signature={{
|
||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie(AppConstants.csrftoken)
|
||||
}
|
||||
}}
|
||||
deleteFile={{
|
||||
enabled: true,
|
||||
method: 'DELETE',
|
||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie(AppConstants.csrftoken)
|
||||
}
|
||||
}}
|
||||
fileClassToUpload={{
|
||||
singular: getLangText('UPDATE'),
|
||||
plural: getLangText('UPDATE')
|
||||
}}
|
||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||
submitFile={this.submitFile}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default ContractSettingsUpdateButton;
|
@ -26,8 +26,6 @@ let SettingsContainer = React.createClass({
|
||||
<APISettings />
|
||||
<BitcoinWalletSettings />
|
||||
<ContractSettings />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -6,20 +6,14 @@ import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
||||
import FileDragAndDropDialog from './file_drag_and_drop_dialog';
|
||||
import FileDragAndDropPreviewIterator from './file_drag_and_drop_preview_iterator';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
|
||||
// Taken from: https://github.com/fedosejev/react-file-drag-and-drop
|
||||
let FileDragAndDrop = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
onDragStart: React.PropTypes.func,
|
||||
onDrop: React.PropTypes.func.isRequired,
|
||||
onDrag: React.PropTypes.func,
|
||||
onDragEnter: React.PropTypes.func,
|
||||
onLeave: React.PropTypes.func,
|
||||
onDragLeave: React.PropTypes.func,
|
||||
onDragOver: React.PropTypes.func,
|
||||
onDragEnd: React.PropTypes.func,
|
||||
onInactive: React.PropTypes.func,
|
||||
filesToUpload: React.PropTypes.array,
|
||||
handleDeleteFile: React.PropTypes.func,
|
||||
@ -37,37 +31,16 @@ let FileDragAndDrop = React.createClass({
|
||||
hashingProgress: React.PropTypes.number,
|
||||
// sets the value of this.state.hashingProgress in reactfineuploader
|
||||
// to -1 which is code for: aborted
|
||||
handleCancelHashing: React.PropTypes.func
|
||||
},
|
||||
handleCancelHashing: React.PropTypes.func,
|
||||
|
||||
handleDragStart(event) {
|
||||
if (typeof this.props.onDragStart === 'function') {
|
||||
this.props.onDragStart(event);
|
||||
}
|
||||
},
|
||||
// A class of a file the user has to upload
|
||||
// Needs to be defined both in singular as well as in plural
|
||||
fileClassToUpload: React.PropTypes.shape({
|
||||
singular: React.PropTypes.string,
|
||||
plural: React.PropTypes.string
|
||||
}),
|
||||
|
||||
handleDrag(event) {
|
||||
if (typeof this.props.onDrag === 'function') {
|
||||
this.props.onDrag(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleDragEnd(event) {
|
||||
if (typeof this.props.onDragEnd === 'function') {
|
||||
this.props.onDragEnd(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleDragEnter(event) {
|
||||
if (typeof this.props.onDragEnter === 'function') {
|
||||
this.props.onDragEnter(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleDragLeave(event) {
|
||||
if (typeof this.props.onDragLeave === 'function') {
|
||||
this.props.onDragLeave(event);
|
||||
}
|
||||
allowedExtensions: React.PropTypes.string
|
||||
},
|
||||
|
||||
handleDragOver(event) {
|
||||
@ -159,14 +132,27 @@ let FileDragAndDrop = React.createClass({
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let { filesToUpload,
|
||||
dropzoneInactive,
|
||||
className,
|
||||
hashingProgress,
|
||||
handleCancelHashing,
|
||||
multiple,
|
||||
enableLocalHashing,
|
||||
fileClassToUpload,
|
||||
areAssetsDownloadable,
|
||||
areAssetsEditable,
|
||||
allowedExtensions
|
||||
} = this.props;
|
||||
|
||||
// has files only is true if there are files that do not have the status deleted or canceled
|
||||
let hasFiles = this.props.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0;
|
||||
let className = hasFiles ? 'has-files ' : '';
|
||||
className += this.props.dropzoneInactive ? 'inactive-dropzone' : 'active-dropzone';
|
||||
className += this.props.className ? ' ' + this.props.className : '';
|
||||
let hasFiles = filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0;
|
||||
let updatedClassName = hasFiles ? 'has-files ' : '';
|
||||
updatedClassName += dropzoneInactive ? 'inactive-dropzone' : 'active-dropzone';
|
||||
updatedClassName += ' file-drag-and-drop';
|
||||
|
||||
// if !== -2: triggers a FileDragAndDrop-global spinner
|
||||
if(this.props.hashingProgress !== -2) {
|
||||
if(hashingProgress !== -2) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className="file-drag-and-drop-hashing-dialog">
|
||||
@ -184,29 +170,26 @@ let FileDragAndDrop = React.createClass({
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
onDragStart={this.handleDragStart}
|
||||
className={updatedClassName}
|
||||
onDrag={this.handleDrop}
|
||||
onDragEnter={this.handleDragEnter}
|
||||
onDragLeave={this.handleDragLeave}
|
||||
onDragOver={this.handleDragOver}
|
||||
onDrop={this.handleDrop}
|
||||
onDragEnd={this.handleDragEnd}>
|
||||
onDrop={this.handleDrop}>
|
||||
<FileDragAndDropDialog
|
||||
multipleFiles={this.props.multiple}
|
||||
multipleFiles={multiple}
|
||||
hasFiles={hasFiles}
|
||||
onClick={this.handleOnClick}
|
||||
enableLocalHashing={this.props.enableLocalHashing}/>
|
||||
enableLocalHashing={enableLocalHashing}
|
||||
fileClassToUpload={fileClassToUpload}/>
|
||||
<FileDragAndDropPreviewIterator
|
||||
files={this.props.filesToUpload}
|
||||
files={filesToUpload}
|
||||
handleDeleteFile={this.handleDeleteFile}
|
||||
handleCancelFile={this.handleCancelFile}
|
||||
handlePauseFile={this.handlePauseFile}
|
||||
handleResumeFile={this.handleResumeFile}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}
|
||||
areAssetsEditable={this.props.areAssetsEditable}/>
|
||||
areAssetsDownloadable={areAssetsDownloadable}
|
||||
areAssetsEditable={areAssetsEditable}/>
|
||||
<input
|
||||
multiple={this.props.multiple}
|
||||
multiple={multiple}
|
||||
ref="fileinput"
|
||||
type="file"
|
||||
style={{
|
||||
@ -214,7 +197,8 @@ let FileDragAndDrop = React.createClass({
|
||||
height: 0,
|
||||
width: 0
|
||||
}}
|
||||
onChange={this.handleDrop} />
|
||||
onChange={this.handleDrop}
|
||||
accept={allowedExtensions}/>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
let Link = Router.Link;
|
||||
|
||||
@ -12,7 +12,14 @@ let FileDragAndDropDialog = React.createClass({
|
||||
hasFiles: React.PropTypes.bool,
|
||||
multipleFiles: React.PropTypes.bool,
|
||||
onClick: React.PropTypes.func,
|
||||
enableLocalHashing: React.PropTypes.bool
|
||||
enableLocalHashing: React.PropTypes.bool,
|
||||
|
||||
// A class of a file the user has to upload
|
||||
// Needs to be defined both in singular as well as in plural
|
||||
fileClassToUpload: React.PropTypes.shape({
|
||||
singular: React.PropTypes.string,
|
||||
plural: React.PropTypes.string
|
||||
})
|
||||
},
|
||||
|
||||
mixins: [Router.State],
|
||||
@ -56,29 +63,29 @@ let FileDragAndDropDialog = React.createClass({
|
||||
} else {
|
||||
if(this.props.multipleFiles) {
|
||||
return (
|
||||
<div className="file-drag-and-drop-dialog">
|
||||
<p>{getLangText('Drag files here')}</p>
|
||||
<span className="file-drag-and-drop-dialog">
|
||||
<p>{getLangText('Drag %s here', this.props.fileClassToUpload.plural)}</p>
|
||||
<p>{getLangText('or')}</p>
|
||||
<span
|
||||
className="btn btn-default"
|
||||
onClick={this.props.onClick}>
|
||||
{getLangText('choose files to upload')}
|
||||
{getLangText('choose %s to upload', this.props.fileClassToUpload.plural)}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
let dialog = queryParams.method === 'hash' ? getLangText('choose a file to hash') : getLangText('choose a file to upload');
|
||||
let dialog = queryParams.method === 'hash' ? getLangText('choose a %s to hash', this.props.fileClassToUpload.singular) : getLangText('choose a %s to upload', this.props.fileClassToUpload.singular);
|
||||
|
||||
return (
|
||||
<div className="file-drag-and-drop-dialog">
|
||||
<p>{getLangText('Drag a file here')}</p>
|
||||
<span className="file-drag-and-drop-dialog">
|
||||
<p>{getLangText('Drag a %s here', this.props.fileClassToUpload.singular)}</p>
|
||||
<p>{getLangText('or')}</p>
|
||||
<span
|
||||
className="btn btn-default"
|
||||
onClick={this.props.onClick}>
|
||||
{dialog}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ import React from 'react';
|
||||
|
||||
import FileDragAndDropPreviewImage from './file_drag_and_drop_preview_image';
|
||||
import FileDragAndDropPreviewOther from './file_drag_and_drop_preview_other';
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
|
||||
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
let FileDragAndDropPreview = React.createClass({
|
||||
|
||||
@ -43,6 +45,7 @@ let FileDragAndDropPreview = React.createClass({
|
||||
|
||||
handleDownloadFile() {
|
||||
if(this.props.file.s3Url) {
|
||||
// This simply opens a new browser tab with the url provided
|
||||
open(this.props.file.s3Url);
|
||||
}
|
||||
},
|
@ -3,8 +3,8 @@
|
||||
import React from 'react';
|
||||
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
import AppConstants from '../../../constants/application_constants';
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
let FileDragAndDropPreviewImage = React.createClass({
|
||||
propTypes: {
|
@ -5,7 +5,7 @@ import React from 'react';
|
||||
import FileDragAndDropPreview from './file_drag_and_drop_preview';
|
||||
import FileDragAndDropPreviewProgress from './file_drag_and_drop_preview_progress';
|
||||
|
||||
import { displayValidFilesFilter } from './react_s3_fine_uploader_utils';
|
||||
import { displayValidFilesFilter } from '../react_s3_fine_uploader_utils';
|
||||
|
||||
|
||||
let FileDragAndDropPreviewIterator = React.createClass({
|
@ -3,8 +3,8 @@
|
||||
import React from 'react';
|
||||
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
import AppConstants from '../../../constants/application_constants';
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
let FileDragAndDropPreviewOther = React.createClass({
|
||||
propTypes: {
|
||||
@ -61,7 +61,7 @@ let FileDragAndDropPreviewOther = React.createClass({
|
||||
<div className="file-drag-and-drop-preview-table-wrapper">
|
||||
<div className="file-drag-and-drop-preview-other">
|
||||
{actionSymbol}
|
||||
<span>{'.' + this.props.type}</span>
|
||||
<p>{'.' + this.props.type}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -4,7 +4,8 @@ import React from 'react';
|
||||
|
||||
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
||||
|
||||
import { displayValidProgressFilesFilter } from './react_s3_fine_uploader_utils';
|
||||
import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils';
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
|
||||
let FileDragAndDropPreviewProgress = React.createClass({
|
||||
@ -54,7 +55,7 @@ let FileDragAndDropPreviewProgress = React.createClass({
|
||||
return (
|
||||
<ProgressBar
|
||||
now={Math.ceil(overallProgress)}
|
||||
label="Overall progress: %(percent)s%"
|
||||
label={getLangText('Overall progress%s', ': %(percent)s%')}
|
||||
className="ascribe-progress-bar"
|
||||
style={style} />
|
||||
);
|
@ -0,0 +1,103 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils';
|
||||
import { getLangText } from '../../../utils/lang_utils';
|
||||
|
||||
|
||||
let UploadButton = React.createClass({
|
||||
propTypes: {
|
||||
onDrop: React.PropTypes.func.isRequired,
|
||||
filesToUpload: React.PropTypes.array,
|
||||
multiple: React.PropTypes.bool,
|
||||
|
||||
// For simplification purposes we're just going to use this prop as a
|
||||
// label for the upload button
|
||||
fileClassToUpload: React.PropTypes.shape({
|
||||
singular: React.PropTypes.string,
|
||||
plural: React.PropTypes.string
|
||||
}),
|
||||
|
||||
allowedExtensions: React.PropTypes.string
|
||||
},
|
||||
|
||||
handleDrop(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let files = event.target.files;
|
||||
|
||||
if(typeof this.props.onDrop === 'function' && files) {
|
||||
this.props.onDrop(files);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getUploadingFiles() {
|
||||
return this.props.filesToUpload.filter((file) => file.status === 'uploading');
|
||||
},
|
||||
|
||||
handleOnClick() {
|
||||
let uploadingFiles = this.getUploadingFiles();
|
||||
|
||||
// We only want the button to be clickable if there are no files currently uploading
|
||||
if(uploadingFiles.length === 0) {
|
||||
// Firefox only recognizes the simulated mouse click if bubbles is set to true,
|
||||
// but since Google Chrome propagates the event much further than needed, we
|
||||
// need to stop propagation as soon as the event is created
|
||||
var evt = new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
|
||||
evt.stopPropagation();
|
||||
this.refs.fileinput.getDOMNode().dispatchEvent(evt);
|
||||
}
|
||||
},
|
||||
|
||||
getButtonLabel() {
|
||||
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) {
|
||||
return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
|
||||
} else {
|
||||
return fileClassToUpload.singular;
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
let {
|
||||
multiple,
|
||||
fileClassToUpload,
|
||||
allowedExtensions
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={this.handleOnClick}
|
||||
className="btn btn-default btn-sm margin-left-2px"
|
||||
disabled={this.getUploadingFiles().length !== 0}>
|
||||
{this.getButtonLabel()}
|
||||
<input
|
||||
multiple={multiple}
|
||||
ref="fileinput"
|
||||
type="file"
|
||||
style={{
|
||||
display: 'none',
|
||||
height: 0,
|
||||
width: 0
|
||||
}}
|
||||
onChange={this.handleDrop}
|
||||
accept={allowedExtensions}/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default UploadButton;
|
@ -1,13 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react/addons';
|
||||
import fineUploader from 'fineUploader';
|
||||
import Router from 'react-router';
|
||||
import Q from 'q';
|
||||
|
||||
import S3Fetcher from '../../fetchers/s3_fetcher';
|
||||
|
||||
import fineUploader from 'fineUploader';
|
||||
import FileDragAndDrop from './file_drag_and_drop';
|
||||
import FileDragAndDrop from './ascribe_file_drag_and_drop/file_drag_and_drop';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
@ -15,10 +15,11 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { computeHashOfFile } from '../../utils/file_utils';
|
||||
import { displayValidFilesFilter } from './react_s3_fine_uploader_utils';
|
||||
import { displayValidFilesFilter, transformAllowedExtensionsToInputAcceptProp } from './react_s3_fine_uploader_utils';
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
|
||||
let ReactS3FineUploader = React.createClass({
|
||||
propTypes: {
|
||||
keyRoutine: React.PropTypes.shape({
|
||||
@ -36,7 +37,7 @@ let ReactS3FineUploader = React.createClass({
|
||||
React.PropTypes.number
|
||||
])
|
||||
}),
|
||||
submitKey: React.PropTypes.func,
|
||||
submitFile: React.PropTypes.func,
|
||||
autoUpload: React.PropTypes.bool,
|
||||
debug: React.PropTypes.bool,
|
||||
objectProperties: React.PropTypes.shape({
|
||||
@ -83,7 +84,8 @@ let ReactS3FineUploader = React.createClass({
|
||||
}),
|
||||
validation: React.PropTypes.shape({
|
||||
itemLimit: React.PropTypes.number,
|
||||
sizeLimit: React.PropTypes.string
|
||||
sizeLimit: React.PropTypes.string,
|
||||
allowedExtensions: React.PropTypes.arrayOf(React.PropTypes.string)
|
||||
}),
|
||||
messages: React.PropTypes.shape({
|
||||
unsupportedBrowser: React.PropTypes.string
|
||||
@ -110,7 +112,22 @@ let ReactS3FineUploader = React.createClass({
|
||||
enableLocalHashing: React.PropTypes.bool,
|
||||
|
||||
// automatically injected by React-Router
|
||||
query: React.PropTypes.object
|
||||
query: React.PropTypes.object,
|
||||
|
||||
// A class of a file the user has to upload
|
||||
// Needs to be defined both in singular as well as in plural
|
||||
fileClassToUpload: React.PropTypes.shape({
|
||||
singular: React.PropTypes.string,
|
||||
plural: React.PropTypes.string
|
||||
}),
|
||||
|
||||
// Uploading functionality of react fineuploader is disconnected from its UI
|
||||
// layer, which means that literally every (properly adjusted) react element
|
||||
// can handle the UI handling.
|
||||
fileInputElement: React.PropTypes.oneOfType([
|
||||
React.PropTypes.func,
|
||||
React.PropTypes.element
|
||||
])
|
||||
},
|
||||
|
||||
mixins: [Router.State],
|
||||
@ -162,7 +179,12 @@ let ReactS3FineUploader = React.createClass({
|
||||
return name;
|
||||
},
|
||||
multiple: false,
|
||||
defaultErrorMessage: getLangText('Unexpected error. Please contact us if this happens repeatedly.')
|
||||
defaultErrorMessage: getLangText('Unexpected error. Please contact us if this happens repeatedly.'),
|
||||
fileClassToUpload: {
|
||||
singular: getLangText('file'),
|
||||
plural: getLangText('files')
|
||||
},
|
||||
fileInputElement: FileDragAndDrop
|
||||
};
|
||||
},
|
||||
|
||||
@ -386,12 +408,12 @@ let ReactS3FineUploader = React.createClass({
|
||||
// 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 submitKey
|
||||
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitFile
|
||||
// are optional, we'll only trigger them when they're actually defined
|
||||
if(this.props.submitKey) {
|
||||
this.props.submitKey(files[id].key);
|
||||
if(this.props.submitFile) {
|
||||
this.props.submitFile(files[id]);
|
||||
} else {
|
||||
console.warn('You didn\'t define submitKey in as a prop in react-s3-fine-uploader');
|
||||
console.warn('You didn\'t define submitFile in as a prop in react-s3-fine-uploader');
|
||||
}
|
||||
|
||||
// for explanation, check comment of if statement above
|
||||
@ -426,7 +448,7 @@ let ReactS3FineUploader = React.createClass({
|
||||
});
|
||||
this.state.uploader.cancelAll();
|
||||
|
||||
let notification = new GlobalNotificationModel(this.props.defaultErrorMessage, 'danger', 5000);
|
||||
let notification = new GlobalNotificationModel(errorReason || this.props.defaultErrorMessage, 'danger', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
@ -451,7 +473,7 @@ let ReactS3FineUploader = React.createClass({
|
||||
let notification = new GlobalNotificationModel(getLangText('File upload canceled'), 'success', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitKey
|
||||
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitFile
|
||||
// are optional, we'll only trigger them when they're actually defined
|
||||
if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) {
|
||||
if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
|
||||
@ -518,7 +540,7 @@ let ReactS3FineUploader = React.createClass({
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
}
|
||||
|
||||
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitKey
|
||||
// since the form validation props isReadyForFormSubmission, setIsUploadReady and submitFile
|
||||
// are optional, we'll only trigger them when they're actually defined
|
||||
if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) {
|
||||
// also, lets check if after the completion of this upload,
|
||||
@ -818,27 +840,48 @@ let ReactS3FineUploader = React.createClass({
|
||||
|
||||
},
|
||||
|
||||
getAllowedExtensions() {
|
||||
let { validation } = this.props;
|
||||
|
||||
if(validation && validation.allowedExtensions && validation.allowedExtensions.length > 0) {
|
||||
return transformAllowedExtensionsToInputAcceptProp(validation.allowedExtensions);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<FileDragAndDrop
|
||||
className="file-drag-and-drop"
|
||||
onDrop={this.handleUploadFile}
|
||||
filesToUpload={this.state.filesToUpload}
|
||||
handleDeleteFile={this.handleDeleteFile}
|
||||
handleCancelFile={this.handleCancelFile}
|
||||
handlePauseFile={this.handlePauseFile}
|
||||
handleResumeFile={this.handleResumeFile}
|
||||
handleCancelHashing={this.handleCancelHashing}
|
||||
multiple={this.props.multiple}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}
|
||||
areAssetsEditable={this.props.areAssetsEditable}
|
||||
onInactive={this.props.onInactive}
|
||||
dropzoneInactive={this.isDropzoneInactive()}
|
||||
hashingProgress={this.state.hashingProgress}
|
||||
enableLocalHashing={this.props.enableLocalHashing} />
|
||||
</div>
|
||||
);
|
||||
let {
|
||||
multiple,
|
||||
areAssetsDownloadable,
|
||||
areAssetsEditable,
|
||||
onInactive,
|
||||
enableLocalHashing,
|
||||
fileClassToUpload,
|
||||
validation,
|
||||
fileInputElement
|
||||
} = this.props;
|
||||
|
||||
// Here we initialize the template that has been either provided from the outside
|
||||
// or the default input that is FileDragAndDrop.
|
||||
return React.createElement(fileInputElement, {
|
||||
onDrop: this.handleUploadFile,
|
||||
filesToUpload: this.state.filesToUpload,
|
||||
handleDeleteFile: this.handleDeleteFile,
|
||||
handleCancelFile: this.handleCancelFile,
|
||||
handlePauseFile: this.handlePauseFile,
|
||||
handleResumeFile: this.handleResumeFile,
|
||||
handleCancelHashing: this.handleCancelHashing,
|
||||
multiple: multiple,
|
||||
areAssetsDownloadable: areAssetsDownloadable,
|
||||
areAssetsEditable: areAssetsEditable,
|
||||
onInactive: onInactive,
|
||||
dropzoneInactive: this.isDropzoneInactive(),
|
||||
hashingProgress: this.state.hashingProgress,
|
||||
enableLocalHashing: enableLocalHashing,
|
||||
fileClassToUpload: fileClassToUpload,
|
||||
allowedExtensions: this.getAllowedExtensions()
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -52,3 +52,22 @@ export function displayValidProgressFilesFilter(file) {
|
||||
return file.status !== 'deleted' && file.status !== 'canceled' && file.status !== 'online';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fineuploader allows to specify the file extensions that are allowed to upload.
|
||||
* For our self defined input, we can reuse those declarations to restrict which files
|
||||
* the user can pick from his hard drive.
|
||||
*
|
||||
* Takes an array of file extensions (['pdf', 'png', ...]) and transforms them into a string
|
||||
* that can be passed into an html5 input via its 'accept' prop.
|
||||
* @param {array} allowedExtensions Array of strings without a dot prefixed
|
||||
* @return {string} Joined string (comma-separated) of the passed-in array
|
||||
*/
|
||||
export function transformAllowedExtensionsToInputAcceptProp(allowedExtensions) {
|
||||
// add a dot in front of the extension
|
||||
let prefixedAllowedExtensions = allowedExtensions.map((ext) => '.' + ext);
|
||||
|
||||
// generate a comma separated list to add them to the DOM element
|
||||
// See: http://stackoverflow.com/questions/4328947/limit-file-format-when-using-input-type-file
|
||||
return prefixedAllowedExtensions.join(', ');
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
</Property>
|
||||
<FurtherDetailsFileuploader
|
||||
uploadStarted={this.uploadStarted}
|
||||
submitKey={this.submitKey}
|
||||
submitFile={this.submitFile}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={formSubmissionValidation.fileOptional}
|
||||
editable={!this.props.disabled}
|
||||
|
@ -57,6 +57,19 @@ let constants = {
|
||||
// Source: http://www.w3schools.com/tags/att_input_type.asp
|
||||
'possibleInputTypes': ['button', 'checkbox', 'color', 'date', 'datetime', 'datetime-local', 'email', 'file', 'hidden', 'image', 'month', 'number', 'password', 'radio', 'range', 'reset', 'search', 'submit', 'tel', 'text', 'time', 'url', 'week'],
|
||||
|
||||
'fineUploader': {
|
||||
'validation': {
|
||||
'additionalData': {
|
||||
'itemLimit': 100,
|
||||
'sizeLimit': '50000000'
|
||||
},
|
||||
'registerWork': {
|
||||
'itemLimit': 1,
|
||||
'sizeLimit': '25000000000'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// in case of whitelabel customization, we store stuff here
|
||||
'whitelabel': {},
|
||||
'raven': {
|
||||
|
@ -48,7 +48,7 @@ let OwnershipFetcher = {
|
||||
return requests.get(ApiUrls.ownership_loans_pieces_request);
|
||||
},
|
||||
|
||||
makeContractPublic(contractObj){
|
||||
changeContract(contractObj){
|
||||
return requests.put(ApiUrls.ownership_contract, { body: contractObj, contract_id: contractObj.id });
|
||||
},
|
||||
|
||||
|
@ -25,8 +25,7 @@
|
||||
border: 0;
|
||||
width: 100%;
|
||||
|
||||
/* Shrink the size of the headline for a nested element */
|
||||
.ascribe-collapsible-wrapper > .ascribe-collapsible-content {
|
||||
.ascribe-collapsible-wrapper {
|
||||
padding-left: 1em;
|
||||
font-size: 95%;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: default !important;
|
||||
padding: 1.5em 0 1.5em 0;
|
||||
|
||||
.file-drag-and-drop-dialog > p:first-child {
|
||||
font-size: 1.5em !important;
|
||||
|
Loading…
Reference in New Issue
Block a user