Work in progress on migration to Bootstrap 4 and CoreUI admin theme
This commit is contained in:
parent
366bd09f2a
commit
3425e2c16a
85 changed files with 2093 additions and 10564 deletions
|
@ -17,6 +17,7 @@ import axios
|
|||
import {Button} from '../lib/bootstrap-components';
|
||||
import {getUrl} from "../lib/urls";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import styles from "./styles.scss"
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
|
@ -66,33 +67,44 @@ export default class API extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.api}>
|
||||
<Title>{t('api')}</Title>
|
||||
|
||||
|
||||
<div className="panel panel-default">
|
||||
<div className="panel-body">
|
||||
<div className="pull-right">
|
||||
<Button label={this.state.accessToken ? t('resetAccessToken') : t('generateAccessToken')} icon="retweet" className="btn-info" onClickAsync={::this.resetAccessToken} />
|
||||
<div className="card mb-3">
|
||||
<div className="card-body">
|
||||
<div className="float-right">
|
||||
<Button label={this.state.accessToken ? t('resetAccessToken') : t('generateAccessToken')} icon="redo" className="btn-info" onClickAsync={::this.resetAccessToken} />
|
||||
</div>
|
||||
{accessTokenMsg}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="well">
|
||||
<h3>{t('notesAboutTheApi')}</h3>
|
||||
<div className="card mb-3">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">{t('notesAboutTheApi')}</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<Trans i18nKey="apiResponseIsAJsonStructureWithErrorAnd">API response is a JSON structure with <code>error</code> and <code>data</code> properties. If the response <code>error</code> has a value set then the request failed.</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans i18nKey="youNeedToDefineProperContentTypeWhen">You need to define proper <code>Content-Type</code> when making a request. You can either use <code>application/x-www-form-urlencoded</code> for normal form data or <code>application/json</code> for a JSON payload. Using <code>multipart/form-data</code> is not supported.</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="card-text">
|
||||
<li>
|
||||
<Trans i18nKey="apiResponseIsAJsonStructureWithErrorAnd">API response is a JSON structure with <code>error</code> and <code>data</code> properties. If the response <code>error</code> has a value set then the request failed.</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans i18nKey="youNeedToDefineProperContentTypeWhen">You need to define proper <code>Content-Type</code> when making a request. You can either use <code>application/x-www-form-urlencoded</code> for normal form data or <code>application/json</code> for a JSON payload. Using <code>multipart/form-data</code> is not supported.</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>POST /api/subscribe/:listId – {t('addSubscription')}</h3>
|
||||
<div className="card mb-3">
|
||||
<div className="card-header">
|
||||
<b>POST /api/subscribe/:listId – {t('addSubscription')}</b>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<p className="card-text">
|
||||
{t('thisApiCallEitherInsertsANewSubscription')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<h4>POST /api/subscribe/:listId – {t('addSubscription')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallEitherInsertsANewSubscription')}
|
||||
|
@ -137,7 +149,7 @@ export default class API extends Component {
|
|||
<pre>curl -XPOST '{getUrl(`api/subscribe/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
--data 'EMAIL=test@example.com&MERGE_CHECKBOX=yes&REQUIRE_CONFIRMATION=yes'</pre>
|
||||
|
||||
<h3>POST /api/unsubscribe/:listId – {t('removeSubscription')}</h3>
|
||||
<h4>POST /api/unsubscribe/:listId – {t('removeSubscription')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallMarksASubscriptionAs')}
|
||||
|
@ -164,7 +176,7 @@ export default class API extends Component {
|
|||
<pre>curl -XPOST '{getUrl(`api/unsubscribe/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
--data 'EMAIL=test@example.com'</pre>
|
||||
|
||||
<h3>POST /api/delete/:listId – {t('deleteSubscription')}</h3>
|
||||
<h4>POST /api/delete/:listId – {t('deleteSubscription')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallDeletesASubscription')}
|
||||
|
@ -191,7 +203,7 @@ export default class API extends Component {
|
|||
<pre>curl -XPOST '{getUrl(`api/delete/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
--data 'EMAIL=test@example.com'</pre>
|
||||
|
||||
<h3>POST /api/field/:listId – {t('addNewCustomField')}</h3>
|
||||
<h4>POST /api/field/:listId – {t('addNewCustomField')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallCreatesANewCustomFieldForA')}
|
||||
|
@ -239,7 +251,7 @@ export default class API extends Component {
|
|||
<pre>curl -XPOST '{getUrl(`api/field/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
--data 'NAME=Birthday&TYPE=birthday-us&VISIBLE=yes'</pre>
|
||||
|
||||
<h3>GET /api/blacklist/get – {t('getListOfBlacklistedEmails')}</h3>
|
||||
<h4>GET /api/blacklist/get – {t('getListOfBlacklistedEmails')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallGetListOfBlacklistedEmails')}
|
||||
|
@ -264,7 +276,7 @@ export default class API extends Component {
|
|||
|
||||
<pre>curl -XGET '{getUrl(`api/blacklist/get?access_token=${accessToken}&limit=10&start=10&search=gmail`)}' </pre>
|
||||
|
||||
<h3>POST /api/blacklist/add – {t('addEmailToBlacklist')}</h3>
|
||||
<h4>POST /api/blacklist/add – {t('addEmailToBlacklist')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallEitherAddEmailsToBlacklist')}
|
||||
|
@ -291,7 +303,7 @@ export default class API extends Component {
|
|||
<pre>curl -XPOST '{getUrl(`api/blacklist/add?access_token={accessToken}`)}' \
|
||||
--data 'EMAIL=test@example.com&'</pre>
|
||||
|
||||
<h3>POST /api/blacklist/delete – {t('deleteEmailFromBlacklist')}</h3>
|
||||
<h4>POST /api/blacklist/delete – {t('deleteEmailFromBlacklist')}</h4>
|
||||
|
||||
<p>
|
||||
{t('thisApiCallEitherDeleteEmailsFrom')}
|
||||
|
@ -318,7 +330,7 @@ export default class API extends Component {
|
|||
<pre>curl -XPOST '{getUrl(`api/blacklist/delete?access_token=${accessToken}`)}' \
|
||||
--data 'EMAIL=test@example.com&'</pre>
|
||||
|
||||
<h3>GET /api/lists/:email – {t('getTheListsAUserHasSubscribedTo')}</h3>
|
||||
<h4>GET /api/lists/:email – {t('getTheListsAUserHasSubscribedTo')}</h4>
|
||||
|
||||
<p>
|
||||
{t('retrieveTheListsThatTheUserWithEmailHas')}
|
||||
|
|
|
@ -207,7 +207,7 @@ export default class Account extends Component {
|
|||
</Fieldset>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('update')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('update')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
|
@ -76,7 +76,7 @@ export default class Forget extends Component {
|
|||
<InputField id="usernameOrEmail" label={t('usernameOrEmail')}/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('sendEmail')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('sendEmail')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
|
@ -121,7 +121,7 @@ export default class Login extends Component {
|
|||
<CheckBox id="remember" text={t('rememberMe')}/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('signIn')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('signIn')}/>
|
||||
{passwordResetLink}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -161,7 +161,7 @@ export default class Account extends Component {
|
|||
<InputField id="password2" label={t('confirmPassword')} type="password"/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('resetPassword')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('resetPassword')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
9
client/src/account/styles.scss
Normal file
9
client/src/account/styles.scss
Normal file
|
@ -0,0 +1,9 @@
|
|||
.api {
|
||||
:global .card h4 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: 45px;
|
||||
}
|
||||
}
|
|
@ -131,7 +131,7 @@ export default class List extends Component {
|
|||
<InputField id="email" label={t('email')}/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('addToBlacklist')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('addToBlacklist')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
||||
|
|
|
@ -507,21 +507,21 @@ export default class CUD extends Component {
|
|||
<div className={campaignsStyles.entryButtons}>
|
||||
{lsts.length > 1 &&
|
||||
<Button
|
||||
className="btn-default"
|
||||
className="btn-secondary"
|
||||
icon="remove"
|
||||
title={t('remove')}
|
||||
onClickAsync={() => this.onRemoveListEntry(lstUid)}
|
||||
/>
|
||||
}
|
||||
<Button
|
||||
className="btn-default"
|
||||
className="btn-secondary"
|
||||
icon="plus"
|
||||
title={t('insertNewEntryBeforeThisOne')}
|
||||
onClickAsync={() => this.onAddListEntry(lstOrderIdxClosure)}
|
||||
/>
|
||||
{lstOrderIdx > 0 &&
|
||||
<Button
|
||||
className="btn-default"
|
||||
className="btn-secondary"
|
||||
icon="chevron-up"
|
||||
title={t('moveUp')}
|
||||
onClickAsync={() => this.onListEntryMoveUp(lstOrderIdxClosure)}
|
||||
|
@ -529,7 +529,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
{lstOrderIdx < lsts.length - 1 &&
|
||||
<Button
|
||||
className="btn-default"
|
||||
className="btn-secondary"
|
||||
icon="chevron-down"
|
||||
title={t('moveDown')}
|
||||
onClickAsync={() => this.onListEntryMoveDown(lstOrderIdxClosure)}
|
||||
|
@ -559,7 +559,7 @@ export default class CUD extends Component {
|
|||
{lstsEditEntries}
|
||||
<div key="newEntry" className={campaignsStyles.newEntry}>
|
||||
<Button
|
||||
className="btn-default"
|
||||
className="btn-secondary"
|
||||
icon="plus"
|
||||
label={t('addList')}
|
||||
onClickAsync={() => this.onAddListEntry(lsts.length)}
|
||||
|
@ -737,7 +737,7 @@ export default class CUD extends Component {
|
|||
{templateEdit}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={saveButtonLabel}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={saveButtonLabel}/>
|
||||
{canDelete && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/campaigns/${this.props.entity.id}/delete`}/> }
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -228,7 +228,7 @@ export default class CustomContent extends Component {
|
|||
{customTemplateTypeKey && getEditForm(this, customTemplateTypeKey, 'data_sourceCustom_')}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
<Button className="btn-danger" icon="send" label={t('testSend')} onClickAsync={async () => this.setState({showTestSendModal: true})}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -308,7 +308,7 @@ class SendControls extends Component {
|
|||
:
|
||||
<Button className="btn-primary" icon="send" label={t('send') + subscrInfo} onClickAsync={::this.startAsync}/>
|
||||
}
|
||||
{entity.status === CampaignStatus.PAUSED && <NavButton className="btn-default" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>}
|
||||
{entity.status === CampaignStatus.PAUSED && <NavButton className="btn-secondary" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
@ -321,7 +321,7 @@ class SendControls extends Component {
|
|||
</AlignedRow>
|
||||
<ButtonRow>
|
||||
<Button className="btn-primary" icon="stop" label={t('stop')} onClickAsync={::this.stopAsync}/>
|
||||
<NavButton className="btn-default" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>
|
||||
<NavButton className="btn-secondary" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
@ -337,7 +337,7 @@ class SendControls extends Component {
|
|||
<ButtonRow>
|
||||
<Button className="btn-primary" icon="play" label={t('continue') + subscrInfo} onClickAsync={::this.startAsync}/>
|
||||
<Button className="btn-primary" icon="refresh" label={t('reset')} onClickAsync={::this.resetAsync}/>
|
||||
<NavButton className="btn-default" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>
|
||||
<NavButton className="btn-secondary" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -235,7 +235,7 @@ export default class CUD extends Component {
|
|||
<CheckBox id="enabled" text={t('enabled')}/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{isEdit && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/campaigns/${this.props.campaign.id}/triggers/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
30
client/src/lib/bootstrap-components.js
vendored
30
client/src/lib/bootstrap-components.js
vendored
|
@ -10,11 +10,11 @@ import {
|
|||
} from './error-handling';
|
||||
import {withComponentMixins} from "./decorator-helpers";
|
||||
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
withErrorHandling
|
||||
])
|
||||
|
||||
class DismissibleAlert extends Component {
|
||||
static propTypes = {
|
||||
severity: PropTypes.string.isRequired,
|
||||
|
@ -49,24 +49,31 @@ class Icon extends Component {
|
|||
}
|
||||
|
||||
static defaultProps = {
|
||||
family: 'glyphicon'
|
||||
family: 'fas'
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
|
||||
return <span className={`${props.family} ${props.family}-${props.icon}` + (props.className ? ' ' + props.className : '')} title={props.title}></span>;
|
||||
if (props.family === 'fas' || props.family === 'far') {
|
||||
return <i className={`${props.family} fa-${props.icon} ${props.className || ''}`} title={props.title}></i>;
|
||||
} else {
|
||||
console.error(`Icon font family ${props.family} not supported. (icon: ${props.icon}, title: ${props.title})`)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@withComponentMixins([
|
||||
withErrorHandling
|
||||
])
|
||||
|
||||
class Button extends Component {
|
||||
static propTypes = {
|
||||
onClickAsync: PropTypes.func,
|
||||
label: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
iconTitle: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
type: PropTypes.string
|
||||
}
|
||||
|
@ -91,7 +98,7 @@ class Button extends Component {
|
|||
|
||||
let icon;
|
||||
if (props.icon) {
|
||||
icon = <Icon icon={props.icon}/>
|
||||
icon = <Icon icon={props.icon} title={props.iconTitle}/>
|
||||
}
|
||||
|
||||
let iconSpacer;
|
||||
|
@ -105,6 +112,7 @@ class Button extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
class DropdownMenu extends Component {
|
||||
static propTypes = {
|
||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
|
@ -141,6 +149,7 @@ class DropdownMenu extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
class DropdownMenuItem extends Component {
|
||||
static propTypes = {
|
||||
label: PropTypes.string,
|
||||
|
@ -151,7 +160,7 @@ class DropdownMenuItem extends Component {
|
|||
render() {
|
||||
const props = this.props;
|
||||
|
||||
let className = 'dropdown';
|
||||
let className = 'nav-item dropdown';
|
||||
if (props.className) {
|
||||
className = className + ' ' + props.className;
|
||||
}
|
||||
|
@ -159,12 +168,12 @@ class DropdownMenuItem extends Component {
|
|||
return (
|
||||
<li className={className}>
|
||||
{props.icon ?
|
||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
<Icon icon={props.icon}/>{' '}{props.label}{' '}<span className="caret"></span>
|
||||
<a href="#" className="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
<Icon icon={props.icon}/>{' '}{props.label}
|
||||
</a>
|
||||
:
|
||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
{props.label}{' '}<span className="caret"></span>
|
||||
<a href="#" className="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
{props.label}
|
||||
</a>
|
||||
}
|
||||
<ul className="dropdown-menu">
|
||||
|
@ -208,6 +217,7 @@ class ActionLink extends Component {
|
|||
withTranslation,
|
||||
withErrorHandling
|
||||
])
|
||||
//TODO
|
||||
class ModalDialog extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -215,7 +225,7 @@ class ModalDialog extends Component {
|
|||
const t = props.t;
|
||||
|
||||
this.state = {
|
||||
buttons: this.props.buttons || [ { label: t('close'), className: 'btn-default', onClickAsync: null } ]
|
||||
buttons: this.props.buttons || [ { label: t('close'), className: 'btn-secondary', onClickAsync: null } ]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ class Form extends Component {
|
|||
const statusMessageText = owner.getFormStatusMessageText();
|
||||
const statusMessageSeverity = owner.getFormStatusMessageSeverity();
|
||||
|
||||
let formClass = `form-horizontal ${styles.form} `;
|
||||
let formClass = styles.form;
|
||||
if (props.format === 'wide') {
|
||||
formClass = '';
|
||||
} else if (props.format === 'inline') {
|
||||
|
@ -166,14 +166,14 @@ class Fieldset extends Component {
|
|||
|
||||
let helpBlock = null;
|
||||
if (this.props.help) {
|
||||
helpBlock = <div className="help-block" id={htmlId + '_help'}>{this.props.help}</div>;
|
||||
helpBlock = <small className="form-text text-muted" id={htmlId + '_help'}>{this.props.help}</small>;
|
||||
}
|
||||
|
||||
let validationBlock = null;
|
||||
if (id) {
|
||||
const validationMsg = id && owner.getFormValidationMessage(id);
|
||||
if (validationMsg) {
|
||||
validationBlock = <div className="help-block" id={htmlId + '_help_validation'}>{validationMsg}</div>;
|
||||
validationBlock = <small className="form-text text-muted" id={htmlId + '_help_validation'}>{validationMsg}</small>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,29 +194,22 @@ function wrapInput(id, htmlId, owner, format, rightContainerClass, label, help,
|
|||
// wrapInput may be used also outside forms to make a kind of fake read-only forms
|
||||
let className;
|
||||
if (owner) {
|
||||
if (id) {
|
||||
className = owner.addFormValidationClass('form-group', id);
|
||||
} else {
|
||||
className = 'form-group';
|
||||
}
|
||||
className = 'form-group row';
|
||||
} else {
|
||||
className = 'row ' + styles.staticFormGroup;
|
||||
}
|
||||
|
||||
let colLeft = '';
|
||||
let colRight = '';
|
||||
let offsetRight = '';
|
||||
|
||||
switch (format) {
|
||||
case 'wide':
|
||||
colLeft = '';
|
||||
colRight = '';
|
||||
offsetRight = '';
|
||||
break;
|
||||
default:
|
||||
colLeft = 'col-sm-2';
|
||||
colLeft = 'col-sm-2 col-form-label';
|
||||
colRight = 'col-sm-10';
|
||||
offsetRight = 'col-sm-offset-2';
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -225,20 +218,22 @@ function wrapInput(id, htmlId, owner, format, rightContainerClass, label, help,
|
|||
|
||||
let helpBlock = null;
|
||||
if (help) {
|
||||
helpBlock = <div className={`help-block ${colRight} ${offsetRight}`} id={htmlId + '_help'}>{help}</div>;
|
||||
helpBlock = <small className={`form-text text-muted`} id={htmlId + '_help'}>{help}</small>;
|
||||
}
|
||||
|
||||
let validationBlock = null;
|
||||
if (id) {
|
||||
const validationMsg = id && owner.getFormValidationMessage(id);
|
||||
if (validationMsg) {
|
||||
validationBlock = <div className={`help-block ${colRight} ${offsetRight}`} id={htmlId + '_help_validation'}>{validationMsg}</div>;
|
||||
validationBlock = <div className="invalid-feedback" id={htmlId + '_help_validation'}>{validationMsg}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
let labelBlock = null;
|
||||
if (label) {
|
||||
labelBlock = <label htmlFor={htmlId} className="control-label">{label}</label>;
|
||||
labelBlock = <label className={colLeft}>{label}</label>;
|
||||
} else {
|
||||
labelBlock = <div className={colLeft}/>
|
||||
}
|
||||
|
||||
if (format === 'inline') {
|
||||
|
@ -252,14 +247,12 @@ function wrapInput(id, htmlId, owner, format, rightContainerClass, label, help,
|
|||
} else {
|
||||
return (
|
||||
<div className={className} >
|
||||
<div className={colLeft}>
|
||||
{labelBlock}
|
||||
</div>
|
||||
{labelBlock}
|
||||
<div className={`${colRight} ${rightContainerClass}`}>
|
||||
{input}
|
||||
{helpBlock}
|
||||
{validationBlock}
|
||||
</div>
|
||||
{helpBlock}
|
||||
{validationBlock}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -325,8 +318,10 @@ class InputField extends Component {
|
|||
type = 'hidden';
|
||||
}
|
||||
|
||||
const className = owner.addFormValidationClass('form-control', id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<input type={type} value={owner.getFormValue(id)} placeholder={props.placeholder} id={htmlId} className="form-control" aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
||||
<input type={type} value={owner.getFormValue(id)} placeholder={props.placeholder} id={htmlId} className={className} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -349,11 +344,13 @@ class CheckBox extends Component {
|
|||
const id = this.props.id;
|
||||
const htmlId = 'form_' + id;
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, 'checkbox', props.label, props.help,
|
||||
<label>
|
||||
<input type="checkbox" checked={owner.getFormValue(id)} id={htmlId} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, !owner.getFormValue(id))}/>
|
||||
{props.text}
|
||||
</label>
|
||||
const className = owner.addFormValidationClass('form-check-input', id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<div className="form-group form-check my-2">
|
||||
<input className={className} type="checkbox" checked={owner.getFormValue(id)} id={htmlId} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, !owner.getFormValue(id))}/>
|
||||
<label className="form-check-label" htmlFor={htmlId}>{props.text}</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -393,12 +390,13 @@ class CheckBoxGroup extends Component {
|
|||
|
||||
const options = [];
|
||||
for (const option of props.options) {
|
||||
options.push(
|
||||
<div key={option.key} className="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" checked={selection.includes(option.key)} onChange={evt => this.onChange(option.key)}/>
|
||||
{option.label}
|
||||
</label>
|
||||
const optClassName = owner.addFormValidationClass('form-check-input', id);
|
||||
const optId = htmlId + '_' + option.key;
|
||||
|
||||
let number = options.push(
|
||||
<div key={option.key} className="form-group form-check my-2">
|
||||
<input id={optId} type="checkbox" className={optClassName} checked={selection.includes(option.key)} onChange={evt => this.onChange(option.key)}/>
|
||||
<label className="form-check-label" htmlFor={optId}>{option.label}</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -440,12 +438,13 @@ class RadioGroup extends Component {
|
|||
|
||||
const options = [];
|
||||
for (const option of props.options) {
|
||||
options.push(
|
||||
<div key={option.key} className="radio">
|
||||
<label>
|
||||
<input type="radio" name={htmlId} checked={value === option.key} onChange={evt => owner.updateFormValue(id, option.key)}/>
|
||||
{option.label}
|
||||
</label>
|
||||
const optClassName = owner.addFormValidationClass('form-check-input', id);
|
||||
const optId = htmlId + '_' + option.key;
|
||||
|
||||
let number = options.push(
|
||||
<div key={option.key} className="form-group form-check my-2">
|
||||
<input id={optId} type="radio" className={optClassName} name={htmlId} checked={value === option.key} onChange={evt => owner.updateFormValue(id, option.key)}/>
|
||||
<label className="form-check-label" htmlFor={optId}>{option.label}</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -481,10 +480,10 @@ class TextArea extends Component {
|
|||
const owner = this.getFormStateOwner();
|
||||
const id = props.id;
|
||||
const htmlId = 'form_' + id;
|
||||
const className = props.className || ''
|
||||
const className = owner.addFormValidationClass('form-control ' + (props.className || '') , id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<textarea id={htmlId} placeholder={props.placeholder} value={owner.getFormValue(id) || ''} className={`form-control ${className}`} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}></textarea>
|
||||
<textarea id={htmlId} placeholder={props.placeholder} value={owner.getFormValue(id) || ''} className={className} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}></textarea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -518,7 +517,7 @@ class DatePicker extends Component {
|
|||
dateFormat: DateFormat.INTL
|
||||
}
|
||||
|
||||
toggleDayPicker() {
|
||||
async toggleDayPicker() {
|
||||
this.setState({
|
||||
opened: !this.state.opened
|
||||
});
|
||||
|
@ -591,11 +590,15 @@ class DatePicker extends Component {
|
|||
placeholder = getDateFormatString(props.dateFormat);
|
||||
}
|
||||
|
||||
const className = owner.addFormValidationClass('form-control', id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<div>
|
||||
<div className="input-group">
|
||||
<input type="text" value={selectedDateStr} placeholder={placeholder} id={htmlId} className="form-control" aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
||||
<span className="input-group-addon" onClick={::this.toggleDayPicker}><Icon icon="calendar" title={t('openCalendar')}/></span>
|
||||
<input type="text" value={selectedDateStr} placeholder={placeholder} id={htmlId} className={className} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
||||
<div className="input-group-append">
|
||||
<Button iconTitle={t('openCalendar')} className="btn-secondary" icon="calendar-alt" onClickAsync={::this.toggleDayPicker}/>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.opened &&
|
||||
<div className={styles.dayPickerWrapper}>
|
||||
|
@ -650,10 +653,7 @@ class Dropdown extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
let className = 'form-control';
|
||||
if (props.className) {
|
||||
className += ' ' + props.className;
|
||||
}
|
||||
const className = owner.addFormValidationClass('form-control ' + (props.className || '') , id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<select id={htmlId} className={className} aria-describedby={htmlId + '_help'} value={owner.getFormValue(id)} onChange={evt => owner.updateFormValue(id, evt.target.value)}>
|
||||
|
@ -730,8 +730,10 @@ class TreeTableSelect extends Component {
|
|||
const id = this.props.id;
|
||||
const htmlId = 'form_' + id;
|
||||
|
||||
const className = owner.addFormValidationClass('' , id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<TreeTable data={props.data} dataUrl={props.dataUrl} selectMode={TreeSelectMode.SINGLE} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||
<TreeTable className={className} data={props.data} dataUrl={props.dataUrl} selectMode={TreeSelectMode.SINGLE} selection={owner.getFormValue(id)} onSelectionChangedAsync={::this.onSelectionChangedAsync}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -823,14 +825,16 @@ class TableSelect extends Component {
|
|||
const t = props.t;
|
||||
|
||||
if (props.dropdown) {
|
||||
const className = owner.addFormValidationClass('form-control' , id);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<div>
|
||||
<div className={(props.disabled ? '' : 'input-group ') + styles.tableSelectDropdown}>
|
||||
<input type="text" className="form-control" value={this.state.selectedLabel} onClick={::this.toggleOpen} readOnly={!props.disabled} disabled={props.disabled}/>
|
||||
<input type="text" className={className} value={this.state.selectedLabel} onClick={::this.toggleOpen} readOnly={!props.disabled} disabled={props.disabled}/>
|
||||
{!props.disabled &&
|
||||
<span className="input-group-btn">
|
||||
<Button label={t('select')} className="btn-default" onClickAsync={::this.toggleOpen}/>
|
||||
</span>
|
||||
<div className="input-group-append">
|
||||
<Button label={t('select')} className="btn-secondary" onClickAsync={::this.toggleOpen}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div className={styles.tableSelectTable + (this.state.open ? '' : ' ' + styles.tableSelectTableHidden)}>
|
||||
|
@ -1243,9 +1247,9 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
if (this.isFormValidationShown()) {
|
||||
const error = this.getFormError(name);
|
||||
if (error) {
|
||||
return className + ' has-error';
|
||||
return className + ' is-invalid';
|
||||
} else {
|
||||
return className + ' has-success';
|
||||
return className + ' is-valid';
|
||||
}
|
||||
} else {
|
||||
return className;
|
||||
|
|
|
@ -228,7 +228,7 @@ export function tableAddDeleteButton(actions, owner, perms, deleteUrl, name, del
|
|||
});
|
||||
} else {
|
||||
actions.push({
|
||||
label: <Icon icon="remove" title={t('delete')}/>,
|
||||
label: <Icon icon="trash-alt" title={t('delete')}/>,
|
||||
action: () => {
|
||||
owner.tableRestActionDialogData = {
|
||||
shown: true,
|
||||
|
|
|
@ -20,7 +20,8 @@ import interoperableErrors
|
|||
from "../../../shared/interoperable-errors";
|
||||
import {
|
||||
Button,
|
||||
DismissibleAlert
|
||||
DismissibleAlert,
|
||||
Icon
|
||||
} from "./bootstrap-components";
|
||||
import mailtrainConfig
|
||||
from "mailtrainConfig";
|
||||
|
@ -62,7 +63,7 @@ class Breadcrumb extends Component {
|
|||
}
|
||||
|
||||
if (isActive) {
|
||||
return <li key={entry.path} className="active">{title}</li>;
|
||||
return <li key={entry.path} className="breadcrumb-item active">{title}</li>;
|
||||
|
||||
} else if (entry.externalLink) {
|
||||
let externalLink;
|
||||
|
@ -72,7 +73,7 @@ class Breadcrumb extends Component {
|
|||
externalLink = entry.externalLink;
|
||||
}
|
||||
|
||||
return <li key={entry.path}><a href={externalLink}>{title}</a></li>;
|
||||
return <li key={entry.path} className="breadcrumb-item"><a href={externalLink}>{title}</a></li>;
|
||||
|
||||
} else if (entry.link) {
|
||||
let link;
|
||||
|
@ -81,10 +82,10 @@ class Breadcrumb extends Component {
|
|||
} else {
|
||||
link = entry.link;
|
||||
}
|
||||
return <li key={entry.path}><Link to={link}>{title}</Link></li>;
|
||||
return <li key={entry.path} className="breadcrumb-item"><Link to={link}>{title}</Link></li>;
|
||||
|
||||
} else {
|
||||
return <li key={entry.path}>{title}</li>;
|
||||
return <li key={entry.path} className="breadcrumb-item">{title}</li>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,10 +94,11 @@ class Breadcrumb extends Component {
|
|||
|
||||
const renderedElems = [...route.parents.map(x => this.renderElement(x)), this.renderElement(route, true)];
|
||||
|
||||
return <ol className="breadcrumb">{renderedElems}</ol>;
|
||||
return <nav aria-label="breadcrumb"><ol className="breadcrumb">{renderedElems}</ol></nav>;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
class SecondaryNavBar extends Component {
|
||||
static propTypes = {
|
||||
route: PropTypes.object.isRequired,
|
||||
|
@ -441,7 +443,7 @@ export class Toolbar extends Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
let className = 'pull-right ' + styles.buttonRow;
|
||||
let className = 'float-right ' + styles.buttonRow;
|
||||
if (this.props.className) {
|
||||
className += ' ' + this.props.className;
|
||||
}
|
||||
|
@ -471,6 +473,7 @@ export class NavButton extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
export class MenuLink extends Component {
|
||||
static propTypes = {
|
||||
to: PropTypes.string,
|
||||
|
@ -480,12 +483,78 @@ export class MenuLink extends Component {
|
|||
render() {
|
||||
const props = this.props;
|
||||
|
||||
const clsName = "nav-item" + (props.className ? " " + props.className : "")
|
||||
return (
|
||||
<li className={props.className}><Link to={props.to}>{props.children}</Link></li>
|
||||
<li className={clsName}><Link to={props.to} className="nav-link">{props.children}</Link></li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class NavLink extends Component {
|
||||
static propTypes = {
|
||||
to: PropTypes.string,
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
|
||||
const clsName = "nav-item" + (props.className ? " " + props.className : "")
|
||||
return (
|
||||
<li className={clsName}><Link to={props.to} className="nav-link">{props.children}</Link></li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class NavDropdown extends Component {
|
||||
static propTypes = {
|
||||
label: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
menuClassName: PropTypes.string
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
|
||||
const className = 'nav-item dropdown' + (props.className ? ' ' + props.className : '');
|
||||
const menuClassName = 'dropdown-menu' + (props.menuClassName ? ' ' + props.menuClassName : '');
|
||||
|
||||
return (
|
||||
<li className={className}>
|
||||
{props.icon ?
|
||||
<a href="#" className="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
<Icon icon={props.icon}/>{' '}{props.label}
|
||||
</a>
|
||||
:
|
||||
<a href="#" className="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
{props.label}
|
||||
</a>
|
||||
}
|
||||
<ul className={menuClassName}>
|
||||
{props.children}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class NavDropdownLink extends Component {
|
||||
static propTypes = {
|
||||
to: PropTypes.string
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this.props;
|
||||
|
||||
return (
|
||||
<Link to={props.to} className="dropdown-item">{props.children}</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const requiresAuthenticatedUser = createComponentMixin([], [withPageHelpers], (TargetClass, InnerClass) => {
|
||||
class RequiresAuthenticatedUser extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
|
@ -29,7 +29,7 @@ $editorNormalHeight: 800px !default;
|
|||
}
|
||||
|
||||
.navbar {
|
||||
background: #DE4320;
|
||||
background: #f86c6b;
|
||||
width: 100%;
|
||||
height: $navbarHeight;
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ $editorNormalHeight: 800px !default;
|
|||
.title {
|
||||
padding: 5px 0 5px 10px;
|
||||
font-size: 18px;
|
||||
font-family: sans-serif;
|
||||
font-family: "Ubuntu",Tahoma,"Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
color: white;
|
||||
|
@ -58,20 +56,29 @@ $editorNormalHeight: 800px !default;
|
|||
padding: 0px 15px;
|
||||
line-height: $navbarHeight;
|
||||
text-align: center;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-family: sans-serif;
|
||||
cursor: pointer;
|
||||
|
||||
&, &:not([href]):not([tabindex]) { // This is to override reboot.scss in bootstrap
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #b1381e;
|
||||
color: white;
|
||||
background-color: #c05454;
|
||||
text-decoration: none;
|
||||
|
||||
&, &:not([href]):not([tabindex]) { // This is to override reboot.scss in bootstrap
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.btnDisabled {
|
||||
color: #581c00;
|
||||
cursor: default;
|
||||
|
||||
&, &:not([href]):not([tabindex]) { // This is to override reboot.scss in bootstrap
|
||||
color: #621d1d;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ export class CKEditorHost extends Component {
|
|||
<div className={styles.navbar}>
|
||||
{this.state.fullscreen && <img className={styles.logo} src={getTrustedUrl('static/mailtrain-notext.png')}/>}
|
||||
<div className={styles.title}>{this.props.title}</div>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="window-maximize"/></a>
|
||||
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
|
||||
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
|
||||
</div>
|
||||
|
|
|
@ -90,7 +90,7 @@ export class CodeEditorHost extends Component {
|
|||
<div className={styles.navbar}>
|
||||
{this.state.fullscreen && <img className={styles.logo} src={getTrustedUrl('static/mailtrain-notext.png')}/>}
|
||||
<div className={styles.title}>{this.props.title}</div>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="window-maximize"/></a>
|
||||
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
|
||||
<a className={styles.btn} onClick={::this.togglePreviewAsync}><Icon icon={this.state.preview ? 'eye-close': 'eye-open'}/></a>
|
||||
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
|
||||
|
|
|
@ -70,7 +70,7 @@ export class GrapesJSHost extends Component {
|
|||
<div className={styles.navbar}>
|
||||
{this.state.fullscreen && <img className={styles.logo} src={getTrustedUrl('static/mailtrain-notext.png')}/>}
|
||||
<div className={styles.title}>{this.props.title}</div>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="window-maximize"/></a>
|
||||
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
|
||||
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
|
||||
</div>
|
||||
|
|
|
@ -73,7 +73,7 @@ export class MosaicoHost extends Component {
|
|||
<div className={styles.navbar}>
|
||||
{this.state.fullscreen && <img className={styles.logo} src={getTrustedUrl('static/mailtrain-notext.png')}/>}
|
||||
<div className={styles.title}>{this.props.title}</div>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="fullscreen"/></a>
|
||||
<a className={styles.btn} onClick={::this.toggleFullscreenAsync}><Icon icon="window-maximize"/></a>
|
||||
<a className={styles.btn} onClick={this.props.onTestSend}><Icon icon="send"/></a>
|
||||
{this.props.canSave ? <a className={styles.btn} onClick={this.props.onSave}><Icon icon="floppy-disk"/></a> : <span className={styles.btnDisabled}><Icon icon="floppy-disk"/></span>}
|
||||
</div>
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
table.dataTable tbody > tr.selected {
|
||||
background-color: rgb(218, 231, 255);
|
||||
}
|
||||
|
||||
table.table-hover.dataTable tbody > tr.selected {
|
||||
background-color: rgb(205, 212, 226);
|
||||
}
|
||||
|
||||
table.table-hover.dataTable tbody {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper .form-control {
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper .table-bordered {
|
||||
border-radius: 3px;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
.has-error div.dataTables_wrapper .table-bordered {
|
||||
border-color: #b94a48;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
div.dataTables_wrapper div.dataTable_selection_info {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,8 +11,8 @@ import jQuery
|
|||
from 'jquery';
|
||||
|
||||
import 'datatables.net';
|
||||
import 'datatables.net-bs';
|
||||
import 'datatables.net-bs/css/dataTables.bootstrap.css';
|
||||
import 'datatables.net-bs4';
|
||||
import 'datatables.net-bs4/css/dataTables.bootstrap4.css';
|
||||
|
||||
import axios
|
||||
from './axios';
|
||||
|
|
|
@ -12,7 +12,7 @@ import jQuery
|
|||
import '../../vendor/jquery/jquery-ui-1.12.1.min.js';
|
||||
import '../../vendor/fancytree/jquery.fancytree-all.min.js';
|
||||
import '../../vendor/fancytree/skin-bootstrap/ui.fancytree.min.css';
|
||||
import './tree.css';
|
||||
import './tree.scss';
|
||||
import axios
|
||||
from './axios';
|
||||
|
||||
|
@ -91,7 +91,8 @@ class TreeTable extends Component {
|
|||
withHeader: PropTypes.bool,
|
||||
withDescription: PropTypes.bool,
|
||||
noTable: PropTypes.bool,
|
||||
withIcons: PropTypes.bool
|
||||
withIcons: PropTypes.bool,
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
@ -106,7 +107,7 @@ class TreeTable extends Component {
|
|||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return this.props.selection !== nextProps.selection || this.state.treeData != nextState.treeData;
|
||||
return this.props.selection !== nextProps.selection || this.state.treeData != nextState.treeData || this.props.className !== nextProps.className;
|
||||
}
|
||||
|
||||
// XSS protection
|
||||
|
@ -183,17 +184,16 @@ class TreeTable extends Component {
|
|||
extensions: ['glyph'],
|
||||
glyph: {
|
||||
map: {
|
||||
expanderClosed: 'glyphicon glyphicon-menu-right',
|
||||
expanderLazy: 'glyphicon glyphicon-menu-right', // glyphicon-plus-sign
|
||||
expanderOpen: 'glyphicon glyphicon-menu-down', // glyphicon-collapse-down
|
||||
checkbox: 'glyphicon glyphicon-unchecked',
|
||||
checkboxSelected: 'glyphicon glyphicon-check',
|
||||
checkboxUnknown: 'glyphicon glyphicon-share',
|
||||
expanderClosed: 'fas fa-angle-right',
|
||||
expanderLazy: 'fas fa-angle-right', // glyphicon-plus-sign
|
||||
expanderOpen: 'fas fa-angle-down', // glyphicon-collapse-down
|
||||
checkbox: 'fas fa-square',
|
||||
checkboxSelected: 'fas fa-check-square',
|
||||
|
||||
folder: 'glyphicon glyphicon-folder-close',
|
||||
folderOpen: 'glyphicon glyphicon-folder-open',
|
||||
doc: 'glyphicon glyphicon-file',
|
||||
docOpen: 'glyphicon glyphicon-file'
|
||||
folder: 'fas fa-folder',
|
||||
folderOpen: 'fas fa-folder-open',
|
||||
doc: 'fas fa-file',
|
||||
docOpen: 'fas fa-file'
|
||||
}
|
||||
},
|
||||
selectMode: (this.selectMode === TreeSelectMode.MULTI ? 2 : 1),
|
||||
|
@ -220,9 +220,14 @@ class TreeTable extends Component {
|
|||
this.updateSelection();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.tree.reload(this.sanitizeTreeData(this.state.treeData));
|
||||
this.updateSelection();
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.props.selection !== prevProps.selection || this.state.treeData != prevState.treeData) {
|
||||
if (this.state.treeData != prevState.treeData) {
|
||||
this.tree.reload(this.sanitizeTreeData(this.state.treeData));
|
||||
}
|
||||
|
||||
this.updateSelection();
|
||||
}
|
||||
}
|
||||
|
||||
updateSelection() {
|
||||
|
@ -303,7 +308,7 @@ class TreeTable extends Component {
|
|||
const withHeader = props.withHeader;
|
||||
const withDescription = props.withDescription;
|
||||
|
||||
let containerClass = 'mt-treetable-container';
|
||||
let containerClass = 'mt-treetable-container ' + (this.props.className || '');
|
||||
if (this.selectMode === TreeSelectMode.NONE) {
|
||||
containerClass += ' mt-treetable-inactivable';
|
||||
} else {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
@import "../../static/scss/variables.scss";
|
||||
|
||||
:global {
|
||||
|
||||
.mt-treetable-container .fancytree-container {
|
||||
border: none;
|
||||
}
|
||||
|
@ -56,8 +60,11 @@
|
|||
|
||||
|
||||
.form-group .mt-treetable-container {
|
||||
border: 1px solid #cccccc;
|
||||
border-radius: 4px;
|
||||
border: $input-border-width solid $input-border-color;
|
||||
border-radius: $input-border-radius;
|
||||
padding-top: $input-padding-y;
|
||||
padding-bottom: $input-padding-y;
|
||||
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
|
||||
|
@ -65,15 +72,21 @@
|
|||
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
.form-group.has-success .mt-treetable-container {
|
||||
border-color: #468847;
|
||||
.form-group .mt-treetable-container.is-valid {
|
||||
border-color: $form-feedback-valid-color;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
}
|
||||
|
||||
.form-group.has-error .mt-treetable-container {
|
||||
border-color: #b94a48;
|
||||
.form-group .mt-treetable-container.is-invalid {
|
||||
border-color: $form-feedback-invalid-color;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
}
|
||||
|
||||
.mt-treetable-container .table td {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
}
|
|
@ -239,7 +239,7 @@ export default class CUD extends Component {
|
|||
<CheckBox id="listunsubscribe_disabled" label={t('unsubscribeHeader')} text={t('doNotSendListUnsubscribeHeaders')}/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{canDelete && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/lists/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -108,14 +108,14 @@ export default class List extends Component {
|
|||
|
||||
if (perms.includes('viewSegments')) {
|
||||
actions.push({
|
||||
label: <Icon icon="tag" title={t('segments')}/>,
|
||||
label: <Icon icon="tags" title={t('segments')}/>,
|
||||
link: `/lists/${data[0]}/segments`
|
||||
});
|
||||
}
|
||||
|
||||
if (perms.includes('viewImports')) {
|
||||
actions.push({
|
||||
label: <Icon icon="sort" title={t('imports')}/>,
|
||||
label: <Icon icon="file-import" title={t('imports')}/>,
|
||||
link: `/lists/${data[0]}/imports`
|
||||
});
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ export default class List extends Component {
|
|||
|
||||
if (perms.includes('share')) {
|
||||
actions.push({
|
||||
label: <Icon icon="share-alt" title={t('share')}/>,
|
||||
label: <Icon icon="share" title={t('share')}/>,
|
||||
link: `/lists/${data[0]}/share`
|
||||
});
|
||||
}
|
||||
|
|
|
@ -480,7 +480,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{isEdit && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/lists/${this.props.list.id}/fields/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -506,8 +506,8 @@ export default class CUD extends Component {
|
|||
<div className={formsStyles.navbar}>
|
||||
{this.state.fullscreen && <img className={formsStyles.logo} src={getTrustedUrl('static/mailtrain-notext.png')}/>}
|
||||
<div className={formsStyles.title}>{t('formPreview') + ' ' + this.state.previewLabel}</div>
|
||||
<a className={formsStyles.btn} onClick={() => this.setState({previewContents: null, previewFullscreen: false})}><Icon icon="remove"/></a>
|
||||
<a className={formsStyles.btn} onClick={() => this.setState({previewFullscreen: !this.state.previewFullscreen})}><Icon icon="fullscreen"/></a>
|
||||
<a className={formsStyles.btn} onClick={() => this.setState({previewContents: null, previewFullscreen: false})}><Icon icon="window-close"/></a>
|
||||
<a className={formsStyles.btn} onClick={() => this.setState({previewFullscreen: !this.state.previewFullscreen})}><Icon icon="window-maximize"/></a>
|
||||
</div>
|
||||
<iframe className={formsStyles.host} src={"data:text/html;charset=utf-8," + encodeURIComponent(this.state.previewContents)}></iframe>
|
||||
</div>
|
||||
|
@ -524,7 +524,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{canDelete && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/lists/forms/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -413,10 +413,10 @@ export default class CUD extends Component {
|
|||
|
||||
const saveButtons = []
|
||||
if (!isEdit) {
|
||||
saveButtons.push(<Button key="default" type="submit" className="btn-primary" icon="ok" label={t('saveAndEditSettings')}/>);
|
||||
saveButtons.push(<Button key="default" type="submit" className="btn-primary" icon="check" label={t('saveAndEditSettings')}/>);
|
||||
} else {
|
||||
saveButtons.push(<Button key="default" type="submit" className="btn-primary" icon="ok" label={t('save')}/>);
|
||||
saveButtons.push(<Button key="saveAndRun" className="btn-primary" icon="ok" label={t('saveAndRun')} onClickAsync={async () => await this.save(true)}/>);
|
||||
saveButtons.push(<Button key="default" type="submit" className="btn-primary" icon="check" label={t('save')}/>);
|
||||
saveButtons.push(<Button key="saveAndRun" className="btn-primary" icon="check" label={t('saveAndRun')} onClickAsync={async () => await this.save(true)}/>);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -354,14 +354,14 @@ export default class CUD extends Component {
|
|||
<Form stateOwner={this} onSubmitAsync={::this.submitAndLeave}>
|
||||
{isEdit ?
|
||||
<ButtonRow format="wide" className={`col-xs-12 ${styles.toolbar}`}>
|
||||
<FormButton type="submit" className="btn-primary" icon="ok" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/>
|
||||
<FormButton type="submit" className="btn-primary" icon="ok" label={t('saveAndLeave')}/>
|
||||
<FormButton type="submit" className="btn-primary" icon="check" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/>
|
||||
<FormButton type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')}/>
|
||||
|
||||
<NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/lists/${this.props.list.id}/segments/${this.props.entity.id}/delete`}/>
|
||||
</ButtonRow>
|
||||
:
|
||||
<ButtonRow format="wide" className={`col-xs-12 ${styles.toolbar}`}>
|
||||
<FormButton type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<FormButton type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
</ButtonRow>
|
||||
}
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ export default class CUD extends Component {
|
|||
</AlignedRow>
|
||||
}
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{isEdit && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/lists/${this.props.list.id}/subscriptions/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -183,7 +183,7 @@ export default class List extends Component {
|
|||
<div>
|
||||
{tableRestActionDialogRender(this)}
|
||||
<Toolbar>
|
||||
<a href={getPublicUrl(`subscription/${this.props.list.cid}`, {withLocale: true})}><Button label={t('subscriptionForm')} className="btn-default"/></a>
|
||||
<a href={getPublicUrl(`subscription/${this.props.list.cid}`, {withLocale: true})}><Button label={t('subscriptionForm')} className="btn-secondary"/></a>
|
||||
<a href={getUrl(`subscriptions/export/${this.props.list.id}/`+ (this.props.segmentId || 0))}><Button label={t('exportAsCsv')} className="btn-primary"/></a>
|
||||
<NavButton linkTo={`/lists/${this.props.list.id}/subscriptions/create`} className="btn-primary" icon="plus" label={t('addSubscriber')}/>
|
||||
</Toolbar>
|
||||
|
|
|
@ -205,7 +205,7 @@ export default class CUD extends Component {
|
|||
<TreeTableSelect id="namespace" label={t('parentNamespace')} data={this.state.treeData}/>}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{canDelete && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/namespaces/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
|
@ -274,7 +274,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{canDelete &&
|
||||
<NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/reports/${this.props.entity.id}/delete`}/>
|
||||
}
|
||||
|
|
|
@ -332,15 +332,15 @@ export default class CUD extends Component {
|
|||
|
||||
{isEdit ?
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('saveAndLeave')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')}/>
|
||||
{canDelete &&
|
||||
<NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/reports/templates/${this.props.entity.id}/delete`}/>
|
||||
}
|
||||
</ButtonRow>
|
||||
:
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
</ButtonRow>
|
||||
}
|
||||
</Form>
|
||||
|
|
|
@ -29,7 +29,9 @@ import settings
|
|||
from './settings/root';
|
||||
|
||||
import {
|
||||
MenuLink,
|
||||
NavDropdown,
|
||||
NavDropdownLink,
|
||||
NavLink,
|
||||
Section
|
||||
} from "./lib/page";
|
||||
|
||||
|
@ -39,7 +41,6 @@ import Home
|
|||
from "./Home";
|
||||
import {
|
||||
ActionLink,
|
||||
DropdownMenuItem,
|
||||
Icon
|
||||
} from "./lib/bootstrap-components";
|
||||
import {Link} from "react-router-dom";
|
||||
|
@ -88,7 +89,7 @@ class Root extends Component {
|
|||
const label = langDesc.getLabel(t);
|
||||
|
||||
languageOptions.push(
|
||||
<li key={lng}><ActionLink onClickAsync={() => i18n.changeLanguage(langDesc.longCode)}>{label}</ActionLink></li>
|
||||
<ActionLink key={lng} className="dropdown-item" onClickAsync={() => i18n.changeLanguage(langDesc.longCode)}>{label}</ActionLink>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -105,63 +106,55 @@ class Root extends Component {
|
|||
const link = entry.link || entry.externalLink;
|
||||
|
||||
if (link && path.startsWith(link)) {
|
||||
topLevelMenu.push(<MenuLink key={entryKey} className="active" to={link}>{entry.title} <span className="sr-only">{t('current')}</span></MenuLink>);
|
||||
topLevelMenu.push(<NavLink key={entryKey} className="active" to={link}>{entry.title} <span className="sr-only">{t('current')}</span></NavLink>);
|
||||
} else {
|
||||
topLevelMenu.push(<MenuLink key={entryKey} to={link}>{entry.title}</MenuLink>);
|
||||
topLevelMenu.push(<NavLink key={entryKey} to={link}>{entry.title}</NavLink>);
|
||||
}
|
||||
}
|
||||
|
||||
const languageChooser = (
|
||||
<NavDropdown menuClassName="dropdown-menu-right" label={currentLngCode}>
|
||||
{languageOptions}
|
||||
</NavDropdown>
|
||||
);
|
||||
|
||||
return (
|
||||
<nav className="navbar navbar-default navbar-static-top">
|
||||
<div className="container-fluid">
|
||||
<div className="navbar-header">
|
||||
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
||||
<span className="sr-only">{t('toggleNavigation')}</span>
|
||||
<span className="icon-bar"></span>
|
||||
<span className="icon-bar"></span>
|
||||
<span className="icon-bar"></span>
|
||||
</button>
|
||||
<Link className="navbar-brand" to="/"><Icon icon="envelope"/> Mailtrain</Link>
|
||||
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<Link className="navbar-brand" to="/"><Icon icon="envelope"/> Mailtrain</Link>
|
||||
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#mtMainNavbar" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
{mailtrainConfig.isAuthenticated ?
|
||||
<div className="collapse navbar-collapse" id="mtMainNavbar">
|
||||
<ul className="navbar-nav mr-auto">
|
||||
{topLevelMenu}
|
||||
<NavDropdown label={t('administration')}>
|
||||
<NavDropdownLink to="/users">{t('users')}</NavDropdownLink>
|
||||
<NavDropdownLink to="/namespaces">{t('namespaces')}</NavDropdownLink>
|
||||
{mailtrainConfig.globalPermissions.manageSettings && <NavDropdownLink to="/settings">{t('globalSettings')}</NavDropdownLink>}
|
||||
<NavDropdownLink to="/send-configurations">{t('sendConfigurations')}</NavDropdownLink>
|
||||
{mailtrainConfig.globalPermissions.manageBlacklist && <NavDropdownLink to="/blacklist">{t('blacklist')}</NavDropdownLink>}
|
||||
<NavDropdownLink to="/account/api">{t('api')}</NavDropdownLink>
|
||||
</NavDropdown>
|
||||
</ul>
|
||||
<ul className="navbar-nav">
|
||||
{languageChooser}
|
||||
<NavDropdown menuClassName="dropdown-menu-right" label={mailtrainConfig.user.username} icon="user">
|
||||
<NavDropdownLink to="/account"><Icon icon='user'/> {t('account')}</NavDropdownLink>
|
||||
<ActionLink className="dropdown-item" onClickAsync={::this.logout}><Icon icon='sign-out-alt'/> {t('logOut')}</ActionLink>
|
||||
</NavDropdown>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{mailtrainConfig.isAuthenticated ?
|
||||
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul className="nav navbar-nav">
|
||||
{topLevelMenu}
|
||||
<DropdownMenuItem label={t('administration')}>
|
||||
<MenuLink to="/users"><Icon icon='cog'/> {t('users')}</MenuLink>
|
||||
<MenuLink to="/namespaces"><Icon icon='cog'/> {t('namespaces')}</MenuLink>
|
||||
{mailtrainConfig.globalPermissions.manageSettings && <MenuLink to="/settings"><Icon icon='cog'/> {t('globalSettings')}</MenuLink>}
|
||||
<MenuLink to="/send-configurations"><Icon icon='cog'/> {t('sendConfigurations')}</MenuLink>
|
||||
{mailtrainConfig.globalPermissions.manageBlacklist && <MenuLink to="/blacklist"><Icon icon='ban-circle'/> {t('blacklist')}</MenuLink>}
|
||||
<MenuLink to="/account/api"><Icon icon='retweet'/> {t('api')}</MenuLink>
|
||||
</DropdownMenuItem>
|
||||
</ul>
|
||||
|
||||
|
||||
<ul className="nav navbar-nav navbar-right">
|
||||
<DropdownMenuItem label={currentLngCode}>
|
||||
{languageOptions}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem label={mailtrainConfig.user.username} icon="user">
|
||||
<MenuLink to="/account"><Icon icon='user'/> {t('account')}</MenuLink>
|
||||
<li>
|
||||
<ActionLink onClickAsync={::this.logout}><Icon icon='log-out'/> {t('logOut')}</ActionLink>
|
||||
</li>
|
||||
</DropdownMenuItem>
|
||||
</ul>
|
||||
</div>
|
||||
:
|
||||
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul className="nav navbar-nav navbar-right">
|
||||
<DropdownMenuItem label={currentLngCode}>
|
||||
{languageOptions}
|
||||
</DropdownMenuItem>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
:
|
||||
<div className="collapse navbar-collapse" id="mtMainNavbar">
|
||||
<ul className="navbar-nav mr-auto">
|
||||
</ul>
|
||||
<ul className="navbar-nav">
|
||||
{languageChooser}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ export default class CUD extends Component {
|
|||
<hr/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{canDelete &&
|
||||
<NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/send-configurations/${this.props.entity.id}/delete`}/>
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ export default class Update extends Component {
|
|||
|
||||
<hr/>
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
|
@ -168,7 +168,7 @@ export default class Share extends Component {
|
|||
<TableSelect id="role" label={t('role')} withHeader dropdown dataUrl={`rest/shares-roles-table/${this.props.entityTypeId}`} columns={rolesColumns} selectionLabelIndex={1}/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('share')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('share')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ export default class CUD extends Component {
|
|||
{editForm}
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={isEdit ? t('save') : t('saveAndEditTemplate')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={isEdit ? t('save') : t('saveAndEditTemplate')}/>
|
||||
{canDelete && <NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/templates/${this.props.entity.id}/delete`}/> }
|
||||
{isEdit && <Button className="btn-danger" icon="send" label={t('testSend')} onClickAsync={async () => this.setState({showTestSendModal: true})}/> }
|
||||
</ButtonRow>
|
||||
|
|
|
@ -451,7 +451,7 @@ export function getEditForm(owner, typeKey, prefix = '') {
|
|||
<div>
|
||||
<AlignedRow>
|
||||
<Button
|
||||
className="btn-default"
|
||||
className="btn-secondary"
|
||||
onClickAsync={::owner.toggleMergeTagReference}
|
||||
label={t('mergeTagReference')}/>
|
||||
{owner.state.showMergeTagReference &&
|
||||
|
|
|
@ -193,15 +193,15 @@ export default class CUD extends Component {
|
|||
|
||||
{isEdit ?
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('saveAndLeave')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')}/>
|
||||
{canDelete &&
|
||||
<NavButton className="btn-danger" icon="remove" label={t('delete')} linkTo={`/templates/mosaico/${this.props.entity.id}/delete`}/>
|
||||
}
|
||||
</ButtonRow>
|
||||
:
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
</ButtonRow>
|
||||
}
|
||||
</Form>
|
||||
|
|
|
@ -248,7 +248,7 @@ export default class CUD extends Component {
|
|||
<NamespaceSelect/>
|
||||
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
{canDelete && <NavButton className="btn-danger" icon="remove" label={t('deleteUser')} linkTo={`/users/${this.props.entity.id}/delete`}/>}
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue