Skip to content

Commit

Permalink
Merge pull request #1138 from creative-commoners/pulls/5/title-versio…
Browse files Browse the repository at this point in the history
…ned-badge

ENH Versioned badge to elements
  • Loading branch information
emteknetnz authored Jan 31, 2024
2 parents 3bea800 + b23847a commit 5279f12
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 47 deletions.
2 changes: 1 addition & 1 deletion 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: 2 additions & 0 deletions client/lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"ElementHeader.NOTITLE": "Untitled {type} block",
"ElementHeader.STATE_DRAFT": "Item has not been published yet",
"ElementHeader.STATE_MODIFIED": "Item has unpublished changes",
"ElementHeader.BADGE_DRAFT": "Draft",
"ElementHeader.BADGE_MODIFIED": "Modified",
"ElementList.ADD_BLOCKS": "Add blocks to place your content",
"ElementPublishAction.ERROR_NOTIFICATION": "Error publishing '{title}'",
"ElementPublishAction.PUBLISH": "Publish",
Expand Down
57 changes: 37 additions & 20 deletions client/src/components/ElementEditor/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@ import { Tooltip } from 'reactstrap';
import { elementType } from 'types/elementType';
import { elementTypeType } from 'types/elementTypeType';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { inject } from 'lib/Injector';
import i18n from 'i18n';
import classNames from 'classnames';
import { loadElementFormStateName } from 'state/editor/loadElementFormStateName';
import { isDirty } from 'redux-form';
import { DragSource } from 'react-dnd';
import getFormState from 'lib/getFormState';
import { elementDragSource } from 'lib/dragHelpers';
import { getEmptyImage } from 'react-dnd-html5-backend';

