mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Merged in AD-544-automatically-share-registered-pr (pull request #32)
Ad 544 automatically share registered pr
This commit is contained in:
commit
d343acaac5
@ -17,21 +17,21 @@ class EditionListActions {
|
||||
);
|
||||
}
|
||||
|
||||
fetchEditionList(pieceId, page, pageSize, orderBy, orderAsc) {
|
||||
if(!orderBy && typeof orderAsc === 'undefined') {
|
||||
fetchEditionList(pieceId, page, pageSize, orderBy, orderAsc, filterBy) {
|
||||
if((!orderBy && typeof orderAsc === 'undefined') || !orderAsc) {
|
||||
orderBy = 'edition_number';
|
||||
orderAsc = true;
|
||||
}
|
||||
|
||||
// Taken from: http://stackoverflow.com/a/519157/1263876
|
||||
if(typeof page === 'undefined' && typeof pageSize === 'undefined') {
|
||||
if((typeof page === 'undefined' || !page) && (typeof pageSize === 'undefined' || !pageSize)) {
|
||||
page = 1;
|
||||
pageSize = 10;
|
||||
}
|
||||
|
||||
return Q.Promise((resolve, reject) => {
|
||||
EditionListFetcher
|
||||
.fetch(pieceId, page, pageSize, orderBy, orderAsc)
|
||||
.fetch(pieceId, page, pageSize, orderBy, orderAsc, filterBy)
|
||||
.then((res) => {
|
||||
this.actions.updateEditionList({
|
||||
pieceId,
|
||||
@ -39,6 +39,7 @@ class EditionListActions {
|
||||
pageSize,
|
||||
orderBy,
|
||||
orderAsc,
|
||||
filterBy,
|
||||
'editionListOfPiece': res.editions,
|
||||
'count': res.count
|
||||
});
|
||||
|
@ -14,7 +14,7 @@ class PieceListActions {
|
||||
);
|
||||
}
|
||||
|
||||
fetchPieceList(page, pageSize, search, orderBy, orderAsc) {
|
||||
fetchPieceList(page, pageSize, search, orderBy, orderAsc, filterBy) {
|
||||
// To prevent flickering on a pagination request,
|
||||
// we overwrite the piecelist with an empty list before
|
||||
// pieceListCount === -1 defines the loading state
|
||||
@ -24,6 +24,7 @@ class PieceListActions {
|
||||
search,
|
||||
orderBy,
|
||||
orderAsc,
|
||||
filterBy,
|
||||
'pieceList': [],
|
||||
'pieceListCount': -1
|
||||
});
|
||||
@ -32,7 +33,7 @@ class PieceListActions {
|
||||
|
||||
return Q.Promise((resolve, reject) => {
|
||||
PieceListFetcher
|
||||
.fetch(page, pageSize, search, orderBy, orderAsc)
|
||||
.fetch(page, pageSize, search, orderBy, orderAsc, filterBy)
|
||||
.then((res) => {
|
||||
this.actions.updatePieceList({
|
||||
page,
|
||||
@ -40,6 +41,7 @@ class PieceListActions {
|
||||
search,
|
||||
orderBy,
|
||||
orderAsc,
|
||||
filterBy,
|
||||
'pieceList': res.pieces,
|
||||
'pieceListCount': res.count
|
||||
});
|
||||
|
34
js/actions/prize_list_actions.js
Normal file
34
js/actions/prize_list_actions.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../alt';
|
||||
import Q from 'q';
|
||||
|
||||
import PrizeListFetcher from '../fetchers/prize_list_fetcher';
|
||||
|
||||
class PrizeListActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'updatePrizeList'
|
||||
);
|
||||
}
|
||||
|
||||
fetchPrizeList() {
|
||||
return Q.Promise((resolve, reject) => {
|
||||
PrizeListFetcher
|
||||
.fetch()
|
||||
.then((res) => {
|
||||
this.actions.updatePrizeList({
|
||||
prizeList: res.prizes,
|
||||
prizeListCount: res.count
|
||||
});
|
||||
resolve(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.logGlobal(err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createActions(PrizeListActions);
|
@ -21,7 +21,7 @@ import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import AclProxy from '../acl_proxy';
|
||||
import SubmitToPrizeButton from '../ascribe_buttons/submit_to_prize_button';
|
||||
import SubmitToPrizeButton from '../whitelabel/prize/components/ascribe_buttons/submit_to_prize_button';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
@ -87,14 +87,16 @@ let AccordionListItem = React.createClass({
|
||||
},
|
||||
|
||||
handleSubmitPrizeSuccess(response) {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
onPollingSuccess(pieceId) {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
EditionListActions.toggleEditionList(pieceId);
|
||||
|
||||
let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000);
|
||||
@ -178,21 +180,13 @@ let AccordionListItem = React.createClass({
|
||||
onPollingSuccess={this.onPollingSuccess}/>
|
||||
</AclProxy>
|
||||
<AclProxy
|
||||
show={this.props.content.prize === null}>
|
||||
aclObject={this.props.content.acl}
|
||||
aclName="acl_submit_to_prize">
|
||||
<SubmitToPrizeButton
|
||||
className="pull-right"
|
||||
piece={this.props.content}
|
||||
handleSuccess={this.handleSubmitPrizeSuccess}/>
|
||||
</AclProxy>
|
||||
<AclProxy
|
||||
show={this.props.content.prize}>
|
||||
<button
|
||||
disabled
|
||||
className="btn btn-default btn-xs pull-right">
|
||||
{getLangText('Submitted to prize')} <span className="glyphicon glyphicon-ok"
|
||||
aria-hidden="true"></span>
|
||||
</button>
|
||||
</AclProxy>
|
||||
{this.getLicences()}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,10 +6,14 @@ import classNames from 'classnames';
|
||||
import EditionListActions from '../../actions/edition_list_actions';
|
||||
import EditionListStore from '../../stores/edition_list_store';
|
||||
|
||||
import PieceListActions from '../../actions/piece_list_actions';
|
||||
import PieceListStore from '../../stores/piece_list_store';
|
||||
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
|
||||
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
|
||||
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let AccordionListItemEditionWidget = React.createClass({
|
||||
@ -21,15 +25,20 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return EditionListStore.getState();
|
||||
return mergeOptions(
|
||||
EditionListStore.getState(),
|
||||
PieceListStore.getState()
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
EditionListStore.listen(this.onChange);
|
||||
PieceListStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
EditionListStore.unlisten(this.onChange);
|
||||
PieceListStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
@ -47,7 +56,7 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
EditionListActions.toggleEditionList(pieceId);
|
||||
} else {
|
||||
EditionListActions.toggleEditionList(pieceId);
|
||||
EditionListActions.fetchEditionList(pieceId);
|
||||
EditionListActions.fetchEditionList(pieceId, null, null, null, null, this.state.filterBy);
|
||||
}
|
||||
},
|
||||
|
||||
@ -85,7 +94,7 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
let numEditions = piece.num_editions;
|
||||
|
||||
if(numEditions <= 0) {
|
||||
if (piece.acl.acl_editions){
|
||||
if (piece.acl.acl_create_editions){
|
||||
return (
|
||||
<CreateEditionsButton
|
||||
label={getLangText('Create editions')}
|
||||
|
@ -76,13 +76,9 @@ let AccordionListItemTableEditions = React.createClass({
|
||||
});
|
||||
|
||||
let editionList = this.state.editionList[this.props.parentId];
|
||||
EditionListActions.fetchEditionList(this.props.parentId, editionList.page + 1, editionList.pageSize);
|
||||
EditionListActions.fetchEditionList(this.props.parentId, editionList.page + 1, editionList.pageSize,
|
||||
editionList.orderBy, editionList.orderAsc, editionList.filterBy);
|
||||
},
|
||||
|
||||
changeEditionListOrder(orderBy, orderAsc) {
|
||||
EditionListActions.fetchEditionList(this.props.parentId, orderBy, orderAsc);
|
||||
},
|
||||
|
||||
render() {
|
||||
let selectedEditionsCount = 0;
|
||||
let allEditionsCount = 0;
|
||||
|
@ -44,14 +44,17 @@ let CreateEditionsButton = React.createClass({
|
||||
startPolling() {
|
||||
// start polling until editions are defined
|
||||
let pollingIntervalIndex = setInterval(() => {
|
||||
EditionListActions.fetchEditionList(this.props.piece.id)
|
||||
|
||||
// requests, will try to merge the filterBy parameter with other parameters (mergeOptions).
|
||||
// Therefore it can't but null but instead has to be an empty object
|
||||
EditionListActions.fetchEditionList(this.props.piece.id, null, null, null, null, {})
|
||||
.then((res) => {
|
||||
|
||||
clearInterval(this.state.pollingIntervalIndex);
|
||||
this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions);
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((err) => {
|
||||
/* Ignore and keep going */
|
||||
});
|
||||
}, 5000);
|
||||
@ -64,7 +67,7 @@ let CreateEditionsButton = React.createClass({
|
||||
render: function () {
|
||||
let piece = this.props.piece;
|
||||
|
||||
if (!piece.acl.acl_editions || piece.num_editions > 0){
|
||||
if (!piece.acl.acl_create_editions || piece.num_editions > 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import ModalWrapper from '../ascribe_modal/modal_wrapper';
|
||||
import PieceSubmitToPrizeForm from '../ascribe_forms/form_submit_to_prize';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let SubmitToPrizeButton = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
handleSuccess: React.PropTypes.func,
|
||||
piece: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getSubmitButton() {
|
||||
return (
|
||||
<button
|
||||
className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
|
||||
{getLangText('Submit to prize')}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ModalWrapper
|
||||
button={this.getSubmitButton()}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
title={getLangText('Submit to prize')}>
|
||||
<PieceSubmitToPrizeForm
|
||||
piece={this.props.piece}
|
||||
handleSuccess={this.props.handleSuccess}/>
|
||||
</ModalWrapper>
|
||||
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default SubmitToPrizeButton;
|
@ -86,7 +86,8 @@ let Edition = React.createClass({
|
||||
},
|
||||
|
||||
handleDeleteSuccess(response) {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
|
||||
EditionListActions.refreshEditionList(this.props.edition.parent);
|
||||
EditionListActions.closeAllEditionLists();
|
||||
|
@ -79,12 +79,14 @@ let Piece = React.createClass({
|
||||
|
||||
handleEditionCreationSuccess() {
|
||||
PieceActions.updateProperty({key: 'num_editions', value: 0});
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
this.toggleCreateEditionsDialog();
|
||||
},
|
||||
|
||||
handleDeleteSuccess(response) {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
|
||||
// since we're deleting a piece, we just need to close
|
||||
// all editions dialogs and not reload them
|
||||
@ -124,7 +126,8 @@ let Piece = React.createClass({
|
||||
// btw.: It's not sufficient to just set num_editions to numEditions, since a single accordion
|
||||
// list item also uses the firstEdition property which we can only get from the server in that case.
|
||||
// Therefore we need to at least refetch the changed piece from the server or on our case simply all
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
|
||||
let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
@ -15,6 +15,9 @@ import { mergeOptionsWithDuplicates } from '../../utils/general_utils';
|
||||
let Form = React.createClass({
|
||||
propTypes: {
|
||||
url: React.PropTypes.string,
|
||||
buttons: React.PropTypes.object,
|
||||
buttonSubmitText: React.PropTypes.string,
|
||||
spinner: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func,
|
||||
getFormData: React.PropTypes.func,
|
||||
children: React.PropTypes.oneOfType([
|
||||
@ -24,6 +27,12 @@ let Form = React.createClass({
|
||||
className: React.PropTypes.string
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
buttonSubmitText: 'SAVE'
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
edited: false,
|
||||
@ -125,7 +134,7 @@ let Form = React.createClass({
|
||||
buttons = (
|
||||
<div className="row" style={{margin: 0}}>
|
||||
<p className="pull-right">
|
||||
<Button className="btn btn-default btn-sm ascribe-margin-1px" type="submit">SAVE</Button>
|
||||
<Button className="btn btn-default btn-sm ascribe-margin-1px" type="submit">{this.props.buttonSubmitText}</Button>
|
||||
<Button className="btn btn-danger btn-delete btn-sm ascribe-margin-1px" onClick={this.reset}>CANCEL</Button>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -27,7 +27,7 @@ let SignupForm = React.createClass({
|
||||
children: React.PropTypes.element
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
mixins: [Router.Navigation, Router.State],
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
@ -35,7 +35,6 @@ let SignupForm = React.createClass({
|
||||
submitMessage: getLangText('Sign up')
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return UserStore.getState();
|
||||
},
|
||||
@ -57,22 +56,32 @@ let SignupForm = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return this.getQuery();
|
||||
},
|
||||
|
||||
handleSuccess(response){
|
||||
if (response.user) {
|
||||
let notification = new GlobalNotificationModel(getLangText('Sign up successful'), 'success', 50000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.');
|
||||
|
||||
}
|
||||
else if (response.redirect) {
|
||||
this.transitionTo('pieces');
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
let tooltipPassword = getLangText('Your password must be at least 10 characters') + '.\n ' +
|
||||
getLangText('This password is securing your digital property like a bank account') + '.\n ' +
|
||||
getLangText('Store it in a safe place') + '!';
|
||||
let email = this.getQuery().email ? this.getQuery().email : null;
|
||||
return (
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref='form'
|
||||
url={apiUrls.users_signup}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.handleSuccess}
|
||||
buttons={
|
||||
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
|
||||
@ -93,6 +102,7 @@ let SignupForm = React.createClass({
|
||||
type="email"
|
||||
placeholder={getLangText('(e.g. andy@warhol.co.uk)')}
|
||||
autoComplete="on"
|
||||
defaultValue={email}
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
|
71
js/components/ascribe_panel/action_panel.js
Normal file
71
js/components/ascribe_panel/action_panel.js
Normal file
@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
|
||||
let ActionPanel = React.createClass({
|
||||
propTypes: {
|
||||
title: React.PropTypes.string,
|
||||
content: React.PropTypes.string,
|
||||
buttons: React.PropTypes.element,
|
||||
onClick: React.PropTypes.func,
|
||||
ignoreFocus: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
isFocused: false
|
||||
};
|
||||
},
|
||||
|
||||
handleFocus() {
|
||||
// if ignoreFocus (bool) is defined, then just ignore focusing on
|
||||
// the property and input
|
||||
if(this.props.ignoreFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if onClick is defined from the outside,
|
||||
// just call it
|
||||
if(this.props.onClick) {
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
this.refs.input.getDOMNode().focus();
|
||||
this.setState({
|
||||
isFocused: true
|
||||
});
|
||||
},
|
||||
|
||||
getClassName() {
|
||||
if(this.state.isFocused) {
|
||||
return 'is-focused';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={'ascribe-panel-wrapper ' + this.getClassName()}
|
||||
onClick={this.handleFocus}
|
||||
onFocus={this.handleFocus}>
|
||||
<div className='ascribe-panel-title'>
|
||||
{this.props.title}
|
||||
</div>
|
||||
<div className='ascribe-panel-content-wrapper'>
|
||||
<span className="ascribe-panel-content pull-left">
|
||||
{this.props.content}
|
||||
</span>
|
||||
<span className='ascribe-panel-buttons pull-right'>
|
||||
{this.props.buttons}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default ActionPanel;
|
@ -76,7 +76,8 @@ let PieceListBulkModal = React.createClass({
|
||||
},
|
||||
|
||||
handleSuccess() {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
|
||||
this.fetchSelectedPieceEditionList()
|
||||
.forEach((pieceId) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
|
||||
let PieceListBulkModalSelectedEditionsWidget = React.createClass({
|
||||
propTypes: {
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget';
|
||||
|
||||
import Input from 'react-bootstrap/lib/Input';
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
@ -11,6 +13,8 @@ let PieceListToolbar = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
searchFor: React.PropTypes.func,
|
||||
filterBy: React.PropTypes.object,
|
||||
applyFilterBy: React.PropTypes.func,
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||
React.PropTypes.element
|
||||
@ -41,6 +45,15 @@ let PieceListToolbar = React.createClass({
|
||||
onChange={this.searchFor}
|
||||
addonAfter={searchIcon} />
|
||||
</span>
|
||||
<span className="pull-right">
|
||||
<PieceListToolbarFilterWidget
|
||||
filterParams={['acl_transfer', 'acl_consign', {
|
||||
key: 'acl_create_editions',
|
||||
label: 'create editions'
|
||||
}]}
|
||||
filterBy={this.props.filterBy}
|
||||
applyFilterBy={this.props.applyFilterBy}/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,30 +2,114 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
||||
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
|
||||
let PieceListToolbarFilterWidgetFilter = React.createClass({
|
||||
propTypes: {
|
||||
// An array of either strings (which represent acl enums) or objects of the form
|
||||
//
|
||||
// {
|
||||
// key: <acl enum>,
|
||||
// label: <a human readable string>
|
||||
// }
|
||||
//
|
||||
filterParams: React.PropTypes.arrayOf(React.PropTypes.any).isRequired,
|
||||
filterBy: React.PropTypes.object,
|
||||
applyFilterBy: React.PropTypes.func
|
||||
},
|
||||
|
||||
generateFilterByStatement(param) {
|
||||
let filterBy = this.props.filterBy;
|
||||
|
||||
if(filterBy) {
|
||||
// we need hasOwnProperty since the values are all booleans
|
||||
if(filterBy.hasOwnProperty(param)) {
|
||||
filterBy[param] = !filterBy[param];
|
||||
|
||||
// if the parameter is false, then we want to remove it again
|
||||
// from the list of queryParameters as this component is only about
|
||||
// which actions *CAN* be done and not what *CANNOT*
|
||||
if(!filterBy[param]) {
|
||||
delete filterBy[param];
|
||||
}
|
||||
|
||||
} else {
|
||||
filterBy[param] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return filterBy;
|
||||
},
|
||||
|
||||
/**
|
||||
* We need overloading here to find the correct parameter of the label
|
||||
* the user is clicking on.
|
||||
*/
|
||||
filterBy(param) {
|
||||
return () => {
|
||||
let filterBy = this.generateFilterByStatement(param);
|
||||
this.props.applyFilterBy(filterBy);
|
||||
};
|
||||
},
|
||||
|
||||
isFilterActive() {
|
||||
let trueValuesOnly = Object.keys(this.props.filterBy).filter((acl) => acl);
|
||||
|
||||
// We're hiding the star in that complicated matter so that,
|
||||
// the surrounding button is not resized up on appearance
|
||||
if(trueValuesOnly.length > 0) {
|
||||
return { visibility: 'visible'};
|
||||
} else {
|
||||
return { visibility: 'hidden' };
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
let filterIcon = <Glyphicon glyph='filter' className="filter-glyph"/>;
|
||||
let filterIcon = (
|
||||
<span>
|
||||
<span className="glyphicon glyphicon-filter" aria-hidden="true"></span>
|
||||
<span style={this.isFilterActive()}>*</span>
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownButton title={filterIcon}>
|
||||
<DropdownButton
|
||||
title={filterIcon}
|
||||
className="ascribe-piece-list-toolbar-filter-widget">
|
||||
<li style={{'textAlign': 'center'}}>
|
||||
<em>{getLangText('Show Pieces that')}:</em>
|
||||
<em>{getLangText('Show works that')}:</em>
|
||||
</li>
|
||||
<MenuItem eventKey='1'>
|
||||
<div className="checkbox">
|
||||
{getLangText('I can transfer')} <input type="checkbox" />
|
||||
</div>
|
||||
</MenuItem>
|
||||
<MenuItem eventKey='2'>
|
||||
<div className="checkbox">
|
||||
{getLangText('I can consign')} <input type="checkbox" />
|
||||
{this.props.filterParams.map((param, i) => {
|
||||
let label;
|
||||
|
||||
if(typeof param !== 'string') {
|
||||
label = param.label;
|
||||
param = param.key;
|
||||
} else {
|
||||
param = param;
|
||||
label = param.split('_')[1];
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={i}
|
||||
onClick={this.filterBy(param)}
|
||||
className="filter-widget-item">
|
||||
<div className="checkbox-line">
|
||||
<span>
|
||||
{getLangText('I can') + ' ' + getLangText(label)}
|
||||
</span>
|
||||
<input
|
||||
readOnly
|
||||
type="checkbox"
|
||||
checked={this.props.filterBy[param]} />
|
||||
</div>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</DropdownButton>
|
||||
);
|
||||
}
|
||||
|
82
js/components/ascribe_prizes_dashboard/prizes_dashboard.js
Normal file
82
js/components/ascribe_prizes_dashboard/prizes_dashboard.js
Normal file
@ -0,0 +1,82 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import PrizeListActions from '../../actions/prize_list_actions';
|
||||
import PrizeListStore from '../../stores/prize_list_store';
|
||||
|
||||
import Table from '../ascribe_table/table';
|
||||
import TableItem from '../ascribe_table/table_item';
|
||||
import TableItemText from '../ascribe_table/table_item_text';
|
||||
|
||||
import { ColumnModel} from '../ascribe_table/models/table_models';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let PrizesDashboard = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return PrizeListStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
PrizeListStore.listen(this.onChange);
|
||||
PrizeListActions.fetchPrizeList();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
PrizeListStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
getColumnList() {
|
||||
return [
|
||||
new ColumnModel(
|
||||
(item) => {
|
||||
return {
|
||||
'content': item.name
|
||||
}; },
|
||||
'name',
|
||||
getLangText('Name'),
|
||||
TableItemText,
|
||||
6,
|
||||
false,
|
||||
null
|
||||
),
|
||||
new ColumnModel(
|
||||
(item) => {
|
||||
return {
|
||||
'content': item.domain
|
||||
}; },
|
||||
'domain',
|
||||
getLangText('Domain'),
|
||||
TableItemText,
|
||||
1,
|
||||
false,
|
||||
null
|
||||
)
|
||||
];
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Table
|
||||
responsive
|
||||
className="ascribe-table"
|
||||
columnList={this.getColumnList()}
|
||||
itemList={this.state.prizeList}>
|
||||
{this.state.prizeList.map((item, i) => {
|
||||
return (
|
||||
<TableItem
|
||||
className="ascribe-table-item-selectable"
|
||||
key={i}/>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PrizesDashboard;
|
@ -2,7 +2,6 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import TableColumnMixin from '../../mixins/table_column_mixin';
|
||||
import TableHeaderItem from './table_header_item';
|
||||
|
||||
import { ColumnModel } from './models/table_models';
|
||||
@ -17,15 +16,12 @@ let TableHeader = React.createClass({
|
||||
orderBy: React.PropTypes.string
|
||||
},
|
||||
|
||||
mixins: [TableColumnMixin],
|
||||
|
||||
render() {
|
||||
return (
|
||||
<thead>
|
||||
<tr>
|
||||
{this.props.columnList.map((column, i) => {
|
||||
|
||||
let columnClasses = this.calcColumnClasses(this.props.columnList, i, 12);
|
||||
let columnName = column.columnName;
|
||||
let canBeOrdered = column.canBeOrdered;
|
||||
|
||||
@ -33,7 +29,6 @@ let TableHeader = React.createClass({
|
||||
<TableHeaderItem
|
||||
className={column.className}
|
||||
key={i}
|
||||
columnClasses={columnClasses}
|
||||
displayName={column.displayName}
|
||||
columnName={columnName}
|
||||
canBeOrdered={canBeOrdered}
|
||||
|
@ -7,7 +7,6 @@ import TableHeaderItemCarret from './table_header_item_carret';
|
||||
let TableHeaderItem = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
columnClasses: React.PropTypes.string.isRequired,
|
||||
displayName: React.PropTypes.oneOfType([
|
||||
React.PropTypes.string,
|
||||
React.PropTypes.element
|
||||
|
@ -1,113 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { ColumnModel } from './models/table_models';
|
||||
|
||||
import EditionListStore from '../../stores/edition_list_store';
|
||||
import EditionListActions from '../../actions/edition_list_actions';
|
||||
|
||||
|
||||
import Table from './table';
|
||||
import TableItemWrapper from './table_item_wrapper';
|
||||
import TableItemText from './table_item_text';
|
||||
import TableItemAcl from './table_item_acl';
|
||||
import TableItemSelectable from './table_item_selectable';
|
||||
import TableItemSubtableButton from './table_item_subtable_button';
|
||||
|
||||
|
||||
let TableItemSubtable = React.createClass({
|
||||
propTypes: {
|
||||
columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(ColumnModel)),
|
||||
columnContent: React.PropTypes.object
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
'open': false
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
EditionListStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
EditionListStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
loadEditionList() {
|
||||
if(this.state.open) {
|
||||
this.setState({
|
||||
'open': false
|
||||
});
|
||||
} else {
|
||||
|
||||
EditionListActions.fetchEditionList(this.props.columnContent.id);
|
||||
this.setState({
|
||||
'open': true,
|
||||
'editionList': EditionListStore.getState()
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
selectItem(parentId, itemId) {
|
||||
EditionListActions.selectEdition({
|
||||
'pieceId': parentId,
|
||||
'editionId': itemId
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
|
||||
let renderEditionListTable = () => {
|
||||
|
||||
let columnList = [
|
||||
new ColumnModel('edition_number', 'Number', TableItemText, 2, false),
|
||||
new ColumnModel('user_registered', 'User', TableItemText, 4, true),
|
||||
new ColumnModel('acl', 'Actions', TableItemAcl, 4, true)
|
||||
];
|
||||
|
||||
if(this.state.open && this.state.editionList[this.props.columnContent.id] && this.state.editionList[this.props.columnContent.id].length) {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<Table itemList={this.state.editionList[this.props.columnContent.id]} columnList={columnList}>
|
||||
{this.state.editionList[this.props.columnContent.id].map((edition, i) => {
|
||||
return (
|
||||
<TableItemSelectable
|
||||
className="ascribe-table-item-selectable"
|
||||
selectItem={this.selectItem}
|
||||
parentId={this.props.columnContent.id}
|
||||
key={i} />
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="col-xs-12 col-sm-12 col-md-12 col-lg-12 ascribe-table-item">
|
||||
<div className="row">
|
||||
<TableItemWrapper
|
||||
columnList={this.props.columnList}
|
||||
columnContent={this.props.columnContent}
|
||||
columnWidth={12} />
|
||||
<div className="col-xs-1 col-sm-1 col-md-1 col-lg-1 ascribe-table-item-column">
|
||||
<TableItemSubtableButton content="+" onClick={this.loadEditionList} />
|
||||
</div>
|
||||
</div>
|
||||
{renderEditionListTable()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default TableItemSubtable;
|
@ -1,23 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
let TableItemSubtableButton = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
content: React.PropTypes.string.isRequired,
|
||||
onClick: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>
|
||||
<button type="button" className="btn btn-default btn-sm ascribe-table-expand-button" onClick={this.props.onClick}>
|
||||
{this.props.content}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default TableItemSubtableButton;
|
@ -34,7 +34,8 @@ let PieceList = React.createClass({
|
||||
let page = this.getQuery().page || 1;
|
||||
PieceListStore.listen(this.onChange);
|
||||
if (this.state.pieceList.length === 0){
|
||||
PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc)
|
||||
PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, this.state.filterBy)
|
||||
.then(PieceListActions.fetchPieceRequestActions());
|
||||
}
|
||||
},
|
||||
@ -59,9 +60,9 @@ let PieceList = React.createClass({
|
||||
// the site should go to the top
|
||||
document.body.scrollTop = document.documentElement.scrollTop = 0;
|
||||
|
||||
return () => PieceListActions.fetchPieceList(page, this.state.pageSize,
|
||||
this.state.search, this.state.orderBy,
|
||||
this.state.orderAsc);
|
||||
return () => PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc,
|
||||
this.state.filterBy);
|
||||
},
|
||||
|
||||
getPagination() {
|
||||
@ -79,13 +80,22 @@ let PieceList = React.createClass({
|
||||
},
|
||||
|
||||
searchFor(searchTerm) {
|
||||
PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy,
|
||||
this.state.orderAsc, this.state.filterBy);
|
||||
this.transitionTo(this.getPathname(), {page: 1});
|
||||
},
|
||||
|
||||
applyFilterBy(filterBy) {
|
||||
PieceListActions.fetchPieceList(1, this.state.pageSize, this.state.search,
|
||||
this.state.orderBy, this.state.orderAsc, filterBy);
|
||||
// we have to redirect the user always to page one as it could be that there is no page two
|
||||
// for filtered pieces
|
||||
this.transitionTo(this.getPathname(), {page: 1});
|
||||
},
|
||||
|
||||
accordionChangeOrder(orderBy, orderAsc) {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize,
|
||||
this.state.search, orderBy, orderAsc);
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
|
||||
orderBy, orderAsc, this.state.filterBy);
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -95,7 +105,9 @@ let PieceList = React.createClass({
|
||||
<div>
|
||||
<PieceListToolbar
|
||||
className="ascribe-piece-list-toolbar"
|
||||
searchFor={this.searchFor}>
|
||||
searchFor={this.searchFor}
|
||||
filterBy={this.state.filterBy}
|
||||
applyFilterBy={this.applyFilterBy}>
|
||||
{this.props.customSubmitButton}
|
||||
</PieceListToolbar>
|
||||
<PieceListBulkModal className="ascribe-piece-list-bulk-modal" />
|
||||
|
@ -101,7 +101,8 @@ let RegisterPiece = React.createClass( {
|
||||
this.state.pageSize,
|
||||
this.state.searchTerm,
|
||||
this.state.orderBy,
|
||||
this.state.orderAsc
|
||||
this.state.orderAsc,
|
||||
this.state.filterBy
|
||||
);
|
||||
|
||||
this.transitionTo('piece', {pieceId: response.piece.id});
|
||||
@ -139,7 +140,7 @@ let RegisterPiece = React.createClass( {
|
||||
},
|
||||
|
||||
getSpecifyEditions() {
|
||||
if(this.state.whitelabel && this.state.whitelabel.acl_editions || Object.keys(this.state.whitelabel).length === 0) {
|
||||
if(this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) {
|
||||
return (
|
||||
<PropertyCollapsible
|
||||
name="num_editions"
|
||||
|
@ -29,12 +29,19 @@ import { getLangText } from '../utils/lang_utils';
|
||||
import { getCookie } from '../utils/fetch_api_utils';
|
||||
|
||||
let SettingsContainer = React.createClass({
|
||||
propTypes: {
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||
React.PropTypes.element])
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="settings-container">
|
||||
<AccountSettings />
|
||||
{this.props.children}
|
||||
<APISettings />
|
||||
<BitcoinWalletSettings />
|
||||
<LoanContractSettings />
|
||||
@ -121,6 +128,7 @@ let AccountSettings = React.createClass({
|
||||
</span>
|
||||
</InputCheckbox>
|
||||
</Property>
|
||||
<hr />
|
||||
{/*<Property
|
||||
name='language'
|
||||
label={getLangText('Choose your Language')}
|
||||
@ -135,7 +143,6 @@ let AccountSettings = React.createClass({
|
||||
</option>
|
||||
</select>
|
||||
</Property>*/}
|
||||
<hr />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
33
js/components/whitelabel/prize/actions/prize_actions.js
Normal file
33
js/components/whitelabel/prize/actions/prize_actions.js
Normal file
@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../../../../alt';
|
||||
import Q from 'q';
|
||||
|
||||
import PrizeFetcher from '../fetchers/prize_fetcher';
|
||||
|
||||
class PrizeActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'updatePrize'
|
||||
);
|
||||
}
|
||||
|
||||
fetchPrize() {
|
||||
return Q.Promise((resolve, reject) => {
|
||||
PrizeFetcher
|
||||
.fetch()
|
||||
.then((res) => {
|
||||
this.actions.updatePrize({
|
||||
prize: res.prize
|
||||
});
|
||||
resolve(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.logGlobal(err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createActions(PrizeActions);
|
31
js/components/whitelabel/prize/actions/prize_jury_actions.js
Normal file
31
js/components/whitelabel/prize/actions/prize_jury_actions.js
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../../../../alt';
|
||||
import Q from 'q';
|
||||
|
||||
import PrizeJuryFetcher from '../fetchers/prize_jury_fetcher';
|
||||
|
||||
class PrizeJuryActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'updatePrizeJury'
|
||||
);
|
||||
}
|
||||
|
||||
fetchJury() {
|
||||
return Q.Promise((resolve, reject) => {
|
||||
PrizeJuryFetcher
|
||||
.fetch()
|
||||
.then((res) => {
|
||||
this.actions.updatePrizeJury(res.members);
|
||||
resolve(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.logGlobal(err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createActions(PrizeJuryActions);
|
@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import ModalWrapper from '../../../../ascribe_modal/modal_wrapper';
|
||||
import PieceSubmitToPrizeForm from '../../../../ascribe_forms/form_submit_to_prize';
|
||||
|
||||
import { getLangText } from '../../../../../utils/lang_utils';
|
||||
|
||||
let SubmitToPrizeButton = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
handleSuccess: React.PropTypes.func,
|
||||
piece: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getSubmitButton() {
|
||||
if (this.props.piece.prize) {
|
||||
return (
|
||||
<button
|
||||
disabled
|
||||
className="btn btn-default btn-xs pull-right">
|
||||
{getLangText('Submitted to prize')} <span className="glyphicon glyphicon-ok"
|
||||
aria-hidden="true"></span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<button
|
||||
className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
|
||||
{getLangText('Submit to prize')}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ModalWrapper
|
||||
button={this.getSubmitButton()}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
title={getLangText('Submit to prize')}>
|
||||
<PieceSubmitToPrizeForm
|
||||
piece={this.props.piece}
|
||||
handleSuccess={this.props.handleSuccess}/>
|
||||
</ModalWrapper>
|
||||
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default SubmitToPrizeButton;
|
250
js/components/whitelabel/prize/components/settings_container.js
Normal file
250
js/components/whitelabel/prize/components/settings_container.js
Normal file
@ -0,0 +1,250 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import UserStore from '../../../../stores/user_store';
|
||||
import UserActions from '../../../../actions/user_actions';
|
||||
import PrizeActions from '../actions/prize_actions';
|
||||
import PrizeStore from '../stores/prize_store';
|
||||
import PrizeJuryActions from '../actions/prize_jury_actions';
|
||||
import PrizeJuryStore from '../stores/prize_jury_store';
|
||||
|
||||
import SettingsContainer from '../../../settings_container';
|
||||
import CollapsibleParagraph from '../../../ascribe_collapsible/collapsible_paragraph';
|
||||
|
||||
import Form from '../../../ascribe_forms/form';
|
||||
import Property from '../../../ascribe_forms/property';
|
||||
import FormPropertyHeader from '../../../ascribe_forms/form_property_header';
|
||||
|
||||
import ActionPanel from '../../../ascribe_panel/action_panel';
|
||||
|
||||
import Table from '../../../ascribe_table/table';
|
||||
import TableItem from '../../../ascribe_table/table_item';
|
||||
import TableItemText from '../../../ascribe_table/table_item_text';
|
||||
|
||||
import GlobalNotificationModel from '../../../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../../../actions/global_notification_actions';
|
||||
|
||||
import AppConstants from '../../../../constants/application_constants';
|
||||
import apiUrls from '../../../../constants/api_urls';
|
||||
|
||||
import { ColumnModel} from '../../../ascribe_table/models/table_models';
|
||||
import { getLangText } from '../../../../utils/lang_utils';
|
||||
|
||||
|
||||
let Settings = React.createClass({
|
||||
getInitialState() {
|
||||
return UserStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
UserActions.fetchCurrentUser();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
render() {
|
||||
let prizeSettings = null;
|
||||
if (this.state.currentUser.is_admin){
|
||||
prizeSettings = <PrizeSettings />;
|
||||
}
|
||||
return (
|
||||
<SettingsContainer>
|
||||
{prizeSettings}
|
||||
</SettingsContainer>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let PrizeSettings = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return PrizeStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
PrizeStore.listen(this.onChange);
|
||||
PrizeActions.fetchPrize();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
PrizeStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<CollapsibleParagraph
|
||||
title={'Prize Settings for ' + this.state.prize.name}
|
||||
show={true}
|
||||
defaultExpanded={true}>
|
||||
<Form >
|
||||
<Property
|
||||
name='prize_name'
|
||||
label={getLangText('Prize name')}
|
||||
editable={false}>
|
||||
<pre className="ascribe-pre">{this.state.prize.name}</pre>
|
||||
</Property>
|
||||
<Property
|
||||
name='prize_rounds'
|
||||
label={getLangText('Active round/Number of rounds')}
|
||||
editable={false}>
|
||||
<pre className="ascribe-pre">{this.state.prize.active_round}/{this.state.prize.rounds}</pre>
|
||||
</Property>
|
||||
<Property
|
||||
name='num_submissions'
|
||||
label={getLangText('Allowed number of submissions per user')}
|
||||
editable={false}>
|
||||
<pre className="ascribe-pre">{this.state.prize.num_submissions}</pre>
|
||||
</Property>
|
||||
<hr />
|
||||
</Form>
|
||||
<PrizeJurySettings
|
||||
prize={this.state.prize}/>
|
||||
</CollapsibleParagraph>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let PrizeJurySettings = React.createClass({
|
||||
propTypes: {
|
||||
prize: React.PropTypes.object
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return PrizeJuryStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
PrizeJuryStore.listen(this.onChange);
|
||||
PrizeJuryActions.fetchJury();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
PrizeJuryStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
handleCreateSuccess(response) {
|
||||
PrizeJuryActions.fetchJury();
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
this.refs.form.refs.email.refs.input.getDOMNode().value = null;
|
||||
},
|
||||
|
||||
render() {
|
||||
let content = (
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />
|
||||
</div>);
|
||||
|
||||
if (this.state.members.length > -1) {
|
||||
content = this.state.members.map(function(member, i) {
|
||||
return (
|
||||
<ActionPanel
|
||||
name={member.email}
|
||||
key={i}
|
||||
title={member.email}
|
||||
content={member.status}
|
||||
buttons={<button
|
||||
className="pull-right btn btn-default btn-sm"
|
||||
data-id={member.name}>
|
||||
{getLangText('RESEND INVITATION')}
|
||||
</button>}
|
||||
/>);
|
||||
}, this);
|
||||
content = (
|
||||
<div>
|
||||
{content}
|
||||
</div>);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
url={apiUrls.jury}
|
||||
handleSuccess={this.handleCreateSuccess}
|
||||
ref='form'
|
||||
buttonSubmitText='INVITE'>
|
||||
<FormPropertyHeader>
|
||||
<h4 style={{margin: '30px 0px 10px 10px'}}>Jury Members</h4>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
name='email'
|
||||
label={getLangText('New jury member')}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder={getLangText('Enter an email to invite a jury member')}
|
||||
required/>
|
||||
</Property>
|
||||
<hr />
|
||||
</Form>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let PrizesDashboard = React.createClass({
|
||||
|
||||
getColumnList() {
|
||||
return [
|
||||
new ColumnModel(
|
||||
(item) => {
|
||||
return {
|
||||
'content': item.name
|
||||
}; },
|
||||
'name',
|
||||
getLangText('Name'),
|
||||
TableItemText,
|
||||
6,
|
||||
false,
|
||||
null
|
||||
),
|
||||
new ColumnModel(
|
||||
(item) => {
|
||||
return {
|
||||
'content': item.domain
|
||||
}; },
|
||||
'domain',
|
||||
getLangText('Domain'),
|
||||
TableItemText,
|
||||
1,
|
||||
false,
|
||||
null
|
||||
)
|
||||
];
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Table
|
||||
responsive
|
||||
className="ascribe-table"
|
||||
columnList={this.getColumnList()}
|
||||
itemList={this.state.prizeList}>
|
||||
{this.state.prizeList.map((item, i) => {
|
||||
return (
|
||||
<TableItem
|
||||
className="ascribe-table-item-selectable"
|
||||
key={i}/>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Settings;
|
@ -1,15 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
import AppConstants from '../../../../constants/application_constants';
|
||||
import AppPrizeConstants from './application_prize_constants';
|
||||
|
||||
function getApiUrls(subdomain) {
|
||||
return {
|
||||
'pieces_list': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/',
|
||||
'users_login': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/login/',
|
||||
'users_signup': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/',
|
||||
'user': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/',
|
||||
'piece_submit_to_prize': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/${piece_id}/submit/',
|
||||
'piece': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/${piece_id}/'
|
||||
'pieces_list': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/',
|
||||
'users_login': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/login/',
|
||||
'users_signup': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/',
|
||||
'user': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/',
|
||||
'piece_submit_to_prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/submit/',
|
||||
'piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/',
|
||||
'prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/',
|
||||
'jury': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/'
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
import AppConstants from '../../../../constants/application_constants';
|
||||
|
||||
let constants = {
|
||||
prizeApiEndpoint: AppConstants.apiEndpoint + 'prizes/'
|
||||
};
|
||||
|
||||
export default constants;
|
12
js/components/whitelabel/prize/fetchers/prize_fetcher.js
Normal file
12
js/components/whitelabel/prize/fetchers/prize_fetcher.js
Normal file
@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
import requests from '../../../../utils/requests';
|
||||
|
||||
|
||||
let PrizeFetcher = {
|
||||
fetch() {
|
||||
return requests.get('prize');
|
||||
}
|
||||
};
|
||||
|
||||
export default PrizeFetcher;
|
@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
import requests from '../../../../utils/requests';
|
||||
|
||||
|
||||
let PrizeJuryFetcher = {
|
||||
fetch() {
|
||||
return requests.get('jury');
|
||||
}
|
||||
};
|
||||
|
||||
export default PrizeJuryFetcher;
|
@ -12,7 +12,7 @@ import PrizeRegisterPiece from './components/register_piece';
|
||||
import PrizePieceList from './components/piece_list';
|
||||
import PrizePieceContainer from './components/ascribe_detail/piece_container';
|
||||
import EditionContainer from '../../ascribe_detail/edition_container';
|
||||
import SettingsContainer from '../../../components/settings_container';
|
||||
import SettingsContainer from './components/settings_container';
|
||||
|
||||
import App from './app';
|
||||
import AppConstants from '../../../constants/application_constants';
|
||||
@ -21,7 +21,7 @@ let Route = Router.Route;
|
||||
let baseUrl = AppConstants.baseUrl;
|
||||
|
||||
|
||||
function getRoutes(commonRoutes) {
|
||||
function getRoutes() {
|
||||
return (
|
||||
<Route name="app" path={baseUrl} handler={App}>
|
||||
<Route name="landing" path={baseUrl} handler={Landing} />
|
||||
|
18
js/components/whitelabel/prize/stores/prize_jury_store.js
Normal file
18
js/components/whitelabel/prize/stores/prize_jury_store.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../../../../alt';
|
||||
|
||||
import PrizeJuryActions from '../actions/prize_jury_actions';
|
||||
|
||||
class PrizeJuryStore {
|
||||
constructor() {
|
||||
this.members = [];
|
||||
this.bindActions(PrizeJuryActions);
|
||||
}
|
||||
|
||||
onUpdatePrizeJury( members ) {
|
||||
this.members = members;
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createStore(PrizeJuryStore, 'PrizeJuryStore');
|
18
js/components/whitelabel/prize/stores/prize_store.js
Normal file
18
js/components/whitelabel/prize/stores/prize_store.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../../../../alt';
|
||||
|
||||
import PrizeActions from '../actions/prize_actions';
|
||||
|
||||
class PrizeStore {
|
||||
constructor() {
|
||||
this.prize = [];
|
||||
this.bindActions(PrizeActions);
|
||||
}
|
||||
|
||||
onUpdatePrize({ prize }) {
|
||||
this.prize = prize;
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createStore(PrizeStore, 'PrizeStore');
|
@ -52,7 +52,8 @@ let apiUrls = {
|
||||
'users_profile': AppConstants.apiEndpoint + 'users/profile/',
|
||||
'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/',
|
||||
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/',
|
||||
'delete_s3_file': AppConstants.serverUrl + 's3/delete/'
|
||||
'delete_s3_file': AppConstants.serverUrl + 's3/delete/',
|
||||
'prize_list': AppConstants.apiEndpoint + 'prize/'
|
||||
};
|
||||
|
||||
|
||||
|
@ -10,9 +10,9 @@ let constants = {
|
||||
'apiEndpoint': window.API_ENDPOINT,
|
||||
'serverUrl': window.SERVER_URL,
|
||||
'baseUrl': window.BASE_URL,
|
||||
'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_editions',
|
||||
'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_create_editions', 'acl_view_editions',
|
||||
'acl_loan', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view',
|
||||
'acl_withdraw_transfer'],
|
||||
'acl_withdraw_transfer', 'acl_submit_to_prize'],
|
||||
|
||||
'version': 0.1,
|
||||
'csrftoken': 'csrftoken2',
|
||||
|
@ -3,20 +3,26 @@
|
||||
import requests from '../utils/requests';
|
||||
|
||||
import { generateOrderingQueryParams } from '../utils/fetch_api_utils';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
|
||||
let EditionListFetcher = {
|
||||
/**
|
||||
* Fetches a list of editions from the API.
|
||||
*/
|
||||
fetch(pieceId, page, pageSize, orderBy, orderAsc) {
|
||||
fetch(pieceId, page, pageSize, orderBy, orderAsc, filterBy) {
|
||||
let ordering = generateOrderingQueryParams(orderBy, orderAsc);
|
||||
return requests.get('editions_list', {
|
||||
'piece_id': pieceId,
|
||||
|
||||
let queryParams = mergeOptions(
|
||||
{
|
||||
page,
|
||||
pageSize,
|
||||
ordering
|
||||
});
|
||||
ordering,
|
||||
piece_id: pieceId
|
||||
},
|
||||
filterBy
|
||||
);
|
||||
|
||||
return requests.get('editions_list', queryParams);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,17 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
import { generateOrderingQueryParams } from '../utils/fetch_api_utils';
|
||||
import requests from '../utils/requests';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
import { generateOrderingQueryParams } from '../utils/fetch_api_utils';
|
||||
|
||||
let PieceListFetcher = {
|
||||
/**
|
||||
* Fetches a list of pieces from the API.
|
||||
* Can be called with all supplied queryparams the API.
|
||||
*/
|
||||
fetch(page, pageSize, search, orderBy, orderAsc) {
|
||||
fetch(page, pageSize, search, orderBy, orderAsc, filterBy) {
|
||||
let ordering = generateOrderingQueryParams(orderBy, orderAsc);
|
||||
return requests.get('pieces_list', { page, pageSize, search, ordering });
|
||||
|
||||
// filterBy is an object of acl key-value pairs.
|
||||
// The values are booleans
|
||||
let queryParams = mergeOptions(
|
||||
{
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
ordering
|
||||
},
|
||||
filterBy
|
||||
);
|
||||
|
||||
return requests.get('pieces_list', queryParams);
|
||||
},
|
||||
|
||||
fetchRequestActions() {
|
||||
|
12
js/fetchers/prize_list_fetcher.js
Normal file
12
js/fetchers/prize_list_fetcher.js
Normal file
@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
import requests from '../utils/requests';
|
||||
|
||||
|
||||
let PrizeListFetcher = {
|
||||
fetch() {
|
||||
return requests.get('prize_list');
|
||||
}
|
||||
};
|
||||
|
||||
export default PrizeListFetcher;
|
@ -1,24 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import { sumNumList } from '../utils/general_utils';
|
||||
|
||||
let TableColumnMixin = {
|
||||
/**
|
||||
* Generates the bootstrap grid column declarations automatically using
|
||||
* the columnMap.
|
||||
*/
|
||||
calcColumnClasses(list, i, numOfColumns) {
|
||||
let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-'];
|
||||
|
||||
let listOfRowValues = list.map((column) => column.rowWidth );
|
||||
let numOfUsedColumns = sumNumList(listOfRowValues);
|
||||
|
||||
if(numOfUsedColumns > numOfColumns) {
|
||||
throw new Error('This table has only ' + numOfColumns + ' columns to assign. You defined ' + numOfUsedColumns + '. Change this in the columnMap you\'re passing to the table.');
|
||||
} else {
|
||||
return bootstrapClasses.join( listOfRowValues[i] + ' ') + listOfRowValues[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default TableColumnMixin;
|
@ -20,6 +20,8 @@ import CoaVerifyContainer from './components/coa_verify_container';
|
||||
|
||||
import RegisterPiece from './components/register_piece';
|
||||
|
||||
import PrizesDashboard from './components/ascribe_prizes_dashboard/prizes_dashboard';
|
||||
|
||||
let Route = Router.Route;
|
||||
|
||||
|
||||
@ -35,6 +37,7 @@ const COMMON_ROUTES = (
|
||||
<Route name="register_piece" path="register_piece" handler={RegisterPiece} />
|
||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
||||
<Route name="prizes" path="prizes" handler={PrizesDashboard} />
|
||||
</Route>
|
||||
);
|
||||
|
||||
|
@ -12,7 +12,7 @@ class EditionListStore {
|
||||
this.bindActions(EditionsListActions);
|
||||
}
|
||||
|
||||
onUpdateEditionList({pieceId, editionListOfPiece, page, pageSize, orderBy, orderAsc, count}) {
|
||||
onUpdateEditionList({pieceId, editionListOfPiece, page, pageSize, orderBy, orderAsc, count, filterBy}) {
|
||||
|
||||
/*
|
||||
Basically there are two modes an edition list can be updated.
|
||||
@ -54,6 +54,7 @@ class EditionListStore {
|
||||
this.editionList[pieceId].orderBy = orderBy;
|
||||
this.editionList[pieceId].orderAsc = orderAsc;
|
||||
this.editionList[pieceId].count = count;
|
||||
this.editionList[pieceId].filterBy = filterBy;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +81,10 @@ class EditionListStore {
|
||||
this.editionList[pieceId].length = 0;
|
||||
|
||||
// refetch editions with adjusted page size
|
||||
EditionsListActions.fetchEditionList(pieceId, 1, prevEditionListLength, this.editionList[pieceId].orderBy, this.editionList[pieceId].orderAsc)
|
||||
EditionsListActions.fetchEditionList(pieceId, 1, prevEditionListLength,
|
||||
this.editionList[pieceId].orderBy,
|
||||
this.editionList[pieceId].orderAsc,
|
||||
this.editionList[pieceId].filterBy)
|
||||
.then(() => {
|
||||
// reset back to the normal pageSize and page
|
||||
this.editionList[pieceId].page = prevEditionListPage;
|
||||
|
@ -26,16 +26,18 @@ class PieceListStore {
|
||||
this.search = '';
|
||||
this.orderBy = 'artist_name';
|
||||
this.orderAsc = true;
|
||||
this.filterBy = {};
|
||||
this.bindActions(PieceListActions);
|
||||
}
|
||||
|
||||
onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount }) {
|
||||
onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount, filterBy }) {
|
||||
this.page = page;
|
||||
this.pageSize = pageSize;
|
||||
this.search = search;
|
||||
this.orderAsc = orderAsc;
|
||||
this.orderBy = orderBy;
|
||||
this.pieceListCount = pieceListCount;
|
||||
this.filterBy = filterBy;
|
||||
|
||||
/**
|
||||
* Pagination - Known Issue:
|
||||
|
20
js/stores/prize_list_store.js
Normal file
20
js/stores/prize_list_store.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../alt';
|
||||
|
||||
import PrizeListActions from '../actions/prize_list_actions';
|
||||
|
||||
class PrizeListStore {
|
||||
constructor() {
|
||||
this.prizeList = [];
|
||||
this.prizeListCount = -1;
|
||||
this.bindActions(PrizeListActions);
|
||||
}
|
||||
|
||||
onUpdatePrizeList({ prizeList, prizeListCount }) {
|
||||
this.prizeList = prizeList;
|
||||
this.prizeListCount = prizeListCount;
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createStore(PrizeListStore, 'PrizeListStore');
|
13
sass/ascribe_panel.scss
Normal file
13
sass/ascribe_panel.scss
Normal file
@ -0,0 +1,13 @@
|
||||
.ascribe-panel-wrapper {
|
||||
border: 1px solid #F5F5F5;
|
||||
}
|
||||
|
||||
.ascribe-panel-title {
|
||||
padding: 1em 0 1em 1.5em;
|
||||
}
|
||||
|
||||
.ascribe-panel-content {
|
||||
padding: .75em 0 .75em 1em;
|
||||
font-size: 1em;
|
||||
color: #616161;
|
||||
}
|
@ -5,5 +5,41 @@
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
max-width: 160px;
|
||||
max-width: 200px;
|
||||
input {
|
||||
height: 33px;
|
||||
}
|
||||
}
|
||||
|
||||
.ascribe-piece-list-toolbar-filter-widget {
|
||||
margin-right: 1em;
|
||||
|
||||
.filter-widget-item {
|
||||
|
||||
> a {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-line {
|
||||
position: relative;
|
||||
height: 25px;
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
left: 9px;
|
||||
top: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 9px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
@ -22,10 +22,11 @@
|
||||
}
|
||||
|
||||
.ascribe-table-item-column {
|
||||
display: table;
|
||||
font-family: 'Source Sans Pro';
|
||||
font-size: .8em;
|
||||
height:3em;
|
||||
vertical-align: middle;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.ascribe-table-item-column > * {
|
||||
@ -37,7 +38,8 @@
|
||||
}
|
||||
|
||||
.ascribe-table-item-column > span > input {
|
||||
margin-top:18px;
|
||||
margin-top:10px;
|
||||
margin-left:2px;
|
||||
}
|
||||
|
||||
.ascribe-table-item-selected {
|
||||
|
@ -27,6 +27,7 @@ $BASE_URL: '<%= BASE_URL %>';
|
||||
@import 'ascribe_settings';
|
||||
@import 'ascribe_slides_container';
|
||||
@import 'ascribe_form';
|
||||
@import 'ascribe_panel';
|
||||
|
||||
@import 'whitelabel/index';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user