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: allow users to add filters dynamically #55992

Merged
merged 35 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ec83c64
Show/Hide filters based on ViewActions menu
oandregal Nov 8, 2023
24228c2
Make author & status filters not hidable
oandregal Nov 9, 2023
084b656
Allow existing filters to be removable per demo purposes
oandregal Nov 9, 2023
cdaba96
Remove enableFiltering prop
oandregal Nov 9, 2023
b988d54
Add/Remove filters from the new affordance
oandregal Nov 10, 2023
efd6a62
Remove FiltersVisibility menu
oandregal Nov 10, 2023
130c916
No filters visible by default
oandregal Nov 10, 2023
5935df8
Add filter value directly from AddFilter affordance
oandregal Nov 10, 2023
a9f9741
AddFilter only lists the hidden filters
oandregal Nov 10, 2023
385e0ff
Add new filters from columns if no present
oandregal Nov 10, 2023
e78c854
Reset filters also hides them back
oandregal Nov 10, 2023
7271f0a
Fix dropdown opening when trigger disabled
oandregal Nov 10, 2023
f3a6a9b
Set visibleFilters from sidebar views
oandregal Nov 13, 2023
9254fd9
Remove visibleFilters and render those that are set
oandregal Nov 13, 2023
6ea1af6
Fix rebase
oandregal Nov 13, 2023
c7fd8c0
Use icon
oandregal Nov 14, 2023
e57ffa3
Do not remove filter when all is selected
oandregal Nov 14, 2023
cae5879
Fix focus loss on adding the last filter
oandregal Nov 14, 2023
9005dd6
Absorb reset filters as part of the AddFilter button
oandregal Nov 14, 2023
e357584
Do not render AddFilter if no filters available
oandregal Nov 14, 2023
753c053
Simplify Filters
oandregal Nov 14, 2023
16f5315
Fix + icon
oandregal Nov 14, 2023
e3777f2
Reset page upon selecting a filter
oandregal Nov 14, 2023
1e99ee9
Fix alignment for Search & AddFilters
oandregal Nov 14, 2023
6daf5f2
Fix for SelectControl as well
oandregal Nov 14, 2023
353ca40
Use __nextHasNoMarginBottom
oandregal Nov 15, 2023
d4d8004
Extract ResetButton to where it was
oandregal Nov 15, 2023
0a655be
Disable AddFilter when no more filters to add
oandregal Nov 15, 2023
c10be61
Use disabled and __experimentalIsFocusable instead of aria-disabled i…
oandregal Nov 15, 2023
e9c62fb
Remove filter from list if it is being used
oandregal Nov 15, 2023
fb601d2
Remove all from the element list
oandregal Nov 15, 2023
7906c6f
Remove true booleans
oandregal Nov 15, 2023
f361400
Use compact size for buttons
oandregal Nov 15, 2023
b61ae18
Remove unnecessary __next40pxDefaultSize prop in buttons
oandregal Nov 15, 2023
a5628ab
Do not show ResetFilters if there are no filters to be used
oandregal Nov 15, 2023
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
5 changes: 1 addition & 4 deletions packages/edit-site/src/components/dataviews/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ Example:
{ field: 'author', operator: 'in', value: 2 },
{ field: 'status', operator: 'in', value: 'publish,draft' }
],
visibleFilters: [ 'author', 'status' ],
Copy link
Member Author

@oandregal oandregal Nov 13, 2023

Choose a reason for hiding this comment

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

We no longer need this, the visible filters are derived from the filters state.

hiddenFields: [ 'date', 'featured-image' ],
layout: {},
}
Expand All @@ -62,8 +61,7 @@ Example:
- `filters`: the filters applied to the dataset. Each item describes:
- `field`: which field this filter is bound to.
- `operator`: which type of filter it is. Only `in` available at the moment.
- `vaule`: the actual value selected by the user.
- `visibleFilters`: the `id` of the filters that are visible in the UI.
- `value`: the actual value selected by the user.
- `hiddenFields`: the `id` of the fields that are hidden in the UI.
- `layout`: ...

Expand All @@ -88,7 +86,6 @@ function MyCustomPageList() {
{ field: 'author', operator: 'in', value: 2 },
{ field: 'status', operator: 'in', value: 'publish,draft' }
],
visibleFilters: [ 'author', 'status' ],
hiddenFields: [ 'date', 'featured-image' ],
layout: {},
} );
Expand Down
111 changes: 111 additions & 0 deletions packages/edit-site/src/components/dataviews/add-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* WordPress dependencies
*/
import {
privateApis as componentsPrivateApis,
Button,
Icon,
} from '@wordpress/components';
import { chevronRightSmall, plus } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import { OPERATOR_IN } from './in-filter';

const {
DropdownMenuV2,
DropdownSubMenuV2,
DropdownSubMenuTriggerV2,
DropdownMenuItemV2,
} = unlock( componentsPrivateApis );

const VALID_OPERATORS = [ OPERATOR_IN ];

export default function AddFilter( { fields, view, onChangeView } ) {
const filters = [];
fields.forEach( ( field ) => {
if ( ! field.filters ) {
return;
}

field.filters.forEach( ( filter ) => {
if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) {
filters.push( {
field: field.id,
name: field.header,
operator: filter,
elements: field.elements || [],
isVisible: view.filters.some(
( f ) => f.field === field.id && f.operator === filter
),
} );
}
} );
} );

if ( filters.length === 0 ) {
return null;
}

