Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pulls/6/remove deprecated #1168

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions client/dist/js/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/dist/styles/bundle.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/src/boot/registerTransforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import readBlocksForAreaQuery from 'state/editor/readBlocksForAreaQuery';
import addElementToArea from 'state/editor/addElementMutation';
import ArchiveAction from 'components/ElementActions/ArchiveAction';
import DuplicateAction from 'components/ElementActions/DuplicateAction';
import PublishAction from 'components/ElementActions/PublishAction';
import SaveAction from 'components/ElementActions/SaveAction';
import PublishAction from 'components/ElementActions/PublishAction';
import UnpublishAction from 'components/ElementActions/UnpublishAction';

export default () => {
Expand Down
164 changes: 32 additions & 132 deletions client/src/components/ElementActions/PublishAction.js
Original file line number Diff line number Diff line change
@@ -1,121 +1,35 @@
/* global window */
import React from 'react';
import React, { useContext, useEffect } from 'react';
import { compose } from 'redux';
import AbstractAction from 'components/ElementActions/AbstractAction';
import publishBlockMutation from 'state/editor/publishBlockMutation';
import i18n from 'i18n';
import backend from 'lib/Backend';
import { connect } from 'react-redux';
import { loadElementSchemaValue } from 'state/editor/loadElementSchemaValue';
import { loadElementFormStateName } from 'state/editor/loadElementFormStateName';
import { initialize } from 'redux-form';

/**
* Show a toast message reporting whether publication of Element was successful
*
* @param {string} type E.g. "Content" - human friendly element type (not PHP FQCN)
* @param {string} title Title of the element, or a false value if unset (e.g. undefined)
* @param {boolean} success Show a success message (true), or an error message (false)
*/
const reportPublicationStatus = (type, title, success) => {
const noTitle = i18n.inject(
i18n._t('ElementHeader.NOTITLE', 'Untitled {type} block'),
{ type }
);
const successMessage = i18n.inject(
i18n._t('ElementPublishAction.SUCCESS_NOTIFICATION', 'Published \'{title}\' successfully'),
{ title: title || noTitle }
);
const errorMessage = i18n.inject(
i18n._t('ElementPublishAction.ERROR_NOTIFICATION', 'Error publishing \'{title}\''),
{ title: title || noTitle }
);
window.jQuery.noticeAdd({
text: success ? successMessage : errorMessage,
stay: false,
type: success ? 'success' : 'error',
});
};

/**
* Post updated Element data to save it
*
* @param {number} id Element ID
* @param {object} formData Information to be saved
* @param {string} securityId Security ID for form submission
*/
const performSaveForElementWithFormData = (id, formData, securityId) => {
const saveEndpoint = backend.createEndpointFetcher({
url: loadElementSchemaValue('saveUrl', id),
method: loadElementSchemaValue('saveMethod'),
payloadFormat: loadElementSchemaValue('payloadFormat'),
defaultData: {
SecurityID: securityId
},
});

// Perform save & get new version number to publish
return saveEndpoint(formData)
.then(() => window.ss.apolloClient.queryManager.reFetchObservableQueries())
.then((input) => {
const preview = window.jQuery('.cms-preview');
preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src'));
return input;
})
.then((newPageData) => {
const newElementData = newPageData[0] && newPageData[0]
.data
.readOneElementalArea
.elements
.find((elementData) => elementData.id === id);
return newElementData && newElementData.version;
});
};
import { ElementContext } from 'components/ElementEditor/Element';

/**
* Adds the elemental menu action to publish a draft/modified block
*/
const PublishAction = (MenuComponent) => (props) => {
if (props.type.broken) {
// Don't allow this action for a broken element.
return (
<MenuComponent {...props} />
);
}

const { element, formDirty } = props;
const {
doPublishElement,
formDirty,
formHasRendered,
onAfterPublish,
onPublishButtonClick,
} = useContext(ElementContext);

const { element, actions } = props;

const publishElement = () => {
// handlePublishBlock is a graphql mutation defined in publishBlockMutation.js
actions.handlePublishBlock(element.id)
.then(() => onAfterPublish(false))
.catch(() => onAfterPublish(true));
};

const handleClick = (event) => {
event.stopPropagation();

const {
element: {
id,
title,
},
type,
securityId,
formData,
actions: { handlePublishBlock },
reinitialiseForm,
} = props;

let actionFlow = new Promise((resolve) => resolve());

// Edits have been made to the form. Peform a "Save & Publish"
if (formDirty) {
actionFlow = performSaveForElementWithFormData(id, formData, securityId)
.then((passthrough) => {
reinitialiseForm(formData);
return passthrough;
});
}

// Perform publish. Data is assumed to be up to date
actionFlow
.then(() => handlePublishBlock(id))
.then(() => reportPublicationStatus(type.title, title, true))
.catch(() => reportPublicationStatus(type.title, title, false));
onPublishButtonClick();
};

const disabled = props.element.canPublish !== undefined && !props.element.canPublish;
Expand All @@ -132,6 +46,19 @@ const PublishAction = (MenuComponent) => (props) => {
toggle: props.toggle,
};

useEffect(() => {
if (formHasRendered && doPublishElement) {
publishElement();
}
}, [formHasRendered, doPublishElement]);

if (props.type.broken) {
// Don't allow this action for a broken element.
return (
<MenuComponent {...props} />
);
}

return (
<MenuComponent {...props}>
{props.children}
Expand All @@ -140,36 +67,9 @@ const PublishAction = (MenuComponent) => (props) => {
);
};

function mapStateToProps(state, ownProps) {
const formName = loadElementFormStateName(ownProps.element.id);

let formData = null;

if (state.form.formState.element && state.form.formState.element[formName]) {
formData = state.form.formState.element[formName].values;
}

return {
formData,
securityId: state.config.SecurityID,
formDirty: state.unsavedForms.find((unsaved) => unsaved.name === `element.${formName}`),
};
}

function mapDispatchToProps(dispatch, ownProps) {
const formName = loadElementFormStateName(ownProps.element.id);

return {
reinitialiseForm(savedData) {
dispatch(initialize(`element.${formName}`, savedData));
}
};
}

export { PublishAction as Component };

export default compose(
publishBlockMutation,
connect(mapStateToProps, mapDispatchToProps),
PublishAction
);
132 changes: 30 additions & 102 deletions client/src/components/ElementActions/SaveAction.js
Original file line number Diff line number Diff line change
@@ -1,128 +1,56 @@
import React from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import React, { useContext, useEffect } from 'react';
import AbstractAction from 'components/ElementActions/AbstractAction';
import backend from 'lib/Backend';
import i18n from 'i18n';
import { loadElementSchemaValue } from 'state/editor/loadElementSchemaValue';
import { loadElementFormStateName } from 'state/editor/loadElementFormStateName';
import { initialize } from 'redux-form';
import { ElementContext } from 'components/ElementEditor/Element';

/**
* Using a REST backend, serialize the current form data and post it to the backend endpoint to save
* the inline edit form's data for the current block.
*/
const SaveAction = (MenuComponent) => (props) => {
if (!props.expandable || props.type.broken) {
// Some elemental blocks can not be edited inline (e.g. User form blocks)
// We don't want to add a "Save" action for those blocks.
return (
<MenuComponent {...props} />
);
}
const {
doSaveElement,
formHasRendered,
onSaveButtonClick,
onAfterSave,
submitForm
} = useContext(ElementContext);

const handleClick = (event) => {
event.stopPropagation();
onSaveButtonClick();
};

const { element, type, securityId, formData, reinitialiseForm } = props;
const { jQuery: $ } = window;
const noTitle = i18n.inject(
i18n._t(
'ElementHeader.NOTITLE',
'Untitled {type} block'
),
{ type: type.title }
);

const endpointSpec = {
url: loadElementSchemaValue('saveUrl', element.id),
method: loadElementSchemaValue('saveMethod'),
payloadFormat: loadElementSchemaValue('payloadFormat'),
defaultData: {
SecurityID: securityId
},
};

const endpoint = backend.createEndpointFetcher(endpointSpec);
endpoint(formData)
.then(() => {
// Update the Apollo query cache with the new form data
const { apolloClient } = window.ss;

apolloClient.queryManager.reFetchObservableQueries();
reinitialiseForm(formData);

const preview = $('.cms-preview');
preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src'));

const newTitle = formData ? formData[`PageElements_${element.id}_Title`] : null;
$.noticeAdd({
text: i18n.inject(
i18n._t(
'ElementSaveAction.SUCCESS_NOTIFICATION',
'Saved \'{title}\' successfully'
),
{ title: newTitle || noTitle }
),
stay: false,
type: 'success'
});
})
.catch(() => {
$.noticeAdd({
text: i18n.inject(
i18n._t(
'ElementSaveAction.ERROR_NOTIFICATION',
'Error saving \'{title}\''
),
{ title: element.Title || noTitle }
),
stay: false,
type: 'error'
});
});
const saveElement = () => {
submitForm();
onAfterSave();
};

const newProps = {
title: i18n._t('ElementSaveAction.SAVE', 'Save'),
className: 'element-editor__actions-save',
onClick: handleClick,
toggle: props.toggle,
};

useEffect(() => {
if (formHasRendered && doSaveElement) {
saveElement();
}
}, [formHasRendered, doSaveElement]);

if (!props.expandable || props.type.broken) {
// Some elemental blocks can not be edited inline (e.g. User form blocks)
// We don't want to add a "Save" action for those blocks.
return (
<MenuComponent {...props} />
);
}

return (
<MenuComponent {...props}>
{props.children}

<AbstractAction {...newProps} />
</MenuComponent>
);
};

function mapStateToProps(state, ownProps) {
const formName = loadElementFormStateName(ownProps.element.id);

let formData = null;

if (state.form.formState.element && state.form.formState.element[formName]) {
formData = state.form.formState.element[formName].values;
}

return {
formData,
securityId: state.config.SecurityID,
};
}

function mapDispatchToProps(dispatch, ownProps) {
const formName = loadElementFormStateName(ownProps.element.id);

return {
reinitialiseForm(savedData) {
dispatch(initialize(`element.${formName}`, savedData));
}
};
}

export { SaveAction as Component };

export default compose(connect(mapStateToProps, mapDispatchToProps), SaveAction);
export default SaveAction;
Loading
Loading