Expand Down Expand Up @@ -92,21 +88,17 @@ class Header extends Component {
renderVersionedStateMessage() {
const {
element: { isLiveVersion, isPublished },
formDirty,
} = this.props;

// No indication required for published elements
if (!formDirty && isPublished && isLiveVersion) {
if (isPublished && isLiveVersion) {
return null;
}

let versionStateButtonTitle = '';
const stateClassNames = ['element-editor-header__version-state'];

if (formDirty) {
versionStateButtonTitle = i18n._t('ElementHeader.STATE_UNSAVED', 'Item has unsaved changes');
stateClassNames.push('element-editor-header__version-state--unsaved');
} else if (!isPublished) {
if (!isPublished) {
versionStateButtonTitle = i18n._t('ElementHeader.STATE_DRAFT', 'Item has not been published yet');
stateClassNames.push('element-editor-header__version-state--draft');
} else if (!isLiveVersion) {
Expand All @@ -122,6 +114,40 @@ class Header extends Component {
);
}

renderStatusBadge() {
const {
element: { isLiveVersion, isPublished },
} = this.props;

// No indication required for published elements
if (isPublished && isLiveVersion) {
return null;
}

let versionStateTitle = '';
let versionStateButtonTitle = '';
const stateClassNames = ['badge'];

if (!isPublished) {
versionStateTitle = i18n._t('ElementHeader.BADGE_DRAFT', 'Draft');
versionStateButtonTitle = i18n._t('ElementHeader.STATE_DRAFT', 'Item has not been published yet');
stateClassNames.push('status-addedtodraft');
} else if (!isLiveVersion) {
versionStateTitle = i18n._t('ElementHeader.BADGE_MODIFIED', 'Modified');
versionStateButtonTitle = i18n._t('ElementHeader.STATE_MODIFIED', 'Item has unpublished changes');
stateClassNames.push('status-modified');
}

return (
<span
className={classNames(stateClassNames)}
title={versionStateButtonTitle}
>
{versionStateTitle}
</span>
);
}

render() {
const {
connectDragSource,
Expand Down Expand Up @@ -183,6 +209,7 @@ class Header extends Component {
</Tooltip>}
</div>
<h3 className={titleClasses}>{title}</h3>
{this.renderStatusBadge()}
</div>
{!simple && <div className="element-editor-header__actions">
<div role="none" onClick={(event) => event.stopPropagation()}>
Expand Down Expand Up @@ -218,7 +245,6 @@ Header.propTypes = {
ElementActionsComponent: PropTypes.elementType,
previewExpanded: PropTypes.bool,
disableTooltip: PropTypes.bool,
formDirty: PropTypes.bool,
connectDragSource: PropTypes.func.isRequired,
connectDragPreview: PropTypes.func.isRequired,
onDragEnd: PropTypes.func, // eslint-disable-line react/no-unused-prop-types
Expand All @@ -228,22 +254,13 @@ Header.defaultProps = {
expandable: true,
};

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

return {
formDirty: isDirty(`element.${formName}`, getFormState)(state),
};
}

export { Header as Component };

export default compose(
DragSource('element', elementDragSource, connector => ({
connectDragSource: connector.dragSource(),
connectDragPreview: connector.dragPreview(),
})),
connect(mapStateToProps),
inject(
['ElementActions'],
(ElementActionsComponent) => ({
Expand Down
12 changes: 7 additions & 5 deletions client/src/components/ElementEditor/Header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@

&__info {
max-width: calc(100% - 60px);

.badge {
color: $state-draft;
background-color: $state-modified-bg;
padding: 2px 3px 2px 4px;
margin-left: 0.5rem;
}
}

&__actions {
Expand Down Expand Up @@ -69,11 +76,6 @@
width: 8px;
z-index: 1;

&--unsaved {
background-color: $link-color;
border: 1px solid $link-hover-color;
}

&--draft {
background-color: $state-draft-bg;
}
Expand Down
34 changes: 34 additions & 0 deletions client/src/components/ElementEditor/tests/Header-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,37 @@ test('Header should not render a versioned state message when the element is pub
/>);
expect(container.querySelectorAll('.element-editor-header__version-state')).toHaveLength(0);
});

test('Header should render a versioned draft badge when the element is not published', () => {
const { container } = render(<Header {...makeProps({
element: {
id: '14',
isPublished: false,
liveVersion: false
}
})}
/>);
expect(
container
.querySelector('.element-editor-header__info')
.querySelector('.badge.status-addedtodraft')
.getAttribute('title')
).toContain('Item has not been published yet');
});

test('Header should render a versioned modified badge when the element is modified and not published', () => {
const { container } = render(<Header {...makeProps({
element: {
id: '14',
isPublished: true,
isLiveVersion: false
}
})}
/>);
expect(
container
.querySelector('.element-editor-header__info')
.querySelector('.badge.status-modified')
.getAttribute('title')
).toContain('Item has unpublished changes');
});
3 changes: 1 addition & 2 deletions docs/en/userguide/edit_content.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ An **Add block** button shown as a bar and plus icon can be activated by moving

States are shown on the block type icon as coloured indicators. Each represents the current workflow status your content block is in.

Blue - The block has unsaved changes.
Orange full - The block state is **Draft** and not publicly visible.
Orange full - The block state is **Draft** if the block has unsaved changes or it is not publicly visible.
Orange outline - The block is **Modified** where it has been published but has some additional draft changes.
No state - The block is published.

Expand Down
24 changes: 12 additions & 12 deletions tests/Behat/features/multiple-wysiwyg-configs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ Feature: multiple elemental blocks with different HTMLEditorConfig instances
Given I see a list of blocks
# Check the link menu in the WYSIWYG "insert link" button is correct for block 1
When I click on block 1
And I click on the "#Form_ElementForm_1 button[aria-label^='Insert link']" element
Then I should see "Page on this site" in the ".tox-menu" element
And I should see "Link to a file" in the ".tox-menu" element
And I should see "Link to external URL" in the ".tox-menu" element
And I should see "Anchor on a page" in the ".tox-menu" element
And I should see "Link to email address" in the ".tox-menu" element
And I click on the "#Form_ElementForm_1 [aria-label^='Insert link'] button" element
Then I should see "Page on this site" in the ".mce-menu.mce-in" element
And I should see "Link to a file" in the ".mce-menu.mce-in" element
And I should see "Link to external URL" in the ".mce-menu.mce-in" element
And I should see "Anchor on a page" in the ".mce-menu.mce-in" element
And I should see "Link to email address" in the ".mce-menu.mce-in" element
# Check the link menu in the WYSIWYG "insert link" button is correct for block 2
When I click on block 2
# In CI, the mouse position just happens to produce a tooltip that stops us clicking on the insert link button
# so we have to move the mouse somewhere else to avoid that
And I click on the "input[type='text']" element
And I click on the "#Form_ElementForm_2 button[aria-label^='Insert link']" element
Then I should see "Page on this site" in the ".tox-menu" element
And I should see "Link to a file" in the ".tox-menu" element
And I should see "Link to external URL" in the ".tox-menu" element
And I should see "Anchor on a page" in the ".tox-menu" element
And I should see "Link to email address" in the ".tox-menu" element
And I click on the "#Form_ElementForm_2 [aria-label^='Insert link'] button" element
Then I should see "Page on this site" in the ".mce-menu.mce-in" element
And I should see "Link to a file" in the ".mce-menu.mce-in" element
And I should see "Link to external URL" in the ".mce-menu.mce-in" element
And I should see "Anchor on a page" in the ".mce-menu.mce-in" element
And I should see "Link to email address" in the ".mce-menu.mce-in" element
# Check the content of both WYSIWYG fields is correct
And the "Content" field for block 1 should contain "<p>Some content</p>"
And the "Content" field for block 2 should contain "<p>completely different stuff</p>"
Expand Down
12 changes: 6 additions & 6 deletions tests/Behat/features/validation-failure.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ Feature: Don't lose content when page or block is invalid
And I left click on "Blocks Page" in the tree
Then I should see a list of blocks
And I should see "Alice's Block"
And I should not see the ".element-editor-header__version-state--unsaved" element
And I should see the ".element-editor-header__version-state--draft" element
When I click on the caret button for block 1
And I fill in "<p>New sample content</p>" for "Content" for block 1
And I fill in "Charlie's Block" for "Title" for block 1
And I press the "Save" button
Then I should see a "Validation error" error toast
And I should see "Page is invalid"
And I should see the ".element-editor-header__version-state--unsaved" element
And I should see the ".element-editor-header__version-state--draft" element
When I click on the caret button for block 1
Then the "Content" field for block 1 should contain "New sample content"
And the "Title" field for block 1 should contain "Charlie's Block"
And I should see the ".element-editor-header__version-state--unsaved" element
And I should see the ".element-editor-header__version-state--draft" element

@unsavedChanges
Scenario: If a block is invalid, changes aren't lost
Expand All @@ -38,15 +38,15 @@ Feature: Don't lose content when page or block is invalid
And I left click on "Blocks Page" in the tree
Then I should see a list of blocks
And I should see "Alice's Block"
And I should not see the ".element-editor-header__version-state--unsaved" element
And I should see the ".element-editor-header__version-state--draft" element
When I click on the caret button for block 1
And I fill in "<p>New sample content</p>" for "Content" for block 1
And I fill in "Charlie's Block" for "Title" for block 1
And I press the "Save" button
Then I should see a "Validation error" error toast
And I should see "ElementContent is invalid"
And I should see the ".element-editor-header__version-state--unsaved" element
And I should see the ".element-editor-header__version-state--draft" element
When I click on the caret button for block 1
Then the "Content" field for block 1 should contain "New sample content"
And the "Title" field for block 1 should contain "Charlie's Block"
And I should see the ".element-editor-header__version-state--unsaved" element
And I should see the ".element-editor-header__version-state--draft" element
45 changes: 45 additions & 0 deletions tests/Behat/features/versioned-status-block-element.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@javascript
Feature: Add elements in the CMS and see currunt status of elements
As a CMS user
I want to see versined status of Element blocks

Background:
Given I add an extension "DNADesign\Elemental\Extensions\ElementalPageExtension" to the "Page" class
And a "page" "Blocks Page"
And the "group" "EDITOR" has permissions "Access to 'Pages' section"
And I am logged in as a member of "EDITOR" group
# Remove with 'And I click "Blocks Page" in the ".breadcrumbs-wrapper" element' once the ElementalArea refreshes,
# See https://github.com/dnadesign/silverstripe-elemental/issues/320
And I go to "/admin/pages"
And I left click on "Blocks Page" in the tree

# Test that the versioned badge is shown when there are some changes in the block
Scenario: I can add elements to the page and see versioned badge
Then I press the "Add block" button
Then I press the "Content" button in the add block popover
Then I should see "Untitled Content block" as the title for block 1

# Block 1 is not published or saved yet, so it should be draft
And I should see "Draft" in the ".element-editor-header__info .badge" element
Then I click on block 1
Then I fill in "<p>New Content</p>" for "Content" for block 1
Then I press the "Publish" button
And I wait 1 second

# Block 1 is published, so it should not have a badge
Then I should not see a ".element-editor-header__info .badge" element
Then I click on block 1
Then I fill in "<p>Updated Content</p>" for "Content" for block 1

# Block 1 is modified and has unsaved changes, so it should not have a badge
And I should not see a ".element-editor-header__info .badge" element
Then I press the "Save" button
And I wait 1 second

# Block 1 is modified and has saved changes, so it should be modified
And I should see "Modified" in the ".element-editor-header__info .badge" element
And I wait 1 second
Then I press the "Publish" button

# Block 1 is published, so it should not have a badge
And I should not see a ".element-editor-header__info .badge" element

0 comments on commit 5279f12

Please sign in to comment.