mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
Merge remote-tracking branch 'remotes/origin/AD-496-add-control-buttons-to-fineupload' into AD-368-harmonize-functionality-of-ascrib
This commit is contained in:
commit
ca3b058b4d
@ -18,7 +18,10 @@ let AccordionList = React.createClass({
|
||||
);
|
||||
} else if(this.props.itemList.length === 0) {
|
||||
return (
|
||||
<p className="text-center">You don't have any works yet...</p>
|
||||
<div>
|
||||
<p className="text-center">You don't have any works yet...</p>
|
||||
<p className="text-center">To register one, click <a href="register_piece">here</a>!</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
|
@ -16,10 +16,10 @@ let AccordionListItem = React.createClass({
|
||||
<div className="row">
|
||||
<div className={this.props.className}>
|
||||
<div className="wrapper">
|
||||
<div className="col-xs-4 col-sm-4 col-md-4 col-lg-4 thumbnail-wrapper">
|
||||
<div className="col-xs-5 col-sm-5 col-md-4 col-lg-4 thumbnail-wrapper">
|
||||
<img src={this.props.content.thumbnail} />
|
||||
</div>
|
||||
<div className="col-xs-7 col-sm-7 col-md-7 col-lg-7 col-xs-offset-1 col-sm-offset-1 col-md-offset-1 col-lg-offset-1">
|
||||
<div className="col-xs-7 col-sm-7 col-md-7 col-lg-7 col-md-offset-1 col-lg-offset-1">
|
||||
<h1>{this.props.content.title}</h1>
|
||||
<h3>{getLangText('by %s', this.props.content.artist_name)}</h3>
|
||||
<h3>{this.props.content.date_created.split('-')[0]}</h3>
|
||||
|
@ -24,6 +24,7 @@ let AccordionListItemTable = React.createClass({
|
||||
return (
|
||||
<div className={this.props.className}>
|
||||
<Table
|
||||
responsive
|
||||
className="ascribe-table"
|
||||
columnList={this.props.columnList}
|
||||
itemList={this.props.itemList}
|
||||
|
@ -121,7 +121,7 @@ let AccordionListItemTableEditions = React.createClass({
|
||||
'Edition',
|
||||
TableItemText,
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
transition
|
||||
),
|
||||
new ColumnModel(
|
||||
@ -130,11 +130,12 @@ let AccordionListItemTableEditions = React.createClass({
|
||||
'content': item.bitcoin_id
|
||||
}; },
|
||||
'bitcoin_id',
|
||||
getLangText('Bitcoin Address'),
|
||||
getLangText('ID'),
|
||||
TableItemText,
|
||||
5,
|
||||
true,
|
||||
transition
|
||||
false,
|
||||
transition,
|
||||
'hidden-xs visible-sm'
|
||||
),
|
||||
new ColumnModel(
|
||||
(item) => {
|
||||
|
@ -19,7 +19,8 @@ let AclButton = React.createClass({
|
||||
availableAcls: React.PropTypes.array.isRequired,
|
||||
editions: React.PropTypes.array.isRequired,
|
||||
currentUser: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func.isRequired
|
||||
handleSuccess: React.PropTypes.func.isRequired,
|
||||
className: React.PropTypes.string
|
||||
},
|
||||
|
||||
actionProperties(){
|
||||
@ -74,9 +75,9 @@ let AclButton = React.createClass({
|
||||
return (
|
||||
<ModalWrapper
|
||||
button={
|
||||
<div className={shouldDisplay ? 'btn btn-default btn-sm' : 'hidden'}>
|
||||
<button className={shouldDisplay ? 'btn btn-default btn-sm ' : 'hidden'}>
|
||||
{this.props.action.toUpperCase()}
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
handleSuccess={ aclProps.handleSuccess }
|
||||
title={ aclProps.title }
|
||||
|
@ -41,7 +41,7 @@ let AclButtonList = React.createClass({
|
||||
action="transfer"
|
||||
editions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
handleSuccess={this.props.handleSuccess}/>
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="consign"
|
||||
|
@ -97,12 +97,12 @@ let PieceListBulkModal = React.createClass({
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
<div className="row">
|
||||
<div className="row-fluid">
|
||||
<AclButtonList
|
||||
availableAcls={availableAcls}
|
||||
editions={selectedEditions}
|
||||
handleSuccess={this.handleSuccess}
|
||||
className="text-center"/>
|
||||
className="text-center ascribe-button-list collapse-group"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,13 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import Input from 'react-bootstrap/lib/Input';
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
|
||||
let Link = Router.Link;
|
||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
import Col from 'react-bootstrap/lib/Col';
|
||||
|
||||
let PieceListToolbar = React.createClass({
|
||||
|
||||
@ -29,15 +28,19 @@ let PieceListToolbar = React.createClass({
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-md-12 col-md-5 col-lg-4 col-sm-offset-1 col-md-offset-2 col-lg-offset-2 clear-paddings">
|
||||
<div className="form-inline">
|
||||
<Input type='text' ref="search" placeholder="Search..." onChange={this.searchFor} addonAfter={searchIcon} />
|
||||
|
||||
{/*<PieceListToolbarFilterWidgetFilter />*/}
|
||||
<Link to="register_piece">
|
||||
<Button>+ Artwork</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-xs-12 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2 clear-paddings">
|
||||
<Input wrapperClassName='wrapper'>
|
||||
<Row>
|
||||
<Col xs={7} sm={4}>
|
||||
<Input type='text' ref="search" placeholder="Search..." onChange={this.searchFor} addonAfter={searchIcon} />
|
||||
</Col>
|
||||
<Col xs={5} sm={5}>
|
||||
<ButtonLink to="register_piece">
|
||||
+ Artwork
|
||||
</ButtonLink>
|
||||
</Col>
|
||||
</Row>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
export class ColumnModel {
|
||||
// ToDo: Add validation for all passed-in parameters
|
||||
constructor(transformFn, columnName, displayName, displayType, rowWidth, canBeOrdered, transition) {
|
||||
constructor(transformFn, columnName, displayName, displayType, rowWidth, canBeOrdered, transition, className) {
|
||||
this.transformFn = transformFn;
|
||||
this.columnName = columnName;
|
||||
this.displayName = displayName;
|
||||
@ -10,6 +10,7 @@ export class ColumnModel {
|
||||
this.rowWidth = rowWidth;
|
||||
this.canBeOrdered = canBeOrdered;
|
||||
this.transition = transition;
|
||||
this.className = className ? className : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,17 +23,18 @@ let TableHeader = React.createClass({
|
||||
return (
|
||||
<thead>
|
||||
<tr>
|
||||
{this.props.columnList.map((val, i) => {
|
||||
{this.props.columnList.map((column, i) => {
|
||||
|
||||
let columnClasses = this.calcColumnClasses(this.props.columnList, i, 12);
|
||||
let columnName = this.props.columnList[i].columnName;
|
||||
let canBeOrdered = this.props.columnList[i].canBeOrdered;
|
||||
let columnName = column.columnName;
|
||||
let canBeOrdered = column.canBeOrdered;
|
||||
|
||||
return (
|
||||
<TableHeaderItem
|
||||
className={column.className}
|
||||
key={i}
|
||||
columnClasses={columnClasses}
|
||||
displayName={val.displayName}
|
||||
displayName={column.displayName}
|
||||
columnName={columnName}
|
||||
canBeOrdered={canBeOrdered}
|
||||
orderAsc={this.props.orderAsc}
|
||||
|
@ -16,7 +16,8 @@ let TableHeaderItem = React.createClass({
|
||||
canBeOrdered: React.PropTypes.bool,
|
||||
changeOrder: React.PropTypes.func,
|
||||
orderAsc: React.PropTypes.bool,
|
||||
orderBy: React.PropTypes.string
|
||||
orderBy: React.PropTypes.string,
|
||||
className: React.PropTypes.string
|
||||
},
|
||||
|
||||
changeOrder() {
|
||||
@ -28,7 +29,7 @@ let TableHeaderItem = React.createClass({
|
||||
if(this.props.columnName === this.props.orderBy) {
|
||||
return (
|
||||
<th
|
||||
className={'ascribe-table-header-column'}
|
||||
className={'ascribe-table-header-column ' + this.props.className}
|
||||
onClick={this.changeOrder}>
|
||||
<span>{this.props.displayName} <TableHeaderItemCarret orderAsc={this.props.orderAsc} /></span>
|
||||
</th>
|
||||
@ -36,7 +37,7 @@ let TableHeaderItem = React.createClass({
|
||||
} else {
|
||||
return (
|
||||
<th
|
||||
className={'ascribe-table-header-column'}
|
||||
className={'ascribe-table-header-column ' + this.props.className}
|
||||
onClick={this.changeOrder}>
|
||||
<span>{this.props.displayName}</span>
|
||||
</th>
|
||||
@ -44,7 +45,7 @@ let TableHeaderItem = React.createClass({
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<th className={'ascribe-table-header-column'}>
|
||||
<th className={'ascribe-table-header-column ' + this.props.className}>
|
||||
<span>
|
||||
{this.props.displayName}
|
||||
</span>
|
||||
|
@ -41,7 +41,7 @@ let TableItemWrapper = React.createClass({
|
||||
* programmatically
|
||||
*/
|
||||
return (
|
||||
<td key={i}>
|
||||
<td key={i} className={column.className}>
|
||||
<Link
|
||||
className={'ascribe-table-item-column'}
|
||||
onClick={column.transition.callback}
|
||||
|
@ -133,7 +133,7 @@ let FileDragAndDrop = React.createClass({
|
||||
|
||||
render: function () {
|
||||
// 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').length > 0;
|
||||
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 : '';
|
||||
|
@ -57,7 +57,7 @@ let FileDragAndDropPreview = React.createClass({
|
||||
url={this.props.file.url}
|
||||
toggleUploadProcess={this.toggleUploadProcess}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}
|
||||
downloadFile={this.handleDownloadFile}/>);
|
||||
downloadUrl={this.props.file.s3UrlSafe}/>);
|
||||
} else {
|
||||
previewElement = (<FileDragAndDropPreviewOther
|
||||
onClick={this.handleDeleteFile}
|
||||
@ -65,7 +65,7 @@ let FileDragAndDropPreview = React.createClass({
|
||||
type={this.props.file.type.split('/')[1]}
|
||||
toggleUploadProcess={this.toggleUploadProcess}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}
|
||||
downloadFile={this.handleDownloadFile}/>);
|
||||
downloadUrl={this.props.file.s3UrlSafe}/>);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -10,7 +10,7 @@ let FileDragAndDropPreviewImage = React.createClass({
|
||||
progress: React.PropTypes.number,
|
||||
url: React.PropTypes.string,
|
||||
toggleUploadProcess: React.PropTypes.func,
|
||||
downloadFile: React.PropTypes.func,
|
||||
downloadUrl: React.PropTypes.string,
|
||||
areAssetsDownloadable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
@ -48,7 +48,7 @@ let FileDragAndDropPreviewImage = React.createClass({
|
||||
// only if assets are actually downloadable, there should be a download icon if the process is already at
|
||||
// 100%. If not, no actionSymbol should be displayed
|
||||
if(this.props.areAssetsDownloadable) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-download action-file" aria-hidden="true" title="Download file" onClick={this.props.downloadFile}/>;
|
||||
actionSymbol = <a href={this.props.downloadUrl} target="_blank" className="glyphicon glyphicon-download action-file" aria-hidden="true" title="Download file"/>;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@ let FileDragAndDropPreviewIterator = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
{this.props.files.map((file, i) => {
|
||||
if(file.status !== 'deleted' && file.status !== 'canceled') {
|
||||
if(file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1) {
|
||||
return (
|
||||
<FileDragAndDropPreview
|
||||
key={i}
|
||||
|
@ -11,7 +11,7 @@ let FileDragAndDropPreviewOther = React.createClass({
|
||||
progress: React.PropTypes.number,
|
||||
areAssetsDownloadable: React.PropTypes.bool,
|
||||
toggleUploadProcess: React.PropTypes.func,
|
||||
downloadFile: React.PropTypes.func
|
||||
downloadUrl: React.PropTypes.string
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
@ -44,7 +44,7 @@ let FileDragAndDropPreviewOther = React.createClass({
|
||||
// only if assets are actually downloadable, there should be a download icon if the process is already at
|
||||
// 100%. If not, no actionSymbol should be displayed
|
||||
if(this.props.areAssetsDownloadable) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-download action-file" aria-hidden="true" title="Download file" onClick={this.props.downloadFile}/>;
|
||||
actionSymbol = <a href={this.props.downloadUrl} target="_blank" className="glyphicon glyphicon-download action-file" aria-hidden="true" title="Download file"/>;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -276,6 +276,11 @@ var ReactS3FineUploader = React.createClass({
|
||||
return res.json();
|
||||
})
|
||||
.then((res) =>{
|
||||
if(res.otherdata) {
|
||||
file.s3Url = res.otherdata.url_safe;
|
||||
} else {
|
||||
throw new Error('Could not find a url to download.');
|
||||
}
|
||||
defer.success(res.key);
|
||||
})
|
||||
.catch((err) => {
|
||||
@ -327,7 +332,7 @@ var ReactS3FineUploader = React.createClass({
|
||||
if(success) {
|
||||
// fetch blobs for images
|
||||
response = response.map((file) => {
|
||||
file.url = file.s3Url;
|
||||
file.url = file.s3UrlSafe;
|
||||
file.status = 'online';
|
||||
file.progress = 100;
|
||||
return file;
|
||||
@ -345,6 +350,7 @@ var ReactS3FineUploader = React.createClass({
|
||||
let newState = React.addons.update(this.state, {filesToUpload: {$set: updatedFilesToUpload}});
|
||||
this.setState(newState);
|
||||
} else {
|
||||
// server has to respond with 204
|
||||
//let notification = new GlobalNotificationModel('Could not load attached files (Further data)', 'danger', 10000);
|
||||
//GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
//
|
||||
@ -388,6 +394,8 @@ var ReactS3FineUploader = React.createClass({
|
||||
// promise
|
||||
} else {
|
||||
let fileToDelete = this.state.filesToUpload[fileId];
|
||||
fileToDelete.status = 'deleted';
|
||||
|
||||
S3Fetcher
|
||||
.deleteFile(fileToDelete.s3Key, fileToDelete.s3Bucket)
|
||||
.then(() => this.onDeleteComplete(fileToDelete.id, null, false))
|
||||
@ -417,7 +425,6 @@ var ReactS3FineUploader = React.createClass({
|
||||
},
|
||||
|
||||
handleUploadFile(files) {
|
||||
|
||||
// If multiple set and user already uploaded its work,
|
||||
// cancel upload
|
||||
if(!this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled').length > 0) {
|
||||
@ -512,7 +519,7 @@ var ReactS3FineUploader = React.createClass({
|
||||
handleResumeFile={this.handleResumeFile}
|
||||
multiple={this.props.multiple}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}
|
||||
dropzoneInactive={!this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled').length > 0} />
|
||||
dropzoneInactive={!this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ let EditionSummary = React.createClass({
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<AclButtonList
|
||||
className="text-center"
|
||||
className="text-center ascribe-button-list"
|
||||
availableAcls={this.props.edition.acl}
|
||||
editions={[this.props.edition]}
|
||||
handleSuccess={this.handleSuccess} />
|
||||
@ -589,14 +589,14 @@ let CoaDetails = React.createClass({
|
||||
if (this.state.coa.url_safe) {
|
||||
return (
|
||||
<div>
|
||||
<p className="text-center">
|
||||
<Button bsSize="xsmall" href={this.state.coa.url_safe} target="_blank">
|
||||
<p className="text-center ascribe-button-list">
|
||||
<button className="btn btn-default btn-xs" href={this.state.coa.url_safe} target="_blank">
|
||||
Download <Glyphicon glyph="cloud-download"/>
|
||||
</Button>
|
||||
</button>
|
||||
<Link to="coa_verify">
|
||||
<Button bsSize="xsmall">
|
||||
<button className="btn btn-default btn-xs">
|
||||
Verify <Glyphicon glyph="check"/>
|
||||
</Button>
|
||||
</button>
|
||||
</Link>
|
||||
|
||||
</p>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { getCookie } from '../utils/fetch_api_utils';
|
||||
import AppConstants from '../constants/application_constants';
|
||||
|
||||
import Router from 'react-router';
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
const languages = {
|
||||
'en-US': {
|
||||
'Bitcoin Address': 'Bitcoin Address',
|
||||
'ID': 'ID',
|
||||
'Actions': 'Actions',
|
||||
'Hide': 'Hide',
|
||||
'Show the edition': 'Show the edition',
|
||||
@ -16,7 +16,7 @@ const languages = {
|
||||
'Next': 'Next'
|
||||
},
|
||||
'de': {
|
||||
'Bitcoin Address': 'Bitcoin Adresse',
|
||||
'ID': 'ID',
|
||||
'Actions': 'Aktionen',
|
||||
'Hide': 'Verstecke',
|
||||
'Show the edition': 'Zeige die Edition',
|
||||
|
@ -27,6 +27,17 @@ class Requests {
|
||||
return response.text();
|
||||
}
|
||||
|
||||
customJSONparse(responseText) {
|
||||
// If the responses' body does not contain any data,
|
||||
// fetch will resolve responseText to the string 'None'.
|
||||
// If this is the case, we can not try to parse it as JSON.
|
||||
if(responseText !== 'None') {
|
||||
return JSON.parse(responseText);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
handleFatalError(err) {
|
||||
this.fatalErrorHandler(err);
|
||||
throw new ServerError(err);
|
||||
@ -36,6 +47,7 @@ class Requests {
|
||||
if (!json.success) {
|
||||
let error = new APIError();
|
||||
error.json = json;
|
||||
console.error(new Error('The \'success\' property is missing in the server\'s response.'));
|
||||
throw error;
|
||||
}
|
||||
return json;
|
||||
@ -83,7 +95,7 @@ class Requests {
|
||||
merged.method = verb;
|
||||
return fetch(url, merged)
|
||||
.then(this.unpackResponse)
|
||||
.then(JSON.parse)
|
||||
.then(this.customJSONparse)
|
||||
.catch(this.handleFatalError.bind(this))
|
||||
.then(this.handleAPIError);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
.ascribe-piece-list-bulk-modal {
|
||||
position: fixed;
|
||||
top:0;
|
||||
width:1170px;
|
||||
height:6em;
|
||||
left: 3%;
|
||||
width:94%;
|
||||
|
||||
background-color: #FAFAFA;
|
||||
|
||||
border-left: 0.1em solid #E0E0E0;
|
||||
@ -12,6 +13,15 @@
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom: 0.2em solid #E0E0E0;
|
||||
z-index:1000;
|
||||
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
@media(min-width:1174px){
|
||||
.ascribe-piece-list-bulk-modal {
|
||||
left: auto;
|
||||
max-width: 1174px;
|
||||
}
|
||||
}
|
||||
|
||||
.piece-list-bulk-modal-clear-all {
|
||||
|
@ -97,6 +97,10 @@
|
||||
text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black;
|
||||
cursor: pointer;
|
||||
|
||||
&:link, &:visited, &:hover, &:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #d9534f;
|
||||
}
|
||||
@ -111,6 +115,10 @@
|
||||
text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black;
|
||||
cursor: pointer;
|
||||
|
||||
&:link, &:visited, &:hover, &:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #d9534f;
|
||||
}
|
||||
|
@ -245,3 +245,8 @@ body {
|
||||
.col-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.ascribe-button-list button {
|
||||
margin-right: 1px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user