Skip to content

Commit

Permalink
Site Editor: Improve loading experience (v3) (#50222)
Browse files Browse the repository at this point in the history
* Data: Introduce hasResolvingSelectors metadata selector

* Edit Site: Display loading screen if we have resolving requests

* Move loading logic to a hook

* Inline again, loading spinner only in beginning, fix flickering

* Hide canvas-overflowing content

* Fix resolveSelect tests

* e2e: try waiting for spinner to disappear

* Add some additional safety to selector

* Simplify timeout clearing

* Add a comment on the arbitrary timeout
  • Loading branch information
tyxla authored May 10, 2023
1 parent ccd529d commit 15d0927
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 5 deletions.
15 changes: 15 additions & 0 deletions packages/data/src/redux-store/metadata/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,18 @@ export function isResolving( state, selectorName, args ) {
export function getCachedResolvers( state ) {
return state;
}

/**
* Whether the store has any currently resolving selectors.
*
* @param {State} state Data state.
*
* @return {boolean} True if one or more selectors are resolving, false otherwise.
*/
export function hasResolvingSelectors( state ) {
return [ ...Object.values( state ) ].some( ( selectorState ) =>
[ ...selectorState._map.values() ].some(
( resolution ) => resolution[ 1 ]?.status === 'resolving'
)
);
}
32 changes: 32 additions & 0 deletions packages/data/src/redux-store/metadata/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,35 @@ describe( 'getResolutionError', () => {
).toBeFalsy();
} );
} );

describe( 'hasResolvingSelectors', () => {
let registry;
beforeEach( () => {
registry = createRegistry();
registry.registerStore( 'testStore', testStore );
} );

it( 'returns false if no requests have started', () => {
const { hasResolvingSelectors } = registry.select( 'testStore' );
const result = hasResolvingSelectors();

expect( result ).toBe( false );
} );

it( 'returns false if all requests have finished', () => {
registry.dispatch( 'testStore' ).startResolution( 'getFoo', [] );
registry.dispatch( 'testStore' ).finishResolution( 'getFoo', [] );
const { hasResolvingSelectors } = registry.select( 'testStore' );
const result = hasResolvingSelectors();

expect( result ).toBe( false );
} );

it( 'returns true if has started but not finished', () => {
registry.dispatch( 'testStore' ).startResolution( 'getFoo', [] );
const { hasResolvingSelectors } = registry.select( 'testStore' );
const result = hasResolvingSelectors();

expect( result ).toBe( true );
} );
} );
1 change: 1 addition & 0 deletions packages/data/src/redux-store/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ describe( 'resolveSelect', () => {

it( 'returns only store native selectors and excludes all meta ones', () => {
expect( Object.keys( registry.resolveSelect( 'store' ) ) ).toEqual( [
'hasResolvingSelectors',
'getItems',
'getItemsNoResolver',
] );
Expand Down
2 changes: 2 additions & 0 deletions packages/e2e-test-utils/src/site-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { addQueryArgs } from '@wordpress/url';

const SELECTORS = {
visualEditor: '.edit-site-visual-editor iframe',
loadingSpinner: '.edit-site-canvas-spinner',
};

/**
Expand Down Expand Up @@ -128,6 +129,7 @@ export async function visitSiteEditor( query, skipWelcomeGuide = true ) {

await visitAdminPage( 'site-editor.php', query );
await page.waitForSelector( SELECTORS.visualEditor );
await page.waitForSelector( SELECTORS.loadingSpinner, { hidden: true } );

if ( skipWelcomeGuide ) {
await disableSiteEditorWelcomeGuide();
Expand Down
39 changes: 34 additions & 5 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';
import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { Notice } from '@wordpress/components';
import { EntityProvider } from '@wordpress/core-data';
import { EntityProvider, store as coreStore } from '@wordpress/core-data';
import { store as preferencesStore } from '@wordpress/preferences';
import {
BlockContextProvider,
Expand Down Expand Up @@ -153,12 +153,41 @@ export default function Editor() {
// action in <URlQueryController> from double-announcing.
useTitle( hasLoadedPost && title );

if ( ! hasLoadedPost ) {
return <CanvasSpinner />;
}
const { hasResolvingSelectors } = useSelect( ( select ) => {
return {
hasResolvingSelectors: select( coreStore ).hasResolvingSelectors(),
};
} );
const [ loaded, setLoaded ] = useState( false );
const timeoutRef = useRef( null );

useEffect( () => {
if ( ! hasResolvingSelectors && ! loaded ) {
clearTimeout( timeoutRef.current );

/*
* We're using an arbitrary 1s timeout here to catch brief moments
* without any resolving selectors that would result in displaying
* brief flickers of loading state and loaded state.
*
* It's worth experimenting with different values, since this also
* adds 1s of artificial delay after loading has finished.
*/
timeoutRef.current = setTimeout( () => {
setLoaded( true );
}, 1000 );

return () => {
clearTimeout( timeoutRef.current );
};
}
}, [ loaded, hasResolvingSelectors ] );

const isLoading = ! loaded || ! hasLoadedPost;

return (
<>
{ isLoading ? <CanvasSpinner /> : null }
{ isEditMode && <WelcomeGuide /> }
<EntityProvider kind="root" type="site">
<EntityProvider
Expand Down
1 change: 1 addition & 0 deletions packages/edit-site/src/components/layout/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
left: 0;
bottom: 0;
width: 100%;
overflow: hidden;

& > div {
color: $gray-900;
Expand Down

1 comment on commit 15d0927

@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 15d0927.
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/4934475528
📝 Reported issues:

Please sign in to comment.