Skip to content
This repository was archived by the owner on Jan 16, 2025. It is now read-only.

Commit 1a12778

Browse files
authored
Merge pull request #1673 from balena-io-modules/add-server-side-pagination
Add server side pagination
2 parents a9f932d + f169c31 commit 1a12778

File tree

6 files changed

+66
-33
lines changed

6 files changed

+66
-33
lines changed

src/components/Table/TableBase.tsx

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ const BaseTableWrapper = styled.div`
2424
max-width: 100%;
2525
border-bottom: 1px solid ${(props) => props.theme.colors.quartenary.main};
2626
`;
27+
export const DEFAULT_ITEMS_PER_PAGE = 50;
28+
export type Pagination = { itemsPerPage?: number } & (
29+
| { serverSide?: undefined }
30+
| {
31+
serverSide: true;
32+
currentPage: number;
33+
totalItems: number;
34+
}
35+
);
2736

2837
interface InternalTableBaseProps {
2938
hasCheckbox: boolean;
@@ -170,7 +179,8 @@ export class TableBase<T extends {}> extends React.Component<
170179
}
171180

172181
public componentDidUpdate(prevProps: TableBaseProps<T>) {
173-
const { sort, checkedItems, data, itemsPerPage, rowKey } = this.props;
182+
const { sort, checkedItems, data, pagination, rowKey } = this.props;
183+
const serverSide = pagination?.serverSide;
174184
if (sort && !isEqual(prevProps.sort, sort)) {
175185
this.setState({
176186
sort,
@@ -186,10 +196,12 @@ export class TableBase<T extends {}> extends React.Component<
186196
this.setRowSelection(checkedItems);
187197
}
188198

189-
const totalItems = data?.length ?? 0;
199+
const totalItems = serverSide ? pagination?.totalItems : data?.length ?? 0;
200+
const currentPage = serverSide ? pagination?.currentPage : this.state.page;
201+
const itemsPerPage = this.props.itemsPerPage ?? pagination?.itemsPerPage;
190202
if (
191-
this.state.page !== 0 &&
192-
totalItems <= this.state.page * (itemsPerPage ?? 50)
203+
currentPage !== 0 &&
204+
totalItems <= currentPage * (itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE)
193205
) {
194206
this.resetPager();
195207
}
@@ -462,19 +474,20 @@ export class TableBase<T extends {}> extends React.Component<
462474
};
463475

464476
public toggleSort = (e: React.MouseEvent<HTMLButtonElement>) => {
465-
const { field } = e.currentTarget.dataset;
477+
const { field, refScheme } = e.currentTarget.dataset;
466478
const { sort } = this.state;
467479
if (!field) {
468480
return;
469481
}
470482

471483
let nextSort = {
472484
field: field as keyof T,
485+
refScheme,
473486
reverse: false,
474487
};
475488

476489
if (sort.field === field) {
477-
nextSort = { field: sort.field, reverse: !sort.reverse };
490+
nextSort = { field: sort.field, refScheme, reverse: !sort.reverse };
478491
}
479492

480493
this.setState({ sort: nextSort });
@@ -522,11 +535,10 @@ export class TableBase<T extends {}> extends React.Component<
522535
}
523536
};
524537

525-
public setPage = (change: any) => {
526-
if (this.props.onPageChange) {
527-
this.props.onPageChange(change);
528-
}
529-
538+
public setPage = (change: number) => {
539+
const { pagination } = this.props;
540+
const itemsPerPage = this.props.itemsPerPage ?? pagination?.itemsPerPage;
541+
this.props.onPageChange?.(change, itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE);
530542
this.setState({ page: change });
531543
};
532544

@@ -547,7 +559,6 @@ export class TableBase<T extends {}> extends React.Component<
547559
columns,
548560
data,
549561
usePager,
550-
itemsPerPage,
551562
pagerPosition,
552563
rowAnchorAttributes,
553564
rowKey,
@@ -557,36 +568,40 @@ export class TableBase<T extends {}> extends React.Component<
557568
getRowClass,
558569
className,
559570
fuzzyPager,
571+
pagination,
560572
} = this.props;
561573

562574
const { page, sort } = this.state;
575+
const serverSide = pagination?.serverSide;
563576
const items = data || [];
564-
const totalItems = items.length;
565-
const _itemsPerPage = itemsPerPage || 50;
577+
const totalItems = serverSide ? pagination?.totalItems : items.length;
578+
const itemsPerPage =
579+
this.props.itemsPerPage ??
580+
pagination?.itemsPerPage ??
581+
DEFAULT_ITEMS_PER_PAGE;
566582
const _pagerPosition = pagerPosition || 'top';
583+
let sortedData = items;
567584

568-
const lowerBound = usePager ? page * _itemsPerPage : 0;
569-
const upperBound = usePager
570-
? Math.min((page + 1) * _itemsPerPage, totalItems)
571-
: totalItems;
572-
573-
const sortedData = this.sortData(items).slice(lowerBound, upperBound);
574-
575-
const shouldShowPaper = !!usePager && totalItems > 0;
585+
if (!serverSide) {
586+
const lowerBound = page * itemsPerPage;
587+
const upperBound = Math.min((page + 1) * itemsPerPage, items.length);
588+
sortedData = this.sortData(items).slice(lowerBound, upperBound);
589+
}
576590

591+
const shouldShowPager = !!usePager && totalItems > 0;
577592
const checkedRowIdentifiers = this.getCheckedRowIdentifiers();
578593
const highlightedRowIdentifiers = this.getHighlightedRowIdentifiers();
579594
const disabledRowIdentifiers = this.getDisabledRowIdentifiers();
580595

581596
return (
582597
<>
583-
{shouldShowPaper &&
598+
{shouldShowPager &&
584599
(_pagerPosition === 'top' || _pagerPosition === 'both') && (
585600
<Pager
586601
fuzzy={fuzzyPager}
587602
totalItems={totalItems}
588-
itemsPerPage={_itemsPerPage}
589-
page={page}
603+
itemsPerPage={itemsPerPage}
604+
page={serverSide ? pagination?.currentPage : page}
590605
nextPage={this.incrementPage}
591606
prevPage={this.decrementPage}
592607
mb={2}
@@ -620,6 +635,7 @@ export class TableBase<T extends {}> extends React.Component<
620635
>
621636
<Button
622637
data-field={item.field}
638+
data-ref-scheme={item.refScheme}
623639
plain
624640
primary={sort.field === item.field}
625641
onClick={this.toggleSort}
@@ -692,12 +708,12 @@ export class TableBase<T extends {}> extends React.Component<
692708
</Base>
693709
</BaseTableWrapper>
694710

695-
{shouldShowPaper &&
711+
{shouldShowPager &&
696712
(_pagerPosition === 'bottom' || _pagerPosition === 'both') && (
697713
<Pager
698714
fuzzy={fuzzyPager}
699715
totalItems={totalItems}
700-
itemsPerPage={_itemsPerPage}
716+
itemsPerPage={itemsPerPage}
701717
page={page}
702718
nextPage={this.incrementPage}
703719
prevPage={this.decrementPage}
@@ -712,6 +728,7 @@ export class TableBase<T extends {}> extends React.Component<
712728
export interface TableSortOptions<T> {
713729
reverse: boolean;
714730
field: keyof T | null;
731+
refScheme?: string;
715732
}
716733

717734
export interface TableBaseProps<T> {
@@ -730,7 +747,7 @@ export interface TableBaseProps<T> {
730747
/** A function that is called when a column is sorted */
731748
onSort?: (sort: TableSortOptions<T>) => void;
732749
/** A function that is called when the page is incremented, decremented and reset */
733-
onPageChange?: (page: number) => void;
750+
onPageChange?: (page: number, itemsPerPage: number) => void;
734751
/** sort options to be used both as a default sort, and on subsequent renders if the passed sort changes */
735752
sort?: TableSortOptions<T>;
736753
/** Attributes to pass to the anchor element used in a row */
@@ -752,7 +769,10 @@ export interface TableBaseProps<T> {
752769
/** If true, the total number of items shown on the page will be indicated as being approximate. Useful for when you don't now the full size of your dataset. Only used if `usePager` is true. */
753770
fuzzyPager?: boolean;
754771
/** The number of items to be shown per page. Only used if `usePager` is true. Defaults to 50. */
772+
/** @deprecated use pagination.itemsPerPage */
755773
itemsPerPage?: number;
774+
/** Information from a server side pagination */
775+
pagination?: Pagination;
756776
/** Sets whether the pager is displayed at the top of the table, the bottom of the table or in both positions. Only used if `usePager` is true. Defaults to `top`. */
757777
pagerPosition?: 'top' | 'bottom' | 'both';
758778
className?: string;

src/components/Table/TableRow.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface TableBaseColumn<T> {
3434
row: T,
3535
) => string | number | JSX.Element | null | undefined;
3636
sortable?: boolean | TableSortFunction<T>;
37+
refScheme?: string;
3738
}
3839

3940
export interface TableRowProps<T> {

src/components/Table/index.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import * as React from 'react';
2-
import { TableBase, TableBaseProps, TableSortOptions } from './TableBase';
2+
import {
3+
TableBase,
4+
TableBaseProps,
5+
TableSortOptions,
6+
Pagination,
7+
} from './TableBase';
38
import styled, { css } from 'styled-components';
49
import keys from 'lodash/keys';
510
import pick from 'lodash/pick';
@@ -710,7 +715,6 @@ export class Table<T extends {}> extends React.Component<
710715
onRowClick,
711716
...props
712717
} = this.props;
713-
714718
const sort =
715719
sortProp || (sortingStateRestorationKey ? this.state.sort : undefined);
716720

@@ -741,4 +745,10 @@ export class Table<T extends {}> extends React.Component<
741745
}
742746
}
743747

744-
export { TableBaseColumn, TableRow, TableSortOptions, TableSortFunction };
748+
export {
749+
TableBaseColumn,
750+
TableRow,
751+
TableSortOptions,
752+
TableSortFunction,
753+
Pagination,
754+
};

src/components/Table/spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ describe('Table component', () => {
890890
}
891891
data={PokeDex}
892892
usePager
893-
itemsPerPage={3}
893+
pagination={{ itemsPerPage: 3 }}
894894
/>
895895
</Provider>,
896896
);
@@ -950,7 +950,7 @@ describe('Table component', () => {
950950
{
951951
columns: [{ field: 'Name' }] as any,
952952
data: PokeDex,
953-
itemsPerPage: 2,
953+
pagination: { itemsPerPage: 2 },
954954
usePager: true,
955955
},
956956
),

src/hooks/useTranslation.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ const translationMap = {
9090

9191
'warning.etcher_min_requirement': 'Etcher v1.7.2 or greater is required',
9292

93+
'loading.generic': 'Loading...',
9394
'loading.generating_configuration_file': 'Generating configuration file...',
9495
'loading.fetching_versions': 'Fetching versions...',
9596

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export {
8989
TableSortOptions,
9090
TableProps,
9191
TableSortFunction,
92+
Pagination,
9293
} from './components/Table';
9394

9495
export { Accordion, AccordionProps } from './components/Accordion';

0 commit comments

Comments
 (0)