@@ -20,22 +20,93 @@ import {
2020 __experimentalToolsPanel as ToolsPanel ,
2121 __experimentalToolsPanelItem as ToolsPanelItem ,
2222} from '@wordpress/components' ;
23+ import { debounce } from '@wordpress/compose' ;
24+ import { useMemo , useState } from '@wordpress/element' ;
2325import { useSelect , useDispatch } from '@wordpress/data' ;
2426import { __ , sprintf } from '@wordpress/i18n' ;
27+ import { decodeEntities } from '@wordpress/html-entities' ;
2528import { store as coreStore } from '@wordpress/core-data' ;
2629
2730/**
2831 * Internal dependencies
2932 */
3033import { useToolsPanelDropdownMenuProps } from '../utils/hooks' ;
3134
32- const minimumUsersForCombobox = 25 ;
33-
3435const AUTHORS_QUERY = {
3536 who : 'authors' ,
3637 per_page : 100 ,
38+ _fields : 'id,name' ,
39+ context : 'view' ,
3740} ;
3841
42+ function AuthorCombobox ( { value, onChange } ) {
43+ const [ filterValue , setFilterValue ] = useState ( '' ) ;
44+ const { authors, isLoading } = useSelect (
45+ ( select ) => {
46+ const { getUsers, isResolving } = select ( coreStore ) ;
47+
48+ const query = { ...AUTHORS_QUERY } ;
49+ if ( filterValue ) {
50+ query . search = filterValue ;
51+ query . search_columns = [ 'name' ] ;
52+ }
53+
54+ return {
55+ authors : getUsers ( query ) ,
56+ isLoading : isResolving ( 'getUsers' , [ query ] ) ,
57+ } ;
58+ } ,
59+ [ filterValue ]
60+ ) ;
61+
62+ const authorOptions = useMemo ( ( ) => {
63+ const fetchedAuthors = ( authors ?? [ ] ) . map ( ( author ) => {
64+ return {
65+ value : author . id ,
66+ label : decodeEntities ( author . name ) ,
67+ } ;
68+ } ) ;
69+
70+ // Ensure the current author is included in the list.
71+ const foundAuthor = fetchedAuthors . findIndex (
72+ ( fetchedAuthor ) => value ?. id === fetchedAuthor . value
73+ ) ;
74+
75+ let currentAuthor = [ ] ;
76+ if ( foundAuthor < 0 && value ) {
77+ currentAuthor = [
78+ {
79+ value : value . id ,
80+ label : decodeEntities ( value . name ) ,
81+ } ,
82+ ] ;
83+ } else if ( foundAuthor < 0 && ! value ) {
84+ currentAuthor = [
85+ {
86+ value : 0 ,
87+ label : __ ( '(No author)' ) ,
88+ } ,
89+ ] ;
90+ }
91+
92+ return [ ...currentAuthor , ...fetchedAuthors ] ;
93+ } , [ authors , value ] ) ;
94+
95+ return (
96+ < ComboboxControl
97+ __next40pxDefaultSize
98+ __nextHasNoMarginBottom
99+ label = { __ ( 'Author' ) }
100+ options = { authorOptions }
101+ value = { value ?. id }
102+ onFilterValueChange = { debounce ( setFilterValue , 300 ) }
103+ onChange = { onChange }
104+ allowReset = { false }
105+ isLoading = { isLoading }
106+ />
107+ ) ;
108+ }
109+
39110function PostAuthorEdit ( {
40111 isSelected,
41112 context : { postType, postId, queryId } ,
@@ -45,22 +116,28 @@ function PostAuthorEdit( {
45116 const isDescendentOfQueryLoop = Number . isFinite ( queryId ) ;
46117 const dropdownMenuProps = useToolsPanelDropdownMenuProps ( ) ;
47118
48- const { authorId , authorDetails, authors , supportsAuthor } = useSelect (
119+ const { authorDetails, canAssignAuthor , supportsAuthor } = useSelect (
49120 ( select ) => {
50- const { getEditedEntityRecord, getUser, getUsers , getPostType } =
121+ const { getEditedEntityRecord, getUser, getPostType } =
51122 select ( coreStore ) ;
52- const _authorId = getEditedEntityRecord (
123+ const currentPost = getEditedEntityRecord (
53124 'postType' ,
54125 postType ,
55126 postId
56- ) ?. author ;
127+ ) ;
128+ const authorId = currentPost ?. author ;
57129
58130 return {
59- authorId : _authorId ,
60- authorDetails : _authorId ? getUser ( _authorId ) : null ,
61- authors : getUsers ( AUTHORS_QUERY ) ,
131+ authorDetails : authorId
132+ ? getUser ( authorId , { context : 'view' } )
133+ : null ,
62134 supportsAuthor :
63135 getPostType ( postType ) ?. supports ?. author ?? false ,
136+ canAssignAuthor : currentPost ?. _links ?. [
137+ 'wp:action-assign-author'
138+ ]
139+ ? true
140+ : false ,
64141 } ;
65142 } ,
66143 [ postType , postId ]
@@ -94,24 +171,14 @@ function PostAuthorEdit( {
94171 } ) ,
95172 } ) ;
96173
97- const authorOptions = authors ?. length
98- ? authors . map ( ( { id, name } ) => {
99- return {
100- value : id ,
101- label : name ,
102- } ;
103- } )
104- : [ ] ;
105-
106174 const handleSelect = ( nextAuthorId ) => {
107175 editEntityRecord ( 'postType' , postType , postId , {
108176 author : nextAuthorId ,
109177 } ) ;
110178 } ;
111179
112- const showCombobox = authorOptions . length >= minimumUsersForCombobox ;
113180 const showAuthorControl =
114- ! ! postId && ! isDescendentOfQueryLoop && authorOptions . length > 0 ;
181+ ! ! postId && ! isDescendentOfQueryLoop && canAssignAuthor ;
115182
116183 if ( ! supportsAuthor && postType !== undefined ) {
117184 return (
@@ -142,26 +209,10 @@ function PostAuthorEdit( {
142209 >
143210 { showAuthorControl && (
144211 < div style = { { gridColumn : '1 / -1' } } >
145- { ( showCombobox && (
146- < ComboboxControl
147- __next40pxDefaultSize
148- __nextHasNoMarginBottom
149- label = { __ ( 'Author' ) }
150- options = { authorOptions }
151- value = { authorId }
152- onChange = { handleSelect }
153- allowReset = { false }
154- />
155- ) ) || (
156- < SelectControl
157- __next40pxDefaultSize
158- __nextHasNoMarginBottom
159- label = { __ ( 'Author' ) }
160- value = { authorId }
161- options = { authorOptions }
162- onChange = { handleSelect }
163- />
164- ) }
212+ < AuthorCombobox
213+ value = { authorDetails }
214+ onChange = { handleSelect }
215+ />
165216 </ div >
166217 ) }
167218 < ToolsPanelItem
0 commit comments