Skip to content

Commit

Permalink
Custom Fields option: Add confirmation step (#15688)
Browse files Browse the repository at this point in the history
* Add confirmation step to Custom Fields option

Add a confirmation step to the Custom Fields option so that the page
doesn't reload without warning.

Co-authored-by: Marek Hrabe <marekhrabe@me.com>

* Update E2E tests for new Custom Fields setting flow

* Remove notice in favor of plain text.

* Custom Fields option: Adjust margin to align text

* update description

Co-Authored-By: Daniel Richards <daniel.richards@automattic.com>

* simplify change handler

* add dynamic button based on the next state to be saved

* add notice about saved content and make sure it won't expand modal

* update snapshot with new button label and confirm msg

* make button label in test dynamic

* simplify condition for determining label

Co-Authored-By: Robert Anderson <robert@noisysocks.com>

* use willEnable as the prop name
  • Loading branch information
marekhrabe authored and gziolo committed Aug 29, 2019
1 parent 693b395 commit f160e16
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 92 deletions.
4 changes: 3 additions & 1 deletion packages/e2e-tests/specs/preview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ async function toggleCustomFieldsOption( shouldBeChecked ) {
);

if ( isChecked !== shouldBeChecked ) {
const navigationCompleted = page.waitForNavigation();
await checkboxHandle.click();
const [ saveButton ] = await page.$x( shouldBeChecked ? '//button[text()="Enable & Reload"]' : '//button[text()="Disable & Reload"]' );
const navigationCompleted = page.waitForNavigation();
saveButton.click();
await navigationCompleted;
return;
}
Expand Down
16 changes: 9 additions & 7 deletions packages/edit-post/src/components/options-modal/options/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
*/
import { CheckboxControl } from '@wordpress/components';

function BaseOption( { label, isChecked, onChange } ) {
function BaseOption( { label, isChecked, onChange, children } ) {
return (
<CheckboxControl
className="edit-post-options-modal__option"
label={ label }
checked={ isChecked }
onChange={ onChange }
/>
<div className="edit-post-options-modal__option">
<CheckboxControl
label={ label }
checked={ isChecked }
onChange={ onChange }
/>
{ children }
</div>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { withSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import BaseOption from './base';

export class EnableCustomFieldsOption extends Component {
constructor( { isChecked } ) {
super( ...arguments );

this.toggleCustomFields = this.toggleCustomFields.bind( this );

this.state = { isChecked };
}

toggleCustomFields() {
// Submit a hidden form which triggers the toggle_custom_fields admin action.
// This action will toggle the setting and reload the editor with the meta box
// assets included on the page.
document.getElementById( 'toggle-custom-fields-form' ).submit();

// Make it look like something happened while the page reloads.
this.setState( { isChecked: ! this.props.isChecked } );
}

render() {
const { label } = this.props;
const { isChecked } = this.state;
export function CustomFieldsConfirmation( { willEnable } ) {
const [ isReloading, setIsReloading ] = useState( false );

return (
<>
<p className="edit-post-options-modal__custom-fields-confirmation-message">
{ __( 'A page reload is required for this change. Make sure your content is saved before reloading.' ) }
</p>
<Button
className="edit-post-options-modal__custom-fields-confirmation-button"
isDefault
isBusy={ isReloading }
disabled={ isReloading }
onClick={ () => {
setIsReloading( true );
document.getElementById( 'toggle-custom-fields-form' ).submit();
} }
>
{ willEnable ? __( 'Enable & Reload' ) : __( 'Disable & Reload' ) }
</Button>
</>
);
}

return (
<BaseOption
label={ label }
isChecked={ isChecked }
onChange={ this.toggleCustomFields }
/>
);
}
export function EnableCustomFieldsOption( { label, areCustomFieldsEnabled } ) {
const [ isChecked, setIsChecked ] = useState( areCustomFieldsEnabled );

return (
<BaseOption
label={ label }
isChecked={ isChecked }
onChange={ setIsChecked }
>
{ isChecked !== areCustomFieldsEnabled && <CustomFieldsConfirmation willEnable={ isChecked } /> }
</BaseOption>
);
}

export default withSelect( ( select ) => ( {
isChecked: !! select( 'core/editor' ).getEditorSettings().enableCustomFields,
areCustomFieldsEnabled: !! select( 'core/editor' ).getEditorSettings().enableCustomFields,
} ) )( EnableCustomFieldsOption );
Original file line number Diff line number Diff line change
@@ -1,17 +1,135 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`EnableCustomFieldsOption renders properly when checked 1`] = `
<BaseOption
isChecked={true}
label="Custom Fields"
onChange={[Function]}
/>
exports[`EnableCustomFieldsOption renders a checked checkbox and a confirmation message when toggled on 1`] = `
<div
className="edit-post-options-modal__option"
>
<div
className="components-base-control"
>
<div
className="components-base-control__field"
>
<input
checked={true}
className="components-checkbox-control__input"
id="inspector-checkbox-control-3"
onChange={[Function]}
type="checkbox"
value="1"
/>
<label
className="components-checkbox-control__label"
htmlFor="inspector-checkbox-control-3"
/>
</div>
</div>
<p
className="edit-post-options-modal__custom-fields-confirmation-message"
>
A page reload is required for this change. Make sure your content is saved before reloading.
</p>
<button
className="components-button edit-post-options-modal__custom-fields-confirmation-button is-button is-default"
disabled={false}
onClick={[Function]}
type="button"
>
Enable & Reload
</button>
</div>
`;

exports[`EnableCustomFieldsOption renders properly when unchecked 1`] = `
<BaseOption
isChecked={false}
label="Custom Fields"
onChange={[Function]}
/>
exports[`EnableCustomFieldsOption renders a checked checkbox when custom fields are enabled 1`] = `
<div
className="edit-post-options-modal__option"
>
<div
className="components-base-control"
>
<div
className="components-base-control__field"
>
<input
checked={true}
className="components-checkbox-control__input"
id="inspector-checkbox-control-0"
onChange={[Function]}
type="checkbox"
value="1"
/>
<label
className="components-checkbox-control__label"
htmlFor="inspector-checkbox-control-0"
/>
</div>
</div>
</div>
`;

exports[`EnableCustomFieldsOption renders an unchecked checkbox and a confirmation message when toggled off 1`] = `
<div
className="edit-post-options-modal__option"
>
<div
className="components-base-control"
>
<div
className="components-base-control__field"
>
<input
checked={false}
className="components-checkbox-control__input"
id="inspector-checkbox-control-2"
onChange={[Function]}
type="checkbox"
value="1"
/>
<label
className="components-checkbox-control__label"
htmlFor="inspector-checkbox-control-2"
/>
</div>
</div>
<p
className="edit-post-options-modal__custom-fields-confirmation-message"
>
A page reload is required for this change. Make sure your content is saved before reloading.
</p>
<button
className="components-button edit-post-options-modal__custom-fields-confirmation-button is-button is-default"
disabled={false}
onClick={[Function]}
type="button"
>
Disable & Reload
</button>
</div>
`;

exports[`EnableCustomFieldsOption renders an unchecked checkbox when custom fields are disabled 1`] = `
<div
className="edit-post-options-modal__option"
>
<div
className="components-base-control"
>
<div
className="components-base-control__field"
>
<input
checked={false}
className="components-checkbox-control__input"
id="inspector-checkbox-control-1"
onChange={[Function]}
type="checkbox"
value="1"
/>
<label
className="components-checkbox-control__label"
htmlFor="inspector-checkbox-control-1"
/>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -1,62 +1,63 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';
import { default as TestRenderer, act } from 'react-test-renderer';

/**
* WordPress dependencies
*/
import { Button } from '@wordpress/components';

/**
* Internal dependencies
*/
import { EnableCustomFieldsOption } from '../enable-custom-fields';
import { EnableCustomFieldsOption, CustomFieldsConfirmation } from '../enable-custom-fields';
import BaseOption from '../base';

describe( 'EnableCustomFieldsOption', () => {
it( 'renders properly when checked', () => {
const wrapper = shallow( <EnableCustomFieldsOption label="Custom Fields" isChecked /> );
expect( wrapper ).toMatchSnapshot();
it( 'renders a checked checkbox when custom fields are enabled', () => {
const renderer = TestRenderer.create( <EnableCustomFieldsOption areCustomFieldsEnabled /> );
expect( renderer ).toMatchSnapshot();
} );

it( 'can be unchecked', () => {
const submit = jest.fn();
const getElementById = jest.spyOn( document, 'getElementById' ).mockImplementation( () => ( {
submit,
} ) );

const wrapper = shallow( <EnableCustomFieldsOption label="Custom Fields" isChecked /> );

expect( wrapper.prop( 'isChecked' ) ).toBe( true );

wrapper.prop( 'onChange' )();
wrapper.update();

expect( wrapper.prop( 'isChecked' ) ).toBe( false );
expect( getElementById ).toHaveBeenCalledWith( 'toggle-custom-fields-form' );
expect( submit ).toHaveBeenCalled();
it( 'renders an unchecked checkbox when custom fields are disabled', () => {
const renderer = TestRenderer.create(
<EnableCustomFieldsOption areCustomFieldsEnabled={ false } />
);
expect( renderer ).toMatchSnapshot();
} );

getElementById.mockRestore();
it( 'renders an unchecked checkbox and a confirmation message when toggled off', () => {
const renderer = new TestRenderer.create( <EnableCustomFieldsOption areCustomFieldsEnabled /> );
act( () => {
renderer.root.findByType( BaseOption ).props.onChange( false );
} );
expect( renderer ).toMatchSnapshot();
} );

it( 'renders properly when unchecked', () => {
const wrapper = shallow(
<EnableCustomFieldsOption label="Custom Fields" isChecked={ false } />
it( 'renders a checked checkbox and a confirmation message when toggled on', () => {
const renderer = new TestRenderer.create(
<EnableCustomFieldsOption areCustomFieldsEnabled={ false } />
);
expect( wrapper ).toMatchSnapshot();
act( () => {
renderer.root.findByType( BaseOption ).props.onChange( true );
} );
expect( renderer ).toMatchSnapshot();
} );
} );

it( 'can be checked', () => {
describe( 'CustomFieldsConfirmation', () => {
it( 'submits the toggle-custom-fields-form', () => {
const submit = jest.fn();
const getElementById = jest.spyOn( document, 'getElementById' ).mockImplementation( () => ( {
submit,
} ) );

const wrapper = shallow(
<EnableCustomFieldsOption label="Custom Fields" isChecked={ false } />
);

expect( wrapper.prop( 'isChecked' ) ).toBe( false );

wrapper.prop( 'onChange' )();
wrapper.update();
const renderer = new TestRenderer.create( <CustomFieldsConfirmation /> );
act( () => {
renderer.root.findByType( Button ).props.onClick();
} );

expect( wrapper.prop( 'isChecked' ) ).toBe( true );
expect( getElementById ).toHaveBeenCalledWith( 'toggle-custom-fields-form' );
expect( submit ).toHaveBeenCalled();

Expand Down
16 changes: 12 additions & 4 deletions packages/edit-post/src/components/options-modal/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@
margin: 0;
}

&.components-base-control + &.components-base-control {
margin-bottom: 0;
}

.components-checkbox-control__label {
flex-grow: 1;
padding: 0.6rem 0 0.6rem 10px;
}
}

&__custom-fields-confirmation-message,
&__custom-fields-confirmation-button {
margin: 0 0 0.6rem 48px;

@include break-medium() {
margin-left: 38px;
}
@include break-small() {
max-width: 300px;
}
}
}

0 comments on commit f160e16

Please sign in to comment.