diff --git a/packages/edit-site/src/components/page-patterns/index.js b/packages/edit-site/src/components/page-patterns/index.js index 7f43bb1b4c3bb4..abe4f42defe347 100644 --- a/packages/edit-site/src/components/page-patterns/index.js +++ b/packages/edit-site/src/components/page-patterns/index.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ @@ -30,6 +35,7 @@ import { lockSmall, } from '@wordpress/icons'; import { usePrevious } from '@wordpress/compose'; +import { useEntityRecords } from '@wordpress/core-data'; /** * Internal dependencies @@ -39,6 +45,7 @@ import Page from '../page'; import { LAYOUT_GRID, LAYOUT_TABLE, + LAYOUT_LIST, PATTERN_TYPES, TEMPLATE_PART_POST_TYPE, PATTERN_SYNC_TYPES, @@ -59,6 +66,7 @@ import { unlock } from '../../lock-unlock'; import usePatterns from './use-patterns'; import PatternsHeader from './header'; import { useLink } from '../routes/link'; +import { useAddedBy } from '../page-templates-template-parts/hooks'; const { ExperimentalBlockEditorProvider, useGlobalStyle } = unlock( blockEditorPrivateApis @@ -201,6 +209,39 @@ function Preview( { item, categoryId, viewType } ) { ); } +function Author( { item, viewType } ) { + const [ isImageLoaded, setIsImageLoaded ] = useState( false ); + const { text, icon, imageUrl } = useAddedBy( item.type, item.id ); + const withIcon = viewType !== LAYOUT_LIST; + + return ( + + { withIcon && imageUrl && ( + + setIsImageLoaded( true ) } + alt="" + src={ imageUrl } + /> + + ) } + { withIcon && ! imageUrl && ( + + + + ) } + { text } + + ); +} + function Title( { item, categoryId } ) { const isUserPattern = item.type === PATTERN_TYPES.user; const isNonUserPattern = item.type === PATTERN_TYPES.theme; @@ -289,6 +330,24 @@ export default function DataviewsPatterns() { syncStatus: viewSyncStatus, } ); + + const { records } = useEntityRecords( 'postType', TEMPLATE_PART_POST_TYPE, { + per_page: -1, + } ); + const authors = useMemo( () => { + if ( ! records ) { + return EMPTY_ARRAY; + } + const authorsSet = new Set(); + records.forEach( ( template ) => { + authorsSet.add( template.author_text ); + } ); + return Array.from( authorsSet ).map( ( author ) => ( { + value: author, + label: author, + } ) ); + }, [ records ] ); + const fields = useMemo( () => { const _fields = [ { @@ -313,6 +372,7 @@ export default function DataviewsPatterns() { enableHiding: false, }, ]; + if ( type === PATTERN_TYPES.theme ) { _fields.push( { header: __( 'Sync status' ), @@ -342,9 +402,26 @@ export default function DataviewsPatterns() { }, enableSorting: false, } ); + } else if ( type === TEMPLATE_PART_POST_TYPE ) { + _fields.push( { + header: __( 'Author' ), + id: 'author', + getValue: ( { item } ) => item.templatePart.author_text, + render: ( { item } ) => { + return ; + }, + type: ENUMERATION_TYPE, + elements: authors, + filterBy: { + isPrimary: true, + }, + width: '1%', + } ); } + return _fields; - }, [ view.type, categoryId, type ] ); + }, [ view.type, categoryId, type, authors ] ); + // Reset the page number when the category changes. useEffect( () => { if ( previousCategoryId !== categoryId ) { @@ -352,13 +429,15 @@ export default function DataviewsPatterns() { } }, [ categoryId, previousCategoryId ] ); const { data, paginationInfo } = useMemo( () => { - // Since filters are applied server-side, - // we need to remove them from the view + // Search is managed server-side as well as filters for patterns. + // However, the author filter in template parts is done client-side. const viewWithoutFilters = { ...view }; delete viewWithoutFilters.search; - viewWithoutFilters.filters = []; + if ( type !== TEMPLATE_PART_POST_TYPE ) { + viewWithoutFilters.filters = []; + } return filterSortAndPaginate( patterns, viewWithoutFilters, fields ); - }, [ patterns, view, fields ] ); + }, [ patterns, view, fields, type ] ); const actions = useMemo( () => [