Skip to content

Commit

Permalink
Directly save if only changing current context (#50567)
Browse files Browse the repository at this point in the history
  • Loading branch information
SaxonF authored Jun 6, 2023
1 parent 2a08cbc commit b30e1ef
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 41 deletions.
6 changes: 6 additions & 0 deletions packages/edit-site/src/components/save-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default function SaveButton( {
className = 'edit-site-save-button__button',
variant = 'primary',
showTooltip = true,
defaultLabel,
icon,
} ) {
const { isDirty, isSaving, isSaveViewOpen } = useSelect( ( select ) => {
Expand All @@ -38,10 +39,15 @@ export default function SaveButton( {
const disabled = isSaving || ! activateSaveEnabled;

const getLabel = () => {
if ( isSaving ) {
return __( 'Saving' );
}
if ( disabled ) {
return __( 'Saved' );
}

if ( defaultLabel ) return defaultLabel;

if ( isPreviewingTheme() && isDirty ) {
return __( 'Activate & Save' );
} else if ( isPreviewingTheme() ) {
Expand Down
181 changes: 143 additions & 38 deletions packages/edit-site/src/components/save-hub/index.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,165 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { __experimentalHStack as HStack } from '@wordpress/components';
import { sprintf, _n } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { Button, __experimentalHStack as HStack } from '@wordpress/components';
import { __, sprintf, _n } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { check } from '@wordpress/icons';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { store as noticesStore } from '@wordpress/notices';

/**
* Internal dependencies
*/
import SaveButton from '../save-button';
import { isPreviewingTheme } from '../../utils/is-previewing-theme';
import { unlock } from '../../private-apis';

const { useLocation } = unlock( routerPrivateApis );

const PUBLISH_ON_SAVE_ENTITIES = [
{
kind: 'postType',
name: 'wp_navigation',
},
];

export default function SaveHub() {
const { countUnsavedChanges, isDirty, isSaving } = useSelect(
( select ) => {
const {
__experimentalGetDirtyEntityRecords,
isSavingEntityRecord,
} = select( coreStore );
const dirtyEntityRecords = __experimentalGetDirtyEntityRecords();
return {
isDirty: dirtyEntityRecords.length > 0,
isSaving: dirtyEntityRecords.some( ( record ) =>
isSavingEntityRecord( record.kind, record.name, record.key )
),
countUnsavedChanges: dirtyEntityRecords.length,
};
},
[]
);
const { params } = useLocation();

const { __unstableMarkLastChangeAsPersistent } =
useDispatch( blockEditorStore );

const { createSuccessNotice, createErrorNotice } =
useDispatch( noticesStore );

const { dirtyCurrentEntity, countUnsavedChanges, isDirty, isSaving } =
useSelect(
( select ) => {
const {
__experimentalGetDirtyEntityRecords,
isSavingEntityRecord,
} = select( coreStore );
const dirtyEntityRecords =
__experimentalGetDirtyEntityRecords();
let calcDirtyCurrentEntity = null;

if ( dirtyEntityRecords.length === 1 ) {
// if we are on global styles
if ( params.path?.includes( 'wp_global_styles' ) ) {
calcDirtyCurrentEntity = dirtyEntityRecords.find(
( record ) => record.name === 'globalStyles'
);
}
// if we are on pages
else if ( params.postId ) {
calcDirtyCurrentEntity = dirtyEntityRecords.find(
( record ) =>
record.name === params.postType &&
String( record.key ) === params.postId
);
}
}

return {
dirtyCurrentEntity: calcDirtyCurrentEntity,
isDirty: dirtyEntityRecords.length > 0,
isSaving: dirtyEntityRecords.some( ( record ) =>
isSavingEntityRecord(
record.kind,
record.name,
record.key
)
),
countUnsavedChanges: dirtyEntityRecords.length,
};
},
[ params.path, params.postType, params.postId ]
);

const {
editEntityRecord,
saveEditedEntityRecord,
__experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits,
} = useDispatch( coreStore );

const disabled = isSaving || ( ! isDirty && ! isPreviewingTheme() );

// if we have only one unsaved change and it matches current context, we can show a more specific label
let label = dirtyCurrentEntity
? __( 'Save' )
: sprintf(
// translators: %d: number of unsaved changes (number).
_n(
'Review %d change…',
'Review %d changes…',
countUnsavedChanges
),
countUnsavedChanges
);

if ( isSaving ) {
label = __( 'Saving' );
}

const saveCurrentEntity = async () => {
if ( ! dirtyCurrentEntity ) return;

const { kind, name, key, property } = dirtyCurrentEntity;

try {
if ( 'root' === dirtyCurrentEntity.kind && 'site' === name ) {
await saveSpecifiedEntityEdits( 'root', 'site', undefined, [
property,
] );
} else {
if (
PUBLISH_ON_SAVE_ENTITIES.some(
( typeToPublish ) =>
typeToPublish.kind === kind &&
typeToPublish.name === name
)
) {
editEntityRecord( kind, name, key, { status: 'publish' } );
}

await saveEditedEntityRecord( kind, name, key );
}

__unstableMarkLastChangeAsPersistent();

createSuccessNotice( __( 'Site updated.' ), {
type: 'snackbar',
} );
} catch ( error ) {
createErrorNotice( `${ __( 'Saving failed.' ) } ${ error }` );
}
};

return (
<HStack className="edit-site-save-hub" alignment="right" spacing={ 4 }>
{ isDirty && (
<span>
{ sprintf(
// translators: %d: number of unsaved changes (number).
_n(
'%d unsaved change',
'%d unsaved changes',
countUnsavedChanges
),
countUnsavedChanges
) }
</span>
{ dirtyCurrentEntity ? (
<Button
variant="primary"
onClick={ saveCurrentEntity }
isBusy={ isSaving }
disabled={ isSaving }
aria-disabled={ isSaving }
className="edit-site-save-hub__button"
>
{ label }
</Button>
) : (
<SaveButton
className="edit-site-save-hub__button"
variant={ disabled ? null : 'primary' }
showTooltip={ false }
icon={ disabled && ! isSaving ? check : null }
defaultLabel={ label }
/>
) }
<SaveButton
className="edit-site-save-hub__button"
variant={ disabled ? null : 'primary' }
showTooltip={ false }
icon={ disabled ? check : null }
/>
</HStack>
);
}
6 changes: 6 additions & 0 deletions packages/edit-site/src/components/save-hub/style.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
.edit-site-save-hub {
color: $gray-600;
border-top: 1px solid $gray-800;
flex-shrink: 0;
margin: 0;
padding: $canvas-padding;
}

.edit-site-save-hub__button {
color: inherit;
width: 100%;
justify-content: center;

&[aria-disabled="true"] {
opacity: 1;
Expand Down
4 changes: 1 addition & 3 deletions packages/edit-site/src/components/sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ function Sidebar() {
>
<SidebarScreens />
</NavigatorProvider>
<div className="edit-site-sidebar__footer">
<SaveHub />
</div>
<SaveHub />
</>
);
}
Expand Down

1 comment on commit b30e1ef

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in b30e1ef.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/5186154261
📝 Reported issues:

Please sign in to comment.