Added delete button to entity lists.

This commit is contained in:
Tomas Bures 2018-09-28 14:51:55 +02:00
parent bc818aaee2
commit 2b57396a5d
22 changed files with 312 additions and 67 deletions

View file

@ -26,6 +26,11 @@ import {
} from "../../../shared/campaigns";
import {checkPermissions} from "../lib/permissions";
import {getCampaignLabels} from "./helpers";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withPageHelpers
@ -42,6 +47,7 @@ export default class List extends Component {
this.campaignStatusLabels = campaignStatusLabels;
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -145,6 +151,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -152,6 +160,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/campaigns`, t('Deleting campaign ...'), t('Campaign deleted'))}
<Toolbar>
{this.state.createPermitted &&
<DropdownMenu className="btn-primary" label={t('Create Campaign')}>
@ -164,7 +173,7 @@ export default class List extends Component {
<Title>{t('Campaigns')}</Title>
<Table withHeader dataUrl="rest/campaigns-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/campaigns-table" columns={columns} />
</div>
);
}

View file

@ -15,6 +15,11 @@ import {Table} from '../../lib/table';
import {getTriggerTypes} from './helpers';
import {Icon} from "../../lib/bootstrap-components";
import mailtrainConfig from 'mailtrainConfig';
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withPageHelpers
@ -29,6 +34,7 @@ export default class List extends Component {
this.eventLabels = eventLabels;
this.state = {};
tableDeleteDialogInit(this);
}
static propTypes = {
@ -59,6 +65,10 @@ export default class List extends Component {
});
}
if (perms.includes('manageTriggers')) {
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]);
}
return actions;
}
}
@ -66,6 +76,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/triggers/${this.props.campaign.id}`, t('Deleting trigger ...'), t('Trigger deleted'))}
{mailtrainConfig.globalPermissions.includes('setupAutomation') && this.props.campaign.permissions.includes('manageTriggers') &&
<Toolbar>
<NavButton linkTo={`/campaigns/${this.props.campaign.id}/triggers/create`} className="btn-primary" icon="plus" label={t('Create Trigger')}/>
@ -74,7 +85,7 @@ export default class List extends Component {
<Title>{t('Triggers')}</Title>
<Table withHeader dataUrl={`rest/triggers-by-campaign-table/${this.props.campaign.id}`} columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl={`rest/triggers-by-campaign-table/${this.props.campaign.id}`} columns={columns} />
</div>
);
}

View file

