RC1 of confirmation dialogs displayed when one navigates from a page with unsaved changes.
Fixes in Share and UserShare.
This commit is contained in:
parent
c4b78c4823
commit
e064948838
6 changed files with 172 additions and 109 deletions
|
@ -1099,9 +1099,8 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
data.originalHash = data.hash;
|
||||
delete data.hash;
|
||||
|
||||
const mutator = this.getFormValuesMutator;
|
||||
if (mutator) {
|
||||
mutator(data);
|
||||
if (this.getFormValuesMutator) {
|
||||
this.getFormValuesMutator(data);
|
||||
}
|
||||
|
||||
this.populateFormValues(data);
|
||||
|
@ -1126,9 +1125,8 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
data.originalHash = data.hash;
|
||||
delete data.hash;
|
||||
|
||||
const mutator = this.getFormValuesMutator;
|
||||
if (mutator) {
|
||||
const newData = mutator(data);
|
||||
if (this.getFormValuesMutator) {
|
||||
const newData = this.getFormValuesMutator(data);
|
||||
|
||||
if (newData !== undefined) {
|
||||
data = newData;
|
||||
|
@ -1157,9 +1155,8 @@ const withForm = createComponentMixin([], [], (TargetClass, InnerClass) => {
|
|||
|
||||
let data = this.getFormValues();
|
||||
|
||||
const mutator = this.submitFormValuesMutator;
|
||||
if (mutator) {
|
||||
const newData = mutator(data);
|
||||
if (this.submitFormValuesMutator) {
|
||||
const newData = this.submitFormValuesMutator(data);
|
||||
if (newData !== undefined) {
|
||||
data = newData;
|
||||
}
|
||||
|
|
|
@ -197,10 +197,22 @@ export function tableRestActionDialogInit(owner) {
|
|||
|
||||
|
||||
function _hide(owner, dontRefresh = false) {
|
||||
owner.tableRestActionDialogData = {};
|
||||
const refreshTables = owner.tableRestActionDialogData.refreshTables;
|
||||
|
||||
owner.setState({ tableRestActionDialogShown: false });
|
||||
|
||||
if (!dontRefresh) {
|
||||
owner.table.refresh();
|
||||
owner.tableRestActionDialogData = {};
|
||||
|
||||
if (refreshTables) {
|
||||
refreshTables();
|
||||
} else {
|
||||
owner.table.refresh();
|
||||
}
|
||||
} else {
|
||||
// _hide is called twice: (1) at performing action, and at (2) success. Here we keep the refreshTables
|
||||
// reference till it is really needed in step #2.
|
||||
owner.tableRestActionDialogData = { refreshTables };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,14 +280,19 @@ export function tableAddRestActionButton(actions, owner, action, button, title,
|
|||
actionData: action.data,
|
||||
actionInProgressMsg: actionInProgressMsg,
|
||||
actionDoneMsg: actionDoneMsg,
|
||||
onErrorAsync: onErrorAsync
|
||||
onErrorAsync: onErrorAsync,
|
||||
refreshTables: action.refreshTables
|
||||
};
|
||||
|
||||
owner.setState({
|
||||
tableRestActionDialogShown: true
|
||||
});
|
||||
|
||||
owner.table.refresh();
|
||||
if (action.refreshTables) {
|
||||
action.refreshTables();
|
||||
} else {
|
||||
owner.table.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,18 +4,16 @@ import React, {Component} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {withTranslation} from '../lib/i18n';
|
||||
import {requiresAuthenticatedUser, Title, withPageHelpers} from '../lib/page';
|
||||
import {withAsyncErrorHandler, withErrorHandling} from '../lib/error-handling';
|
||||
import {Button, ButtonRow, Form, FormSendMethod, TableSelect, withForm, withFormErrorHandlers} from '../lib/form';
|
||||
import {Table} from '../lib/table';
|
||||
import axios from '../lib/axios';
|
||||
import {HTTPMethod} from '../lib/axios';
|
||||
import mailtrainConfig from 'mailtrainConfig';
|
||||
import {getUrl} from "../lib/urls";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import {tableAddRestActionButton, tableRestActionDialogInit, tableRestActionDialogRender} from "../lib/modals";
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
withForm,
|
||||
withErrorHandling,
|
||||
withPageHelpers,
|
||||
requiresAuthenticatedUser
|
||||
])
|
||||
|
@ -23,9 +21,13 @@ export default class Share extends Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
|
||||
this.initForm({
|
||||
leaveConfirmation: false
|
||||
});
|
||||
|
||||
tableRestActionDialogInit(this);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -34,19 +36,6 @@ export default class Share extends Component {
|
|||
entityTypeId: PropTypes.string
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async deleteShare(userId) {
|
||||
const data = {
|
||||
entityTypeId: this.props.entityTypeId,
|
||||
entityId: this.props.entity.id,
|
||||
userId
|
||||
};
|
||||
|
||||
await axios.put(getUrl('rest/shares'), data);
|
||||
this.sharesTable.refresh();
|
||||
this.usersTableSelect.refresh();
|
||||
}
|
||||
|
||||
clearShareFields() {
|
||||
this.populateFormValues({
|
||||
entityTypeId: this.props.entityTypeId,
|
||||
|
@ -116,15 +105,37 @@ export default class Share extends Component {
|
|||
const autoGenerated = data[4];
|
||||
|
||||
if (!autoGenerated) {
|
||||
actions.push({
|
||||
label: 'Delete',
|
||||
action: () => this.deleteShare(data[3])
|
||||
});
|
||||
const username = data[0];
|
||||
const userId = data[3];
|
||||
|
||||
tableAddRestActionButton(
|
||||
actions,
|
||||
this,
|
||||
{
|
||||
method: HTTPMethod.PUT,
|
||||
url: 'rest/shares',
|
||||
data: {
|
||||
entityTypeId: this.props.entityTypeId,
|
||||
entityId: this.props.entity.id,
|
||||
userId
|
||||
},
|
||||
refreshTables: () => {
|
||||
this.sharesTable.refresh();
|
||||
this.usersTableSelect.refresh();
|
||||
}
|
||||
},
|
||||
{ icon: 'trash-alt', label: t('Unshare') },
|
||||
t('Confirm Unsharing'),
|
||||
t('Are you sure you want to remove the share to user "{{username}}"?', {username}),
|
||||
t('Removing share for user "{{username}}"', {username}),
|
||||
t('Share for user "{{username}}" removed', {username}),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let usersLabelIndex = 1;
|
||||
const usersColumns = [
|
||||
|
@ -146,6 +157,7 @@ export default class Share extends Component {
|
|||
|
||||
return (
|
||||
<div>
|
||||
{tableRestActionDialogRender(this)}
|
||||
<Title>{this.props.title}</Title>
|
||||
|
||||
<h3 className="legend">{t('addUser')}</h3>
|
||||
|
|
|
@ -4,16 +4,13 @@ import React, {Component} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {withTranslation} from '../lib/i18n';
|
||||
import {requiresAuthenticatedUser, Title, withPageHelpers} from '../lib/page';
|
||||
import {withAsyncErrorHandler, withErrorHandling} from '../lib/error-handling';
|
||||
import {Table} from '../lib/table';
|
||||
import axios from '../lib/axios';
|
||||
import {Icon} from "../lib/bootstrap-components";
|
||||
import {getUrl} from "../lib/urls";
|
||||
import {HTTPMethod} from '../lib/axios';
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import {tableAddRestActionButton, tableRestActionDialogInit, tableRestActionDialogRender} from "../lib/modals";
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
withErrorHandling,
|
||||
withPageHelpers,
|
||||
requiresAuthenticatedUser
|
||||
])
|
||||
|
@ -22,33 +19,19 @@ export default class UserShares extends Component {
|
|||
super(props);
|
||||
|
||||
this.sharesTables = {};
|
||||
|
||||
this.state = {};
|
||||
tableRestActionDialogInit(this);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
user: PropTypes.object
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async deleteShare(entityTypeId, entityId) {
|
||||
const data = {
|
||||
entityTypeId,
|
||||
entityId,
|
||||
userId: this.props.user.id
|
||||
};
|
||||
|
||||
await axios.put(getUrl('rest/shares'), data);
|
||||
for (const key in this.sharesTables) {
|
||||
this.sharesTables[key].refresh();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
|
||||
const renderSharesTable = (entityTypeId, title) => {
|
||||
const renderSharesTable = (entityTypeId, title, typeName) => {
|
||||
const columns = [
|
||||
{ data: 0, title: t('name') },
|
||||
{ data: 1, title: t('role') },
|
||||
|
@ -59,10 +42,33 @@ export default class UserShares extends Component {
|
|||
const perms = data[4];
|
||||
|
||||
if (!autoGenerated && perms.includes('share')) {
|
||||
actions.push({
|
||||
label: <Icon icon="trash-alt" title={t('remove')}/>,
|
||||
action: () => this.deleteShare(entityTypeId, data[2])
|
||||
});
|
||||
const name = data[0];
|
||||
const entityId = data[2];
|
||||
|
||||
tableAddRestActionButton(
|
||||
actions,
|
||||
this,
|
||||
{
|
||||
method: HTTPMethod.PUT,
|
||||
url: 'rest/shares',
|
||||
data: {
|
||||
entityTypeId,
|
||||
entityId,
|
||||
userId: this.props.user.id
|
||||
},
|
||||
refreshTables: () => {
|
||||
for (const key in this.sharesTables) {
|
||||
this.sharesTables[key].refresh();
|
||||
}
|
||||
}
|
||||
},
|
||||
{ icon: 'trash-alt', label: t('Unshare') },
|
||||
t('Confirm Unsharing'),
|
||||
t('Are you sure you want to remove the sharing of the {{typeName}} "{{name}}"?', {typeName, name}),
|
||||
t('Removing sharing of the {{typeName}} "{{name}}"', {typeName, name}),
|
||||
t('Sharing of the {{typeName}} "{{name}}" removed', {typeName, name}),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return actions;
|
||||
|
@ -80,17 +86,18 @@ export default class UserShares extends Component {
|
|||
|
||||
return (
|
||||
<div>
|
||||
{tableRestActionDialogRender(this)}
|
||||
<Title>{t('sharesForUserUsername', {username: this.props.user.username})}</Title>
|
||||
|
||||
{renderSharesTable('namespace', t('namespaces'))}
|
||||
{renderSharesTable('list', t('lists'))}
|
||||
{renderSharesTable('template', t('Templates'))}
|
||||
{renderSharesTable('mosaicoTemplate', t('Mosaico Templates'))}
|
||||
{renderSharesTable('campaign', t('Campaigns'))}
|
||||
{renderSharesTable('customForm', t('customForms-1'))}
|
||||
{renderSharesTable('report', t('reports'))}
|
||||
{renderSharesTable('reportTemplate', t('reportTemplates'))}
|
||||
{renderSharesTable('sendConfiguration', t('Send Configurations'))}
|
||||
{renderSharesTable('namespace', t('namespaces'), t('namespace_lc'))}
|
||||
{renderSharesTable('list', t('lists'), t('list_lc'))}
|
||||
{renderSharesTable('template', t('Templates'), t('template_lc'))}
|
||||
{renderSharesTable('mosaicoTemplate', t('Mosaico Templates'), t('Mosaico template'))}
|
||||
{renderSharesTable('campaign', t('Campaigns'), t('campaign_lc'))}
|
||||
{renderSharesTable('customForm', t('customForms-1', t('custom forms')))}
|
||||
{renderSharesTable('report', t('reports'), t('report_lc'))}
|
||||
{renderSharesTable('reportTemplate', t('reportTemplates'), t('report template'))}
|
||||
{renderSharesTable('sendConfiguration', t('Send Configurations'), t('send configuration'))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -103,14 +103,19 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
|
|||
/>
|
||||
</AlignedRow>,
|
||||
exportHTMLEditorData: async owner => {
|
||||
const {html, metadata, model} = await owner.editorNode.exportState();
|
||||
return {
|
||||
[prefix + 'html']: html,
|
||||
[prefix + 'mosaicoData']: {
|
||||
metadata,
|
||||
model
|
||||
}
|
||||
};
|
||||
const state = await owner.editorNode.exportState();
|
||||
// If the sandbox is still loading, the exportState returns null.
|
||||
if (state) {
|
||||
return {
|
||||
[prefix + 'html']: state.html,
|
||||
[prefix + 'mosaicoData']: {
|
||||
metadata: state.metadata,
|
||||
model: state.model
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
exportContent: async (owner, contentType) => {
|
||||
const {html, metadata, model} = await owner.editorNode.exportState();
|
||||
|
@ -184,14 +189,19 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
|
|||
/>
|
||||
</AlignedRow>,
|
||||
exportHTMLEditorData: async owner => {
|
||||
const {html, metadata, model} = await owner.editorNode.exportState();
|
||||
return {
|
||||
[prefix + 'html']: html,
|
||||
[prefix + 'mosaicoData']: {
|
||||
metadata,
|
||||
model
|
||||
}
|
||||
};
|
||||
const state = await owner.editorNode.exportState();
|
||||
// If the sandbox is still loading, the exportState returns null.
|
||||
if (state) {
|
||||
return {
|
||||
[prefix + 'html']: state.html,
|
||||
[prefix + 'mosaicoData']: {
|
||||
metadata: state.metadata,
|
||||
model: state.model
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
exportContent: async (owner, contentType) => {
|
||||
const {html, metadata, model} = await owner.editorNode.exportState();
|
||||
|
@ -265,14 +275,19 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
|
|||
/>
|
||||
</AlignedRow>,
|
||||
exportHTMLEditorData: async owner => {
|
||||
const {html, source, style} = await owner.editorNode.exportState();
|
||||
return {
|
||||
[prefix + 'html']: html,
|
||||
[prefix + 'grapesJSData']: {
|
||||
source,
|
||||
style
|
||||
}
|
||||
};
|
||||
const state = await owner.editorNode.exportState();
|
||||
// If the sandbox is still loading, the exportState returns null.
|
||||
if (state) {
|
||||
return {
|
||||
[prefix + 'html']: state.html,
|
||||
[prefix + 'grapesJSData']: {
|
||||
source: state.source,
|
||||
style: state.style
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
exportContent: async (owner, contentType) => {
|
||||
const {html, source, style} = await owner.editorNode.exportState();
|
||||
|
@ -326,13 +341,18 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
|
|||
/>
|
||||
</AlignedRow>,
|
||||
exportHTMLEditorData: async owner => {
|
||||
const {html, source} = await owner.editorNode.exportState();
|
||||
return {
|
||||
[prefix + 'html']: html,
|
||||
[prefix + 'ckeditor4Data']: {
|
||||
source
|
||||
}
|
||||
};
|
||||
const state = await owner.editorNode.exportState();
|
||||
// If the sandbox is still loading, the exportState returns null.
|
||||
if (state) {
|
||||
return {
|
||||
[prefix + 'html']: state.html,
|
||||
[prefix + 'ckeditor4Data']: {
|
||||
source: state.source
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
exportContent: async (owner, contentType) => {
|
||||
const {html, source} = await owner.editorNode.exportState();
|
||||
|
@ -401,13 +421,18 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
|
|||
/>
|
||||
</AlignedRow>,
|
||||
exportHTMLEditorData: async owner => {
|
||||
const {html, source} = await owner.editorNode.exportState();
|
||||
return {
|
||||
[prefix + 'html']: html,
|
||||
[prefix + 'codeEditorData']: {
|
||||
source
|
||||
}
|
||||
};
|
||||
const state = await owner.editorNode.exportState();
|
||||
// If the sandbox is still loading, the exportState returns null.
|
||||
if (state) {
|
||||
return {
|
||||
[prefix + 'html']: state.html,
|
||||
[prefix + 'codeEditorData']: {
|
||||
source: state.source
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
exportContent: async (owner, contentType) => {
|
||||
const {html, source} = await owner.editorNode.exportState();
|
||||
|
|
|
@ -125,6 +125,7 @@
|
|||
"editRssCampaign": "Edit RSS Campaign",
|
||||
"editTriggeredCampaign": "Edit Triggered Campaign",
|
||||
"template": "Template",
|
||||
"template_lc": "template",
|
||||
"template_plural": "Templates",
|
||||
"customContentClonedFromTemplate": "Custom content cloned from template",
|
||||
"customContentClonedFromAnotherCampaign": "Custom content cloned from another campaign",
|
||||
|
@ -147,6 +148,7 @@
|
|||
"subscribers": "Subscribers",
|
||||
"description": "Description",
|
||||
"namespace": "Namespace",
|
||||
"namespace_lc": "namespace",
|
||||
"namespace_plural": "Namespaces",
|
||||
"namespaceFiltering": "Namespace filtering",
|
||||
"remove": "Remove",
|
||||
|
@ -154,6 +156,7 @@
|
|||
"moveUp": "Move up",
|
||||
"moveDown": "Move down",
|
||||
"list": "List",
|
||||
"list_lc": "list",
|
||||
"list_plural": "Lists",
|
||||
"segment": "Segment",
|
||||
"useAParticularSegment": "Use a particular segment",
|
||||
|
@ -170,6 +173,7 @@
|
|||
"contentSource": "Content source",
|
||||
"selectingATemplateCreatesACampaign": "Selecting a template creates a campaign specific copy from it.",
|
||||
"campaign": "Campaign",
|
||||
"campaign_lc": "campaign",
|
||||
"campaign_plural": "Campaigns",
|
||||
"contentOfTheSelectedCampaignWillBeCopied": "Content of the selected campaign will be copied into this campaign.",
|
||||
"renderUrl": "Render URL",
|
||||
|
@ -350,6 +354,7 @@
|
|||
"itSeemsThatSomeoneElseHasDeletedThe-1": "It seems that someone else has deleted the entity in the meantime.",
|
||||
"customForms": "Custom forms",
|
||||
"report": "Report",
|
||||
"report_lc": "report",
|
||||
"report_plural": "Reports",
|
||||
"reportTemplate": "Report template",
|
||||
"reportTemplate_plural": "Report templates",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue