From 02622aee4bd75935ed73c19a40fdcbc9a1b7d5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:57:41 +0200 Subject: [PATCH] Add `comment_status` field to quick edit (#64370) Co-authored-by: oandregal Co-authored-by: youknowriad Co-authored-by: ntsekouras --- .../components/dataform-controls/index.tsx | 46 +++++++++++++++++++ .../components/dataform-controls/radio.tsx | 43 +++++++++++++++++ .../dataform/stories/index.story.tsx | 22 ++++++++- packages/dataviews/src/normalize-fields.ts | 3 +- packages/dataviews/src/types.ts | 22 ++++++++- .../src/components/post-edit/index.js | 2 +- .../src/components/post-fields/index.js | 26 +++++++++++ 7 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 packages/dataviews/src/components/dataform-controls/index.tsx create mode 100644 packages/dataviews/src/components/dataform-controls/radio.tsx diff --git a/packages/dataviews/src/components/dataform-controls/index.tsx b/packages/dataviews/src/components/dataform-controls/index.tsx new file mode 100644 index 00000000000000..dd913269cd09ea --- /dev/null +++ b/packages/dataviews/src/components/dataform-controls/index.tsx @@ -0,0 +1,46 @@ +/** + * External dependencies + */ +import type { ComponentType } from 'react'; + +/** + * Internal dependencies + */ +import type { + DataFormControlProps, + Field, + FieldTypeDefinition, +} from '../../types'; +import radio from './radio'; + +interface FormControls { + [ key: string ]: ComponentType< DataFormControlProps< any > >; +} + +const FORM_CONTROLS: FormControls = { + radio, +}; + +export function getControl< Item >( + field: Field< Item >, + fieldTypeDefinition: FieldTypeDefinition< Item > +) { + if ( typeof field.Edit === 'function' ) { + return field.Edit; + } + + let control; + if ( typeof field.Edit === 'string' ) { + control = getControlByType( field.Edit ); + } + + return control || fieldTypeDefinition.Edit; +} + +export function getControlByType( type: string ) { + if ( Object.keys( FORM_CONTROLS ).includes( type ) ) { + return FORM_CONTROLS[ type ]; + } + + return null; +} diff --git a/packages/dataviews/src/components/dataform-controls/radio.tsx b/packages/dataviews/src/components/dataform-controls/radio.tsx new file mode 100644 index 00000000000000..d264aa6c24b7fb --- /dev/null +++ b/packages/dataviews/src/components/dataform-controls/radio.tsx @@ -0,0 +1,43 @@ +/** + * WordPress dependencies + */ +import { RadioControl } from '@wordpress/components'; +import { useCallback } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import type { DataFormControlProps } from '../../types'; + +export default function Edit< Item >( { + data, + field, + onChange, + hideLabelFromVision, +}: DataFormControlProps< Item > ) { + const { id, label } = field; + const value = field.getValue( { item: data } ); + + const onChangeControl = useCallback( + ( newValue: string ) => + onChange( ( prevItem: Item ) => ( { + ...prevItem, + [ id ]: newValue, + } ) ), + [ id, onChange ] + ); + + if ( field.elements ) { + return ( + + ); + } + + return null; +} diff --git a/packages/dataviews/src/components/dataform/stories/index.story.tsx b/packages/dataviews/src/components/dataform/stories/index.story.tsx index 7808756b7b6557..7f3c5ff879b72a 100644 --- a/packages/dataviews/src/components/dataform/stories/index.story.tsx +++ b/packages/dataviews/src/components/dataform/stories/index.story.tsx @@ -56,6 +56,17 @@ const fields = [ { value: 2, label: 'John' }, ], }, + { + id: 'reviewer', + label: 'Reviewer', + type: 'text' as const, + Edit: 'radio' as const, + elements: [ + { value: 'fulano', label: 'Fulano' }, + { value: 'mengano', label: 'Mengano' }, + { value: 'zutano', label: 'Zutano' }, + ], + }, { id: 'status', label: 'Status', @@ -73,12 +84,21 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { order: 2, author: 1, status: 'draft', + reviewer: 'fulano', date: '2021-01-01T12:00:00', birthdate: '1950-02-23T12:00:00', } ); const form = { - fields: [ 'title', 'order', 'author', 'status', 'date', 'birthdate' ], + fields: [ + 'title', + 'order', + 'author', + 'reviewer', + 'status', + 'date', + 'birthdate', + ], }; return ( diff --git a/packages/dataviews/src/normalize-fields.ts b/packages/dataviews/src/normalize-fields.ts index 680749df5344a6..54992ff22fe2ae 100644 --- a/packages/dataviews/src/normalize-fields.ts +++ b/packages/dataviews/src/normalize-fields.ts @@ -3,6 +3,7 @@ */ import getFieldTypeDefinition from './field-types'; import type { Field, NormalizedField } from './types'; +import { getControl } from './components/dataform-controls'; /** * Apply default values and normalize the fields config. @@ -38,7 +39,7 @@ export function normalizeFields< Item >( ); }; - const Edit = field.Edit || fieldTypeDefinition.Edit; + const Edit = getControl( field, fieldTypeDefinition ); const renderFromElements = ( { item }: { item: Item } ) => { const value = getValue( { item } ); diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 2e87d1371acb61..d8a5ee8f68ecef 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -53,6 +53,26 @@ export type ValidationContext = { elements?: Option[]; }; +/** + * An abstract interface for Field based on the field type. + */ +export type FieldTypeDefinition< Item > = { + /** + * Callback used to sort the field. + */ + sort: ( a: Item, b: Item, direction: SortDirection ) => number; + + /** + * Callback used to validate the field. + */ + isValid: ( item: Item, context?: ValidationContext ) => boolean; + + /** + * Callback used to render an edit control for the field. + */ + Edit: ComponentType< DataFormControlProps< Item > >; +}; + /** * A dataview field for a specific property of a data type. */ @@ -90,7 +110,7 @@ export type Field< Item > = { /** * Callback used to render an edit control for the field. */ - Edit?: ComponentType< DataFormControlProps< Item > >; + Edit?: ComponentType< DataFormControlProps< Item > > | 'radio'; /** * Callback used to sort the field. diff --git a/packages/edit-site/src/components/post-edit/index.js b/packages/edit-site/src/components/post-edit/index.js index 35141f743cd2e3..0a56fdfe5786b7 100644 --- a/packages/edit-site/src/components/post-edit/index.js +++ b/packages/edit-site/src/components/post-edit/index.js @@ -51,7 +51,7 @@ function PostEditForm( { postType, postId } ) { const { fields } = usePostFields(); const form = { type: 'panel', - fields: [ 'title', 'author', 'date' ], + fields: [ 'title', 'author', 'date', 'comment_status' ], }; const [ edits, setEdits ] = useState( initialEdits ); const itemWithEdits = useMemo( () => { diff --git a/packages/edit-site/src/components/post-fields/index.js b/packages/edit-site/src/components/post-fields/index.js index 44625fbfbfafb9..b03b2c6f5be3c4 100644 --- a/packages/edit-site/src/components/post-fields/index.js +++ b/packages/edit-site/src/components/post-fields/index.js @@ -345,6 +345,32 @@ function usePostFields( viewType ) { return ; }, }, + { + id: 'comment_status', + label: __( 'Discussion' ), + type: 'text', + Edit: 'radio', + enableSorting: false, + filterBy: { + operators: [], + }, + elements: [ + { + value: 'open', + label: __( 'Open' ), + description: __( + 'Visitors can add new comments and replies.' + ), + }, + { + value: 'closed', + label: __( 'Closed' ), + description: __( + 'Visitors cannot add new comments or replies. Existing comments remain visible.' + ), + }, + ], + }, ], [ authors, viewType, frontPageId, postsPageId ] );