@ -10,8 +10,7 @@ import {
import {withErrorHandling} from "./error-handling";
import {Table} from "./table";
import Dropzone from "react-dropzone";
import {ModalDialog} from "./modals";
import {Icon} from "./bootstrap-components";
import {Icon, ModalDialog} from "./bootstrap-components";
import axios from './axios';
import styles from "./styles.scss";
import {withPageHelpers} from "./page";

View file

@ -4,44 +4,72 @@ import React, { Component } from 'react';
import axios, { HTTPMethod } from './axios';
import { translate } from 'react-i18next';
import PropTypes from 'prop-types';
import {ModalDialog} from "./bootstrap-components";
import {
Icon,
ModalDialog
} from "./bootstrap-components";
import {getUrl} from "./urls";
import {withPageHelpers} from "./page";
import styles from './styles.scss';
@translate()
class RestActionModalDialog extends Component {
@withPageHelpers
export class RestActionModalDialog extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
stateOwner: PropTypes.object.isRequired,
stateOwner: PropTypes.object,
visible: PropTypes.bool.isRequired,
actionMethod: PropTypes.func.isRequired,
actionUrl: PropTypes.string.isRequired,
backUrl: PropTypes.string.isRequired,
successUrl: PropTypes.string.isRequired,
backUrl: PropTypes.string,
successUrl: PropTypes.string,
onBack: PropTypes.func,
onSuccess: PropTypes.func,
onPerformingAction: PropTypes.func,
actionInProgressMsg: PropTypes.string.isRequired,
actionDoneMsg: PropTypes.string.isRequired,
onErrorAsync: PropTypes.func
}
async hideModal() {
this.props.stateOwner.navigateTo(this.props.backUrl);
async hideModal(isBack) {
if (this.props.backUrl) {
this.props.stateOwner.navigateTo(this.props.backUrl);
} else {
if (isBack) {
this.props.onBack();
} else {
this.props.onPerformingAction();
}
}
}
async performAction() {
const t = this.props.t;
const owner = this.props.stateOwner;
const props = this.props;
const t = props.t;
const owner = props.stateOwner;
await this.hideModal();
await this.hideModal(false);
try {
owner.disableForm();
owner.setFormStatusMessage('info', this.props.actionInProgressMsg);
await axios.method(this.props.actionMethod, getUrl(this.props.actionUrl));
if (!owner) {
this.setFlashMessage('info', props.actionInProgressMsg);
} else {
owner.disableForm();
owner.setFormStatusMessage('info', props.actionInProgressMsg);
}
owner.navigateToWithFlashMessage(this.props.successUrl, 'success', this.props.actionDoneMsg);
await axios.method(props.actionMethod, getUrl(props.actionUrl));
if (props.successUrl) {
owner.navigateToWithFlashMessage(props.successUrl, 'success', props.actionDoneMsg);
} else {
props.onSuccess();
this.setFlashMessage('success', props.actionDoneMsg);
}
} catch (err) {
if (this.props.onErrorAsync) {
await this.props.onErrorAsync(err);
if (props.onErrorAsync) {
await props.onErrorAsync(err);
} else {
throw err;
}
@ -52,8 +80,8 @@ class RestActionModalDialog extends Component {
const t = this.props.t;
return (
<ModalDialog hidden={!this.props.visible} title={this.props.title} onCloseAsync={::this.hideModal} buttons={[
{ label: t('No'), className: 'btn-primary', onClickAsync: ::this.hideModal },
<ModalDialog hidden={!this.props.visible} title={this.props.title} onCloseAsync={() => this.hideModal(true)} buttons={[
{ label: t('No'), className: 'btn-primary', onClickAsync: () => this.hideModal(true) },
{ label: t('Yes'), className: 'btn-danger', onClickAsync: ::this.performAction }
]}>
{this.props.message}
@ -63,13 +91,17 @@ class RestActionModalDialog extends Component {
}
@translate()
class DeleteModalDialog extends Component {
export class DeleteModalDialog extends Component {
static propTypes = {
stateOwner: PropTypes.object.isRequired,
stateOwner: PropTypes.object,
visible: PropTypes.bool.isRequired,
deleteUrl: PropTypes.string.isRequired,
backUrl: PropTypes.string.isRequired,
successUrl: PropTypes.string.isRequired,
backUrl: PropTypes.string,
successUrl: PropTypes.string,
name: PropTypes.string,
onBack: PropTypes.func,
onSuccess: PropTypes.func,
onPerformingAction: PropTypes.func,
deletingMsg: PropTypes.string.isRequired,
deletedMsg: PropTypes.string.isRequired,
onErrorAsync: PropTypes.func
@ -78,16 +110,20 @@ class DeleteModalDialog extends Component {
render() {
const t = this.props.t;
const owner = this.props.stateOwner;
const name = this.props.name !== undefined ? this.props.name : (owner ? owner.getFormValue('name') : '');
return <RestActionModalDialog
title={t('Confirm deletion')}
message={t('Are you sure you want to delete "{{name}}"?', {name: owner.getFormValue('name')})}
message={t('Are you sure you want to delete "{{name}}"?', {name})}
stateOwner={this.props.stateOwner}
visible={this.props.visible}
actionMethod={HTTPMethod.DELETE}
actionUrl={this.props.deleteUrl}
backUrl={this.props.backUrl}
successUrl={this.props.successUrl}
onBack={this.props.onBack}
onSuccess={this.props.onSuccess}
onPerformingAction={this.props.onPerformingAction}
actionInProgressMsg={this.props.deletingMsg}
actionDoneMsg={this.props.deletedMsg}
onErrorAsync={this.props.onErrorAsync}
@ -95,9 +131,51 @@ class DeleteModalDialog extends Component {
}
}
export {
ModalDialog,
DeleteModalDialog,
RestActionModalDialog
export function tableDeleteDialogInit(owner) {
owner.deleteDialogData = {};
owner.state.deleteDialogShown = false;
}
export function tableDeleteDialogAddDeleteButton(actions, owner, perms, id, name) {
const t = owner.props.t;
if (!perms || perms.includes('delete')) {
if (owner.deleteDialogData.id) {
actions.push({
label: <Icon className={styles.iconDisabled} icon="remove" title={t('Delete')}/>
});
} else {
actions.push({
label: <Icon icon="remove" title={t('Delete')}/>,
action: () => {
owner.deleteDialogData = {name, id};
owner.setState({
deleteDialogShown: true
});
owner.table.refresh();
}
});
}
}
}
export function tableDeleteDialogRender(owner, deleteUrlBase, deletingMsg, deletedMsg) {
function hide() {
owner.deleteDialogData = {};
owner.setState({ deleteDialogShown: false });
owner.table.refresh();
}
return (
<DeleteModalDialog
visible={owner.state.deleteDialogShown}
name={owner.deleteDialogData.name}
deleteUrl={deleteUrlBase + '/' + owner.deleteDialogData.id}
onBack={hide}
onPerformingAction={() => owner.setState({ deleteDialogShown: false })}
onSuccess={hide}
deletingMsg={deletingMsg}
deletedMsg={deletedMsg}
/>
);
}

View file

@ -132,3 +132,7 @@
height: 0px;
overflow: hidden;
}
.iconDisabled {
color: #888;
}

View file

@ -16,6 +16,7 @@ import { withPageHelpers } from './page'
import { withErrorHandling, withAsyncErrorHandler } from './error-handling';
import styles from "./styles.scss";
import {getUrl} from "./urls";
import {Table} from "./table";
const TreeSelectMode = {
NONE: 0,
@ -23,7 +24,7 @@ const TreeSelectMode = {
MULTI: 2
};
@translate()
@translate(null, { withRef: true })
@withPageHelpers
@withErrorHandling
class TreeTable extends Component {
@ -46,6 +47,13 @@ class TreeTable extends Component {
selectMode: TreeSelectMode.NONE
}
refresh() {
if (this.tree) {
this.tree.reload(this.sanitizeTreeData(this.state.treeData));
this.updateSelection();
}
}
@withAsyncErrorHandler
async loadData(dataUrl) {
const response = await axios.get(getUrl(dataUrl));
@ -323,6 +331,15 @@ class TreeTable extends Component {
}
}
/*
Refreshes the table. This method is provided to allow programmatic refresh from a handler outside the table.
The reference to the table can be obtained by ref.
*/
TreeTable.prototype.refresh = function() {
this.getWrappedInstance().refresh();
};
export {
TreeTable,
TreeSelectMode

View file

@ -9,6 +9,11 @@ import axios from '../lib/axios';
import {Link} from "react-router-dom";
import {Icon} from "../lib/bootstrap-components";
import {checkPermissions} from "../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withPageHelpers
@ -19,6 +24,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -115,6 +121,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -122,6 +130,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/lists`, t('Deleting list ...'), t('List deleted'))}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/lists/create" className="btn-primary" icon="plus" label={t('Create List')}/>
@ -131,7 +140,7 @@ export default class List extends Component {
<Title>{t('Lists')}</Title>
<Table withHeader dataUrl="rest/lists-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/lists-table" columns={columns} />
</div>
);
}

View file

@ -13,6 +13,11 @@ import {Table} from '../lib/table';
import {getTriggerTypes} from '../campaigns/triggers/helpers';
import {Icon} from "../lib/bootstrap-components";
import mailtrainConfig from 'mailtrainConfig';
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withPageHelpers
@ -27,6 +32,7 @@ export default class List extends Component {
this.eventLabels = eventLabels;
this.state = {};
tableDeleteDialogInit(this);
}
static propTypes = {
@ -60,6 +66,10 @@ export default class List extends Component {
});
}
if (perms.includes('manageTriggers')) {
tableDeleteDialogAddDeleteButton(actions, this, null, campaignId + '/' + data[0], data[1]);
}
return actions;
}
}
@ -67,9 +77,10 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/triggers`, t('Deleting trigger ...'), t('Trigger deleted'))}
<Title>{t('Triggers')}</Title>
<Table withHeader dataUrl={`rest/triggers-by-list-table/${this.props.list.id}`} columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl={`rest/triggers-by-list-table/${this.props.list.id}`} columns={columns} />
</div>
);
}

View file

@ -8,6 +8,11 @@ import { withErrorHandling } from '../../lib/error-handling';
import { Table } from '../../lib/table';
import { getFieldTypes } from './helpers';
import {Icon} from "../../lib/bootstrap-components";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withPageHelpers
@ -18,6 +23,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
this.fieldTypes = getFieldTypes(props.t);
}
@ -48,6 +54,8 @@ export default class List extends Component {
label: <Icon icon="edit" title={t('Edit')}/>,
link: `/lists/${this.props.list.id}/fields/${data[0]}/edit`
});
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]);
}
return actions;
@ -57,6 +65,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/fields/${this.props.list.id}`, t('Deleting field ...'), t('Field deleted'))}
{this.props.list.permissions.includes('manageFields') &&
<Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/fields/create`} className="btn-primary" icon="plus" label={t('Create Field')}/>
@ -65,7 +74,7 @@ export default class List extends Component {
<Title>{t('Fields')}</Title>
<Table withHeader dataUrl={`rest/fields-table/${this.props.list.id}`} columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl={`rest/fields-table/${this.props.list.id}`} columns={columns} />
</div>
);
}

View file

@ -8,6 +8,11 @@ import { Table } from '../../lib/table';
import axios from '../../lib/axios';
import {Icon} from "../../lib/bootstrap-components";
import {checkPermissions} from "../../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withPageHelpers
@ -18,6 +23,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -64,6 +70,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -71,6 +79,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/forms`, t('Deleting form ...'), t('Form deleted'))}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/lists/forms/create" className="btn-primary" icon="plus" label={t('Create Custom Form')}/>
@ -79,7 +88,7 @@ export default class List extends Component {
<Title>{t('Forms')}</Title>
<Table withHeader dataUrl="rest/forms-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/forms-table" columns={columns} />
</div>
);
}

View file

@ -401,7 +401,7 @@ export default class CUD extends Component {
backUrl={`/lists/${this.props.list.id}/imports/${this.props.entity.id}/edit`}
successUrl={`/lists/${this.props.list.id}/imports`}
deletingMsg={t('Deleting import ...')}
deletedMsg={t('Field deleted')}/>
deletedMsg={t('Import deleted')}/>
}
<Title>{isEdit ? t('Edit Import') : t('Create Import')}</Title>

View file

@ -17,6 +17,11 @@ import {Icon} from "../../lib/bootstrap-components";
import mailtrainConfig from 'mailtrainConfig';
import moment from "moment";
import {inProgress} from '../../../../shared/imports';
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withPageHelpers
@ -27,6 +32,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
const {importSourceLabels, importStatusLabels} = getImportLabels(props.t);
this.importSourceLabels = importSourceLabels;
@ -72,6 +78,10 @@ export default class List extends Component {
link: `/lists/${this.props.list.id}/imports/${data[0]}/status`
});
if (this.props.list.permissions.includes('manageImports')) {
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]);
}
return { refreshTimeout, actions };
}
}
@ -79,6 +89,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/imports/${this.props.list.id}`, t('Deleting import ...'), t('Import deleted'))}
{mailtrainConfig.globalPermissions.includes('setupAutomation') && this.props.list.permissions.includes('manageImports') &&
<Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/imports/create`} className="btn-primary" icon="plus" label={t('Create Import')}/>
@ -87,7 +98,7 @@ export default class List extends Component {
<Title>{t('Imports')}</Title>
<Table withHeader dataUrl={`rest/imports-table/${this.props.list.id}`} columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl={`rest/imports-table/${this.props.list.id}`} columns={columns} />
</div>
);
}

View file

@ -7,6 +7,11 @@ import {requiresAuthenticatedUser, withPageHelpers, Title, Toolbar, NavButton} f
import { withErrorHandling } from '../../lib/error-handling';
import { Table } from '../../lib/table';
import {Icon} from "../../lib/bootstrap-components";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withPageHelpers
@ -17,6 +22,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
static propTypes = {
@ -40,6 +46,8 @@ export default class List extends Component {
label: <Icon icon="edit" title={t('Edit')}/>,
link: `/lists/${this.props.list.id}/segments/${data[0]}/edit`
});
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]);
}
return actions;
@ -49,6 +57,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/segments/${this.props.list.id}`, t('Deleting segment ...'), t('Segment deleted'))}
{this.props.list.permissions.includes('manageSegments') &&
<Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/segments/create`} className="btn-primary" icon="plus" label={t('Create Segment')}/>
@ -57,7 +66,7 @@ export default class List extends Component {
<Title>{t('Segment')}</Title>
<Table withHeader dataUrl={`rest/segments-table/${this.props.list.id}`} columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl={`rest/segments-table/${this.props.list.id}`} columns={columns} />
</div>
);
}

View file

@ -16,6 +16,11 @@ import {Icon, Button} from "../../lib/bootstrap-components";
import axios from '../../lib/axios';
import {getFieldTypes, getSubscriptionStatusLabels} from './helpers';
import {getUrl, getPublicUrl} from "../../lib/urls";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withForm
@ -29,6 +34,7 @@ export default class List extends Component {
const t = props.t;
this.state = {};
tableDeleteDialogInit(this);
this.subscriptionStatusLabels = getSubscriptionStatusLabels(t);
this.fieldTypes = getFieldTypes(t);
@ -62,22 +68,16 @@ export default class List extends Component {
this.updateSegmentSelection(nextProps);
}
@withAsyncErrorHandler
async deleteSubscription(id) {
await axios.delete(getUrl(`rest/subscriptions/${this.props.list.id}/${id}`));
this.blacklistTable.refresh();
}
@withAsyncErrorHandler
async unsubscribeSubscription(id) {
await axios.post(getUrl(`rest/subscriptions-unsubscribe/${this.props.list.id}/${id}`));
this.blacklistTable.refresh();
this.table.refresh();
}
@withAsyncErrorHandler
async blacklistSubscription(email) {
await axios.post(getUrl('rest/blacklist'), { email });
this.blacklistTable.refresh();
this.table.refresh();
}
render() {
@ -132,10 +132,7 @@ export default class List extends Component {
});
}
actions.push({
label: <Icon icon="remove" title={t('Remove')}/>,
action: () => this.deleteSubscription(data[0])
});
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[2]);
return actions;
}
@ -157,6 +154,7 @@ export default class List extends Component {
// FIXME - presents segments in a data table as in campaign edit
return (
<div>
{tableDeleteDialogRender(this, `rest/subscriptions/${this.props.list.id}`, t('Deleting subscription ...'), t('Subscription deleted'))}
<Toolbar>
<a href={getPublicUrl(`subscription/${this.props.list.cid}`)} className="btn-default"><Button label={t('Subscription Form')} className="btn-default"/></a>
<NavButton linkTo={`/lists/${this.props.list.id}/subscriptions/create`} className="btn-primary" icon="plus" label={t('Add Subscriber')}/>
@ -175,7 +173,7 @@ export default class List extends Component {
</div>
<Table ref={node => this.blacklistTable = node} withHeader dataUrl={dataUrl} columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl={dataUrl} columns={columns} />
</div>
);
}

View file

@ -8,6 +8,11 @@ import { withErrorHandling, withAsyncErrorHandler } from '../lib/error-handling'
import axios from '../lib/axios';
import {Icon} from "../lib/bootstrap-components";
import {checkPermissions} from "../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withErrorHandling
@ -18,6 +23,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -44,6 +50,7 @@ export default class List extends Component {
const actions = node => {
const actions = [];
console.log(node);
if (node.data.permissions.includes('edit')) {
actions.push({
@ -59,11 +66,14 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, node.data.permissions, node.key, node.key);
return actions;
};
return (
<div>
{tableDeleteDialogRender(this, `rest/namespaces`, t('Deleting namespace ...'), t('Namespace deleted'))}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/namespaces/create" className="btn-primary" icon="plus" label={t('Create Namespace')}/>
@ -72,7 +82,7 @@ export default class List extends Component {
<Title>{t('Namespaces')}</Title>
<TreeTable withHeader withDescription dataUrl="rest/namespaces-tree" actions={actions} />
<TreeTable ref={node => this.table = node} withHeader withDescription dataUrl="rest/namespaces-tree" actions={actions} />
</div>
);
}

View file

@ -11,6 +11,11 @@ import { ReportState } from '../../../shared/reports';
import {Icon} from "../lib/bootstrap-components";
import {checkPermissions} from "../lib/permissions";
import {getUrl} from "../lib/urls";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withErrorHandling
@ -21,6 +26,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -159,6 +165,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return { refreshTimeout, actions };
}
}
@ -167,6 +175,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/reports`, t('Deleting report ...'), t('Report deleted'))}
<Toolbar>
{this.state.createPermitted &&
<NavButton linkTo="/reports/create" className="btn-primary" icon="plus" label={t('Create Report')}/>
@ -178,7 +187,7 @@ export default class List extends Component {
<Title>{t('Reports')}</Title>
<Table withHeader dataUrl="rest/reports-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/reports-table" columns={columns} />
</div>
);
}

View file

@ -10,6 +10,11 @@ import axios from '../../lib/axios';
import moment from 'moment';
import mailtrainConfig from 'mailtrainConfig';
import {checkPermissions} from "../../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@withPageHelpers
@ -20,6 +25,7 @@ export default class List extends Component {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -68,6 +74,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -75,6 +83,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/reports/templates`, t('Deleting report template ...'), t('Report template deleted'))}
{this.state.createPermitted &&
<Toolbar>
<DropdownMenu className="btn-primary" label={t('Create Report Template')}>
@ -88,7 +97,7 @@ export default class List extends Component {
<Title>{t('Report Templates')}</Title>
<Table withHeader dataUrl="rest/report-templates-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/report-templates-table" columns={columns} />
</div>
);
}

View file

@ -19,6 +19,11 @@ import axios from '../lib/axios';
import moment from 'moment';
import {getMailerTypes} from './helpers';
import {checkPermissions} from "../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@ -32,6 +37,7 @@ export default class List extends Component {
this.mailerTypes = getMailerTypes(props.t);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -82,6 +88,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -89,6 +97,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/send-configurations`, t('Deleting send configuration ...'), t('Send configuration deleted'))}
{this.state.createPermitted &&
<Toolbar>
<NavButton linkTo="/send-configurations/create" className="btn-primary" icon="plus" label={t('Create Send Configuration')}/>
@ -97,7 +106,7 @@ export default class List extends Component {
<Title>{t('Send Configurations')}</Title>
<Table withHeader dataUrl="rest/send-configurations-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/send-configurations-table" columns={columns} />
</div>
);
}

