1
0
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:
diminator 2015-07-01 11:22:49 +02:00
commit ca3b058b4d
25 changed files with 112 additions and 59 deletions

View File

@ -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 (

View File

@ -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>

View File

@ -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}

View File

@ -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) => {

View File

@ -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 }

View File

@ -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"

View File

@ -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>

View File

@ -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} />
&nbsp;&nbsp;
{/*<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>

View File

@ -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 : '';
}
}

View File

@ -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}

View File

@ -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>

View File

@ -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}

View File

@ -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 : '';

View File

@ -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 (

View File

@ -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 {

View File

@ -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}

View File

@ -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 {

View File

@ -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>
);
}

View File

@ -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>

View File

@ -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';

View File

@ -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',

View File

@ -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);
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -245,3 +245,8 @@ body {
.col-bottom {
vertical-align: bottom;
}
.ascribe-button-list button {
margin-right: 1px;
margin-top: 1px;
}