From 563abae01c23d4ab894e3923aa85744c9bb22113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:01:48 +0200 Subject: [PATCH 1/6] Simplify useDefaultViews --- .../src/components/post-list/index.js | 14 +- .../sidebar-dataviews/add-new-view.js | 6 +- .../sidebar-dataviews/default-views.js | 188 +++++++++--------- .../src/components/sidebar-dataviews/index.js | 4 +- 4 files changed, 104 insertions(+), 108 deletions(-) diff --git a/packages/edit-site/src/components/post-list/index.js b/packages/edit-site/src/components/post-list/index.js index 2724abcff714f..139ca2ee57534 100644 --- a/packages/edit-site/src/components/post-list/index.js +++ b/packages/edit-site/src/components/post-list/index.js @@ -44,13 +44,12 @@ function useView( postType ) { params: { activeView = 'all', isCustom = 'false', layout }, } = useLocation(); const history = useHistory(); - const DEFAULT_VIEWS = useDefaultViews( { postType } ); + + const defaultViews = useDefaultViews( { postType } ); const selectedDefaultView = useMemo( () => { const defaultView = isCustom === 'false' && - DEFAULT_VIEWS[ postType ].find( - ( { slug } ) => slug === activeView - )?.view; + defaultViews.find( ( { slug } ) => slug === activeView )?.view; if ( isCustom === 'false' && layout ) { return { ...defaultView, @@ -59,7 +58,7 @@ function useView( postType ) { }; } return defaultView; - }, [ isCustom, activeView, layout, postType, DEFAULT_VIEWS ] ); + }, [ isCustom, activeView, layout, defaultViews ] ); const [ view, setView ] = useState( selectedDefaultView ); useEffect( () => { @@ -131,8 +130,9 @@ function useView( postType ) { } else if ( isCustom === 'true' && customView ) { return [ customView, setCustomView ]; } - // Loading state where no the view was not found on custom views or default views. - return [ DEFAULT_VIEWS[ postType ][ 0 ].view, setDefaultViewAndUpdateUrl ]; + + // No view was found. + return [ defaultViews[ 0 ].view, setDefaultViewAndUpdateUrl ]; } const DEFAULT_STATUSES = 'draft,future,pending,private,publish'; // All but 'trash'. diff --git a/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js b/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js index ceb2a11f2c523..aabb49c14a2ff 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js +++ b/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js @@ -29,7 +29,7 @@ function AddNewItemModalContent( { type, setIsAdding } ) { const { saveEntityRecord } = useDispatch( coreStore ); const [ title, setTitle ] = useState( '' ); const [ isSaving, setIsSaving ] = useState( false ); - const DEFAULT_VIEWS = useDefaultViews( { postType: type } ); + const defaultViews = useDefaultViews( { postType: type } ); return (
{ @@ -61,9 +61,7 @@ function AddNewItemModalContent( { type, setIsAdding } ) { title, status: 'publish', wp_dataviews_type: dataViewTaxonomyId, - content: JSON.stringify( - DEFAULT_VIEWS[ type ][ 0 ].view - ), + content: JSON.stringify( defaultViews[ 0 ].view ), } ); const { diff --git a/packages/edit-site/src/components/sidebar-dataviews/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js index 2b8a9de4c2262..906d9f0e216dc 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -77,105 +77,103 @@ export function useDefaultViews( { postType } ) { [ postType ] ); return useMemo( () => { - return { - [ postType ]: [ - { - title: labels?.all_items || __( 'All items' ), - slug: 'all', - icon: pages, - view: DEFAULT_POST_BASE, - }, - { - title: __( 'Published' ), - slug: 'published', - icon: published, - view: { - ...DEFAULT_POST_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'publish', - }, - ], - }, + return [ + { + title: labels?.all_items || __( 'All items' ), + slug: 'all', + icon: pages, + view: DEFAULT_POST_BASE, + }, + { + title: __( 'Published' ), + slug: 'published', + icon: published, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'publish', + }, + ], }, - { - title: __( 'Scheduled' ), - slug: 'future', - icon: scheduled, - view: { - ...DEFAULT_POST_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'future', - }, - ], - }, + }, + { + title: __( 'Scheduled' ), + slug: 'future', + icon: scheduled, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'future', + }, + ], }, - { - title: __( 'Drafts' ), - slug: 'drafts', - icon: drafts, - view: { - ...DEFAULT_POST_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'draft', - }, - ], - }, + }, + { + title: __( 'Drafts' ), + slug: 'drafts', + icon: drafts, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'draft', + }, + ], }, - { - title: __( 'Pending' ), - slug: 'pending', - icon: pending, - view: { - ...DEFAULT_POST_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'pending', - }, - ], - }, + }, + { + title: __( 'Pending' ), + slug: 'pending', + icon: pending, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'pending', + }, + ], }, - { - title: __( 'Private' ), - slug: 'private', - icon: notAllowed, - view: { - ...DEFAULT_POST_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'private', - }, - ], - }, + }, + { + title: __( 'Private' ), + slug: 'private', + icon: notAllowed, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'private', + }, + ], }, - { - title: __( 'Trash' ), - slug: 'trash', - icon: trash, - view: { - ...DEFAULT_POST_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'trash', - }, - ], - }, + }, + { + title: __( 'Trash' ), + slug: 'trash', + icon: trash, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'trash', + }, + ], }, - ], - }; - }, [ labels, postType ] ); + }, + ]; + }, [ labels ] ); } diff --git a/packages/edit-site/src/components/sidebar-dataviews/index.js b/packages/edit-site/src/components/sidebar-dataviews/index.js index e0a5b08a028f0..b2dc0c9781b6b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/index.js +++ b/packages/edit-site/src/components/sidebar-dataviews/index.js @@ -52,7 +52,7 @@ export default function DataViewsSidebarContent() { params: { postType, activeView = 'all', isCustom = 'false' }, } = useLocation(); useSwitchToTableOnTrash(); - const DEFAULT_VIEWS = useDefaultViews( { postType } ); + const defaultViews = useDefaultViews( { postType } ); if ( ! postType ) { return null; } @@ -61,7 +61,7 @@ export default function DataViewsSidebarContent() { return ( <> - { DEFAULT_VIEWS[ postType ].map( ( dataview ) => { + { defaultViews.map( ( dataview ) => { return ( Date: Tue, 30 Jul 2024 10:17:00 +0200 Subject: [PATCH 2/6] Simplify useView --- .../src/components/post-list/index.js | 156 ++++++++++-------- .../sidebar-dataviews/default-views.js | 4 +- .../src/components/sidebar-dataviews/index.js | 36 +--- 3 files changed, 94 insertions(+), 102 deletions(-) diff --git a/packages/edit-site/src/components/post-list/index.js b/packages/edit-site/src/components/post-list/index.js index 139ca2ee57534..18c23ca6e5319 100644 --- a/packages/edit-site/src/components/post-list/index.js +++ b/packages/edit-site/src/components/post-list/index.js @@ -26,6 +26,7 @@ import { OPERATOR_IS_ANY, OPERATOR_IS_NONE, LAYOUT_LIST, + LAYOUT_TABLE, } from '../../utils/constants'; import AddNewPostModal from '../add-new-post'; @@ -39,6 +40,36 @@ const { useLocation, useHistory } = unlock( routerPrivateApis ); const { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis ); const EMPTY_ARRAY = []; +const getDefaultView = ( defaultViews, activeView ) => { + return defaultViews.find( ( { slug } ) => slug === activeView )?.view; +}; + +const getCustomView = ( editedEntityRecord ) => { + if ( ! editedEntityRecord?.content ) { + return undefined; + } + + const content = JSON.parse( editedEntityRecord.content ); + if ( ! content ) { + return undefined; + } + + return { + ...content, + layout: defaultLayouts[ content.type ]?.layout, + }; +}; + +/** + * This function abstracts working with default & custom views by + * providing a [ state, setState ] tuple based on the URL parameters. + * + * Consumers use the provided tuple to work with state + * and don't have to deal with the specifics of default & custom views. + * + * @param {string} postType Post type to retrieve default views for. + * @return {Array} The [ state, setState ] tuple. + */ function useView( postType ) { const { params: { activeView = 'all', isCustom = 'false', layout }, @@ -46,93 +77,86 @@ function useView( postType ) { const history = useHistory(); const defaultViews = useDefaultViews( { postType } ); - const selectedDefaultView = useMemo( () => { - const defaultView = - isCustom === 'false' && - defaultViews.find( ( { slug } ) => slug === activeView )?.view; - if ( isCustom === 'false' && layout ) { - return { - ...defaultView, - type: layout, - layout: defaultLayouts[ layout ]?.layout, - }; - } - return defaultView; - }, [ isCustom, activeView, layout, defaultViews ] ); - const [ view, setView ] = useState( selectedDefaultView ); - - useEffect( () => { - if ( selectedDefaultView ) { - setView( selectedDefaultView ); - } - }, [ selectedDefaultView ] ); - const editedViewRecord = useSelect( + const { editEntityRecord } = useDispatch( coreStore ); + const editedEntityRecord = useSelect( ( select ) => { if ( isCustom !== 'true' ) { - return; + return undefined; } + const { getEditedEntityRecord } = select( coreStore ); - const dataviewRecord = getEditedEntityRecord( + return getEditedEntityRecord( 'postType', 'wp_dataviews', Number( activeView ) ); - return dataviewRecord; }, [ activeView, isCustom ] ); - const { editEntityRecord } = useDispatch( coreStore ); - - const customView = useMemo( () => { - const storedView = - editedViewRecord?.content && - JSON.parse( editedViewRecord?.content ); - if ( ! storedView ) { - return storedView; - } - - return { - ...storedView, - layout: defaultLayouts[ storedView?.type ]?.layout, - }; - }, [ editedViewRecord?.content ] ); - - const setCustomView = useCallback( - ( viewToSet ) => { - editEntityRecord( - 'postType', - 'wp_dataviews', - editedViewRecord?.id, - { - content: JSON.stringify( viewToSet ), + const [ view, setView ] = useState( () => { + if ( isCustom === 'true' ) { + return ( + getCustomView( editedEntityRecord ) ?? { + type: layout ?? LAYOUT_TABLE, } ); - }, - [ editEntityRecord, editedViewRecord?.id ] - ); + } + return ( + getDefaultView( defaultViews, activeView ) ?? { + type: layout ?? LAYOUT_TABLE, + } + ); + } ); + + const setViewWithUrlUpdate = useCallback( + ( newView ) => { + const { params } = history.getLocationWithParams(); - const setDefaultViewAndUpdateUrl = useCallback( - ( viewToSet ) => { - if ( viewToSet.type !== view?.type ) { - const { params } = history.getLocationWithParams(); + if ( newView.type !== params?.layout ) { history.push( { ...params, - layout: viewToSet.type, + layout: newView.type, } ); } - setView( viewToSet ); + + setView( newView ); + + if ( isCustom === 'true' && editedEntityRecord?.id ) { + editEntityRecord( + 'postType', + 'wp_dataviews', + editedEntityRecord?.id, + { + content: JSON.stringify( newView ), + } + ); + } }, - [ history, view?.type ] + [ history, isCustom, editedEntityRecord?.id ] ); - if ( isCustom === 'false' ) { - return [ view, setDefaultViewAndUpdateUrl ]; - } else if ( isCustom === 'true' && customView ) { - return [ customView, setCustomView ]; - } + // When layout URL param changes, update the view type + // without affecting any other config. + useEffect( () => { + setView( ( prevView ) => ( { ...prevView, type: layout } ) ); + }, [ layout ] ); + + // When activeView or isCustom URL parameters change, + // reset the view & update the layout URL param to match the view's type. + useEffect( () => { + let newView; + if ( isCustom === 'true' ) { + newView = getCustomView( editedEntityRecord ); + } else { + newView = getDefaultView( defaultViews, activeView ); + } + + if ( newView ) { + setViewWithUrlUpdate( newView ); + } + }, [ activeView, isCustom, defaultViews, editedEntityRecord ] ); - // No view was found. - return [ defaultViews[ 0 ].view, setDefaultViewAndUpdateUrl ]; + return [ view, setViewWithUrlUpdate ]; } const DEFAULT_STATUSES = 'draft,future,pending,private,publish'; // All but 'trash'. @@ -165,7 +189,7 @@ export default function PostList( { postType } ) { const queryArgs = useMemo( () => { const filters = {}; - view.filters.forEach( ( filter ) => { + view.filters?.forEach( ( filter ) => { if ( filter.field === 'status' && filter.operator === OPERATOR_IS_ANY diff --git a/packages/edit-site/src/components/sidebar-dataviews/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js index 906d9f0e216dc..5797bb525a2e6 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -54,7 +54,7 @@ export const defaultLayouts = { }, }; -const DEFAULT_POST_BASE = { +export const DEFAULT_POST_BASE = { type: LAYOUT_LIST, search: '', filters: [], @@ -165,6 +165,8 @@ export function useDefaultViews( { postType } ) { icon: trash, view: { ...DEFAULT_POST_BASE, + type: LAYOUT_TABLE, + layout: defaultLayouts[ LAYOUT_TABLE ].layout, filters: [ { field: 'status', diff --git a/packages/edit-site/src/components/sidebar-dataviews/index.js b/packages/edit-site/src/components/sidebar-dataviews/index.js index b2dc0c9781b6b..86420c4eec1d1 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/index.js +++ b/packages/edit-site/src/components/sidebar-dataviews/index.js @@ -3,8 +3,6 @@ */ import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; import { privateApis as routerPrivateApis } from '@wordpress/router'; -import { useRef, useEffect } from '@wordpress/element'; -import { usePrevious } from '@wordpress/compose'; /** * Internal dependencies @@ -14,44 +12,12 @@ import { unlock } from '../../lock-unlock'; import DataViewItem from './dataview-item'; import CustomDataViewsList from './custom-dataviews-list'; -const { useLocation, useHistory } = unlock( routerPrivateApis ); - -/** - * Hook to switch to table layout when switching to the trash view. - * When going out of the trash view, it switches back to the previous layout if - * there was an automatic switch to table layout. - */ -function useSwitchToTableOnTrash() { - const { - params: { activeView, layout, ...restParams }, - } = useLocation(); - const history = useHistory(); - const viewToSwitchOutOfTrash = useRef( undefined ); - const previousActiveView = usePrevious( activeView ); - useEffect( () => { - if ( activeView === 'trash' && previousActiveView !== 'trash' ) { - viewToSwitchOutOfTrash.current = layout || 'list'; - history.push( { ...restParams, layout: 'table', activeView } ); - } else if ( - previousActiveView === 'trash' && - activeView !== 'trash' && - viewToSwitchOutOfTrash.current - ) { - history.push( { - ...restParams, - layout: viewToSwitchOutOfTrash.current, - activeView, - } ); - viewToSwitchOutOfTrash.current = undefined; - } - }, [ previousActiveView, activeView, layout, history, restParams ] ); -} +const { useLocation } = unlock( routerPrivateApis ); export default function DataViewsSidebarContent() { const { params: { postType, activeView = 'all', isCustom = 'false' }, } = useLocation(); - useSwitchToTableOnTrash(); const defaultViews = useDefaultViews( { postType } ); if ( ! postType ) { return null; From 272d3552dc3f1eb3c887aff6cb8d219d2135e539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 1 Aug 2024 08:51:23 +0200 Subject: [PATCH 3/6] No need to export DEFAULT_POST_BASE --- .../edit-site/src/components/sidebar-dataviews/default-views.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/sidebar-dataviews/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js index 5797bb525a2e6..e5db492fce17d 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -54,7 +54,7 @@ export const defaultLayouts = { }, }; -export const DEFAULT_POST_BASE = { +const DEFAULT_POST_BASE = { type: LAYOUT_LIST, search: '', filters: [], From 6aae380ca0fa9d9c407ba8c282bb884862542cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:54:22 +0200 Subject: [PATCH 4/6] Provide default type if layout is undefined --- .../edit-site/src/components/post-list/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/edit-site/src/components/post-list/index.js b/packages/edit-site/src/components/post-list/index.js index 18c23ca6e5319..c9d54bebdc189 100644 --- a/packages/edit-site/src/components/post-list/index.js +++ b/packages/edit-site/src/components/post-list/index.js @@ -26,7 +26,6 @@ import { OPERATOR_IS_ANY, OPERATOR_IS_NONE, LAYOUT_LIST, - LAYOUT_TABLE, } from '../../utils/constants'; import AddNewPostModal from '../add-new-post'; @@ -97,13 +96,13 @@ function useView( postType ) { if ( isCustom === 'true' ) { return ( getCustomView( editedEntityRecord ) ?? { - type: layout ?? LAYOUT_TABLE, + type: layout ?? LAYOUT_LIST, } ); } return ( getDefaultView( defaultViews, activeView ) ?? { - type: layout ?? LAYOUT_TABLE, + type: layout ?? LAYOUT_LIST, } ); } ); @@ -132,13 +131,16 @@ function useView( postType ) { ); } }, - [ history, isCustom, editedEntityRecord?.id ] + [ history, isCustom, editEntityRecord, editedEntityRecord?.id ] ); // When layout URL param changes, update the view type // without affecting any other config. useEffect( () => { - setView( ( prevView ) => ( { ...prevView, type: layout } ) ); + setView( ( prevView ) => ( { + ...prevView, + type: layout ?? LAYOUT_LIST, + } ) ); }, [ layout ] ); // When activeView or isCustom URL parameters change, @@ -156,7 +158,7 @@ function useView( postType ) { } }, [ activeView, isCustom, defaultViews, editedEntityRecord ] ); - return [ view, setViewWithUrlUpdate ]; + return [ view, setViewWithUrlUpdate, setViewWithUrlUpdate ]; } const DEFAULT_STATUSES = 'draft,future,pending,private,publish'; // All but 'trash'. From 6958d2280f3b3da32c9e0a2a3d5bc09795067328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:07:08 +0200 Subject: [PATCH 5/6] Skip updating the layout URL param if type is list and layout undefined --- packages/edit-site/src/components/post-list/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/post-list/index.js b/packages/edit-site/src/components/post-list/index.js index c9d54bebdc189..e63ed4ccebcf9 100644 --- a/packages/edit-site/src/components/post-list/index.js +++ b/packages/edit-site/src/components/post-list/index.js @@ -111,7 +111,10 @@ function useView( postType ) { ( newView ) => { const { params } = history.getLocationWithParams(); - if ( newView.type !== params?.layout ) { + if ( newView.type === LAYOUT_LIST && ! params?.layout ) { + // Skip updating the layout URL param if + // it is not present and the newView.type is LAYOUT_LIST. + } else if ( newView.type !== params?.layout ) { history.push( { ...params, layout: newView.type, From f727f52840c55a76eedf9a740e85bc9bfaf907cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:26:49 +0200 Subject: [PATCH 6/6] Fix performance test --- test/performance/specs/site-editor.spec.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/performance/specs/site-editor.spec.js b/test/performance/specs/site-editor.spec.js index 520ad76de22ee..9c9d8aec71da4 100644 --- a/test/performance/specs/site-editor.spec.js +++ b/test/performance/specs/site-editor.spec.js @@ -438,9 +438,7 @@ test.describe( 'Site Editor Performance', () => { await Promise.all( Array.from( { length: perPage }, async ( el, index ) => { return await page - .getByRole( 'link', { - name: `Page (${ index })`, - } ) + .getByLabel( `Page (${ index })` ) .waitFor( { state: 'attached' } ); } ) );