Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataViews: Refactor the edit function to be based on discrete controls #64404

Merged
merged 1 commit into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/dataviews/src/dataform-controls/datetime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* WordPress dependencies
*/
import { BaseControl, TimePicker } from '@wordpress/components';
import { useCallback } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { DataFormControlProps } from '../types';

export default function DateTime< Item >( {
data,
field,
onChange,
}: DataFormControlProps< Item > ) {
const { id, label } = field;
const value = field.getValue( { item: data } );

const onChangeControl = useCallback(
( newValue: string | null ) => onChange( { [ id ]: newValue } ),
[ id, onChange ]
);

return (
<fieldset>
<BaseControl.VisualLabel as="legend">
{ label }
</BaseControl.VisualLabel>
<TimePicker
currentTime={ value }
onChange={ onChangeControl }
hideLabelFromVision
/>
</fieldset>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ import type {
DataFormControlProps,
Field,
FieldTypeDefinition,
} from '../../types';
} from '../types';
import datetime from './datetime';
import integer from './integer';
import radio from './radio';
import select from './select';
import text from './text';

interface FormControls {
[ key: string ]: ComponentType< DataFormControlProps< any > >;
}

const FORM_CONTROLS: FormControls = {
datetime,
integer,
radio,
select,
text,
};

export function getControl< Item >(
Expand All @@ -29,18 +37,25 @@ export function getControl< Item >(
return field.Edit;
}

let control;
if ( typeof field.Edit === 'string' ) {
control = getControlByType( field.Edit );
return getControlByType( field.Edit );
}

return control || fieldTypeDefinition.Edit;
if ( field.elements ) {
return getControlByType( 'select' );
}

if ( typeof fieldTypeDefinition.Edit === 'string' ) {
return getControlByType( fieldTypeDefinition.Edit );
}

return fieldTypeDefinition.Edit;
}

export function getControlByType( type: string ) {
if ( Object.keys( FORM_CONTROLS ).includes( type ) ) {
return FORM_CONTROLS[ type ];
}

return null;
throw 'Control ' + type + ' not found';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that, for TypeScript, getControlByType always returns a control? When implementing this same idea the issue I had was working with the null through all the chain of components.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We we need to throw an error here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason, is what @oandregal said above, it's the way to force typescript to consider that this function should always return a defined control.

}
38 changes: 38 additions & 0 deletions packages/dataviews/src/dataform-controls/integer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* WordPress dependencies
*/
import { __experimentalNumberControl as NumberControl } from '@wordpress/components';
import { useCallback } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { DataFormControlProps } from '../types';

export default function Integer< Item >( {
data,
field,
onChange,
hideLabelFromVision,
}: DataFormControlProps< Item > ) {
const { id, label, description } = field;
const value = field.getValue( { item: data } ) ?? '';
const onChangeControl = useCallback(
( newValue: string | undefined ) =>
onChange( {
[ id ]: Number( newValue ),
} ),
[ id, onChange ]
);

return (
<NumberControl
label={ label }
help={ description }
value={ value }
onChange={ onChangeControl }
__next40pxDefaultSize
hideLabelFromVision={ hideLabelFromVision }
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { useCallback } from '@wordpress/element';
/**
* Internal dependencies
*/
import type { DataFormControlProps } from '../../types';
import type { DataFormControlProps } from '../types';

export default function Edit< Item >( {
export default function Radio< Item >( {
data,
field,
onChange,
Expand All @@ -20,10 +20,9 @@ export default function Edit< Item >( {

const onChangeControl = useCallback(
( newValue: string ) =>
onChange( ( prevItem: Item ) => ( {
...prevItem,
onChange( {
[ id ]: newValue,
} ) ),
} ),
[ id, onChange ]
);

Expand Down
52 changes: 52 additions & 0 deletions packages/dataviews/src/dataform-controls/select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* WordPress dependencies
*/
import { SelectControl } from '@wordpress/components';
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import type { DataFormControlProps } from '../types';

export default function Select< Item >( {
data,
field,
onChange,
hideLabelFromVision,
}: DataFormControlProps< Item > ) {
const { id, label } = field;
const value = field.getValue( { item: data } ) ?? '';
const onChangeControl = useCallback(
( newValue: any ) =>
onChange( {
[ id ]: newValue,
} ),
[ id, onChange ]
);

const elements = [
/*
* Value can be undefined when:
*
* - the field is not required
* - in bulk editing
*
*/
{ label: __( 'Select item' ), value: '' },
...( field?.elements ?? [] ),
];

return (
<SelectControl
label={ label }
value={ value }
options={ elements }
onChange={ onChangeControl }
__next40pxDefaultSize
__nextHasNoMarginBottom
hideLabelFromVision={ hideLabelFromVision }
/>
);
}
40 changes: 40 additions & 0 deletions packages/dataviews/src/dataform-controls/text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* WordPress dependencies
*/
import { TextControl } from '@wordpress/components';
import { useCallback } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { DataFormControlProps } from '../types';

export default function Text< Item >( {
data,
field,
onChange,
hideLabelFromVision,
}: DataFormControlProps< Item > ) {
const { id, label, placeholder } = field;
const value = field.getValue( { item: data } );

const onChangeControl = useCallback(
( newValue: string ) =>
onChange( {
[ id ]: newValue,
} ),
[ id, onChange ]
);

return (
<TextControl
label={ label }
placeholder={ placeholder }
value={ value ?? '' }
onChange={ onChangeControl }
__next40pxDefaultSize
__nextHasNoMarginBottom
hideLabelFromVision={ hideLabelFromVision }
/>
);
}
67 changes: 2 additions & 65 deletions packages/dataviews/src/field-types/datetime.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
/**
* WordPress dependencies
*/
import { BaseControl, TimePicker, SelectControl } from '@wordpress/components';
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import type {
SortDirection,
ValidationContext,
DataFormControlProps,
} from '../types';
import type { SortDirection, ValidationContext } from '../types';

function sort( a: any, b: any, direction: SortDirection ) {
const timeA = new Date( a ).getTime();
Expand All @@ -32,60 +21,8 @@ function isValid( value: any, context?: ValidationContext ) {
return true;
}

function Edit< Item >( {
data,
field,
onChange,
}: DataFormControlProps< Item > ) {
const { id, label } = field;
const value = field.getValue( { item: data } );

const onChangeControl = useCallback(
( newValue: string | null ) => onChange( { [ id ]: newValue } ),
[ id, onChange ]
);

if ( field.elements ) {
const elements = [
/*
* Value can be undefined when:
*
* - the field is not required
* - in bulk editing
*
*/
{ label: __( 'Select item' ), value: '' },
...field.elements,
];

return (
<SelectControl
label={ label }
value={ value }
options={ elements }
onChange={ onChangeControl }
__next40pxDefaultSize
__nextHasNoMarginBottom
/>
);
}

return (
<fieldset>
<BaseControl.VisualLabel as="legend">
{ label }
</BaseControl.VisualLabel>
<TimePicker
currentTime={ value }
onChange={ onChangeControl }
hideLabelFromVision
/>
</fieldset>
);
}

export default {
sort,
isValid,
Edit,
Edit: 'datetime',
};
Loading
Loading