View file

@ -18,6 +18,11 @@ import {Table} from '../lib/table';
import moment from 'moment';
import {getTemplateTypes} from './helpers';
import {checkPermissions} from "../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withPageHelpers
@ -30,6 +35,7 @@ export default class List extends Component {
this.templateTypes = getTemplateTypes(props.t);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -95,6 +101,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -102,6 +110,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/templates`, t('Deleting template ...'), t('Template deleted'))}
<Toolbar>
{this.state.createPermitted &&
<NavButton linkTo="/templates/create" className="btn-primary" icon="plus" label={t('Create Template')}/>
@ -113,7 +122,7 @@ export default class List extends Component {
<Title>{t('Templates')}</Title>
<Table withHeader dataUrl="rest/templates-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/templates-table" columns={columns} />
</div>
);
}

View file

@ -10,6 +10,11 @@ import axios from '../../lib/axios';
import moment from 'moment';
import { getTemplateTypes } from './helpers';
import {checkPermissions} from "../../lib/permissions";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../../lib/modals";
@translate()
@ -23,6 +28,7 @@ export default class List extends Component {
this.templateTypes = getTemplateTypes(props.t);
this.state = {};
tableDeleteDialogInit(this);
}
@withAsyncErrorHandler
@ -86,6 +92,8 @@ export default class List extends Component {
});
}
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]);
return actions;
}
}
@ -93,6 +101,7 @@ export default class List extends Component {
return (
<div>
{tableDeleteDialogRender(this, `rest/mosaico-templates`, t('Deleting Mosaico template ...'), t('Mosaico template deleted'))}
{this.state.createPermitted &&
<Toolbar>
<DropdownMenu className="btn-primary" label={t('Create Mosaico Template')}>
@ -104,7 +113,7 @@ export default class List extends Component {
<Title>{t('Mosaico Templates')}</Title>
<Table withHeader dataUrl="rest/mosaico-templates-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/mosaico-templates-table" columns={columns} />
</div>
);
}

View file

@ -6,6 +6,11 @@ import {NavButton, requiresAuthenticatedUser, Title, Toolbar, withPageHelpers} f
import {Table} from "../lib/table";
import mailtrainConfig from "mailtrainConfig";
import {Icon} from "../lib/bootstrap-components";
import {
tableDeleteDialogAddDeleteButton,
tableDeleteDialogInit,
tableDeleteDialogRender
} from "../lib/modals";
@translate()
@withPageHelpers
@ -13,6 +18,9 @@ import {Icon} from "../lib/bootstrap-components";
export default class List extends Component {
constructor(props) {
super(props);
this.state = {};
tableDeleteDialogInit(this);
}
render() {
@ -33,27 +41,35 @@ export default class List extends Component {
columns.push({ data: 4, title: "Role" });
columns.push({
actions: data => [
{
actions: data => {
const actions = [];
actions.push({
label: <Icon icon="edit" title={t('Edit')}/>,
link: `/users/${data[0]}/edit`
},
{
});
actions.push({
label: <Icon icon="share" title={t('Share')}/>,
link: `/users/${data[0]}/shares`
}
]
});
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]);
return actions;
}
});
return (
<div>
{tableDeleteDialogRender(this, `rest/users`, t('Deleting user ...'), t('User deleted'))}
<Toolbar>
<NavButton linkTo="/users/create" className="btn-primary" icon="plus" label={t('Create User')}/>
</Toolbar>
<Title>{t('Users')}</Title>
<Table withHeader dataUrl="rest/users-table" columns={columns} />
<Table ref={node => this.table = node} withHeader dataUrl="rest/users-table" columns={columns} />
</div>
);
}

View file

@ -578,7 +578,7 @@ async function _removeAndGetTx(tx, context, listId, existing) {
throw new interoperableErrors.NotFoundError();
}
await tx(getSubscriptionTableName(listId)).where('id', id).del();
await tx(getSubscriptionTableName(listId)).where('id', existing.id).del();
if (existing.status === SubscriptionStatus.SUBSCRIBED) {
await tx('lists').where('id', listId).decrement('subscribers', 1);