@wordpress/dataviews 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +49 -18
- package/build/constants.js +28 -10
- package/build/constants.js.map +1 -1
- package/build/dataviews.js +3 -7
- package/build/dataviews.js.map +1 -1
- package/build/filter-and-sort-data-view.js +147 -0
- package/build/filter-and-sort-data-view.js.map +1 -0
- package/build/filter-summary.js +33 -12
- package/build/filter-summary.js.map +1 -1
- package/build/filters.js +11 -16
- package/build/filters.js.map +1 -1
- package/build/index.js +3 -9
- package/build/index.js.map +1 -1
- package/build/item-actions.js +20 -39
- package/build/item-actions.js.map +1 -1
- package/build/normalize-fields.js +25 -0
- package/build/normalize-fields.js.map +1 -0
- package/build/pagination.js +2 -2
- package/build/pagination.js.map +1 -1
- package/build/search-widget.js +34 -10
- package/build/search-widget.js.map +1 -1
- package/build/utils.js +25 -67
- package/build/utils.js.map +1 -1
- package/build/view-grid.js +25 -12
- package/build/view-grid.js.map +1 -1
- package/build/view-list.js +122 -58
- package/build/view-list.js.map +1 -1
- package/build/view-table.js +53 -8
- package/build/view-table.js.map +1 -1
- package/build-module/constants.js +27 -9
- package/build-module/constants.js.map +1 -1
- package/build-module/dataviews.js +3 -7
- package/build-module/dataviews.js.map +1 -1
- package/build-module/filter-and-sort-data-view.js +139 -0
- package/build-module/filter-and-sort-data-view.js.map +1 -0
- package/build-module/filter-summary.js +34 -13
- package/build-module/filter-summary.js.map +1 -1
- package/build-module/filters.js +12 -17
- package/build-module/filters.js.map +1 -1
- package/build-module/index.js +1 -1
- package/build-module/index.js.map +1 -1
- package/build-module/item-actions.js +20 -39
- package/build-module/item-actions.js.map +1 -1
- package/build-module/normalize-fields.js +19 -0
- package/build-module/normalize-fields.js.map +1 -0
- package/build-module/pagination.js +2 -2
- package/build-module/pagination.js.map +1 -1
- package/build-module/search-widget.js +35 -11
- package/build-module/search-widget.js.map +1 -1
- package/build-module/utils.js +25 -66
- package/build-module/utils.js.map +1 -1
- package/build-module/view-grid.js +26 -13
- package/build-module/view-grid.js.map +1 -1
- package/build-module/view-list.js +124 -60
- package/build-module/view-list.js.map +1 -1
- package/build-module/view-table.js +55 -10
- package/build-module/view-table.js.map +1 -1
- package/build-style/style-rtl.css +41 -11
- package/build-style/style.css +41 -11
- package/package.json +11 -11
- package/src/constants.js +35 -9
- package/src/dataviews.js +3 -7
- package/src/filter-and-sort-data-view.js +154 -0
- package/src/filter-summary.js +76 -23
- package/src/filters.js +20 -26
- package/src/index.js +1 -1
- package/src/item-actions.js +19 -55
- package/src/normalize-fields.js +17 -0
- package/src/pagination.js +2 -2
- package/src/search-widget.js +63 -21
- package/src/stories/fixtures.js +87 -2
- package/src/stories/index.story.js +5 -74
- package/src/style.scss +53 -14
- package/src/test/filter-and-sort-data-view.js +276 -0
- package/src/utils.js +38 -56
- package/src/view-grid.js +36 -11
- package/src/view-list.js +159 -69
- package/src/view-table.js +71 -9
package/src/dataviews.js
CHANGED
|
@@ -13,6 +13,7 @@ import Filters from './filters';
|
|
|
13
13
|
import Search from './search';
|
|
14
14
|
import { VIEW_LAYOUTS, LAYOUT_TABLE, LAYOUT_GRID } from './constants';
|
|
15
15
|
import BulkActions from './bulk-actions';
|
|
16
|
+
import { normalizeFields } from './normalize-fields';
|
|
16
17
|
|
|
17
18
|
const defaultGetItemId = ( item ) => item.id;
|
|
18
19
|
const defaultOnSelectionChange = () => {};
|
|
@@ -33,7 +34,7 @@ export default function DataViews( {
|
|
|
33
34
|
fields,
|
|
34
35
|
search = true,
|
|
35
36
|
searchLabel = undefined,
|
|
36
|
-
actions,
|
|
37
|
+
actions = [],
|
|
37
38
|
data,
|
|
38
39
|
getItemId = defaultGetItemId,
|
|
39
40
|
isLoading = false,
|
|
@@ -76,12 +77,7 @@ export default function DataViews( {
|
|
|
76
77
|
const ViewComponent = VIEW_LAYOUTS.find(
|
|
77
78
|
( v ) => v.type === view.type
|
|
78
79
|
).component;
|
|
79
|
-
const _fields = useMemo( () =>
|
|
80
|
-
return fields.map( ( field ) => ( {
|
|
81
|
-
...field,
|
|
82
|
-
render: field.render || field.getValue,
|
|
83
|
-
} ) );
|
|
84
|
-
}, [ fields ] );
|
|
80
|
+
const _fields = useMemo( () => normalizeFields( fields ), [ fields ] );
|
|
85
81
|
|
|
86
82
|
const hasPossibleBulkAction = useSomeItemHasAPossibleBulkAction(
|
|
87
83
|
actions,
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import removeAccents from 'remove-accents';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
OPERATOR_IS,
|
|
11
|
+
OPERATOR_IS_NOT,
|
|
12
|
+
OPERATOR_IS_NONE,
|
|
13
|
+
OPERATOR_IS_ANY,
|
|
14
|
+
OPERATOR_IS_ALL,
|
|
15
|
+
OPERATOR_IS_NOT_ALL,
|
|
16
|
+
} from './constants';
|
|
17
|
+
import { normalizeFields } from './normalize-fields';
|
|
18
|
+
|
|
19
|
+
function normalizeSearchInput( input = '' ) {
|
|
20
|
+
return removeAccents( input.trim().toLowerCase() );
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const EMPTY_ARRAY = [];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Applies the filtering, sorting and pagination to the raw data based on the view configuration.
|
|
27
|
+
*
|
|
28
|
+
* @param {any[]} data Raw data.
|
|
29
|
+
* @param {Object} view View config.
|
|
30
|
+
* @param {Object[]} fields Fields config.
|
|
31
|
+
*
|
|
32
|
+
* @return {Object} { data: any[], paginationInfo: { totalItems: number, totalPages: number } }
|
|
33
|
+
*/
|
|
34
|
+
export function filterSortAndPaginate( data, view, fields ) {
|
|
35
|
+
if ( ! data ) {
|
|
36
|
+
return {
|
|
37
|
+
data: EMPTY_ARRAY,
|
|
38
|
+
paginationInfo: { totalItems: 0, totalPages: 0 },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const _fields = normalizeFields( fields );
|
|
42
|
+
let filteredData = [ ...data ];
|
|
43
|
+
// Handle global search.
|
|
44
|
+
if ( view.search ) {
|
|
45
|
+
const normalizedSearch = normalizeSearchInput( view.search );
|
|
46
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
47
|
+
return _fields
|
|
48
|
+
.filter( ( field ) => field.enableGlobalSearch )
|
|
49
|
+
.map( ( field ) => {
|
|
50
|
+
return normalizeSearchInput( field.getValue( { item } ) );
|
|
51
|
+
} )
|
|
52
|
+
.some( ( field ) => field.includes( normalizedSearch ) );
|
|
53
|
+
} );
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if ( view.filters.length > 0 ) {
|
|
57
|
+
view.filters.forEach( ( filter ) => {
|
|
58
|
+
const field = _fields.find(
|
|
59
|
+
( _field ) => _field.id === filter.field
|
|
60
|
+
);
|
|
61
|
+
if (
|
|
62
|
+
filter.operator === OPERATOR_IS_ANY &&
|
|
63
|
+
filter?.value?.length > 0
|
|
64
|
+
) {
|
|
65
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
66
|
+
const fieldValue = field.getValue( { item } );
|
|
67
|
+
if ( Array.isArray( fieldValue ) ) {
|
|
68
|
+
return filter.value.some( ( filterValue ) =>
|
|
69
|
+
fieldValue.includes( filterValue )
|
|
70
|
+
);
|
|
71
|
+
} else if ( typeof fieldValue === 'string' ) {
|
|
72
|
+
return filter.value.includes( fieldValue );
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
} );
|
|
76
|
+
} else if (
|
|
77
|
+
filter.operator === OPERATOR_IS_NONE &&
|
|
78
|
+
filter?.value?.length > 0
|
|
79
|
+
) {
|
|
80
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
81
|
+
const fieldValue = field.getValue( { item } );
|
|
82
|
+
if ( Array.isArray( fieldValue ) ) {
|
|
83
|
+
return ! filter.value.some( ( filterValue ) =>
|
|
84
|
+
fieldValue.includes( filterValue )
|
|
85
|
+
);
|
|
86
|
+
} else if ( typeof fieldValue === 'string' ) {
|
|
87
|
+
return ! filter.value.includes( fieldValue );
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
} );
|
|
91
|
+
} else if (
|
|
92
|
+
filter.operator === OPERATOR_IS_ALL &&
|
|
93
|
+
filter?.value?.length > 0
|
|
94
|
+
) {
|
|
95
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
96
|
+
return filter.value.every( ( value ) => {
|
|
97
|
+
return field.getValue( { item } ).includes( value );
|
|
98
|
+
} );
|
|
99
|
+
} );
|
|
100
|
+
} else if (
|
|
101
|
+
filter.operator === OPERATOR_IS_NOT_ALL &&
|
|
102
|
+
filter?.value?.length > 0
|
|
103
|
+
) {
|
|
104
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
105
|
+
return filter.value.every( ( value ) => {
|
|
106
|
+
return ! field.getValue( { item } ).includes( value );
|
|
107
|
+
} );
|
|
108
|
+
} );
|
|
109
|
+
} else if ( filter.operator === OPERATOR_IS ) {
|
|
110
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
111
|
+
return filter.value === field.getValue( { item } );
|
|
112
|
+
} );
|
|
113
|
+
} else if ( filter.operator === OPERATOR_IS_NOT ) {
|
|
114
|
+
filteredData = filteredData.filter( ( item ) => {
|
|
115
|
+
return filter.value !== field.getValue( { item } );
|
|
116
|
+
} );
|
|
117
|
+
}
|
|
118
|
+
} );
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Handle sorting.
|
|
122
|
+
if ( view.sort ) {
|
|
123
|
+
const fieldId = view.sort.field;
|
|
124
|
+
const fieldToSort = _fields.find( ( field ) => {
|
|
125
|
+
return field.id === fieldId;
|
|
126
|
+
} );
|
|
127
|
+
filteredData.sort( ( a, b ) => {
|
|
128
|
+
const valueA = fieldToSort.getValue( { item: a } ) ?? '';
|
|
129
|
+
const valueB = fieldToSort.getValue( { item: b } ) ?? '';
|
|
130
|
+
return view.sort.direction === 'asc'
|
|
131
|
+
? valueA.localeCompare( valueB )
|
|
132
|
+
: valueB.localeCompare( valueA );
|
|
133
|
+
} );
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Handle pagination.
|
|
137
|
+
const hasPagination = view.page && view.perPage;
|
|
138
|
+
const start = hasPagination ? ( view.page - 1 ) * view.perPage : 0;
|
|
139
|
+
const totalItems = filteredData?.length || 0;
|
|
140
|
+
const totalPages = hasPagination
|
|
141
|
+
? Math.ceil( totalItems / view.perPage )
|
|
142
|
+
: 1;
|
|
143
|
+
filteredData = hasPagination
|
|
144
|
+
? filteredData?.slice( start, start + view.perPage )
|
|
145
|
+
: filteredData;
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
data: filteredData,
|
|
149
|
+
paginationInfo: {
|
|
150
|
+
totalItems,
|
|
151
|
+
totalPages,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
package/src/filter-summary.js
CHANGED
|
@@ -24,43 +24,93 @@ import { ENTER, SPACE } from '@wordpress/keycodes';
|
|
|
24
24
|
* Internal dependencies
|
|
25
25
|
*/
|
|
26
26
|
import SearchWidget from './search-widget';
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
OPERATORS,
|
|
29
|
+
OPERATOR_IS,
|
|
30
|
+
OPERATOR_IS_NOT,
|
|
31
|
+
OPERATOR_IS_ANY,
|
|
32
|
+
OPERATOR_IS_NONE,
|
|
33
|
+
OPERATOR_IS_ALL,
|
|
34
|
+
OPERATOR_IS_NOT_ALL,
|
|
35
|
+
} from './constants';
|
|
28
36
|
|
|
29
|
-
const FilterText = ( {
|
|
30
|
-
if (
|
|
37
|
+
const FilterText = ( { activeElements, filterInView, filter } ) => {
|
|
38
|
+
if ( activeElements === undefined || activeElements.length === 0 ) {
|
|
31
39
|
return filter.name;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
const filterTextWrappers = {
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
Name: <span className="dataviews-filter-summary__filter-text-name" />,
|
|
44
|
+
Value: <span className="dataviews-filter-summary__filter-text-value" />,
|
|
37
45
|
};
|
|
38
46
|
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
if ( filterInView?.operator === OPERATOR_IS_ANY ) {
|
|
48
|
+
return createInterpolateElement(
|
|
49
|
+
sprintf(
|
|
50
|
+
/* translators: 1: Filter name. 3: Filter value. e.g.: "Author is any: Admin, Editor". */
|
|
51
|
+
__( '<Name>%1$s is any: </Name><Value>%2$s</Value>' ),
|
|
52
|
+
filter.name,
|
|
53
|
+
activeElements.map( ( element ) => element.label ).join( ', ' )
|
|
54
|
+
),
|
|
55
|
+
filterTextWrappers
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ( filterInView?.operator === OPERATOR_IS_NONE ) {
|
|
60
|
+
return createInterpolateElement(
|
|
61
|
+
sprintf(
|
|
62
|
+
/* translators: 1: Filter name. 3: Filter value. e.g.: "Author is none: Admin, Editor". */
|
|
63
|
+
__( '<Name>%1$s is none: </Name><Value>%2$s</Value>' ),
|
|
64
|
+
filter.name,
|
|
65
|
+
activeElements.map( ( element ) => element.label ).join( ', ' )
|
|
66
|
+
),
|
|
67
|
+
filterTextWrappers
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if ( filterInView?.operator === OPERATOR_IS_ALL ) {
|
|
43
72
|
return createInterpolateElement(
|
|
44
73
|
sprintf(
|
|
45
|
-
/* translators: 1: Filter name.
|
|
46
|
-
__( '<
|
|
74
|
+
/* translators: 1: Filter name. 3: Filter value. e.g.: "Author is all: Admin, Editor". */
|
|
75
|
+
__( '<Name>%1$s is all: </Name><Value>%2$s</Value>' ),
|
|
47
76
|
filter.name,
|
|
48
|
-
|
|
77
|
+
activeElements.map( ( element ) => element.label ).join( ', ' )
|
|
49
78
|
),
|
|
50
79
|
filterTextWrappers
|
|
51
80
|
);
|
|
52
81
|
}
|
|
53
82
|
|
|
54
|
-
if (
|
|
55
|
-
activeElement !== undefined &&
|
|
56
|
-
filterInView?.operator === OPERATOR_NOT_IN
|
|
57
|
-
) {
|
|
83
|
+
if ( filterInView?.operator === OPERATOR_IS_NOT_ALL ) {
|
|
58
84
|
return createInterpolateElement(
|
|
59
85
|
sprintf(
|
|
60
|
-
/* translators: 1: Filter name.
|
|
61
|
-
__( '<
|
|
86
|
+
/* translators: 1: Filter name. 3: Filter value. e.g.: "Author is not all: Admin, Editor". */
|
|
87
|
+
__( '<Name>%1$s is not all: </Name><Value>%2$s</Value>' ),
|
|
62
88
|
filter.name,
|
|
63
|
-
|
|
89
|
+
activeElements.map( ( element ) => element.label ).join( ', ' )
|
|
90
|
+
),
|
|
91
|
+
filterTextWrappers
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if ( filterInView?.operator === OPERATOR_IS ) {
|
|
96
|
+
return createInterpolateElement(
|
|
97
|
+
sprintf(
|
|
98
|
+
/* translators: 1: Filter name. 3: Filter value. e.g.: "Author is: Admin". */
|
|
99
|
+
__( '<Name>%1$s is: </Name><Value>%2$s</Value>' ),
|
|
100
|
+
filter.name,
|
|
101
|
+
activeElements[ 0 ].label
|
|
102
|
+
),
|
|
103
|
+
filterTextWrappers
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if ( filterInView?.operator === OPERATOR_IS_NOT ) {
|
|
108
|
+
return createInterpolateElement(
|
|
109
|
+
sprintf(
|
|
110
|
+
/* translators: 1: Filter name. 3: Filter value. e.g.: "Author is not: Admin". */
|
|
111
|
+
__( '<Name>%1$s is not: </Name><Value>%2$s</Value>' ),
|
|
112
|
+
filter.name,
|
|
113
|
+
activeElements[ 0 ].label
|
|
64
114
|
),
|
|
65
115
|
filterTextWrappers
|
|
66
116
|
);
|
|
@@ -140,9 +190,12 @@ export default function FilterSummary( {
|
|
|
140
190
|
const toggleRef = useRef();
|
|
141
191
|
const { filter, view, onChangeView } = commonProps;
|
|
142
192
|
const filterInView = view.filters.find( ( f ) => f.field === filter.field );
|
|
143
|
-
const
|
|
144
|
-
(
|
|
145
|
-
|
|
193
|
+
const activeElements = filter.elements.filter( ( element ) => {
|
|
194
|
+
if ( filter.singleSelection ) {
|
|
195
|
+
return element.value === filterInView?.value;
|
|
196
|
+
}
|
|
197
|
+
return filterInView?.value?.includes( element.value );
|
|
198
|
+
} );
|
|
146
199
|
const isPrimary = filter.isPrimary;
|
|
147
200
|
const hasValues = filterInView?.value !== undefined;
|
|
148
201
|
const canResetOrRemove = ! isPrimary || hasValues;
|
|
@@ -188,7 +241,7 @@ export default function FilterSummary( {
|
|
|
188
241
|
ref={ toggleRef }
|
|
189
242
|
>
|
|
190
243
|
<FilterText
|
|
191
|
-
|
|
244
|
+
activeElements={ activeElements }
|
|
192
245
|
filterInView={ filterInView }
|
|
193
246
|
filter={ filter }
|
|
194
247
|
/>
|
package/src/filters.js
CHANGED
|
@@ -10,7 +10,7 @@ import FilterSummary from './filter-summary';
|
|
|
10
10
|
import AddFilter from './add-filter';
|
|
11
11
|
import ResetFilters from './reset-filters';
|
|
12
12
|
import { sanitizeOperators } from './utils';
|
|
13
|
-
import {
|
|
13
|
+
import { ALL_OPERATORS, OPERATOR_IS, OPERATOR_IS_NOT } from './constants';
|
|
14
14
|
import { __experimentalHStack as HStack } from '@wordpress/components';
|
|
15
15
|
|
|
16
16
|
const Filters = memo( function Filters( {
|
|
@@ -23,7 +23,7 @@ const Filters = memo( function Filters( {
|
|
|
23
23
|
const addFilterRef = useRef();
|
|
24
24
|
const filters = [];
|
|
25
25
|
fields.forEach( ( field ) => {
|
|
26
|
-
if ( ! field.
|
|
26
|
+
if ( ! field.elements?.length ) {
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -32,30 +32,24 @@ const Filters = memo( function Filters( {
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
f.operator
|
|
54
|
-
)
|
|
55
|
-
),
|
|
56
|
-
isPrimary,
|
|
57
|
-
} );
|
|
58
|
-
}
|
|
35
|
+
const isPrimary = !! field.filterBy?.isPrimary;
|
|
36
|
+
filters.push( {
|
|
37
|
+
field: field.id,
|
|
38
|
+
name: field.header,
|
|
39
|
+
elements: field.elements,
|
|
40
|
+
singleSelection: operators.some( ( op ) =>
|
|
41
|
+
[ OPERATOR_IS, OPERATOR_IS_NOT ].includes( op )
|
|
42
|
+
),
|
|
43
|
+
operators,
|
|
44
|
+
isVisible:
|
|
45
|
+
isPrimary ||
|
|
46
|
+
view.filters.some(
|
|
47
|
+
( f ) =>
|
|
48
|
+
f.field === field.id &&
|
|
49
|
+
ALL_OPERATORS.includes( f.operator )
|
|
50
|
+
),
|
|
51
|
+
isPrimary,
|
|
52
|
+
} );
|
|
59
53
|
} );
|
|
60
54
|
// Sort filters by primary property. We need the primary filters to be first.
|
|
61
55
|
// Then we sort by name.
|
package/src/index.js
CHANGED
package/src/item-actions.js
CHANGED
|
@@ -105,37 +105,28 @@ function ActionsDropdownMenuGroup( { actions, item } ) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
export default function ItemActions( { item, actions, isCompact } ) {
|
|
108
|
-
const { primaryActions,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if ( action.isPrimary && !! action.icon ) {
|
|
117
|
-
accumulator.primaryActions.push( action );
|
|
118
|
-
} else {
|
|
119
|
-
accumulator.secondaryActions.push( action );
|
|
120
|
-
}
|
|
121
|
-
return accumulator;
|
|
122
|
-
},
|
|
123
|
-
{ primaryActions: [], secondaryActions: [] }
|
|
108
|
+
const { primaryActions, eligibleActions } = useMemo( () => {
|
|
109
|
+
// If an action is eligible for all items, doesn't need
|
|
110
|
+
// to provide the `isEligible` function.
|
|
111
|
+
const _eligibleActions = actions.filter(
|
|
112
|
+
( action ) => ! action.isEligible || action.isEligible( item )
|
|
113
|
+
);
|
|
114
|
+
const _primaryActions = _eligibleActions.filter(
|
|
115
|
+
( action ) => action.isPrimary && !! action.icon
|
|
124
116
|
);
|
|
117
|
+
return {
|
|
118
|
+
primaryActions: _primaryActions,
|
|
119
|
+
eligibleActions: _eligibleActions,
|
|
120
|
+
};
|
|
125
121
|
}, [ actions, item ] );
|
|
126
122
|
if ( isCompact ) {
|
|
127
|
-
return
|
|
128
|
-
<CompactItemActions
|
|
129
|
-
item={ item }
|
|
130
|
-
primaryActions={ primaryActions }
|
|
131
|
-
secondaryActions={ secondaryActions }
|
|
132
|
-
/>
|
|
133
|
-
);
|
|
123
|
+
return <CompactItemActions item={ item } actions={ eligibleActions } />;
|
|
134
124
|
}
|
|
135
125
|
return (
|
|
136
126
|
<HStack
|
|
137
127
|
spacing={ 1 }
|
|
138
128
|
justify="flex-end"
|
|
129
|
+
className="dataviews-item-actions"
|
|
139
130
|
style={ {
|
|
140
131
|
flexShrink: '0',
|
|
141
132
|
width: 'auto',
|
|
@@ -161,27 +152,12 @@ export default function ItemActions( { item, actions, isCompact } ) {
|
|
|
161
152
|
/>
|
|
162
153
|
);
|
|
163
154
|
} ) }
|
|
164
|
-
<
|
|
165
|
-
trigger={
|
|
166
|
-
<Button
|
|
167
|
-
size="compact"
|
|
168
|
-
icon={ moreVertical }
|
|
169
|
-
label={ __( 'Actions' ) }
|
|
170
|
-
disabled={ ! secondaryActions.length }
|
|
171
|
-
/>
|
|
172
|
-
}
|
|
173
|
-
placement="bottom-end"
|
|
174
|
-
>
|
|
175
|
-
<ActionsDropdownMenuGroup
|
|
176
|
-
actions={ secondaryActions }
|
|
177
|
-
item={ item }
|
|
178
|
-
/>
|
|
179
|
-
</DropdownMenu>
|
|
155
|
+
<CompactItemActions item={ item } actions={ eligibleActions } />
|
|
180
156
|
</HStack>
|
|
181
157
|
);
|
|
182
158
|
}
|
|
183
159
|
|
|
184
|
-
function CompactItemActions( { item,
|
|
160
|
+
function CompactItemActions( { item, actions } ) {
|
|
185
161
|
return (
|
|
186
162
|
<DropdownMenu
|
|
187
163
|
trigger={
|
|
@@ -189,25 +165,13 @@ function CompactItemActions( { item, primaryActions, secondaryActions } ) {
|
|
|
189
165
|
size="compact"
|
|
190
166
|
icon={ moreVertical }
|
|
191
167
|
label={ __( 'Actions' ) }
|
|
192
|
-
disabled={
|
|
193
|
-
|
|
194
|
-
}
|
|
168
|
+
disabled={ ! actions.length }
|
|
169
|
+
className="dataviews-all-actions-button"
|
|
195
170
|
/>
|
|
196
171
|
}
|
|
197
172
|
placement="bottom-end"
|
|
198
173
|
>
|
|
199
|
-
{
|
|
200
|
-
<ActionsDropdownMenuGroup
|
|
201
|
-
actions={ primaryActions }
|
|
202
|
-
item={ item }
|
|
203
|
-
/>
|
|
204
|
-
) }
|
|
205
|
-
{ !! secondaryActions.length && (
|
|
206
|
-
<ActionsDropdownMenuGroup
|
|
207
|
-
actions={ secondaryActions }
|
|
208
|
-
item={ item }
|
|
209
|
-
/>
|
|
210
|
-
) }
|
|
174
|
+
<ActionsDropdownMenuGroup actions={ actions } item={ item } />
|
|
211
175
|
</DropdownMenu>
|
|
212
176
|
);
|
|
213
177
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply default values and normalize the fields config.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object[]} fields Raw Fields.
|
|
5
|
+
* @return {Object[]} Normalized fields.
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeFields( fields ) {
|
|
8
|
+
return fields.map( ( field ) => {
|
|
9
|
+
const getValue = field.getValue || ( ( { item } ) => item[ field.id ] );
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
...field,
|
|
13
|
+
getValue,
|
|
14
|
+
render: field.render || getValue,
|
|
15
|
+
};
|
|
16
|
+
} );
|
|
17
|
+
}
|
package/src/pagination.js
CHANGED
|
@@ -36,11 +36,11 @@ const Pagination = memo( function Pagination( {
|
|
|
36
36
|
{ createInterpolateElement(
|
|
37
37
|
sprintf(
|
|
38
38
|
// translators: %s: Total number of pages.
|
|
39
|
-
_x( 'Page <
|
|
39
|
+
_x( 'Page <CurrentPageControl /> of %s', 'paging' ),
|
|
40
40
|
totalPages
|
|
41
41
|
),
|
|
42
42
|
{
|
|
43
|
-
|
|
43
|
+
CurrentPageControl: (
|
|
44
44
|
<SelectControl
|
|
45
45
|
aria-label={ __( 'Current page' ) }
|
|
46
46
|
value={ view.page }
|