return (
<DropdownMenuV2
label={ __( 'Add filter' ) }
trigger={
<Button
disabled={ filters.length === view.filters?.length }
__experimentalIsFocusable
icon={ plus }
variant="tertiary"
size="compact"
>
{ __( 'Add filter' ) }
</Button>
}
>
{ filters.map( ( filter ) => {
if ( filter.isVisible ) {
return null;
}

return (
<DropdownSubMenuV2
key={ filter.field }
trigger={
<DropdownSubMenuTriggerV2
suffix={ <Icon icon={ chevronRightSmall } /> }
>
{ filter.name }
</DropdownSubMenuTriggerV2>
}
>
{ filter.elements.map( ( element ) => (
<DropdownMenuItemV2
key={ element.value }
onSelect={ () => {
onChangeView( ( currentView ) => ( {
...currentView,
page: 1,
filters: [
...currentView.filters,
{
field: filter.field,
operator: 'in',
oandregal marked this conversation as resolved.
Show resolved Hide resolved
value: element.value,
},
],
} ) );
} }
role="menuitemcheckbox"
>
{ element.label }
</DropdownMenuItemV2>
) ) }
</DropdownSubMenuV2>
);
} ) }
</DropdownMenuV2>
);
}
68 changes: 34 additions & 34 deletions packages/edit-site/src/components/dataviews/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import { default as InFilter, OPERATOR_IN } from './in-filter';
import AddFilter from './add-filter';
import ResetFilters from './reset-filters';

const VALID_OPERATORS = [ OPERATOR_IN ];

export default function Filters( { fields, view, onChangeView } ) {
const filtersRegistered = [];
const filters = [];
fields.forEach( ( field ) => {
if ( ! field.filters ) {
return;
}

field.filters.forEach( ( filter ) => {
if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) {
filtersRegistered.push( {
filters.push( {
field: field.id,
name: field.header,
operator: filter,
Expand All @@ -31,46 +32,45 @@ export default function Filters( { fields, view, onChangeView } ) {
},
...( field.elements || [] ),
],
isVisible: view.filters.some(
( f ) => f.field === field.id && f.operator === filter
),
} );
}
} );
} );

const visibleFilters = view.visibleFilters
?.map( ( fieldName ) => {
const visibleFiltersForField = filtersRegistered.filter(
( f ) => f.field === fieldName
const filterComponents = filters?.map( ( filter ) => {
if ( ! filter.isVisible ) {
return null;
}

if ( OPERATOR_IN === filter.operator ) {
return (
<InFilter
key={ filter.field + '.' + filter.operator }
filter={ filter }
view={ view }
onChangeView={ onChangeView }
/>
);
}

if ( visibleFiltersForField.length === 0 ) {
return null;
}
return null;
} );

return visibleFiltersForField.map( ( filter ) => {
if ( OPERATOR_IN === filter.operator ) {
return (
<InFilter
key={ fieldName + '.' + filter.operator }
filter={ visibleFiltersForField[ 0 ] }
view={ view }
onChangeView={ onChangeView }
/>
);
}
return null;
} );
} )
.filter( Boolean );
filterComponents.push(
<AddFilter
key="add-filter"
fields={ fields }
view={ view }
onChangeView={ onChangeView }
/>
);

if ( visibleFilters?.length > 0 ) {
visibleFilters.push(
<ResetFilters
key="reset-filters"
view={ view }
onChangeView={ onChangeView }
/>
);
}
filterComponents.push(
<ResetFilters view={ view } onChangeView={ onChangeView } />
);

return visibleFilters;
return filterComponents.filter( Boolean );
}
14 changes: 7 additions & 7 deletions packages/edit-site/src/components/dataviews/in-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default ( { filter, view, onChangeView } ) => {
return (
<SelectControl
id={ id }
__nextHasNoMarginBottom
value={ activeValue }
prefix={
<InputControlPrefixWrapper
Expand All @@ -44,13 +45,12 @@ export default ( { filter, view, onChangeView } ) => {
( f ) =>
f.field !== filter.field || f.operator !== OPERATOR_IN
);
if ( value !== '' ) {
filters.push( {
field: filter.field,
operator: OPERATOR_IN,
value,
} );
}

filters.push( {
field: filter.field,
operator: OPERATOR_IN,
value,
} );

onChangeView( ( currentView ) => ( {
...currentView,
Expand Down
34 changes: 17 additions & 17 deletions packages/edit-site/src/components/dataviews/reset-filters.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
/**
* WordPress dependencies
*/
import { BaseControl, Button } from '@wordpress/components';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

export default ( { view, onChangeView } ) => {
return (
<BaseControl>
<Button
disabled={ view.search === '' && view.filters?.length === 0 }
variant="tertiary"
onClick={ () => {
onChangeView( ( currentView ) => ( {
...currentView,
page: 1,
search: '',
filters: [],
} ) );
} }
>
{ __( 'Reset filters' ) }
</Button>
</BaseControl>
<Button
disabled={ view.search === '' && view.filters?.length === 0 }
__experimentalIsFocusable
size="compact"
variant="tertiary"
onClick={ () => {
onChangeView( ( currentView ) => ( {
...currentView,
page: 1,
search: '',
filters: [],
} ) );
} }
>
{ __( 'Reset filters' ) }
</Button>
);
};
1 change: 1 addition & 0 deletions packages/edit-site/src/components/dataviews/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function Search( { label, view, onChangeView } ) {
const searchLabel = label || __( 'Filter list' );
return (
<SearchControl
__nextHasNoMarginBottom
onChange={ setSearch }
value={ search }
label={ searchLabel }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const DEFAULT_PAGE_BASE = {
field: 'date',
direction: 'desc',
},
visibleFilters: [ 'author', 'status' ],
// All fields are visible by default, so it's
// better to keep track of the hidden ones.
hiddenFields: [ 'date', 'featured-image' ],
Expand Down
Loading