Skip to content
Open
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
38 changes: 34 additions & 4 deletions packages/dataviews/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,25 @@ function MyCustomPageTable() {
};
}, [ view ] );

const { records } = useEntityRecords( 'postType', 'page', queryArgs );
const { records, totalItems, totalPages } = useEntityRecords( 'postType', 'page', queryArgs );

// You can use filterSortAndPaginate to apply additional client-side filtering if needed
// Pass totalItems and totalPages from the API to ensure correct pagination info
const { data: filteredData, paginationInfo } = useMemo(() => {
return filterSortAndPaginate(
records || [],
view,
fields,
{ totalItems, totalPages } // If you skip this, then ensure that the data is not paginated and -1 is passed to the API
);
}, [records, view, fields, totalItems, totalPages]);

return (
<DataViews
data={ records }
data={ filteredData }
view={ view }
onChangeView={ setView }
paginationInfo={ paginationInfo }
// ...
/>
);
Expand Down Expand Up @@ -528,13 +540,31 @@ Parameters:
- `data`: the dataset, as described in the "data" property of DataViews.
- `view`: the view config, as described in the "view" property of DataViews.
- `fields`: the fields config, as described in the "fields" property of DataViews.
- `options`: (optional) additional configuration options:
- `totalItems`: (optional) override the calculated total number of items. Useful when working with paginated data from an API.
- `totalPages`: (optional) override the calculated total number of pages. Useful when working with paginated data from an API.

Returns an object containing:

- `data`: the new dataset, with the view config applied.
- `paginationInfo`: object containing the following properties:
- `totalItems`: total number of items for the current view config.
- `totalPages`: total number of pages for the current view config.
- `totalItems`: total number of items for the current view config. If provided in options, uses that value instead of calculating from the data.
- `totalPages`: total number of pages for the current view config. If provided in options, uses that value instead of calculating from the data.

Example with server-side pagination:

```js
// When using with data that's already paginated from an API
const { records, totalItems, totalPages } = useEntityRecords('postType', 'page', queryArgs);

// Pass the totalItems and totalPages from the API to filterSortAndPaginate
const { data: filteredData, paginationInfo } = filterSortAndPaginate(
records,
view,
fields,
{ totalItems, totalPages }
);
```

### `isItemValid`

Expand Down
35 changes: 26 additions & 9 deletions packages/dataviews/src/filter-and-sort-data-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,23 @@ const EMPTY_ARRAY: [] = [];
/**
* Applies the filtering, sorting and pagination to the raw data based on the view configuration.
*
* @param data Raw data.
* @param view View config.
* @param fields Fields config.
* @param data Raw data.
* @param view View config.
* @param fields Fields config.
* @param options Optional parameters.
* @param options.totalItems Optional total number of items (used when data is already paginated).
* @param options.totalPages Optional total number of pages (used when data is already paginated).
*
* @return Filtered, sorted and paginated data.
*/
export function filterSortAndPaginate< Item >(
data: Item[],
view: View,
fields: Field< Item >[]
fields: Field< Item >[],
options?: {
totalItems?: number;
totalPages?: number;
}
): {
data: Item[];
paginationInfo: { totalItems: number; totalPages: number };
Expand Down Expand Up @@ -145,13 +152,23 @@ export function filterSortAndPaginate< Item >(
}
}

// Handle pagination.
let totalItems = filteredData.length;
let totalPages = 1;
let totalItems =
options?.totalItems !== undefined
? options.totalItems
: filteredData.length;
let totalPages = options?.totalPages !== undefined ? options.totalPages : 1;

if ( view.page !== undefined && view.perPage !== undefined ) {
// Only calculate pagination values if they weren't provided in options
if ( options?.totalItems === undefined ) {
totalItems = filteredData?.length || 0;
}
if ( options?.totalPages === undefined ) {
totalPages = Math.ceil( totalItems / view.perPage );
}

// Always slice the data for pagination
const start = ( view.page - 1 ) * view.perPage;
totalItems = filteredData?.length || 0;
totalPages = Math.ceil( totalItems / view.perPage );
filteredData = filteredData?.slice( start, start + view.perPage );
}

Expand Down
30 changes: 30 additions & 0 deletions packages/dataviews/src/test/filter-and-sort-data-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,34 @@ describe( 'pagination', () => {
totalPages: 6,
} );
} );

it( 'should use provided totalItems and totalPages', () => {
// This test simulates the case where we have a paginated dataset from an API
// and we want to use the totalItems and totalPages from the API response
const paginatedData = data.slice( 0, 2 ); // Just the first 2 items
const { data: result, paginationInfo } = filterSortAndPaginate(
paginatedData,
{
perPage: 2,
page: 1,
filters: [],
},
fields,
{
totalItems: 100000, // Custom totalItems value
totalPages: 50, // Custom totalPages value
}
);

// The result should contain the 2 items we passed in
expect( result ).toHaveLength( 2 );
expect( result[ 0 ].title ).toBe( 'Apollo' );
expect( result[ 1 ].title ).toBe( 'Space' );

// But the pagination info should use our custom values
expect( paginationInfo ).toStrictEqual( {
totalItems: 100000,
totalPages: 50,
} );
} );
} );
Loading