All create/edit forms now allow staying on the page after save.

This commit is contained in:
Tomas Bures 2019-02-24 11:10:23 +00:00
parent d54f941caa
commit 4a6aed4cf7
31 changed files with 1118 additions and 1454 deletions

1621
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -26,8 +26,9 @@
"bootstrap": "^4.2.1", "bootstrap": "^4.2.1",
"datatables.net": "^1.10.19", "datatables.net": "^1.10.19",
"datatables.net-bs4": "^1.10.19", "datatables.net-bs4": "^1.10.19",
"ellipsize": "^0.1.0",
"grapesjs": "^0.14.49", "grapesjs": "^0.14.49",
"grapesjs-mjml": "0.0.27", "grapesjs-mjml": "0.0.31",
"grapesjs-preset-newsletter": "^0.2.20", "grapesjs-preset-newsletter": "^0.2.20",
"i18next": "^13.1.0", "i18next": "^13.1.0",
"i18next-browser-languagedetector": "^2.2.4", "i18next-browser-languagedetector": "^2.2.4",

View file

@ -164,43 +164,45 @@ export default class CUD extends Component {
} }
} }
getFormValuesMutator(data) {
// The source cannot be changed once campaign is created. Thus we don't have to initialize fields for all other sources
if (data.source === CampaignSource.TEMPLATE) {
data.data_sourceTemplate = data.data.sourceTemplate;
}
if (data.source === CampaignSource.URL) {
data.data_sourceUrl = data.data.sourceUrl;
}
if (data.type === CampaignType.RSS) {
data.data_feedUrl = data.data.feedUrl;
}
for (const overridable of campaignOverridables) {
data[overridable + '_overriden'] = data[overridable + '_override'] !== null;
}
const lsts = [];
for (const lst of data.lists) {
const lstUid = this.getNextListEntryId();
const prefix = 'lists_' + lstUid + '_';
data[prefix + 'list'] = lst.list;
data[prefix + 'segment'] = lst.segment;
data[prefix + 'useSegmentation'] = !!lst.segment;
lsts.push(lstUid);
}
data.lists = lsts;
// noinspection JSIgnoredPromiseFromCall
this.fetchSendConfiguration(data.send_configuration);
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
// The source cannot be changed once campaign is created. Thus we don't have to initialize fields for all other sources
if (data.source === CampaignSource.TEMPLATE) {
data.data_sourceTemplate = data.data.sourceTemplate;
}
if (data.source === CampaignSource.URL) {
data.data_sourceUrl = data.data.sourceUrl;
}
if (data.type === CampaignType.RSS) {
data.data_feedUrl = data.data.feedUrl;
}
for (const overridable of campaignOverridables) {
data[overridable + '_overriden'] = data[overridable + '_override'] !== null;
}
const lsts = [];
for (const lst of data.lists) {
const lstUid = this.getNextListEntryId();
const prefix = 'lists_' + lstUid + '_';
data[prefix + 'list'] = lst.list;
data[prefix + 'segment'] = lst.segment;
data[prefix + 'useSegmentation'] = !!lst.segment;
lsts.push(lstUid);
}
data.lists = lsts;
// noinspection JSIgnoredPromiseFromCall
this.fetchSendConfiguration(data.send_configuration);
});
if (this.props.entity.status === CampaignStatus.SENDING) { if (this.props.entity.status === CampaignStatus.SENDING) {
this.disableForm(); this.disableForm();
@ -337,7 +339,13 @@ export default class CUD extends Component {
validateNamespace(t, state); validateNamespace(t, state);
} }
async submitHandler() { static AfterSubmitAction = {
STAY: 0,
LEAVE: 1,
STATUS: 2
}
async submitHandler(afterSubmitAction) {
const isEdit = !!this.props.entity; const isEdit = !!this.props.entity;
const t = this.props.t; const t = this.props.t;
@ -353,7 +361,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitResponse = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
data.source = Number.parseInt(data.source); data.source = Number.parseInt(data.source);
data.data = {}; data.data = {};
@ -411,14 +419,31 @@ export default class CUD extends Component {
} }
}); });
if (submitResponse) { if (submitResult) {
const sourceTypeKey = Number.parseInt(this.getFormValue('source'));
if (this.props.entity) { if (this.props.entity) {
this.navigateToWithFlashMessage('/campaigns', 'success', t('campaignSaved')); if (afterSubmitAction === CUD.AfterSubmitAction.STATUS) {
} else if (sourceTypeKey === CampaignSource.CUSTOM || sourceTypeKey === CampaignSource.CUSTOM_FROM_TEMPLATE || sourceTypeKey === CampaignSource.CUSTOM_FROM_CAMPAIGN) { this.navigateToWithFlashMessage(`/campaigns/${this.props.entity.id}/status`, 'success', t('Campaign updated'));
this.navigateToWithFlashMessage(`/campaigns/${submitResponse}/content`, 'success', t('campaignSaved')); } else if (afterSubmitAction === CUD.AfterSubmitAction.LEAVE) {
this.navigateToWithFlashMessage('/campaigns', 'success', t('Campaign updated'));
} else {
await this.getFormValuesFromURL(`rest/campaigns-settings/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Campaign updated'));
}
} else { } else {
this.navigateToWithFlashMessage(`/campaigns/${submitResponse}/status`, 'success', t('campaignSaved')); const sourceTypeKey = Number.parseInt(this.getFormValue('source'));
if (sourceTypeKey === CampaignSource.CUSTOM || sourceTypeKey === CampaignSource.CUSTOM_FROM_TEMPLATE || sourceTypeKey === CampaignSource.CUSTOM_FROM_CAMPAIGN) {
this.navigateToWithFlashMessage(`/campaigns/${submitResult}/content`, 'success', t('Campaign created'));
} else {
if (afterSubmitAction === CUD.AfterSubmitAction.STATUS) {
this.navigateToWithFlashMessage(`/campaigns/${submitResult}/status`, 'success', t('Campaign created'));
} else if (afterSubmitAction === CUD.AfterSubmitAction.LEAVE) {
this.navigateToWithFlashMessage(`/campaigns`, 'success', t('Campaign created'));
} else {
this.navigateToWithFlashMessage(`/campaigns/${submitResult}/edit`, 'success', t('Campaign created'));
}
}
} }
} else { } else {
this.enableForm(); this.enableForm();
@ -666,17 +691,6 @@ export default class CUD extends Component {
templateEdit = <InputField id="data_sourceUrl" label={t('renderUrl')} help={t('ifAMessageIsSentThenThisUrlWillBePosTed')}/> templateEdit = <InputField id="data_sourceUrl" label={t('renderUrl')} help={t('ifAMessageIsSentThenThisUrlWillBePosTed')}/>
} }
let saveButtonLabel;
if (isEdit) {
saveButtonLabel = t('save');
} else if (sourceTypeKey === CampaignSource.CUSTOM || sourceTypeKey === CampaignSource.CUSTOM_FROM_TEMPLATE || sourceTypeKey === CampaignSource.CUSTOM_FROM_CAMPAIGN) {
saveButtonLabel = t('saveAndEditContent');
} else {
saveButtonLabel = t('saveCampaignAndGoToStatus');
}
return ( return (
<div> <div>
{canDelete && {canDelete &&
@ -737,7 +751,15 @@ export default class CUD extends Component {
{templateEdit} {templateEdit}
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={saveButtonLabel}/> {!isEdit && (sourceTypeKey === CampaignSource.CUSTOM || sourceTypeKey === CampaignSource.CUSTOM_FROM_TEMPLATE || sourceTypeKey === CampaignSource.CUSTOM_FROM_CAMPAIGN) ?
<Button type="submit" className="btn-primary" icon="check" label={t('Save and edit content')}/>
:
<>
<Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(CUD.AfterSubmitAction.LEAVE)}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and go to status')} onClickAsync={async () => this.submitHandler(CUD.AfterSubmitAction.STATUS)}/>
</>
}
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -71,7 +71,8 @@ export default class CustomContent extends Component {
setPanelInFullScreen: PropTypes.func setPanelInFullScreen: PropTypes.func
} }
loadFromEntityMutator(data) {
getFormValuesMutator(data) {
data.data_sourceCustom_type = data.data.sourceCustom.type; data.data_sourceCustom_type = data.data.sourceCustom.type;
data.data_sourceCustom_data = data.data.sourceCustom.data; data.data_sourceCustom_data = data.data.sourceCustom.data;
data.data_sourceCustom_html = data.data.sourceCustom.html; data.data_sourceCustom_html = data.data.sourceCustom.html;
@ -80,8 +81,9 @@ export default class CustomContent extends Component {
this.templateTypes[data.data.sourceCustom.type].afterLoad(data); this.templateTypes[data.data.sourceCustom.type].afterLoad(data);
} }
componentDidMount() { componentDidMount() {
this.getFormValuesFromEntity(this.props.entity, data => this.loadFromEntityMutator(data)); this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
} }
localValidateFormValues(state) { localValidateFormValues(state) {
@ -95,14 +97,16 @@ export default class CustomContent extends Component {
} }
async save() { async save() {
await this.doSave(true); await this.submitHandler(CustomContent.AfterSubmitAction.STAY);
} }
async submitHandler() { static AfterSubmitAction = {
await this.doSave(false); STAY: 0,
LEAVE: 1,
STATUS: 2
} }
async doSave(stayOnPage) { async submitHandler(afterSubmitAction) {
const t = this.props.t; const t = this.props.t;
const customTemplateTypeKey = this.getFormValue('data_sourceCustom_type'); const customTemplateTypeKey = this.getFormValue('data_sourceCustom_type');
@ -114,7 +118,7 @@ export default class CustomContent extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitResponse = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
Object.assign(data, exportedData); Object.assign(data, exportedData);
this.templateTypes[data.data_sourceCustom_type].beforeSave(data); this.templateTypes[data.data_sourceCustom_type].beforeSave(data);
@ -132,15 +136,15 @@ export default class CustomContent extends Component {
} }
}); });
if (submitResponse) { if (submitResult) {
if (stayOnPage) { if (afterSubmitAction === CustomContent.AfterSubmitAction.STATUS) {
await this.getFormValuesFromURL(`rest/campaigns-content/${this.props.entity.id}`, data => this.loadFromEntityMutator(data)); this.navigateToWithFlashMessage(`/campaigns/${this.props.entity.id}/status`, 'success', t('Campaign updated'));
this.enableForm(); } else if (afterSubmitAction === CustomContent.AfterSubmitAction.LEAVE) {
this.clearFormStatusMessage(); this.navigateToWithFlashMessage('/campaigns', 'success', t('Campaign updated'));
this.setFlashMessage('success', t('campaignSaved'));
} else { } else {
this.navigateToWithFlashMessage('/campaigns', 'success', t('campaignSaved')); await this.getFormValuesFromURL(`rest/campaigns-content/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Campaign updated'));
} }
} else { } else {
this.enableForm(); this.enableForm();
@ -230,8 +234,10 @@ export default class CustomContent extends Component {
{customTemplateTypeKey && getEditForm(this, customTemplateTypeKey, 'data_sourceCustom_')} {customTemplateTypeKey && getEditForm(this, customTemplateTypeKey, 'data_sourceCustom_')}
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" 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})}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(CustomContent.AfterSubmitAction.LEAVE)}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and go to status')} onClickAsync={async () => this.submitHandler(CustomContent.AfterSubmitAction.STATUS)}/>
<Button className="btn-success" icon="at" label={t('testSend')} onClickAsync={async () => this.setState({showTestSendModal: true})}/>
</ButtonRow> </ButtonRow>
</Form> </Form>
</div> </div>

View file

@ -115,8 +115,8 @@ export class TestSendModalDialog extends Component {
return ( return (
<ModalDialog hidden={!this.props.visible} title={t('sendTestEmail')} onCloseAsync={() => this.hideModal()} buttons={[ <ModalDialog hidden={!this.props.visible} title={t('sendTestEmail')} onCloseAsync={() => this.hideModal()} buttons={[
{ label: t('send'), className: 'btn-danger', onClickAsync: ::this.performAction }, { label: t('send'), className: 'btn-primary', onClickAsync: ::this.performAction },
{ label: t('cancel'), className: 'btn-primary', onClickAsync: ::this.hideModal } { label: t('cancel'), className: 'btn-danger', onClickAsync: ::this.hideModal }
]}> ]}>
<Form stateOwner={this} format="wide"> <Form stateOwner={this} format="wide">
<TableSelect id="testUser" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/campaigns-test-users-table/${this.props.entity.id}`} columns={testUsersColumns} selectionLabelIndex={1} /> <TableSelect id="testUser" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/campaigns-test-users-table/${this.props.entity.id}`} columns={testUsersColumns} selectionLabelIndex={1} />

View file

@ -34,7 +34,7 @@ import StatisticsOpened
import StatisticsLinkClicks import StatisticsLinkClicks
from "./StatisticsLinkClicks"; from "./StatisticsLinkClicks";
import TemplatesCUD from "../templates/root"; import TemplatesCUD from "../templates/root";
import {ellipsizeBreadcrumbLabel} from "../lib/helpers"
function getMenus(t) { function getMenus(t) {
const aggLabels = { const aggLabels = {
@ -49,7 +49,7 @@ function getMenus(t) {
panelComponent: CampaignsList, panelComponent: CampaignsList,
children: { children: {
':campaignId([0-9]+)': { ':campaignId([0-9]+)': {
title: resolved => t('campaignName', {name: resolved.campaign.name}), title: resolved => t('campaignName', {name: ellipsizeBreadcrumbLabel(resolved.campaign.name)}),
resolve: { resolve: {
campaign: params => `rest/campaigns-settings/${params.campaignId}` campaign: params => `rest/campaigns-settings/${params.campaignId}`
}, },
@ -142,7 +142,7 @@ function getMenus(t) {
panelRender: props => <TriggersList campaign={props.resolved.campaign} />, panelRender: props => <TriggersList campaign={props.resolved.campaign} />,
children: { children: {
':triggerId([0-9]+)': { ':triggerId([0-9]+)': {
title: resolved => t('triggerName', {name: resolved.trigger.name}), title: resolved => t('triggerName', {name: ellipsizeBreadcrumbLabel(resolved.trigger.name)}),
resolve: { resolve: {
trigger: params => `rest/triggers/${params.campaignId}/${params.triggerId}`, trigger: params => `rest/triggers/${params.campaignId}/${params.triggerId}`,
}, },

View file

@ -86,23 +86,25 @@ export default class CUD extends Component {
entity: PropTypes.object entity: PropTypes.object
} }
getFormValuesMutator(data) {
data.daysAfter = (Math.round(data.seconds / (3600 * 24))).toString();
if (data.entity === Entity.SUBSCRIPTION) {
data.subscriptionEvent = data.event;
} else {
data.subscriptionEvent = Event[Entity.SUBSCRIPTION].CREATED;
}
if (data.entity === Entity.CAMPAIGN) {
data.campaignEvent = data.event;
} else {
data.campaignEvent = Event[Entity.CAMPAIGN].DELIVERED;
}
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
data.daysAfter = (Math.round(data.seconds / (3600 * 24))).toString();
if (data.entity === Entity.SUBSCRIPTION) {
data.subscriptionEvent = data.event;
} else {
data.subscriptionEvent = Event[Entity.SUBSCRIPTION].CREATED;
}
if (data.entity === Entity.CAMPAIGN) {
data.campaignEvent = data.event;
} else {
data.campaignEvent = Event[Entity.CAMPAIGN].DELIVERED;
}
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
@ -145,7 +147,7 @@ export default class CUD extends Component {
} }
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -161,7 +163,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
data.seconds = Number.parseInt(data.daysAfter) * 3600 * 24; data.seconds = Number.parseInt(data.daysAfter) * 3600 * 24;
if (data.entity === Entity.SUBSCRIPTION) { if (data.entity === Entity.SUBSCRIPTION) {
@ -171,8 +173,22 @@ export default class CUD extends Component {
} }
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage(`/campaigns/${this.props.campaign.id}/triggers`, 'success', t('triggerSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage(`/campaigns/${this.props.campaign.id}/triggers`, 'success', t('Trigger updated'));
} else {
await this.getFormValuesFromURL(`rest/triggers/${this.props.campaign.id}/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Trigger updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage(`/campaigns/${this.props.campaign.id}/triggers`, 'success', t('Trigger created'));
} else {
this.navigateToWithFlashMessage(`/campaigns/${this.props.campaign.id}/triggers/${submitResult}/edit`, 'success', t('Trigger created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -235,7 +251,8 @@ export default class CUD extends Component {
<CheckBox id="enabled" text={t('enabled')}/> <CheckBox id="enabled" text={t('enabled')}/>
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -100,7 +100,7 @@ class Form extends Component {
evt.preventDefault(); evt.preventDefault();
if (this.props.onSubmitAsync) { if (this.props.onSubmitAsync) {
await owner.formHandleChangedError(async () => await this.props.onSubmitAsync(evt)); await owner.formHandleChangedError(async () => await this.props.onSubmitAsync());
} }
} }

View file

@ -0,0 +1,8 @@
'use strict';
import ellipsize from "ellipsize";
export function ellipsizeBreadcrumbLabel(label) {
return ellipsize(label, 40)
}

View file

@ -13,9 +13,10 @@ export function needsResolve(route, nextRoute, match, nextMatch) {
const resolve = route.resolve; const resolve = route.resolve;
const nextResolve = nextRoute.resolve; const nextResolve = nextRoute.resolve;
// This compares whether two objects have the same content and returns TRUE if they don't
if (Object.keys(resolve).length === Object.keys(nextResolve).length) { if (Object.keys(resolve).length === Object.keys(nextResolve).length) {
for (const key in resolve) { for (const key in nextResolve) {
if (!(key in nextResolve) || if (!(key in resolve) ||
resolve[key](match.params) !== nextResolve[key](nextMatch.params)) { resolve[key](match.params) !== nextResolve[key](nextMatch.params)) {
return true; return true;
} }

View file

@ -250,7 +250,7 @@ class RouteContent extends Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
this.registerSidebarAnimationListener(); this.registerSidebarAnimationListener();
if (this.props.match.params !== prevProps.match.params && needsResolve(prevProps.route, this.props.route, prevProps.match, this.props.match)) { if (this.props.location.state !== prevProps.location.state || (this.props.match.params !== prevProps.match.params && needsResolve(prevProps.route, this.props.route, prevProps.match, this.props.match))) {
// noinspection JSIgnoredPromiseFromCall // noinspection JSIgnoredPromiseFromCall
this.resolve(); this.resolve();
} }
@ -332,7 +332,7 @@ class RouteContent extends Component {
} else { } else {
content = ( content = (
<div className="container-fluid"> <div className="container-fluid my-3">
{t('loading')} {t('loading')}
</div> </div>
); );

View file

@ -61,12 +61,15 @@ export default class CUD extends Component {
entity: PropTypes.object entity: PropTypes.object
} }
getFormValuesMutator(data) {
data.form = data.default_form ? 'custom' : 'default';
data.listunsubscribe_disabled = !!data.listunsubscribe_disabled;
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
data.form = data.default_form ? 'custom' : 'default';
data.listunsubscribe_disabled = !!data.listunsubscribe_disabled;
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
name: '', name: '',
@ -110,7 +113,7 @@ export default class CUD extends Component {
validateNamespace(t, state); validateNamespace(t, state);
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -125,7 +128,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
if (data.form === 'default') { if (data.form === 'default') {
data.default_form = null; data.default_form = null;
} }
@ -136,8 +139,22 @@ export default class CUD extends Component {
} }
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage('/lists', 'success', t('listSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/lists', 'success', t('List updated'));
} else {
await this.getFormValuesFromURL(`rest/lists/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('List updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/lists', 'success', t('List created'));
} else {
this.navigateToWithFlashMessage(`/lists/${submitResult}/edit`, 'success', t('List created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -270,7 +287,8 @@ export default class CUD extends Component {
<CheckBox id="listunsubscribe_disabled" label={t('unsubscribeHeader')} text={t('doNotSendListUnsubscribeHeaders')}/> <CheckBox id="listunsubscribe_disabled" label={t('unsubscribeHeader')} text={t('doNotSendListUnsubscribeHeaders')}/>
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -87,50 +87,52 @@ export default class CUD extends Component {
} }
} }
getFormValuesMutator(data) {
data.settings = data.settings || {};
if (data.default_value === null) {
data.default_value = '';
}
data.isInGroup = data.group !== null;
data.enumOptions = '';
data.dateFormat = DateFormat.EUR;
data.renderTemplate = '';
switch (data.type) {
case 'checkbox-grouped':
case 'radio-grouped':
case 'dropdown-grouped':
case 'json':
data.renderTemplate = data.settings.renderTemplate;
break;
case 'radio-enum':
case 'dropdown-enum':
data.enumOptions = this.renderEnumOptions(data.settings.options);
data.renderTemplate = data.settings.renderTemplate;
break;
case 'date':
case 'birthday':
data.dateFormat = data.settings.dateFormat;
break;
case 'option':
data.checkedLabel = data.isInGroup ? '' : data.settings.checkedLabel;
data.uncheckedLabel = data.isInGroup ? '' : data.settings.uncheckedLabel;
break;
}
data.orderListBefore = data.orderListBefore.toString();
data.orderSubscribeBefore = data.orderSubscribeBefore.toString();
data.orderManageBefore = data.orderManageBefore.toString();
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
data.settings = data.settings || {};
if (data.default_value === null) {
data.default_value = '';
}
data.isInGroup = data.group !== null;
data.enumOptions = '';
data.dateFormat = DateFormat.EUR;
data.renderTemplate = '';
switch (data.type) {
case 'checkbox-grouped':
case 'radio-grouped':
case 'dropdown-grouped':
case 'json':
data.renderTemplate = data.settings.renderTemplate;
break;
case 'radio-enum':
case 'dropdown-enum':
data.enumOptions = this.renderEnumOptions(data.settings.options);
data.renderTemplate = data.settings.renderTemplate;
break;
case 'date':
case 'birthday':
data.dateFormat = data.settings.dateFormat;
break;
case 'option':
data.checkedLabel = data.isInGroup ? '' : data.settings.checkedLabel;
data.uncheckedLabel = data.isInGroup ? '' : data.settings.uncheckedLabel;
break;
}
data.orderListBefore = data.orderListBefore.toString();
data.orderSubscribeBefore = data.orderSubscribeBefore.toString();
data.orderManageBefore = data.orderManageBefore.toString();
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
@ -248,7 +250,7 @@ export default class CUD extends Component {
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -264,7 +266,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
if (data.default_value.trim() === '') { if (data.default_value.trim() === '') {
data.default_value = null; data.default_value = null;
} }
@ -317,8 +319,22 @@ export default class CUD extends Component {
} }
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/fields`, 'success', t('fieldSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/fields`, 'success', t('Field updated'));
} else {
await this.getFormValuesFromURL(`rest/fields/${this.props.list.id}/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Field updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/fields`, 'success', t('Field created'));
} else {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/fields/${submitResult}/edit`, 'success', t('Field created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -508,7 +524,8 @@ export default class CUD extends Component {
} }
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -302,20 +302,22 @@ export default class CUD extends Component {
} }
componentDidMount() { supplyDefaults(data) {
function supplyDefaults(data) { for (const key in mailtrainConfig.defaultCustomFormValues) {
for (const key in mailtrainConfig.defaultCustomFormValues) { if (!data[key]) {
if (!data[key]) { data[key] = mailtrainConfig.defaultCustomFormValues[key];
data[key] = mailtrainConfig.defaultCustomFormValues[key];
}
} }
} }
}
getFormValuesMutator(data) {
data.selectedTemplate = 'layout';
this.supplyDefaults(data);
}
componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
data.selectedTemplate = 'layout';
supplyDefaults(data);
});
} else { } else {
const data = { const data = {
@ -324,7 +326,7 @@ export default class CUD extends Component {
selectedTemplate: 'layout', selectedTemplate: 'layout',
namespace: mailtrainConfig.user.namespace namespace: mailtrainConfig.user.namespace
}; };
supplyDefaults(data); this.supplyDefaults(data);
this.populateFormValues(data); this.populateFormValues(data);
} }
@ -370,7 +372,7 @@ export default class CUD extends Component {
} }
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -385,13 +387,27 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
delete data.selectedTemplate; delete data.selectedTemplate;
delete data.previewList; delete data.previewList;
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage('/lists/forms', 'success', t('formsSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/lists/forms', 'success', t('Custom forms updated'));
} else {
await this.getFormValuesFromURL(`rest/forms/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Custom forms updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/lists/forms', 'success', t('Custom forms created'));
} else {
this.navigateToWithFlashMessage(`/lists/forms/${submitResult}/edit`, 'success', t('Custom forms created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -530,7 +546,8 @@ export default class CUD extends Component {
} }
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -18,6 +18,7 @@ import ImportsStatus from './imports/Status';
import ImportRunsStatus from './imports/RunStatus'; import ImportRunsStatus from './imports/RunStatus';
import Share from '../shares/Share'; import Share from '../shares/Share';
import TriggersList from './TriggersList'; import TriggersList from './TriggersList';
import {ellipsizeBreadcrumbLabel} from "../lib/helpers";
function getMenus(t) { function getMenus(t) {
return { return {
@ -27,7 +28,7 @@ function getMenus(t) {
panelComponent: ListsList, panelComponent: ListsList,
children: { children: {
':listId([0-9]+)': { ':listId([0-9]+)': {
title: resolved => t('listName', {name: resolved.list.name}), title: resolved => t('listName', {name: ellipsizeBreadcrumbLabel(resolved.list.name)}),
resolve: { resolve: {
list: params => `rest/lists/${params.listId}` list: params => `rest/lists/${params.listId}`
}, },
@ -78,7 +79,7 @@ function getMenus(t) {
panelRender: props => <FieldsList list={props.resolved.list} />, panelRender: props => <FieldsList list={props.resolved.list} />,
children: { children: {
':fieldId([0-9]+)': { ':fieldId([0-9]+)': {
title: resolved => t('fieldName-1', {name: resolved.field.name}), title: resolved => t('fieldName-1', {name: ellipsizeBreadcrumbLabel(resolved.field.name)}),
resolve: { resolve: {
field: params => `rest/fields/${params.listId}/${params.fieldId}`, field: params => `rest/fields/${params.listId}/${params.fieldId}`,
fields: params => `rest/fields/${params.listId}` fields: params => `rest/fields/${params.listId}`
@ -108,7 +109,7 @@ function getMenus(t) {
panelRender: props => <SegmentsList list={props.resolved.list} />, panelRender: props => <SegmentsList list={props.resolved.list} />,
children: { children: {
':segmentId([0-9]+)': { ':segmentId([0-9]+)': {
title: resolved => t('segmentName', {name: resolved.segment.name}), title: resolved => t('segmentName', {name: ellipsizeBreadcrumbLabel(resolved.segment.name)}),
resolve: { resolve: {
segment: params => `rest/segments/${params.listId}/${params.segmentId}`, segment: params => `rest/segments/${params.listId}/${params.segmentId}`,
fields: params => `rest/fields/${params.listId}` fields: params => `rest/fields/${params.listId}`
@ -138,7 +139,7 @@ function getMenus(t) {
panelRender: props => <ImportsList list={props.resolved.list} />, panelRender: props => <ImportsList list={props.resolved.list} />,
children: { children: {
':importId([0-9]+)': { ':importId([0-9]+)': {
title: resolved => t('importName-1', {name: resolved.import.name}), title: resolved => t('importName-1', {name: ellipsizeBreadcrumbLabel(resolved.import.name)}),
resolve: { resolve: {
import: params => `rest/imports/${params.listId}/${params.importId}`, import: params => `rest/imports/${params.listId}/${params.importId}`,
}, },
@ -198,7 +199,7 @@ function getMenus(t) {
panelComponent: FormsList, panelComponent: FormsList,
children: { children: {
':formsId([0-9]+)': { ':formsId([0-9]+)': {
title: resolved => t('customFormsName', {name: resolved.forms.name}), title: resolved => t('customFormsName', {name: ellipsizeBreadcrumbLabel(resolved.forms.name)}),
resolve: { resolve: {
forms: params => `rest/forms/${params.formsId}` forms: params => `rest/forms/${params.formsId}`
}, },

View file

@ -119,16 +119,18 @@ export default class CUD extends Component {
return tree; return tree;
} }
getFormValuesMutator(data) {
data.rootRuleType = data.settings.rootRule.type;
data.selectedRule = null; // Validation errors of the selected rule are attached to this which makes sure we don't submit the segment if the opened rule has errors
this.setState({
rulesTree: this.getTreeFromRules(data.settings.rootRule.rules)
});
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.setState({ this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
rulesTree: this.getTreeFromRules(this.props.entity.settings.rootRule.rules)
});
this.getFormValuesFromEntity(this.props.entity, data => {
data.rootRuleType = data.settings.rootRule.type;
data.selectedRule = null; // Validation errors of the selected rule are attached to this which makes sure we don't submit the segment if the opened rule has errors
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
@ -159,7 +161,7 @@ export default class CUD extends Component {
} }
} }
async doSubmit(stay) { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -175,7 +177,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
const keep = ['name', 'settings', 'originalHash']; const keep = ['name', 'settings', 'originalHash'];
data.settings.rootRule.type = data.rootRuleType; data.settings.rootRule.type = data.rootRuleType;
@ -184,20 +186,22 @@ export default class CUD extends Component {
delete data.selectedRule; delete data.selectedRule;
}); });
if (submitSuccessful) { if (submitResult) {
if (stay) { if (this.props.entity) {
await this.getFormValuesFromURL(`rest/segments/${this.props.list.id}/${this.props.entity.id}`, data => { if (submitAndLeave) {
data.rootRuleType = data.settings.rootRule.type; this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/segments`, 'success', t('Segment updated'));
data.selectedRule = null; // Validation errors of the selected rule are attached to this which makes sure we don't submit the segment if the opened rule has errors } else {
await this.getFormValuesFromURL(`rest/segments/${this.props.list.id}/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.setState({ this.enableForm();
rulesTree: this.getTreeFromRules(data.settings.rootRule.rules) this.setFormStatusMessage('success', t('Segment updated'));
}); }
});
this.enableForm();
this.setFormStatusMessage('success', t('segmentSaved'));
} else { } else {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/segments`, 'success', t('segmentSaved')); if (submitAndLeave) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/segments`, 'success', t('Segment created'));
} else {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/segments/${submitResult}/edit`, 'success', t('Segment created'));
}
} }
} else { } else {
this.enableForm(); this.enableForm();
@ -208,14 +212,6 @@ export default class CUD extends Component {
} }
} }
async submitAndStay() {
await this.formHandleChangedError(async () => await this.doSubmit(true));
}
async submitAndLeave() {
await this.formHandleChangedError(async () => await this.doSubmit(false));
}
onRulesChanged(rulesTree) { onRulesChanged(rulesTree) {
// This assumes that !this.state.ruleOptionsVisible // This assumes that !this.state.ruleOptionsVisible
this.getFormValue('settings').rootRule.rules = this.getRulesFromTree(rulesTree); this.getFormValue('settings').rootRule.rules = this.getRulesFromTree(rulesTree);
@ -354,7 +350,7 @@ export default class CUD extends Component {
<Title>{isEdit ? t('editSegment') : t('createSegment')}</Title> <Title>{isEdit ? t('editSegment') : t('createSegment')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitAndLeave}> <Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<h3>{t('segmentOptions')}</h3> <h3>{t('segmentOptions')}</h3>
<InputField id="name" label={t('name')} /> <InputField id="name" label={t('name')} />
@ -407,19 +403,12 @@ export default class CUD extends Component {
</div> </div>
<hr/> <hr/>
{isEdit ? <ButtonRow format="wide" className={`col-12 ${styles.toolbar}`}>
<ButtonRow format="wide" className={`col-xs-12 ${styles.toolbar}`}> <Button type="submit" className="btn-primary" icon="check" label={t('save')} onClickAsync={async () => this.submitHandler(false)}/>
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')} onClickAsync={::this.submitAndLeave}/>
<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}`}>
<Button type="submit" className="btn-primary" icon="check" label={t('save')} onClickAsync={::this.submitAndLeave}/>
</ButtonRow>
}
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/lists/${this.props.list.id}/segments/${this.props.entity.id}/delete`}/> }
</ButtonRow>
</div> </div>
); );
} }

View file

@ -69,16 +69,18 @@ export default class CUD extends Component {
entity: PropTypes.object entity: PropTypes.object
} }
getFormValuesMutator(data) {
data.status = data.status.toString();
data.tz = data.tz || '';
for (const fld of this.props.fieldsGrouped) {
this.fieldTypes[fld.type].assignFormData(fld, data);
}
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
data.status = data.status.toString();
data.tz = data.tz || '';
for (const fld of this.props.fieldsGrouped) {
this.fieldTypes[fld.type].assignFormData(fld, data);
}
});
} else { } else {
const data = { const data = {
@ -115,7 +117,7 @@ export default class CUD extends Component {
} }
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -131,7 +133,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
data.status = parseInt(data.status); data.status = parseInt(data.status);
data.tz = data.tz || null; data.tz = data.tz || null;
@ -140,8 +142,22 @@ export default class CUD extends Component {
} }
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions`, 'success', t('susbscriptionSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions`, 'success', t('Subscription updated'));
} else {
await this.getFormValuesFromURL(`rest/subscriptions/${this.props.list.id}/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Subscription updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions`, 'success', t('Subscription created'));
} else {
this.navigateToWithFlashMessage(`/lists/${this.props.list.id}/subscriptions/${submitResult}/edit`, 'success', t('Subscription created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -222,7 +238,8 @@ export default class CUD extends Component {
</AlignedRow> </AlignedRow>
} }
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{isEdit && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -77,19 +77,21 @@ export default class CUD extends Component {
@withAsyncErrorHandler @withAsyncErrorHandler
async loadTreeData() { async loadTreeData() {
const response = await axios.get(getUrl('rest/namespaces-tree')); if (!this.isEditGlobal()) {
const data = response.data; const response = await axios.get(getUrl('rest/namespaces-tree'));
for (const root of data) { const data = response.data;
root.expanded = true; for (const root of data) {
} root.expanded = true;
}
if (this.props.entity && !this.isEditGlobal()) { if (this.props.entity && !this.isEditGlobal()) {
this.removeNsIdSubtree(data); this.removeNsIdSubtree(data);
} }
this.setState({ this.setState({
treeData: data treeData: data
}); });
}
} }
componentDidMount() { componentDidMount() {
@ -103,10 +105,8 @@ export default class CUD extends Component {
}); });
} }
if (!this.isEditGlobal()) { // noinspection JSIgnoredPromiseFromCall
// noinspection JSIgnoredPromiseFromCall this.loadTreeData();
this.loadTreeData();
}
} }
localValidateFormValues(state) { localValidateFormValues(state) {
@ -127,7 +127,7 @@ export default class CUD extends Component {
} }
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -143,10 +143,26 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url); const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url);
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage('/namespaces', 'success', t('namespaceSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/namespaces', 'success', t('Namespace updated'));
} else {
await this.getFormValuesFromURL(`rest/namespaces/${this.props.entity.id}`);
await this.loadTreeData();
this.enableForm();
this.setFormStatusMessage('success', t('Namespace updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/namespaces', 'success', t('Namespace created'));
} else {
this.navigateToWithFlashMessage(`/namespaces/${submitResult}/edit`, 'success', t('Namespace created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -205,7 +221,8 @@ export default class CUD extends Component {
<TreeTableSelect id="namespace" label={t('parentNamespace')} data={this.state.treeData}/>} <TreeTableSelect id="namespace" label={t('parentNamespace')} data={this.state.treeData}/>}
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -4,6 +4,7 @@ import React from 'react';
import CUD from './CUD'; import CUD from './CUD';
import List from './List'; import List from './List';
import Share from '../shares/Share'; import Share from '../shares/Share';
import {ellipsizeBreadcrumbLabel} from "../lib/helpers";
function getMenus(t) { function getMenus(t) {
return { return {
@ -13,7 +14,7 @@ function getMenus(t) {
panelComponent: List, panelComponent: List,
children: { children: {
':namespaceId([0-9]+)': { ':namespaceId([0-9]+)': {
title: resolved => t('namespaceName', {name: resolved.namespace.name}), title: resolved => t('namespaceName', {name: ellipsizeBreadcrumbLabel(resolved.namespace.name)}),
resolve: { resolve: {
namespace: params => `rest/namespaces/${params.namespaceId}` namespace: params => `rest/namespaces/${params.namespaceId}`
}, },

View file

@ -82,13 +82,16 @@ export default class CUD extends Component {
} }
} }
getFormValuesMutator(data) {
for (const key in data.params) {
data[`param_${key}`] = data.params[key];
}
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
for (const key in data.params) {
data[`param_${key}`] = data.params[key];
}
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
name: '', name: '',
@ -145,7 +148,7 @@ export default class CUD extends Component {
validateNamespace(t, state); validateNamespace(t, state);
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
if (this.getFormValue('report_template') && !this.getFormValue('user_fields')) { if (this.getFormValue('report_template') && !this.getFormValue('user_fields')) {
@ -165,7 +168,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
const params = {}; const params = {};
for (const spec of data.user_fields) { for (const spec of data.user_fields) {
@ -178,8 +181,22 @@ export default class CUD extends Component {
data.params = params; data.params = params;
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage('/reports', 'success', t('reportSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/reports', 'success', t('Report updated'));
} else {
await this.getFormValuesFromURL(`rest/reports/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Report updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/reports', 'success', t('Report created'));
} else {
this.navigateToWithFlashMessage(`/reports/${submitResult}/edit`, 'success', t('Report created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -274,7 +291,8 @@ export default class CUD extends Component {
} }
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{canDelete && {canDelete &&
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/reports/${this.props.entity.id}/delete`}/> <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/reports/${this.props.entity.id}/delete`}/>
} }

View file

@ -9,6 +9,7 @@ import ReportTemplatesList from './templates/List';
import Share from '../shares/Share'; import Share from '../shares/Share';
import {ReportState} from '../../../shared/reports'; import {ReportState} from '../../../shared/reports';
import mailtrainConfig from 'mailtrainConfig'; import mailtrainConfig from 'mailtrainConfig';
import {ellipsizeBreadcrumbLabel} from "../lib/helpers";
function getMenus(t) { function getMenus(t) {
@ -19,7 +20,7 @@ function getMenus(t) {
panelComponent: ReportsList, panelComponent: ReportsList,
children: { children: {
':reportId([0-9]+)': { ':reportId([0-9]+)': {
title: resolved => t('reportName-1', {name: resolved.report.name}), title: resolved => t('reportName-1', {name: ellipsizeBreadcrumbLabel(resolved.report.name)}),
resolve: { resolve: {
report: params => `rest/reports/${params.reportId}` report: params => `rest/reports/${params.reportId}`
}, },
@ -66,7 +67,7 @@ function getMenus(t) {
panelComponent: ReportTemplatesList, panelComponent: ReportTemplatesList,
children: { children: {
':templateId([0-9]+)': { ':templateId([0-9]+)': {
title: resolved => t('templateName', {name: resolved.template.name}), title: resolved => t('templateName', {name: ellipsizeBreadcrumbLabel(resolved.template.name)}),
resolve: { resolve: {
template: params => `rest/report-templates/${params.templateId}` template: params => `rest/report-templates/${params.templateId}`
}, },

View file

@ -262,15 +262,7 @@ export default class CUD extends Component {
validateNamespace(t, state); validateNamespace(t, state);
} }
async submitAndStay() { async submitHandler(submitAndLeave) {
await this.formHandleChangedError(async () => await this.doSubmit(true));
}
async submitAndLeave() {
await this.formHandleChangedError(async () => await this.doSubmit(false));
}
async doSubmit(stay) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -285,15 +277,23 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url); const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url);
if (submitSuccessful) { if (submitResult) {
if (stay) { if (this.props.entity) {
await this.getFormValuesFromURL(`rest/report-templates/${this.props.entity.id}`); if (submitAndLeave) {
this.enableForm(); this.navigateToWithFlashMessage('/reports/templates', 'success', t('Report template updated'));
this.setFormStatusMessage('success', t('reportTemplateSaved')); } else {
await this.getFormValuesFromURL(`rest/report-templates/${this.props.entity.id}`);
this.enableForm();
this.setFormStatusMessage('success', t('Report template updated'));
}
} else { } else {
this.navigateToWithFlashMessage('/reports/templates', 'success', t('reportTemplateSaved')); if (submitAndLeave) {
this.navigateToWithFlashMessage('/reports/templates', 'success', t('Report template created'));
} else {
this.navigateToWithFlashMessage(`/reports/templates/${submitResult}/edit`, 'success', t('Report template created'));
}
} }
} else { } else {
this.enableForm(); this.enableForm();
@ -321,7 +321,7 @@ export default class CUD extends Component {
<Title>{isEdit ? t('editReportTemplate') : t('createReportTemplate')}</Title> <Title>{isEdit ? t('editReportTemplate') : t('createReportTemplate')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitAndLeave}> <Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<InputField id="name" label={t('name')}/> <InputField id="name" label={t('name')}/>
<TextArea id="description" label={t('description')}/> <TextArea id="description" label={t('description')}/>
<Dropdown id="mime_type" label={t('type')} options={[{key: 'text/html', label: t('html')}, {key: 'text/csv', label: t('csv')}]}/> <Dropdown id="mime_type" label={t('type')} options={[{key: 'text/html', label: t('html')}, {key: 'text/csv', label: t('csv')}]}/>
@ -330,19 +330,13 @@ export default class CUD extends Component {
<ACEEditor id="js" height="700px" mode="javascript" label={t('dataProcessingCode')} help={<Trans i18nKey="writeTheBodyOfTheJavaScriptFunctionWith">Write the body of the JavaScript function with signature <code>async function(inputs)</code> that returns an object to be rendered by the Handlebars template below.</Trans>}/> <ACEEditor id="js" height="700px" mode="javascript" label={t('dataProcessingCode')} help={<Trans i18nKey="writeTheBodyOfTheJavaScriptFunctionWith">Write the body of the JavaScript function with signature <code>async function(inputs)</code> that returns an object to be rendered by the Handlebars template below.</Trans>}/>
<ACEEditor id="hbs" height="700px" mode="handlebars" label={t('renderingTemplate')} help={<Trans i18nKey="useHtmlWithHandlebarsSyntaxSee">Use HTML with Handlebars syntax. See documentation <a href="http://handlebarsjs.com/">here</a>.</Trans>}/> <ACEEditor id="hbs" height="700px" mode="handlebars" label={t('renderingTemplate')} help={<Trans i18nKey="useHtmlWithHandlebarsSyntaxSee">Use HTML with Handlebars syntax. See documentation <a href="http://handlebarsjs.com/">here</a>.</Trans>}/>
{isEdit ? <ButtonRow>
<ButtonRow> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')}/> {canDelete &&
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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>
</ButtonRow>
:
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
</ButtonRow>
}
</Form> </Form>
</div> </div>
); );

View file

@ -80,15 +80,16 @@ export default class CUD extends Component {
} }
getFormValuesMutator(data) {
this.mailerTypes[data.mailer_type].afterLoad(data);
data.verpEnabled = !!data.verp_hostname;
data.verp_hostname = data.verp_hostname || '';
data.verp_disable_sender_header = data.verpEnabled ? !!data.verp_disable_sender_header : false;
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
this.mailerTypes[data.mailer_type].afterLoad(data);
data.verpEnabled = !!data.verp_hostname;
data.verp_hostname = data.verp_hostname || '';
data.verp_disable_sender_header = data.verpEnabled ? !!data.verp_disable_sender_header : false;
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
name: '', name: '',
@ -142,7 +143,7 @@ export default class CUD extends Component {
} }
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -157,7 +158,7 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
this.mailerTypes[data.mailer_type].beforeSave(data); this.mailerTypes[data.mailer_type].beforeSave(data);
if (!data.verpEnabled) { if (!data.verpEnabled) {
data.verp_hostname = null; data.verp_hostname = null;
@ -165,8 +166,22 @@ export default class CUD extends Component {
} }
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage('/send-configurations', 'success', t('sendConfigurationSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/send-configurations', 'success', t('Send configuration updated'));
} else {
await this.getFormValuesFromURL(`rest/send-configurations-private/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('Send configuration updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/send-configurations', 'success', t('Send configuration created'));
} else {
this.navigateToWithFlashMessage(`/send-configurations/${submitResult}/edit`, 'success', t('Send configuration created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -247,7 +262,8 @@ export default class CUD extends Component {
<hr/> <hr/>
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{canDelete && {canDelete &&
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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`}/>
} }

View file

@ -5,6 +5,7 @@ import React from 'react';
import CUD from './CUD'; import CUD from './CUD';
import List from './List'; import List from './List';
import Share from '../shares/Share'; import Share from '../shares/Share';
import {ellipsizeBreadcrumbLabel} from "../lib/helpers";
function getMenus(t) { function getMenus(t) {
@ -15,7 +16,7 @@ function getMenus(t) {
panelComponent: List, panelComponent: List,
children: { children: {
':sendConfigurationId([0-9]+)': { ':sendConfigurationId([0-9]+)': {
title: resolved => t('templateName', {name: resolved.sendConfiguration.name}), title: resolved => t('templateName', {name: ellipsizeBreadcrumbLabel(resolved.sendConfiguration.name)}),
resolve: { resolve: {
sendConfiguration: params => `rest/send-configurations-private/${params.sendConfigurationId}` sendConfiguration: params => `rest/send-configurations-private/${params.sendConfigurationId}`
}, },

View file

@ -54,7 +54,6 @@ import moment
]) ])
export default class CUD extends Component { export default class CUD extends Component {
constructor(props) { constructor(props) {
console.log('constructor')
super(props); super(props);
this.templateTypes = getTemplateTypes(props.t); this.templateTypes = getTemplateTypes(props.t);
@ -87,13 +86,14 @@ console.log('constructor')
} }
} }
loadFromEntityMutator(data) { getFormValuesMutator(data) {
this.templateTypes[data.type].afterLoad(data); this.templateTypes[data.type].afterLoad(data);
} }
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => this.loadFromEntityMutator(data)); this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
} else { } else {
this.populateFormValues({ this.populateFormValues({
name: '', name: '',
@ -141,7 +141,11 @@ console.log('constructor')
} }
} }
async doSave(stayOnPage) { async save() {
await this.submitHandler();
}
async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let exportedData = {}; let exportedData = {};
@ -162,23 +166,26 @@ console.log('constructor')
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitResponse = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
Object.assign(data, exportedData); Object.assign(data, exportedData);
this.templateTypes[data.type].beforeSave(data); this.templateTypes[data.type].beforeSave(data);
}); });
if (submitResponse) { if (submitResult) {
if (stayOnPage) { if (this.props.entity) {
await this.getFormValuesFromURL(`rest/templates/${this.props.entity.id}`, data => this.loadFromEntityMutator(data)); if (submitAndLeave) {
this.enableForm(); this.navigateToWithFlashMessage('/templates', 'success', t('Template updated'));
this.clearFormStatusMessage(); } else {
this.setFlashMessage('success', t('templateSaved')); await this.getFormValuesFromURL(`rest/templates/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
} else if (this.props.entity) { this.setFormStatusMessage('success', t('Template updated'));
this.navigateToWithFlashMessage('/templates', 'success', t('templateSaved')); }
} else { } else {
this.navigateToWithFlashMessage(`/templates/${submitResponse}/edit`, 'success', t('templateSaved')); if (submitAndLeave) {
this.navigateToWithFlashMessage('/templates', 'success', t('Template created'));
} else {
this.navigateToWithFlashMessage(`/templates/${submitResult}/edit`, 'success', t('Template created'));
}
} }
} else { } else {
this.enableForm(); this.enableForm();
@ -186,14 +193,6 @@ console.log('constructor')
} }
} }
async save() {
await this.doSave(true);
}
async submitHandler() {
await this.doSave(false);
}
async extractPlainText() { async extractPlainText() {
const typeKey = this.getFormValue('type'); const typeKey = this.getFormValue('type');
const exportedData = await this.templateTypes[typeKey].exportHTMLEditorData(this); const exportedData = await this.templateTypes[typeKey].exportHTMLEditorData(this);
@ -325,9 +324,10 @@ console.log('constructor')
{editForm} {editForm}
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={isEdit ? t('save') : t('saveAndEditTemplate')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
{isEdit && <Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>}
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/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})}/> } {isEdit && <Button className="btn-success" icon="at" label={t('testSend')} onClickAsync={async () => this.setState({showTestSendModal: true})}/> }
</ButtonRow> </ButtonRow>
</Form> </Form>
</div> </div>

View file

@ -141,8 +141,8 @@ export class TestSendModalDialog extends Component {
return ( return (
<ModalDialog hidden={!this.props.visible} title={t('sendTestEmail')} onCloseAsync={() => this.hideModal()} buttons={[ <ModalDialog hidden={!this.props.visible} title={t('sendTestEmail')} onCloseAsync={() => this.hideModal()} buttons={[
{ label: t('send'), className: 'btn-danger', onClickAsync: ::this.performAction }, { label: t('send'), className: 'btn-primary', onClickAsync: ::this.performAction },
{ label: t('cancel'), className: 'btn-primary', onClickAsync: ::this.hideModal } { label: t('cancel'), className: 'btn-danger', onClickAsync: ::this.hideModal }
]}> ]}>
<Form stateOwner={this} format="wide"> <Form stateOwner={this} format="wide">
<TableSelect id="sendConfiguration" format="wide" label={t('sendConfiguration')} withHeader dropdown dataUrl='rest/send-configurations-with-send-permission-table' columns={sendConfigurationsColumns} selectionLabelIndex={1} /> <TableSelect id="sendConfiguration" format="wide" label={t('sendConfiguration')} withHeader dropdown dataUrl='rest/send-configurations-with-send-permission-table' columns={sendConfigurationsColumns} selectionLabelIndex={1} />

View file

@ -66,11 +66,13 @@ export default class CUD extends Component {
entity: PropTypes.object entity: PropTypes.object
} }
getFormValuesMutator(data) {
this.templateTypes[data.type].afterLoad(data);
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
this.templateTypes[data.type].afterLoad(data);
});
} else { } else {
const wizard = this.props.wizard; const wizard = this.props.wizard;
@ -114,15 +116,7 @@ export default class CUD extends Component {
validateNamespace(t, state); validateNamespace(t, state);
} }
async submitAndStay() { async submitHandler(submitAndLeave) {
await this.formHandleChangedError(async () => await this.doSubmit(true));
}
async submitAndLeave() {
await this.formHandleChangedError(async () => await this.doSubmit(false));
}
async doSubmit(stay) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -137,19 +131,25 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
this.templateTypes[data.type].beforeSave(data); this.templateTypes[data.type].beforeSave(data);
}); });
if (submitSuccessful) { if (submitResult) {
if (stay) { if (this.props.entity) {
await this.getFormValuesFromURL(`rest/mosaico-templates/${this.props.entity.id}`, data => { if (submitAndLeave) {
this.templateTypes[data.type].afterLoad(data); this.navigateToWithFlashMessage('/templates/mosaico', 'success', t('Mosaico template updated'));
}); } else {
this.enableForm(); await this.getFormValuesFromURL(`rest/mosaico-templates/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.setFormStatusMessage('success', t('mosaicoTemplateSaved')); this.enableForm();
this.setFormStatusMessage('success', t('Mosaico template updated'));
}
} else { } else {
this.navigateToWithFlashMessage('/templates/mosaico', 'success', t('mosaicoTemplateSaved')); if (submitAndLeave) {
this.navigateToWithFlashMessage('/templates/mosaico', 'success', t('Mosaico template created'));
} else {
this.navigateToWithFlashMessage(`/templates/mosaico/${submitResult}/edit`, 'success', t('Mosaico template created'));
}
} }
} else { } else {
this.enableForm(); this.enableForm();
@ -183,7 +183,7 @@ export default class CUD extends Component {
<Title>{isEdit ? t('editMosaicoTemplate') : t('createMosaicoTemplate')}</Title> <Title>{isEdit ? t('editMosaicoTemplate') : t('createMosaicoTemplate')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitAndLeave}> <Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<InputField id="name" label={t('name')}/> <InputField id="name" label={t('name')}/>
<TextArea id="description" label={t('description')}/> <TextArea id="description" label={t('description')}/>
<Dropdown id="type" label={t('type')} options={this.typeOptions}/> <Dropdown id="type" label={t('type')} options={this.typeOptions}/>
@ -191,19 +191,11 @@ export default class CUD extends Component {
{form} {form}
{isEdit ? <ButtonRow>
<ButtonRow> <Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndStay')} onClickAsync={::this.submitAndStay}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')}/> {canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/templates/mosaico/${this.props.entity.id}/delete`}/>}
{canDelete && </ButtonRow>
<LinkButton className="btn-danger" icon="trash-alt" label={t('delete')} to={`/templates/mosaico/${this.props.entity.id}/delete`}/>
}
</ButtonRow>
:
<ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
</ButtonRow>
}
</Form> </Form>
</div> </div>
); );

View file

@ -8,6 +8,7 @@ import Share from '../shares/Share';
import Files from "../lib/files"; import Files from "../lib/files";
import MosaicoCUD from './mosaico/CUD'; import MosaicoCUD from './mosaico/CUD';
import MosaicoList from './mosaico/List'; import MosaicoList from './mosaico/List';
import {ellipsizeBreadcrumbLabel} from "../lib/helpers";
function getMenus(t) { function getMenus(t) {
@ -18,7 +19,7 @@ function getMenus(t) {
panelComponent: TemplatesList, panelComponent: TemplatesList,
children: { children: {
':templateId([0-9]+)': { ':templateId([0-9]+)': {
title: resolved => t('templateName', {name: resolved.template.name}), title: resolved => t('templateName', {name: ellipsizeBreadcrumbLabel(resolved.template.name)}),
resolve: { resolve: {
template: params => `rest/templates/${params.templateId}` template: params => `rest/templates/${params.templateId}`
}, },
@ -54,7 +55,7 @@ function getMenus(t) {
panelComponent: MosaicoList, panelComponent: MosaicoList,
children: { children: {
':mosaiceTemplateId([0-9]+)': { ':mosaiceTemplateId([0-9]+)': {
title: resolved => t('mosaicoTemplateName', {name: resolved.mosaicoTemplate.name}), title: resolved => t('mosaicoTemplateName', {name: ellipsizeBreadcrumbLabel(resolved.mosaicoTemplate.name)}),
resolve: { resolve: {
mosaicoTemplate: params => `rest/mosaico-templates/${params.mosaiceTemplateId}` mosaicoTemplate: params => `rest/mosaico-templates/${params.mosaiceTemplateId}`
}, },

View file

@ -62,12 +62,14 @@ export default class CUD extends Component {
entity: PropTypes.object entity: PropTypes.object
} }
getFormValuesMutator(data) {
data.password = '';
data.password2 = '';
}
componentDidMount() { componentDidMount() {
if (this.props.entity) { if (this.props.entity) {
this.getFormValuesFromEntity(this.props.entity, data => { this.getFormValuesFromEntity(this.props.entity, ::this.getFormValuesMutator);
data.password = '';
data.password2 = '';
});
} else { } else {
this.populateFormValues({ this.populateFormValues({
username: '', username: '',
@ -156,7 +158,7 @@ export default class CUD extends Component {
validateNamespace(t, state); validateNamespace(t, state);
} }
async submitHandler() { async submitHandler(submitAndLeave) {
const t = this.props.t; const t = this.props.t;
let sendMethod, url; let sendMethod, url;
@ -172,12 +174,26 @@ export default class CUD extends Component {
this.disableForm(); this.disableForm();
this.setFormStatusMessage('info', t('saving')); this.setFormStatusMessage('info', t('saving'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => { const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
delete data.password2; delete data.password2;
}); });
if (submitSuccessful) { if (submitResult) {
this.navigateToWithFlashMessage('/users', 'success', t('userSaved')); if (this.props.entity) {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/users', 'success', t('User updated'));
} else {
await this.getFormValuesFromURL(`rest/users/${this.props.entity.id}`, ::this.getFormValuesMutator);
this.enableForm();
this.setFormStatusMessage('success', t('User updated'));
}
} else {
if (submitAndLeave) {
this.navigateToWithFlashMessage('/users', 'success', t('User created'));
} else {
this.navigateToWithFlashMessage(`/users/${submitResult}/edit`, 'success', t('User created'));
}
}
} else { } else {
this.enableForm(); this.enableForm();
this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd')); this.setFormStatusMessage('warning', t('thereAreErrorsInTheFormPleaseFixThemAnd'));
@ -248,7 +264,8 @@ export default class CUD extends Component {
<NamespaceSelect/> <NamespaceSelect/>
<ButtonRow> <ButtonRow>
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/> <Button type="submit" className="btn-primary" icon="check" label={t('Save')}/>
<Button type="submit" className="btn-primary" icon="check" label={t('Save and leave')} onClickAsync={async () => this.submitHandler(true)}/>
{canDelete && <LinkButton className="btn-danger" icon="trash-alt" label={t('deleteUser')} to={`/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> </ButtonRow>
</Form> </Form>

View file

@ -8,6 +8,7 @@ import List
from './List'; from './List';
import UserShares import UserShares
from '../shares/UserShares'; from '../shares/UserShares';
import {ellipsizeBreadcrumbLabel} from "../lib/helpers";
function getMenus(t) { function getMenus(t) {
return { return {
@ -17,7 +18,7 @@ function getMenus(t) {
panelComponent: List, panelComponent: List,
children: { children: {
':userId([0-9]+)': { ':userId([0-9]+)': {
title: resolved => t('userName-1', {name: resolved.user.name}), title: resolved => t('userName-1', {name: ellipsizeBreadcrumbLabel(resolved.user.name)}),
resolve: { resolve: {
user: params => `rest/users/${params.userId}` user: params => `rest/users/${params.userId}`
}, },

View file

@ -357,7 +357,7 @@
"mjml": "MJML", "mjml": "MJML",
"html": "HTML", "html": "HTML",
"countEntriesSelected": "{{ count }} entries selected.", "countEntriesSelected": "{{ count }} entries selected.",
"loading-1": "Loading...", "loading-1": "Loading ...",
"customFormMustBeSelected": "Custom form must be selected", "customFormMustBeSelected": "Custom form must be selected",
"listSaved": "List saved", "listSaved": "List saved",
"onestepIeNoEmailWithConfirmationLink": "One-step (i.e. no email with confirmation link)", "onestepIeNoEmailWithConfirmationLink": "One-step (i.e. no email with confirmation link)",