From 7493f95fe60edee53fe4a02625093584ff409a93 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 20 Jun 2024 17:10:25 +0300 Subject: [PATCH] WIP: Posts list --- lib/experimental/posts/load.php | 13 ++ .../{add-new-page => add-new-post}/index.js | 12 +- .../edit-site/src/components/layout/router.js | 6 +- .../src/components/page-pages/style.scss | 3 + .../src/components/posts-app/index.js | 20 +- .../index.js => posts-app/posts-list.js} | 57 +++-- .../src/components/posts-app/router.js | 82 +++++++ .../sidebar-dataviews/add-new-view.js | 3 +- .../sidebar-dataviews/default-views.js | 203 ++++++++++-------- .../src/components/sidebar-dataviews/index.js | 6 +- packages/edit-site/src/posts.js | 2 + 11 files changed, 268 insertions(+), 139 deletions(-) rename packages/edit-site/src/components/{add-new-page => add-new-post}/index.js (83%) rename packages/edit-site/src/components/{page-pages/index.js => posts-app/posts-list.js} (92%) create mode 100644 packages/edit-site/src/components/posts-app/router.js diff --git a/lib/experimental/posts/load.php b/lib/experimental/posts/load.php index 3fff8a151dfef..3a9feba2750c1 100644 --- a/lib/experimental/posts/load.php +++ b/lib/experimental/posts/load.php @@ -23,6 +23,19 @@ function gutenberg_posts_dashboard() { echo '
'; } +/** + * Redirects to the new posts dashboard page and adds the postType query arg. + * TODO: there should be a better way to do this.. + */ +function gutenberg_add_post_type_arg() { + global $pagenow; + if ( $pagenow == 'admin.php' && isset( $_GET['page'] ) && $_GET['page'] == 'gutenberg-posts-dashboard' && empty( $_GET['postType'] ) ) { + wp_redirect( admin_url( '/admin.php?page=gutenberg-posts-dashboard&postType=post' ) ); + exit; + } +} +add_action( 'admin_init', 'gutenberg_add_post_type_arg' ); + /** * Replaces the default posts menu item with the new posts dashboard. */ diff --git a/packages/edit-site/src/components/add-new-page/index.js b/packages/edit-site/src/components/add-new-post/index.js similarity index 83% rename from packages/edit-site/src/components/add-new-page/index.js rename to packages/edit-site/src/components/add-new-post/index.js index 9a227faccebcd..4b43a026624e1 100644 --- a/packages/edit-site/src/components/add-new-page/index.js +++ b/packages/edit-site/src/components/add-new-post/index.js @@ -16,7 +16,10 @@ import { store as noticesStore } from '@wordpress/notices'; import { decodeEntities } from '@wordpress/html-entities'; import { serialize, synchronizeBlocksWithTemplate } from '@wordpress/blocks'; -export default function AddNewPageModal( { onSave, onClose } ) { +// TODO: check how/if to reuse this and make it work for other post types. +// Currently this creates drafts, so we should look into that.. +// Also lot's of labels need to be updated properly.. +export default function AddNewPostModal( { postType, onSave, onClose } ) { const [ isCreatingPage, setIsCreatingPage ] = useState( false ); const [ title, setTitle ] = useState( '' ); @@ -33,11 +36,12 @@ export default function AddNewPageModal( { onSave, onClose } ) { } setIsCreatingPage( true ); try { + // TODO: also check this change.. It was merged(https://github.com/WordPress/gutenberg/pull/62488/) as I was coding this.. const pagePostType = - await resolveSelect( coreStore ).getPostType( 'page' ); + await resolveSelect( coreStore ).getPostType( postType ); const newPage = await saveEntityRecord( 'postType', - 'page', + postType, { status: 'draft', title, @@ -70,7 +74,7 @@ export default function AddNewPageModal( { onSave, onClose } ) { const errorMessage = error.message && error.code !== 'unknown_error' ? error.message - : __( 'An error occurred while creating the page.' ); + : __( 'An error occurred while creating the item.' ); createErrorNotice( errorMessage, { type: 'snackbar', diff --git a/packages/edit-site/src/components/layout/router.js b/packages/edit-site/src/components/layout/router.js index 25ab81d9a173c..64406391c76f0 100644 --- a/packages/edit-site/src/components/layout/router.js +++ b/packages/edit-site/src/components/layout/router.js @@ -10,7 +10,7 @@ import { useEffect } from '@wordpress/element'; import { unlock } from '../../lock-unlock'; import { useIsSiteEditorLoading } from './hooks'; import Editor from '../editor'; -import PagePages from '../page-pages'; +import PostsList from '../posts-app/posts-list'; import PagePatterns from '../page-patterns'; import PageTemplates from '../page-templates'; import SidebarNavigationScreen from '../sidebar-navigation-screen'; @@ -92,7 +92,7 @@ export default function useLayoutAreas() { content={ } /> ), - content: , + content: , preview: ( isListLayout || canvas === 'edit' ) && ( ), @@ -100,7 +100,7 @@ export default function useLayoutAreas() { canvas === 'edit' ? ( ) : ( - + ), }, widths: { diff --git a/packages/edit-site/src/components/page-pages/style.scss b/packages/edit-site/src/components/page-pages/style.scss index 41dcac76e27b5..0dc97851676a9 100644 --- a/packages/edit-site/src/components/page-pages/style.scss +++ b/packages/edit-site/src/components/page-pages/style.scss @@ -1,3 +1,6 @@ +// TODO: we need to examine if these styles could be the default styles +// for every post type and/or how to have different styles for different post types. +// Example is `posts` and `pages`. .edit-site-page-pages__featured-image { height: 100%; object-fit: cover; diff --git a/packages/edit-site/src/components/posts-app/index.js b/packages/edit-site/src/components/posts-app/index.js index 3d803f0241d78..12bdf33711031 100644 --- a/packages/edit-site/src/components/posts-app/index.js +++ b/packages/edit-site/src/components/posts-app/index.js @@ -10,29 +10,27 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ +import useInitEditedEntityFromURL from '../sync-state-with-url/use-init-edited-entity-from-url'; import Layout from '../layout'; -import Page from '../page'; +import useLayoutAreas from './router'; import { unlock } from '../../lock-unlock'; const { RouterProvider } = unlock( routerPrivateApis ); const { GlobalStylesProvider } = unlock( editorPrivateApis ); -const defaultRoute = { - key: 'index', - areas: { - sidebar: 'Empty Sidebar', - content: Welcome to Posts, - preview: undefined, - mobile: Welcome to Posts, - }, -}; +function PostsLayout() { + // This ensures the edited entity id and type are initialized properly. + useInitEditedEntityFromURL(); + const route = useLayoutAreas(); + return ; +} export default function PostsApp() { return ( - + ); diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/posts-app/posts-list.js similarity index 92% rename from packages/edit-site/src/components/page-pages/index.js rename to packages/edit-site/src/components/posts-app/posts-list.js index c1eb6ddbdc00b..5d71794b7566e 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/posts-app/posts-list.js @@ -24,7 +24,7 @@ import { privateApis as editorPrivateApis } from '@wordpress/editor'; import Page from '../page'; import { default as Link, useLink } from '../routes/link'; import { - DEFAULT_VIEWS, + useDefaultViews, DEFAULT_CONFIG_PER_VIEW_TYPE, } from '../sidebar-dataviews/default-views'; import { @@ -35,7 +35,7 @@ import { OPERATOR_IS_NONE, } from '../../utils/constants'; -import AddNewPageModal from '../add-new-page'; +import AddNewPostModal from '../add-new-post'; import Media from '../media'; import { unlock } from '../../lock-unlock'; import { useEditPostAction } from '../dataviews-actions'; @@ -55,6 +55,7 @@ function useView( postType ) { params: { activeView = 'all', isCustom = 'false', layout }, } = useLocation(); const history = useHistory(); + const DEFAULT_VIEWS = useDefaultViews( { postType } ); const selectedDefaultView = useMemo( () => { const defaultView = isCustom === 'false' && @@ -71,7 +72,7 @@ function useView( postType ) { }; } return defaultView; - }, [ isCustom, activeView, layout, postType ] ); + }, [ isCustom, activeView, layout, postType, DEFAULT_VIEWS ] ); const [ view, setView ] = useState( selectedDefaultView ); useEffect( () => { @@ -232,11 +233,9 @@ function usePostIdLinkInSelection( }, [ postIdToSelect, selection, setSelection, isLoadingItems, items ] ); } -export default function PagePages() { - const postType = 'page'; +export default function PostsList( { postType } ) { const [ view, setView ] = useView( postType ); const history = useHistory(); - const [ selection, setSelection ] = useState( [] ); const onSelectionChange = useCallback( @@ -293,13 +292,18 @@ export default function PagePages() { }; }, [ view ] ); const { - records: pages, + records, isResolving: isLoadingPages, totalItems, totalPages, } = useEntityRecords( 'postType', postType, queryArgs ); - usePostIdLinkInSelection( selection, setSelection, isLoadingPages, pages ); + usePostIdLinkInSelection( + selection, + setSelection, + isLoadingPages, + records + ); const { records: authors, isResolving: isLoadingAuthors } = useEntityRecords( 'root', 'user', { per_page: -1 } ); @@ -312,7 +316,7 @@ export default function PagePages() { [ totalItems, totalPages ] ); - const { frontPageId, postsPageId, addNewLabel, canCreatePage } = useSelect( + const { frontPageId, postsPageId, labels, canCreateRecord } = useSelect( ( select ) => { const { getEntityRecord, getPostType, canUser } = select( coreStore ); @@ -320,12 +324,18 @@ export default function PagePages() { return { frontPageId: siteSettings?.page_on_front, postsPageId: siteSettings?.page_for_posts, - addNewLabel: getPostType( 'page' )?.labels?.add_new_item, - canCreatePage: canUser( 'create', 'pages' ), + labels: getPostType( postType )?.labels, + // TODO: check what is the proper way to make this work for any post type.. + canCreateRecord: canUser( + 'create', + postType === 'page' ? 'pages' : 'posts' + ), }; - } + }, + [ postType ] ); + // TODO: this should be abstracted into a hook similar to `usePostActions`. const fields = useMemo( () => [ { @@ -496,7 +506,7 @@ export default function PagePages() { ); const postTypeActions = usePostActions( { - postType: 'page', + postType, context: 'list', } ); const editAction = useEditPostAction(); @@ -521,10 +531,10 @@ export default function PagePages() { [ view.type, setView ] ); - const [ showAddPageModal, setShowAddPageModal ] = useState( false ); + const [ showAddPostModal, setShowAddPostModal ] = useState( false ); - const openModal = () => setShowAddPageModal( true ); - const closeModal = () => setShowAddPageModal( false ); + const openModal = () => setShowAddPostModal( true ); + const closeModal = () => setShowAddPostModal( false ); const handleNewPage = ( { type, id } ) => { history.push( { postId: id, @@ -536,20 +546,21 @@ export default function PagePages() { return ( - { showAddPageModal && ( - @@ -562,7 +573,7 @@ export default function PagePages() { paginationInfo={ paginationInfo } fields={ fields } actions={ actions } - data={ pages || EMPTY_ARRAY } + data={ records || EMPTY_ARRAY } isLoading={ isLoadingPages || isLoadingAuthors } view={ view } onChangeView={ onChangeView } diff --git a/packages/edit-site/src/components/posts-app/router.js b/packages/edit-site/src/components/posts-app/router.js new file mode 100644 index 0000000000000..76c4525e48f22 --- /dev/null +++ b/packages/edit-site/src/components/posts-app/router.js @@ -0,0 +1,82 @@ +/** + * WordPress dependencies + */ +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { useIsSiteEditorLoading } from '../layout/hooks'; +import Editor from '../editor'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import SidebarNavigationScreenMain from '../sidebar-navigation-screen-main'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import PostsList from '../posts-app/posts-list'; + +const { useLocation } = unlock( routerPrivateApis ); + +export default function useLayoutAreas() { + const isSiteEditorLoading = useIsSiteEditorLoading(); + const { params = {} } = useLocation(); + const { postType, layout, canvas } = params; + const labels = useSelect( + ( select ) => { + return select( coreStore ).getPostType( postType )?.labels; + }, + [ postType ] + ); + + // Posts list. + if ( [ 'page', 'post' ].includes( postType ) ) { + const isListLayout = layout === 'list' || ! layout; + return { + key: 'pages', + areas: { + sidebar: ( + } + /> + ), + content: , + preview: ( isListLayout || canvas === 'edit' ) && ( + + ), + mobile: + canvas === 'edit' ? ( + + ) : ( + + ), + }, + widths: { + content: isListLayout ? 380 : undefined, + }, + }; + } + + // const defaultRoute = { + // key: 'index', + // areas: { + // sidebar: 'Empty Sidebar', + // content: , + // preview: undefined, + // mobile: Welcome to Posts, + // }, + // }; + // Fallback shows the home page preview + return { + key: 'default', + areas: { + sidebar: , + preview: , + mobile: canvas === 'edit' && ( + + ), + }, + }; +} 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 ffddddb9cad29..ceb2a11f2c523 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 @@ -19,7 +19,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; * Internal dependencies */ import SidebarNavigationItem from '../sidebar-navigation-item'; -import { DEFAULT_VIEWS } from './default-views'; +import { useDefaultViews } from './default-views'; import { unlock } from '../../lock-unlock'; const { useHistory } = unlock( routerPrivateApis ); @@ -29,6 +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 } ); return (
{ 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 e7c2471fe44bc..6c98ec7346488 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; + import { trash, pages, @@ -11,6 +12,9 @@ import { pending, notAllowed, } from '@wordpress/icons'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -36,7 +40,7 @@ export const DEFAULT_CONFIG_PER_VIEW_TYPE = { }, }; -const DEFAULT_PAGE_BASE = { +const DEFAULT_POST_BASE = { type: LAYOUT_LIST, search: '', filters: [], @@ -54,103 +58,114 @@ const DEFAULT_PAGE_BASE = { }, }; -export const DEFAULT_VIEWS = { - page: [ - { - title: __( 'All pages' ), - slug: 'all', - icon: pages, - view: DEFAULT_PAGE_BASE, +export function useDefaultViews( { postType } ) { + const labels = useSelect( + ( select ) => { + const { getPostType } = select( coreStore ); + return getPostType( postType )?.labels; }, - { - title: __( 'Published' ), - slug: 'published', - icon: published, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'publish', + [ 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', + }, + ], }, - ], - }, - }, - { - title: __( 'Scheduled' ), - slug: 'future', - icon: scheduled, - view: { - ...DEFAULT_PAGE_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_PAGE_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_PAGE_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_PAGE_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_PAGE_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 ] ); +} diff --git a/packages/edit-site/src/components/sidebar-dataviews/index.js b/packages/edit-site/src/components/sidebar-dataviews/index.js index 9362308172f89..37f16b2e1f68b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/index.js +++ b/packages/edit-site/src/components/sidebar-dataviews/index.js @@ -2,13 +2,12 @@ * WordPress dependencies */ import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; - import { privateApis as routerPrivateApis } from '@wordpress/router'; + /** * Internal dependencies */ - -import { DEFAULT_VIEWS } from './default-views'; +import { useDefaultViews } from './default-views'; import { unlock } from '../../lock-unlock'; const { useLocation } = unlock( routerPrivateApis ); import DataViewItem from './dataview-item'; @@ -18,6 +17,7 @@ export default function DataViewsSidebarContent() { const { params: { postType, activeView = 'all', isCustom = 'false' }, } = useLocation(); + const DEFAULT_VIEWS = useDefaultViews( { postType } ); if ( ! postType ) { return null; } diff --git a/packages/edit-site/src/posts.js b/packages/edit-site/src/posts.js index 19e787fff4630..04ea525c03153 100644 --- a/packages/edit-site/src/posts.js +++ b/packages/edit-site/src/posts.js @@ -6,6 +6,7 @@ import { createRoot, StrictMode } from '@wordpress/element'; /** * Internal dependencies */ +// import { initializeEditor } from './index'; import PostsApp from './components/posts-app'; /** @@ -16,6 +17,7 @@ export function initializePostsDashboard( id ) { if ( ! globalThis.IS_GUTENBERG_PLUGIN ) { return; } + // initializeEditor( 'site-editor', {} ); const target = document.getElementById( id ); const root = createRoot( target );