Alignments with IVIS

This commit is contained in:
Tomas Bures 2019-01-12 00:57:10 +01:00
parent c1731bf09f
commit ab6c6b7d27
45 changed files with 476 additions and 263 deletions

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -738,7 +738,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={saveButtonLabel}/>
{canDelete && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/campaigns/${this.props.entity.id}/delete`}/> }
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/campaigns/${this.props.entity.id}/delete`}/> }
</ButtonRow>
</Form>
</div>

View file

@ -7,7 +7,7 @@ import {
Icon
} from '../lib/bootstrap-components';
import {
ButtonDropdownLink,
DropdownLink,
NavDropdown,
requiresAuthenticatedUser,
Title,
@ -175,9 +175,9 @@ export default class List extends Component {
<Toolbar>
{this.state.createPermitted &&
<ButtonDropdown buttonClassName="btn-primary" menuClassName="dropdown-menu-right" label={t('createCampaign')}>
<ButtonDropdownLink to="/campaigns/create-regular">{t('regular')}</ButtonDropdownLink>
<ButtonDropdownLink to="/campaigns/create-rss">{t('rss')}</ButtonDropdownLink>
<ButtonDropdownLink to="/campaigns/create-triggered">{t('triggered')}</ButtonDropdownLink>
<DropdownLink to="/campaigns/create-regular">{t('regular')}</DropdownLink>
<DropdownLink to="/campaigns/create-rss">{t('rss')}</DropdownLink>
<DropdownLink to="/campaigns/create-triggered">{t('triggered')}</DropdownLink>
</ButtonDropdown>
}
</Toolbar>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -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-secondary" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>}
{entity.status === CampaignStatus.PAUSED && <LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/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-secondary" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>
<LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/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-secondary" icon="signal" label={t('viewStatistics')} linkTo={`/campaigns/${entity.id}/statistics`}/>
<LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/campaigns/${entity.id}/statistics`}/>
</ButtonRow>
</div>
);

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -236,7 +236,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{isEdit && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/campaigns/${this.props.campaign.id}/triggers/${this.props.entity.id}/delete`}/>}
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/campaigns/${this.props.campaign.id}/triggers/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -84,7 +84,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{mailtrainConfig.globalPermissions.setupAutomation && this.props.campaign.permissions.includes('manageTriggers') &&
<Toolbar>
<NavButton linkTo={`/campaigns/${this.props.campaign.id}/triggers/create`} className="btn-primary" icon="plus" label={t('createTrigger')}/>
<LinkButton to={`/campaigns/${this.props.campaign.id}/triggers/create`} className="btn-primary" icon="plus" label={t('createTrigger')}/>
</Toolbar>
}

View file

@ -14,7 +14,7 @@ import {withComponentMixins} from "./decorator-helpers";
withTranslation,
withErrorHandling
])
class DismissibleAlert extends Component {
export class DismissibleAlert extends Component {
static propTypes = {
severity: PropTypes.string.isRequired,
onCloseAsync: PropTypes.func
@ -39,7 +39,7 @@ class DismissibleAlert extends Component {
}
}
class Icon extends Component {
export class Icon extends Component {
static propTypes = {
icon: PropTypes.string.isRequired,
family: PropTypes.string,
@ -66,7 +66,7 @@ class Icon extends Component {
@withComponentMixins([
withErrorHandling
])
class Button extends Component {
export class Button extends Component {
static propTypes = {
onClickAsync: PropTypes.func,
label: PropTypes.string,
@ -111,7 +111,7 @@ class Button extends Component {
}
}
class ButtonDropdown extends Component {
export class ButtonDropdown extends Component {
static propTypes = {
label: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
className: PropTypes.string,
@ -143,7 +143,7 @@ class ButtonDropdown extends Component {
@withComponentMixins([
withErrorHandling
])
class ActionLink extends Component {
export class ActionLink extends Component {
static propTypes = {
onClickAsync: PropTypes.func,
className: PropTypes.string
@ -169,7 +169,7 @@ class ActionLink extends Component {
}
class ButtonDropdownActionLink extends Component {
export class DropdownActionLink extends Component {
static propTypes = {
onClickAsync: PropTypes.func,
className: PropTypes.string,
@ -193,11 +193,31 @@ class ButtonDropdownActionLink extends Component {
}
export class DropdownDivider extends Component {
static propTypes = {
className: PropTypes.string
}
render() {
const props = this.props;
let className = 'dropdown-divider';
if (props.className) {
className = className + ' ' + props.className;
}
return (
<div className={className}/>
);
}
}
@withComponentMixins([
withTranslation,
withErrorHandling
])
class ModalDialog extends Component {
export class ModalDialog extends Component {
constructor(props) {
super(props);
@ -307,14 +327,3 @@ class ModalDialog extends Component {
}
}
export {
Button,
ButtonDropdown,
ActionLink,
ButtonDropdownActionLink,
DismissibleAlert,
ModalDialog,
Icon
};

View file

@ -27,6 +27,29 @@ export function withComponentMixins(mixins, delegateFuns) {
}
return TargetClass => {
const ctors = [];
function TargetClassWithCtors(props, context) {
if (!new.target) {
throw new TypeError();
}
const self = Reflect.construct(TargetClass, [props, context], new.target);
for (const ctor of ctors) {
ctor(self);
}
return self;
}
TargetClassWithCtors.prototype = TargetClass.prototype;
for (const attr in TargetClass) {
TargetClassWithCtors[attr] = TargetClass[attr];
}
class ComponentMixinsInner extends React.Component {
render() {
const props = {
@ -36,7 +59,7 @@ export function withComponentMixins(mixins, delegateFuns) {
delete props._decoratorInnerInstanceRefFn;
return (
<TargetClass {...props}/>
<TargetClassWithCtors {...props}/>
);
}
}
@ -44,7 +67,15 @@ export function withComponentMixins(mixins, delegateFuns) {
let DecoratedInner = ComponentMixinsInner;
for (const mixin of mixinsClosure.values()) {
DecoratedInner = mixin.decoratorFn(DecoratedInner, TargetClass);
const res = mixin.decoratorFn(DecoratedInner, TargetClassWithCtors);
if (res.cls) {
DecoratedInner = res.cls;
}
if (res.ctor) {
ctors.push(res.ctor);
}
}
class ComponentMixinsOuter extends React.Component {

View file

@ -48,7 +48,7 @@ export const withErrorHandling = createComponentMixin([{context: ParentErrorHand
handleError(this, error);
};
return TargetClass;
return {};
});
export function withAsyncErrorHandler(target, name, descriptor) {

View file

@ -74,7 +74,7 @@ const withFormStateOwner = createComponentMixin([{context: FormStateOwnerContext
return this.props.formStateOwner;
}
return TargetClass;
return {};
});
@ -1395,7 +1395,7 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
}
};
return TargetClass;
return {};
});

View file

@ -62,7 +62,9 @@ export default i18n;
export const withTranslation = createComponentMixin([], [], (TargetClass, InnerClass) => {
return withNamespaces()(TargetClass)
return {
cls: withNamespaces()(TargetClass)
}
});
export function tMark(key) {

View file

@ -139,5 +139,5 @@ export const withPageHelpers = createComponentMixin([{context: SectionContentCon
return this.props.sectionContent.navigateToWithFlashMessage(path, severity, text);
}
return TargetClass;
return {};
});

View file

@ -1,7 +1,7 @@
'use strict';
import React, {Component} from "react";
import {withTranslation} from './i18n';
import i18n, {withTranslation} from './i18n';
import PropTypes
from "prop-types";
import {withRouter} from "react-router";
@ -19,8 +19,10 @@ import {
import interoperableErrors
from "../../../shared/interoperable-errors";
import {
ActionLink,
Button,
DismissibleAlert,
DropdownActionLink,
Icon
} from "./bootstrap-components";
import mailtrainConfig
@ -39,6 +41,7 @@ import {
createComponentMixin,
withComponentMixins
} from "./decorator-helpers";
import {getLang} from "../../../shared/langs";
export { withPageHelpers }
@ -98,7 +101,7 @@ class Breadcrumb extends Component {
}
}
class SecondaryNavBar extends Component {
class TertiaryNavBar extends Component {
static propTypes = {
route: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
@ -167,7 +170,7 @@ class SecondaryNavBar extends Component {
}
if (renderedElems.length > 1) {
let className = styles.secondaryNav + ' nav nav-pills';
let className = styles.tertiaryNav + ' nav nav-pills';
if (this.props.className) {
className += ' ' + this.props.className;
}
@ -191,6 +194,12 @@ class RouteContent extends Component {
if (Object.keys(props.route.resolve).length === 0) {
this.state.resolved = {};
}
this.sidebarAnimationNodeListener = evt => {
if (evt.propertyName === 'left') {
this.forceUpdate();
}
};
}
static propTypes = {
@ -220,12 +229,20 @@ class RouteContent extends Component {
}
}
registerSidebarAnimationListener() {
if (this.sidebarAnimationNode) {
this.sidebarAnimationNode.addEventListener("transitionend", this.sidebarAnimationNodeListener);
}
}
componentDidMount() {
// noinspection JSIgnoredPromiseFromCall
this.resolve(this.props);
this.registerSidebarAnimationListener();
}
componentDidUpdate() {
this.registerSidebarAnimationListener();
}
componentWillReceiveProps(nextProps) {
@ -245,6 +262,8 @@ class RouteContent extends Component {
const params = this.props.match.params;
const resolved = this.state.resolved;
const showSidebar = !!route.secondaryMenuComponent;
if (!route.panelRender && !route.panelComponent && route.link) {
let link;
if (typeof route.link === 'function') {
@ -256,12 +275,8 @@ class RouteContent extends Component {
return <Redirect to={link}/>;
} else {
const primaryMenuProps = {
location: this.props.location
};
const primaryMenuComponent = React.createElement(route.primaryMenuComponent, primaryMenuProps);
let primaryMenu = null;
let secondaryMenu = null;
let content = null;
if (resolved) {
@ -278,11 +293,19 @@ class RouteContent extends Component {
panel = route.panelRender(compProps);
}
if (route.primaryMenuComponent) {
primaryMenu = React.createElement(route.primaryMenuComponent, compProps);
}
if (route.secondaryMenuComponent) {
secondaryMenu = React.createElement(route.secondaryMenuComponent, compProps);
}
content = (
<>
<div className={styles.breadcrumbAndSecondaryNavbar}>
<div className="mt-breadcrumb-and-tertiary-navbar">
<Breadcrumb route={route} params={params} resolved={resolved}/>
<SecondaryNavBar route={route} params={params} resolved={resolved}/>
<TertiaryNavBar route={route} params={params} resolved={resolved}/>
</div>
<div className="container-fluid">
@ -291,6 +314,7 @@ class RouteContent extends Component {
</div>
</>
);
} else {
content = (
<div className="container-fluid">
@ -299,13 +323,35 @@ class RouteContent extends Component {
);
}
return (
<div className="app">
<div className={"app " + (showSidebar ? 'sidebar-lg-show' : '')}>
<header className="app-header">
{primaryMenuComponent}
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
{showSidebar &&
<button className="navbar-toggler sidebar-toggler" data-toggle="sidebar-show" type="button">
<span className="navbar-toggler-icon"/>
</button>
}
<Link className="navbar-brand" to="/"><div><Icon icon="envelope"/> Mailtrain</div></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"/>
</button>
<div className="collapse navbar-collapse" id="mtMainNavbar">
{primaryMenu}
</div>
</nav>
</header>
<div className="app-body">
{showSidebar &&
<div className="sidebar">
{secondaryMenu}
</div>
}
<main className="main">
{content}
</main>
@ -330,6 +376,7 @@ export class SectionContent extends Component {
super(props);
this.state = {
flashMessageText: ''
};
this.historyUnlisten = props.history.listen((location, action) => {
@ -457,7 +504,7 @@ export class Toolbar extends Component {
};
render() {
let className = 'float-right ' + styles.buttonRow;
let className = styles.toolbar + ' ' + styles.buttonRow;
if (this.props.className) {
className += ' ' + this.props.className;
}
@ -470,24 +517,24 @@ export class Toolbar extends Component {
}
}
export class NavButton extends Component {
export class LinkButton extends Component {
static propTypes = {
label: PropTypes.string,
icon: PropTypes.string,
className: PropTypes.string,
linkTo: PropTypes.string
to: PropTypes.string
};
render() {
const props = this.props;
return (
<Link to={props.linkTo}><Button label={props.label} icon={props.icon} className={props.className}/></Link>
<Link to={props.to}><Button label={props.label} icon={props.icon} className={props.className}/></Link>
);
}
}
export class ButtonDropdownLink extends Component {
export class DropdownLink extends Component {
static propTypes = {
to: PropTypes.string,
className: PropTypes.string
@ -506,6 +553,8 @@ export class ButtonDropdownLink extends Component {
export class NavLink extends Component {
static propTypes = {
to: PropTypes.string,
icon: PropTypes.string,
iconFamily: PropTypes.string,
className: PropTypes.string
}
@ -513,8 +562,38 @@ export class NavLink extends Component {
const props = this.props;
const clsName = "nav-item" + (props.className ? " " + props.className : "")
let icon;
if (props.icon) {
icon = <><Icon icon={props.icon} family={props.iconFamily}/>{' '}</>;
}
return (
<li className={clsName}><Link to={props.to} className="nav-link">{props.children}</Link></li>
<li className={clsName}><Link to={props.to} className="nav-link">{icon}{props.children}</Link></li>
);
}
}
export class NavActionLink extends Component {
static propTypes = {
onClickAsync: PropTypes.func,
icon: PropTypes.string,
iconFamily: PropTypes.string,
className: PropTypes.string
}
render() {
const props = this.props;
const clsName = "nav-item" + (props.className ? " " + props.className : "")
let icon;
if (props.icon) {
icon = <><Icon icon={props.icon} family={props.iconFamily}/>{' '}</>;
}
return (
<li className={clsName}><ActionLink onClickAsync={this.props.onClickAsync} className="nav-link">{icon}{props.children}</ActionLink></li>
);
}
}
@ -552,21 +631,6 @@ export class NavDropdown extends Component {
}
}
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 {
@ -580,5 +644,29 @@ export const requiresAuthenticatedUser = createComponentMixin([], [withPageHelpe
}
}
return RequiresAuthenticatedUser;
return {
cls: RequiresAuthenticatedUser
};
});
export function getLanguageChooser(t) {
const languageOptions = [];
for (const lng of mailtrainConfig.enabledLanguages) {
const langDesc = getLang(lng);
const label = langDesc.getLabel(t);
languageOptions.push(
<DropdownActionLink key={lng} onClickAsync={() => i18n.changeLanguage(langDesc.longCode)}>{label}</DropdownActionLink>
)
}
const currentLngCode = getLang(i18n.language).getShortLabel(t);
const languageChooser = (
<NavDropdown menuClassName="dropdown-menu-right" label={currentLngCode}>
{languageOptions}
</NavDropdown>
);
return languageChooser;
}

View file

@ -1,5 +1,9 @@
@import "../scss/variables.scss";
.toolbar {
float: right;
}
.form { // This is here to give the styles below higher priority than Bootstrap has
:global .DayPicker {
border: $input-border-width solid $input-border-color;
@ -84,32 +88,17 @@
margin-bottom: 20px;
}
.breadcrumbAndSecondaryNavbar {
/*
display: flex;
flex-wrap: wrap;
justify-content: space-between;
*/
:global .breadcrumb {
margin-bottom: 0px;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
margin-bottom: 1.5rem;
.secondaryNav {
.tertiaryNav {
justify-content: flex-end;
flex-grow: 1;
align-self: center;
margin-top: 0.5rem;
margin-left: 5px;
margin-right: 5px;
:global .nav-item .nav-link {
padding: 3px 10px;
}
}
}
.colorPickerWrapper {

View file

@ -6,7 +6,7 @@ import PropTypes
import {Trans} from 'react-i18next';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -271,7 +271,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{canDelete && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/lists/${this.props.entity.id}/delete`}/>}
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -3,7 +3,7 @@
import React, {Component} from 'react';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -146,8 +146,8 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/lists/create" className="btn-primary" icon="plus" label={t('createList')}/>
<NavButton linkTo="/lists/forms" className="btn-primary" label={t('customForms-1')}/>
<LinkButton to="/lists/create" className="btn-primary" icon="plus" label={t('createList')}/>
<LinkButton to="/lists/forms" className="btn-primary" label={t('customForms-1')}/>
</Toolbar>
}

View file

@ -6,7 +6,7 @@ import PropTypes
import {Trans} from 'react-i18next';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -509,7 +509,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{isEdit && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/lists/${this.props.list.id}/fields/${this.props.entity.id}/delete`}/>}
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/${this.props.list.id}/fields/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -78,7 +78,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{this.props.list.permissions.includes('manageFields') &&
<Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/fields/create`} className="btn-primary" icon="plus" label={t('createField')}/>
<LinkButton to={`/lists/${this.props.list.id}/fields/create`} className="btn-primary" icon="plus" label={t('createField')}/>
</Toolbar>
}

View file

@ -6,7 +6,7 @@ import PropTypes
import {Trans} from 'react-i18next';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -525,7 +525,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{canDelete && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/lists/forms/${this.props.entity.id}/delete`}/>}
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/forms/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -3,7 +3,7 @@
import React, {Component} from 'react';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -93,7 +93,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/lists/forms/create" className="btn-primary" icon="plus" label={t('createCustomForm')}/>
<LinkButton to="/lists/forms/create" className="btn-primary" icon="plus" label={t('createCustomForm')}/>
</Toolbar>
}

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -452,7 +452,7 @@ export default class CUD extends Component {
<ButtonRow>
{saveButtons}
{isEdit && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/lists/${this.props.list.id}/imports/${this.props.entity.id}/delete`}/>}
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/${this.props.list.id}/imports/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -98,7 +98,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{mailtrainConfig.globalPermissions.setupAutomation && this.props.list.permissions.includes('manageImports') &&
<Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/imports/create`} className="btn-primary" icon="plus" label={t('createImport')}/>
<LinkButton to={`/lists/${this.props.list.id}/imports/create`} className="btn-primary" icon="plus" label={t('createImport')}/>
</Toolbar>
}

View file

@ -5,7 +5,7 @@ import PropTypes
from "prop-types";
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -412,7 +412,7 @@ export default class CUD extends Component {
<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')} onClickAsync={::this.submitAndLeave}/>
<NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/lists/${this.props.list.id}/segments/${this.props.entity.id}/delete`}/>
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/${this.props.list.id}/segments/${this.props.entity.id}/delete`}/>
</ButtonRow>
:
<ButtonRow format="wide" className={`col-xs-12 ${styles.toolbar}`}>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -70,7 +70,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{this.props.list.permissions.includes('manageSegments') &&
<Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/segments/create`} className="btn-primary" icon="plus" label={t('createSegment')}/>
<LinkButton to={`/lists/${this.props.list.id}/segments/create`} className="btn-primary" icon="plus" label={t('createSegment')}/>
</Toolbar>
}

View file

@ -6,7 +6,7 @@ import PropTypes
import {HTTPMethod} from '../../lib/axios';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -223,7 +223,7 @@ export default class CUD extends Component {
}
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{isEdit && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/lists/${this.props.list.id}/subscriptions/${this.props.entity.id}/delete`}/>}
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/${this.props.list.id}/subscriptions/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -185,7 +185,7 @@ export default class List extends Component {
<Toolbar>
<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')}/>
<LinkButton to={`/lists/${this.props.list.id}/subscriptions/create`} className="btn-primary" icon="plus" label={t('addSubscriber')}/>
</Toolbar>
<Title>{t('subscribers')}</Title>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -206,7 +206,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{canDelete && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/namespaces/${this.props.entity.id}/delete`}/>}
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/namespaces/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -3,7 +3,7 @@
import React, {Component} from 'react';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -89,7 +89,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/namespaces/create" className="btn-primary" icon="plus" label={t('createNamespace')}/>
<LinkButton to="/namespaces/create" className="btn-primary" icon="plus" label={t('createNamespace')}/>
</Toolbar>
}

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -276,7 +276,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{canDelete &&
<NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/reports/${this.props.entity.id}/delete`}/>
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/reports/${this.props.entity.id}/delete`}/>
}
</ButtonRow>
</Form>

View file

@ -3,7 +3,7 @@
import React, {Component} from 'react';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -192,10 +192,10 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
<Toolbar>
{this.state.createPermitted &&
<NavButton linkTo="/reports/create" className="btn-primary" icon="plus" label={t('createReport')}/>
<LinkButton to="/reports/create" className="btn-primary" icon="plus" label={t('createReport')}/>
}
{this.state.templatesPermitted &&
<NavButton linkTo="/reports/templates" className="btn-primary" label={t('reportTemplates')}/>
<LinkButton to="/reports/templates" className="btn-primary" label={t('reportTemplates')}/>
}
</Toolbar>

View file

@ -6,7 +6,7 @@ import PropTypes
import {Trans} from 'react-i18next';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -335,7 +335,7 @@ export default class CUD extends Component {
<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="trash-alt" label={t('delete')} linkTo={`/reports/templates/${this.props.entity.id}/delete`}/>
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/reports/templates/${this.props.entity.id}/delete`}/>
}
</ButtonRow>
:

View file

@ -7,7 +7,7 @@ import {
Icon
} from '../../lib/bootstrap-components';
import {
ButtonDropdownLink,
DropdownLink,
NavDropdown,
requiresAuthenticatedUser,
Title,
@ -104,10 +104,10 @@ export default class List extends Component {
{this.state.createPermitted &&
<Toolbar>
<ButtonDropdown buttonClassName="btn-primary" menuClassName="dropdown-menu-right" label={t('createReportTemplate')}>
<ButtonDropdownLink to="/reports/templates/create">{t('blank')}</ButtonDropdownLink>
<ButtonDropdownLink to="/reports/templates/create/open-counts">{t('openCounts')}</ButtonDropdownLink>
<ButtonDropdownLink to="/reports/templates/create/open-counts-csv">{t('openCountsAsCsv')}</ButtonDropdownLink>
<ButtonDropdownLink to="/reports/templates/create/aggregated-open-counts">{t('aggregatedOpenCounts')}</ButtonDropdownLink>
<DropdownLink to="/reports/templates/create">{t('blank')}</DropdownLink>
<DropdownLink to="/reports/templates/create/open-counts">{t('openCounts')}</DropdownLink>
<DropdownLink to="/reports/templates/create/open-counts-csv">{t('openCountsAsCsv')}</DropdownLink>
<DropdownLink to="/reports/templates/create/aggregated-open-counts">{t('aggregatedOpenCounts')}</DropdownLink>
</ButtonDropdown>
</Toolbar>
}

View file

@ -31,8 +31,9 @@ import settings
from './settings/root';
import {
DropdownLink,
getLanguageChooser,
NavDropdown,
NavDropdownLink,
NavLink,
Section
} from "./lib/page";
@ -42,15 +43,13 @@ import mailtrainConfig
import Home
from "./Home";
import {
ActionLink,
ButtonDropdownActionLink,
DropdownActionLink,
Icon
} from "./lib/bootstrap-components";
import {Link} from "react-router-dom";
import axios
from './lib/axios';
import {getUrl} from "./lib/urls";
import {getLang} from "../../shared/langs";
import {withComponentMixins} from "./lib/decorator-helpers";
const topLevelMenuKeys = ['lists', 'templates', 'campaigns'];
@ -86,18 +85,6 @@ class Root extends Component {
}
render() {
const languageOptions = [];
for (const lng of mailtrainConfig.enabledLanguages) {
const langDesc = getLang(lng);
const label = langDesc.getLabel(t);
languageOptions.push(
<ButtonDropdownActionLink key={lng} onClickAsync={() => i18n.changeLanguage(langDesc.longCode)}>{label}</ButtonDropdownActionLink>
)
}
const currentLngCode = getLang(i18n.language).getShortLabel(t);
const path = this.props.location.pathname;
const topLevelItems = structure[""].children;
@ -115,53 +102,40 @@ class Root extends Component {
}
}
const languageChooser = (
<NavDropdown menuClassName="dropdown-menu-right" label={currentLngCode}>
{languageOptions}
</NavDropdown>
);
if (mailtrainConfig.isAuthenticated) {
return (
<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">
<>
<ul className="navbar-nav mt-navbar-nav-left">
{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>
<DropdownLink to="/users">{t('users')}</DropdownLink>
<DropdownLink to="/namespaces">{t('namespaces')}</DropdownLink>
{mailtrainConfig.globalPermissions.manageSettings && <DropdownLink to="/settings">{t('globalSettings')}</DropdownLink>}
<DropdownLink to="/send-configurations">{t('sendConfigurations')}</DropdownLink>
{mailtrainConfig.globalPermissions.manageBlacklist && <DropdownLink to="/blacklist">{t('blacklist')}</DropdownLink>}
<DropdownLink to="/account/api">{t('api')}</DropdownLink>
</NavDropdown>
</ul>
<ul className="navbar-nav">
{languageChooser}
<ul className="navbar-nav mt-navbar-nav-right">
{getLanguageChooser(t)}
<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>
<DropdownLink to="/account"><Icon icon='user'/> {t('account')}</DropdownLink>
<DropdownActionLink onClickAsync={::this.logout}><Icon icon='sign-out-alt'/> {t('logOut')}</DropdownActionLink>
</NavDropdown>
</ul>
</div>
:
<div className="collapse navbar-collapse" id="mtMainNavbar">
<ul className="navbar-nav mr-auto">
</ul>
<ul className="navbar-nav">
</>
);
} else {
return (
<>
<ul className="navbar-nav mt-navbar-nav-right">
{languageChooser}
</ul>
</div>
}
</nav>
</>
);
}
}
}
structure[''] ={
title: t('home'),

View file

@ -13,19 +13,111 @@ $fa-font-path: "../static-npm/fontawesome";
body.mailtrain {
background-color: white;
.dropdown-item {
border-bottom: none 0px;
}
.mt-breadcrumb-and-tertiary-navbar {
display: flex;
border-radius: 0;
@include border-radius($breadcrumb-border-radius);
@include borders($breadcrumb-borders);
background-color: $breadcrumb-bg;
.breadcrumb {
border: 0px none;
margin-bottom: 0px;
padding-top: 11px;
padding-bottom: 12px;
}
margin-bottom: 1.5rem;
}
@include media-breakpoint-down(md) {
.app-header {
height: auto;
padding: 0;
flex: none;
border-bottom: 0px none;
position: relative;
}
.app-body {
margin-top: 0px;
}
}
.app-header {
.navbar {
padding: 0 15px;
.navbar-brand {
width: auto;
height: auto;
display: inline-block;
padding-top: $navbar-brand-padding-y;
padding-bottom: $navbar-brand-padding-y;
margin-right: $navbar-padding-x;
width: $sidebar-width - 30px;
justify-content: left;
@include media-breakpoint-down(md) {
// This is to keep the title and the menu buttons in order. Normally the brand is position: absolute which distorts the order
position: relative;
top: auto;
left: auto;
margin: 0px;
}
}
}
@include media-breakpoint-down(md) {
.navbar-toggler {
color: #fff;
height: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
}
.navbar-toggler {
.navbar-toggler-icon, &:hover .navbar-toggler-icon {
background-image: $navbar-dark-toggler-icon-bg;
}
}
.navbar-nav {
margin-top: 8px;
margin-bottom: 8px;
}
.mt-navbar-nav-right {
@include media-breakpoint-up(lg) {
flex-grow: 1;
justify-content: flex-end;
}
.nav-item {
.nav-link {
padding: 0px;
}
@include media-breakpoint-up(lg) {
margin-left: 15px;
}
@include media-breakpoint-down(md) {
margin-right: 15px;
.dropdown-menu-right {
right: auto;
left: 0;
}
}
}
}
.mt-navbar-nav-left {
@include media-breakpoint-up(lg) {
margin-left: 15px;
}
.nav-item {
margin-right: 15px;
}
}
.nav-item {
@ -35,6 +127,10 @@ body.mailtrain {
.main .container-fluid {
padding: 0 15px;
@include media-breakpoint-down(md) {
padding: 0 3px;
}
}
.navbar-dark {
@ -44,8 +140,9 @@ body.mailtrain {
}
}
}
.gpg-text {
font-family: monospace;
}
}
.gpg-text {
font-family: monospace;
}

View file

@ -6,7 +6,7 @@ import PropTypes
import {Trans} from 'react-i18next';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -249,7 +249,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{canDelete &&
<NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/send-configurations/${this.props.entity.id}/delete`}/>
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/send-configurations/${this.props.entity.id}/delete`}/>
}
</ButtonRow>
</Form>

View file

@ -4,7 +4,7 @@ import React, {Component} from 'react';
import {withTranslation} from '../lib/i18n';
import {Icon} from '../lib/bootstrap-components';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -103,7 +103,7 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/send-configurations/create" className="btn-primary" icon="plus" label={t('createSendConfiguration')}/>
<LinkButton to="/send-configurations/create" className="btn-primary" icon="plus" label={t('createSendConfiguration')}/>
</Toolbar>
}

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -295,7 +295,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={isEdit ? t('save') : t('saveAndEditTemplate')}/>
{canDelete && <NavButton className="btn-danger" icon="trash-alt" label={t('delete')} linkTo={`/templates/${this.props.entity.id}/delete`}/> }
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/templates/${this.props.entity.id}/delete`}/> }
{isEdit && <Button className="btn-danger" icon="send" label={t('testSend')} onClickAsync={async () => this.setState({showTestSendModal: true})}/> }
</ButtonRow>
</Form>

View file

@ -4,7 +4,7 @@ import React, {Component} from 'react';
import {withTranslation} from '../lib/i18n';
import {Icon} from '../lib/bootstrap-components';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -117,10 +117,10 @@ export default class List extends Component {
{tableRestActionDialogRender(this)}
<Toolbar>
{this.state.createPermitted &&
<NavButton linkTo="/templates/create" className="btn-primary" icon="plus" label={t('createTemplate')}/>
<LinkButton to="/templates/create" className="btn-primary" icon="plus" label={t('createTemplate')}/>
}
{this.state.mosaicoTemplatesPermitted &&
<NavButton linkTo="/templates/mosaico" className="btn-primary" label={t('mosaicoTemplates')}/>
<LinkButton to="/templates/mosaico" className="btn-primary" label={t('mosaicoTemplates')}/>
}
</Toolbar>

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -196,7 +196,7 @@ export default class CUD extends Component {
<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="trash-alt" label={t('delete')} linkTo={`/templates/mosaico/${this.props.entity.id}/delete`}/>
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/templates/mosaico/${this.props.entity.id}/delete`}/>
}
</ButtonRow>
:

View file

@ -7,7 +7,7 @@ import {
Icon
} from '../../lib/bootstrap-components';
import {
ButtonDropdownLink,
DropdownLink,
NavDropdown,
requiresAuthenticatedUser,
Title,
@ -121,8 +121,8 @@ export default class List extends Component {
{this.state.createPermitted &&
<Toolbar>
<ButtonDropdown buttonClassName="btn-primary" menuClassName="dropdown-menu-right" label={t('createMosaicoTemplate')}>
<ButtonDropdownLink to="/templates/mosaico/create">{t('blank')}</ButtonDropdownLink>
<ButtonDropdownLink to="/templates/mosaico/create/versafix">{t('versafixOne')}</ButtonDropdownLink>
<DropdownLink to="/templates/mosaico/create">{t('blank')}</DropdownLink>
<DropdownLink to="/templates/mosaico/create/versafix">{t('versafixOne')}</DropdownLink>
</ButtonDropdown>
</Toolbar>
}

View file

@ -5,7 +5,7 @@ import PropTypes
from 'prop-types';
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
withPageHelpers
@ -249,7 +249,7 @@ export default class CUD extends Component {
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
{canDelete && <NavButton className="btn-danger" icon="trash-alt" label={t('deleteUser')} linkTo={`/users/${this.props.entity.id}/delete`}/>}
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('deleteUser')} to={`/users/${this.props.entity.id}/delete`}/>}
</ButtonRow>
</Form>
</div>

View file

@ -3,7 +3,7 @@
import React, {Component} from "react";
import {withTranslation} from '../lib/i18n';
import {
NavButton,
LinkButton,
requiresAuthenticatedUser,
Title,
Toolbar,
@ -74,7 +74,7 @@ export default class List extends Component {
<div>
{tableRestActionDialogRender(this)}
<Toolbar>
<NavButton linkTo="/users/create" className="btn-primary" icon="plus" label={t('createUser')}/>
<LinkButton to="/users/create" className="btn-primary" icon="plus" label={t('createUser')}/>
</Toolbar>
<Title>{t('users')}</Title>

View file

@ -1263,6 +1263,22 @@
}
}
},
"@babel/polyfill": {
"version": "7.2.5",
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.2.5.tgz",
"integrity": "sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==",
"requires": {
"core-js": "^2.5.7",
"regenerator-runtime": "^0.12.0"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
}
}
},
"@babel/preset-env": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.2.3.tgz",
@ -1414,6 +1430,26 @@
}
}
},
"@coreui/coreui": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@coreui/coreui/-/coreui-2.1.5.tgz",
"integrity": "sha512-wHmfvLYgdzFDsaNT0hCs2UTTEjfSbHDmUxYC74cbe1Z5QvgId4Fco4sN/slNA3bYd+OUp6f8lR4BVtPD2AU8gQ==",
"requires": {
"@babel/polyfill": "^7.2.5",
"@coreui/coreui-plugin-npm-postinstall": "^1.0.2",
"bootstrap": "^4.2.1"
}
},
"@coreui/coreui-plugin-npm-postinstall": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@coreui/coreui-plugin-npm-postinstall/-/coreui-plugin-npm-postinstall-1.0.2.tgz",
"integrity": "sha512-yeeoWp+bNS84nP1977Y8UCiQ9pssO+f4QuVj3i0/gYZFjjvOgxx0dnyWhtowD5sLYnCRMPlPpqyjwXze3SlkYg=="
},
"@fortawesome/fontawesome-free": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.6.3.tgz",
"integrity": "sha512-s5PLdI9NYgjBvfrv6rhirPHlAHWx+Sfo/IjsAeiXYfmemC/GSjwsyz1wLnGPazbLPXWfk62ks980o9AmsxYUEQ=="
},
"@webassemblyjs/ast": {
"version": "1.7.11",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz",
@ -2014,6 +2050,11 @@
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
"dev": true
},
"bootstrap": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.2.1.tgz",
"integrity": "sha512-tt/7vIv3Gm2mnd/WeDx36nfGGHleil0Wg8IeB7eMrVkY0fZ5iTaBisSh8oNANc2IBsCc6vCgCNTIM/IEN0+50Q=="
},
"boxen": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
@ -2672,8 +2713,7 @@
"core-js": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz",
"integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==",
"dev": true
"integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg=="
},
"core-util-is": {
"version": "1.0.2",
@ -3861,14 +3901,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -3883,20 +3921,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -4013,8 +4048,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -4026,7 +4060,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -4041,7 +4074,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -4049,14 +4081,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@ -4075,7 +4105,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -4156,8 +4185,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -4169,7 +4197,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4291,7 +4318,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",

View file

@ -7,8 +7,8 @@
"js": "webpack",
"watch-js": "webpack --watch",
"css": "npm-run-all --sequential css-compile css-minify",
"css-compile": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 ../ivis-core/client/src/scss/ivis.scss ../ivis-core/client/dist/ivis.css",
"css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output ../ivis-core/client/dist/ivis.min.css ../ivis-core/client/dist/ivis.css",
"css-compile": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 ../ivis-core/client/src/scss/ivis.scss dist/ivis.css",
"css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output dist/ivis.min.css dist/ivis.css",
"watch-css": "nodemon --watch ../ivis-core/client/src/scss -e scss -x \"npm run css\"",
"watch": "node ../ivis-core/client/pre-build.js && npm-run-all --parallel watch-css watch-js",
"build": "node ../ivis-core/client/pre-build.js && npm-run-all --parallel css js"

View file

@ -1,3 +0,0 @@
:global .navbar-custom .navbar-header .navbar-brand {
width: 200px;
}

@ -1 +1 @@
Subproject commit 43735807e7594f3b8a75f0c58122ef2a913c6053
Subproject commit 4aae36e44f1332bdbd063a107604fbf55e78ae91