@ifto/mantine-kit 0.4.0 → 0.5.2
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/README.md +81 -10
- package/dist/component/organism/Table/Table.d.ts +9 -9
- package/dist/component/organism/Table/Table.js +21 -24
- package/dist/component/organism/Table/Table.js.map +1 -1
- package/dist/component/organism/Table/TableData.d.ts +24 -0
- package/dist/component/organism/Table/TableData.js +1 -0
- package/dist/component/organism/Table/useClientPagination.d.ts +21 -0
- package/dist/component/organism/Table/useClientPagination.js +43 -0
- package/dist/component/organism/Table/useClientPagination.js.map +1 -0
- package/dist/component/organism/Table/useServerPagination.d.ts +24 -0
- package/dist/component/organism/Table/useServerPagination.js +105 -0
- package/dist/component/organism/Table/useServerPagination.js.map +1 -0
- package/dist/component/organism/ViewTable/DataTableView.d.ts +39 -0
- package/dist/component/organism/ViewTable/DataTableView.js +52 -0
- package/dist/component/organism/ViewTable/DataTableView.js.map +1 -0
- package/dist/component/organism/ViewTable/TableState.d.ts +30 -0
- package/dist/component/organism/ViewTable/TableState.js +19 -0
- package/dist/component/organism/ViewTable/TableState.js.map +1 -0
- package/dist/component/organism/ViewTable/ViewTable.d.ts +11 -33
- package/dist/component/organism/ViewTable/ViewTable.js +16 -101
- package/dist/component/organism/ViewTable/ViewTable.js.map +1 -1
- package/dist/component/organism/ViewTable/useClientTableState.d.ts +25 -0
- package/dist/component/organism/ViewTable/useClientTableState.js +68 -0
- package/dist/component/organism/ViewTable/useClientTableState.js.map +1 -0
- package/dist/component/template/ListPage/ListPage.d.ts +9 -19
- package/dist/component/template/ListPage/ListPage.js +5 -14
- package/dist/component/template/ListPage/ListPage.js.map +1 -1
- package/dist/data/PageDataSource.d.ts +10 -0
- package/dist/data/PageDataSource.js +1 -0
- package/dist/data/PageRequest.d.ts +29 -0
- package/dist/data/PageRequest.js +1 -0
- package/dist/hook/useService.d.ts +3 -3
- package/dist/hook/useService.js +2 -0
- package/dist/hook/useService.js.map +1 -1
- package/dist/util/ArrayUtil.d.ts +4 -3
- package/dist/util/ArrayUtil.js +3 -2
- package/dist/util/ArrayUtil.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useKitConfig } from "../../../provider/useKit.js";
|
|
3
|
+
import { PAGE_SIZES } from "./TableState.js";
|
|
4
|
+
import { useRowKey } from "./useRowKey.js";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { DataTable } from "mantine-datatable";
|
|
7
|
+
// src/component/organism/ViewTable/DataTableView.tsx
|
|
8
|
+
/**
|
|
9
|
+
* Shows records as received, with the given pagination and sort (e.g. kept by a backend that paginates). It is the
|
|
10
|
+
* visual part of the tables, on top of the mantine-datatable `DataTable`, with the texts of the locale.
|
|
11
|
+
* @template M type of the records, shown one per row
|
|
12
|
+
*/
|
|
13
|
+
var DataTableView = ({ records, state, paginated, columns, loading, showIdColumn = true, getPaginationControlProps, ...rest }) => {
|
|
14
|
+
const { messages } = useKitConfig();
|
|
15
|
+
const rowKey = useRowKey();
|
|
16
|
+
const effectiveColumns = [{
|
|
17
|
+
title: "ID",
|
|
18
|
+
accessor: "id",
|
|
19
|
+
hidden: !showIdColumn,
|
|
20
|
+
sortable: true,
|
|
21
|
+
render: (item) => /* @__PURE__ */ jsx("span", { children: item.id })
|
|
22
|
+
}, ...columns];
|
|
23
|
+
const paginationProps = paginated ? {
|
|
24
|
+
page: state.page,
|
|
25
|
+
onPageChange: state.onPageChange,
|
|
26
|
+
totalRecords: state.totalRecords,
|
|
27
|
+
recordsPerPage: state.pageSize,
|
|
28
|
+
recordsPerPageOptions: PAGE_SIZES,
|
|
29
|
+
onRecordsPerPageChange: state.onPageSizeChange,
|
|
30
|
+
recordsPerPageLabel: messages.table.recordsPerPage,
|
|
31
|
+
paginationText: messages.table.pagination,
|
|
32
|
+
getPaginationControlProps
|
|
33
|
+
} : {};
|
|
34
|
+
return /* @__PURE__ */ jsx(DataTable, {
|
|
35
|
+
minHeight: 200,
|
|
36
|
+
verticalSpacing: "sm",
|
|
37
|
+
striped: true,
|
|
38
|
+
columns: effectiveColumns,
|
|
39
|
+
records,
|
|
40
|
+
idAccessor: rowKey,
|
|
41
|
+
noRecordsText: messages.table.noRecords,
|
|
42
|
+
fetching: loading,
|
|
43
|
+
sortStatus: state.sortStatus,
|
|
44
|
+
onSortStatusChange: state.onSortStatusChange,
|
|
45
|
+
customRowAttributes: (record) => ({ "data-testid": `row-${record.id}` }),
|
|
46
|
+
...paginationProps,
|
|
47
|
+
...rest
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
export { DataTableView as default };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=DataTableView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTableView.js","names":[],"sources":["../../../../src/component/organism/ViewTable/DataTableView.tsx"],"sourcesContent":["'use client';\n\nimport { DataTable, DataTableColumn, DataTablePaginationProps, DataTableProps } from 'mantine-datatable';\n\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useKitConfig } from '../../../provider/useKit';\nimport { PAGE_SIZES, TableState } from './TableState';\nimport { useRowKey } from './useRowKey';\n\n/** Function that defines extra attributes (e.g. aria-label) for each pagination control button. */\ntype PaginationControlPropsGetter = Extract<DataTablePaginationProps, { page: number }>['getPaginationControlProps'];\n\n/**\n * Props of the {@link DataTable} passed straight through.\n * Only the props actually used by the callers are accepted: using `Partial<DataTableProps<M>>` makes TypeScript combine\n * the variants of the `DataTableProps` union with the ones of `paginationProps`, which exhausts the memory of `tsc`.\n */\ntype DataTablePassThroughProps<M extends Identifiable> = Pick<\n DataTableProps<M>,\n | 'onRowClick'\n | 'rowStyle'\n | 'noRecordsText'\n | 'highlightOnHover'\n | 'highlightOnHoverColor'\n | 'className'\n | 'minHeight'\n | 'withColumnBorders'\n | 'verticalSpacing'\n | 'horizontalSpacing'\n>;\n\n/** Props of the {@link DataTableView} that do not depend on where the table is sorted and paginated. */\nexport type DataTableViewBaseProps<M extends Identifiable> = {\n columns: DataTableColumn<M>[];\n\n /** Whether the records are being loaded. */\n loading?: boolean;\n\n /** Shows the ID column, automatically added to the given columns. */\n showIdColumn?: boolean;\n\n /** Extra attributes for the pagination control buttons, when the table is paginated. */\n getPaginationControlProps?: PaginationControlPropsGetter;\n} & DataTablePassThroughProps<M>;\n\n/** Props of the {@link DataTableView}. */\ntype DataTableViewProps<M extends Identifiable> = DataTableViewBaseProps<M> & {\n /** Records shown, already sorted and cut to the current page. */\n records: M[];\n\n /** Pagination and sort of the table. */\n state: TableState<M>;\n\n /** Whether the pagination controls are shown. */\n paginated: boolean;\n};\n\n/**\n * Shows records as received, with the given pagination and sort (e.g. kept by a backend that paginates). It is the\n * visual part of the tables, on top of the mantine-datatable `DataTable`, with the texts of the locale.\n * @template M type of the records, shown one per row\n */\nconst DataTableView = <M extends Identifiable>({\n records,\n state,\n paginated,\n columns,\n loading,\n showIdColumn = true,\n getPaginationControlProps,\n ...rest\n}: DataTableViewProps<M>) => {\n const { messages } = useKitConfig();\n const rowKey = useRowKey<M>();\n\n const effectiveColumns: DataTableColumn<M>[] = [\n {\n title: 'ID',\n accessor: 'id',\n hidden: !showIdColumn,\n sortable: true,\n render: item => <span>{item.id}</span>\n },\n ...columns\n ];\n\n /* Typed only with the pagination props (and not as Partial<DataTableProps>) to not exhaust the memory of tsc.\n See the comment of DataTablePassThroughProps. */\n const paginationProps: DataTablePaginationProps = paginated\n ? {\n page: state.page,\n onPageChange: state.onPageChange,\n totalRecords: state.totalRecords,\n recordsPerPage: state.pageSize,\n recordsPerPageOptions: PAGE_SIZES,\n onRecordsPerPageChange: state.onPageSizeChange,\n recordsPerPageLabel: messages.table.recordsPerPage,\n paginationText: messages.table.pagination,\n getPaginationControlProps\n }\n : {};\n\n // This DataTable is the one of https://www.npmjs.com/package/mantine-datatable (there are other libraries with this name).\n return (\n <DataTable\n minHeight={200}\n verticalSpacing=\"sm\"\n striped\n columns={effectiveColumns}\n records={records}\n idAccessor={rowKey}\n noRecordsText={messages.table.noRecords}\n fetching={loading}\n sortStatus={state.sortStatus}\n onSortStatusChange={state.onSortStatusChange}\n customRowAttributes={record => ({ 'data-testid': `row-${record.id}` })}\n {...paginationProps}\n {...rest}\n />\n );\n};\n\nexport default DataTableView;\n"],"mappings":";;;;;;;;;;;;AA8DA,IAAM,iBAAyC,EAC3C,SACA,OACA,WACA,SACA,SACA,eAAe,MACf,2BACA,GAAG,WACsB;CACzB,MAAM,EAAE,aAAa,aAAa;CAClC,MAAM,SAAS,UAAa;CAE5B,MAAM,mBAAyC,CAC3C;EACI,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;EACT,UAAU;EACV,SAAQ,SAAQ,oBAAC,QAAD,EAAA,UAAO,KAAK,GAAS,CAAA;CACzC,GACA,GAAG,OACP;CAIA,MAAM,kBAA4C,YAC5C;EACI,MAAM,MAAM;EACZ,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,gBAAgB,MAAM;EACtB,uBAAuB;EACvB,wBAAwB,MAAM;EAC9B,qBAAqB,SAAS,MAAM;EACpC,gBAAgB,SAAS,MAAM;EAC/B;CACJ,IACA,CAAC;CAGP,OACI,oBAAC,WAAD;EACI,WAAW;EACX,iBAAgB;EAChB,SAAA;EACA,SAAS;EACA;EACT,YAAY;EACZ,eAAe,SAAS,MAAM;EAC9B,UAAU;EACV,YAAY,MAAM;EAClB,oBAAoB,MAAM;EAC1B,sBAAqB,YAAW,EAAE,eAAe,OAAO,OAAO,KAAK;EACpE,GAAI;EACJ,GAAI;CACP,CAAA;AAET"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DataTableSortStatus } from 'mantine-datatable';
|
|
2
|
+
/** Options of records per page. The largest one lets long tables (and end-to-end tests) show every row in one page. */
|
|
3
|
+
export declare const PAGE_SIZES: number[];
|
|
4
|
+
/** Number of the first page of a table. */
|
|
5
|
+
export declare const FIRST_PAGE = 1;
|
|
6
|
+
/** Default sort when neither `defaultSortStatus` nor `compare` is given. */
|
|
7
|
+
export declare const DEFAULT_SORT_STATUS: {
|
|
8
|
+
readonly columnAccessor: 'id';
|
|
9
|
+
readonly direction: 'asc';
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Pagination and sort of a table, with the callbacks that change them.
|
|
13
|
+
* @template M type of the records
|
|
14
|
+
*/
|
|
15
|
+
export type TableState<M> = {
|
|
16
|
+
/** Current page, starting at 1. */
|
|
17
|
+
page: number;
|
|
18
|
+
/** Records per page. */
|
|
19
|
+
pageSize: number;
|
|
20
|
+
/** Current sort. */
|
|
21
|
+
sortStatus: DataTableSortStatus<M>;
|
|
22
|
+
/** Total of records of all pages. */
|
|
23
|
+
totalRecords: number;
|
|
24
|
+
/** Called when the user chooses a page. */
|
|
25
|
+
onPageChange: (page: number) => void;
|
|
26
|
+
/** Called when the user chooses the records per page. */
|
|
27
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
28
|
+
/** Called when the user chooses the sort. */
|
|
29
|
+
onSortStatusChange: (sortStatus: DataTableSortStatus<M>) => void;
|
|
30
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/component/organism/ViewTable/TableState.ts
|
|
3
|
+
/** Options of records per page. The largest one lets long tables (and end-to-end tests) show every row in one page. */
|
|
4
|
+
var PAGE_SIZES = [
|
|
5
|
+
10,
|
|
6
|
+
20,
|
|
7
|
+
50,
|
|
8
|
+
200
|
|
9
|
+
];
|
|
10
|
+
/** Number of the first page of a table. */
|
|
11
|
+
var FIRST_PAGE = 1;
|
|
12
|
+
/** Default sort when neither `defaultSortStatus` nor `compare` is given. */
|
|
13
|
+
var DEFAULT_SORT_STATUS = {
|
|
14
|
+
columnAccessor: "id",
|
|
15
|
+
direction: "asc"
|
|
16
|
+
};
|
|
17
|
+
export { DEFAULT_SORT_STATUS, FIRST_PAGE, PAGE_SIZES };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=TableState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableState.js","names":[],"sources":["../../../../src/component/organism/ViewTable/TableState.ts"],"sourcesContent":["import type { DataTableSortStatus } from 'mantine-datatable';\n\n/*\nPagination and sort state of a table, and its initial values, shared by the state kept in the browser and the one kept\nfor a backend that paginates.\n*/\n\n/** Options of records per page. The largest one lets long tables (and end-to-end tests) show every row in one page. */\nexport const PAGE_SIZES = [10, 20, 50, 200];\n\n/** Number of the first page of a table. */\nexport const FIRST_PAGE = 1;\n\n/** Default sort when neither `defaultSortStatus` nor `compare` is given. */\nexport const DEFAULT_SORT_STATUS = { columnAccessor: 'id', direction: 'asc' } as const;\n\n/**\n * Pagination and sort of a table, with the callbacks that change them.\n * @template M type of the records\n */\nexport type TableState<M> = {\n /** Current page, starting at 1. */\n page: number;\n\n /** Records per page. */\n pageSize: number;\n\n /** Current sort. */\n sortStatus: DataTableSortStatus<M>;\n\n /** Total of records of all pages. */\n totalRecords: number;\n\n /** Called when the user chooses a page. */\n onPageChange: (page: number) => void;\n\n /** Called when the user chooses the records per page. */\n onPageSizeChange: (pageSize: number) => void;\n\n /** Called when the user chooses the sort. */\n onSortStatusChange: (sortStatus: DataTableSortStatus<M>) => void;\n};\n"],"mappings":";;;AAQA,IAAa,aAAa;CAAC;CAAI;CAAI;CAAI;AAAG;;AAG1C,IAAa,aAAa;;AAG1B,IAAa,sBAAsB;CAAE,gBAAgB;CAAM,WAAW;AAAM"}
|
|
@@ -1,26 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DataTableSortStatus } from 'mantine-datatable';
|
|
2
2
|
import { Identifiable } from '../../../model/Identifiable';
|
|
3
3
|
import { Comparator } from './ColumnComparator';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Props of the {@link DataTable} passed straight through by the ViewTable.
|
|
10
|
-
* Only the props actually used by the callers are accepted: using `Partial<DataTableProps<M>>` makes TypeScript combine
|
|
11
|
-
* the variants of the `DataTableProps` union with the ones of `paginationProps`, which exhausts the memory of `tsc`.
|
|
12
|
-
*/
|
|
13
|
-
type DataTablePassThroughProps<M extends Identifiable> = Pick<DataTableProps<M>, 'onRowClick' | 'rowStyle' | 'noRecordsText' | 'highlightOnHover' | 'highlightOnHoverColor' | 'className' | 'minHeight' | 'withColumnBorders' | 'verticalSpacing' | 'horizontalSpacing'>;
|
|
14
|
-
/**
|
|
15
|
-
* TableProps is a generic type for the ViewTable component props.
|
|
16
|
-
*/
|
|
17
|
-
type TableProps<M extends Identifiable> = {
|
|
4
|
+
import { DataTableViewBaseProps } from './DataTableView';
|
|
5
|
+
/** Props of the {@link ViewTable}. */
|
|
6
|
+
type ViewTableProps<M extends Identifiable> = DataTableViewBaseProps<M> & {
|
|
7
|
+
/** All records of the table. */
|
|
18
8
|
data: M[];
|
|
19
|
-
|
|
20
|
-
loading?: boolean;
|
|
9
|
+
/** Whether the table is paginated; defaults to true. Without it, every record is shown (e.g. a printed report). */
|
|
21
10
|
pagination?: boolean;
|
|
22
|
-
/** Shows the ID column, automatically added to the given columns. */
|
|
23
|
-
showIdColumn?: boolean;
|
|
24
11
|
/**
|
|
25
12
|
* Initial sort of the table. Default: by `id`, ascending.
|
|
26
13
|
* Give another value when the natural order of the data should not be by `id` (e.g. when the backend already
|
|
@@ -34,20 +21,11 @@ type TableProps<M extends Identifiable> = {
|
|
|
34
21
|
* header of a column, the sort of the column applies.
|
|
35
22
|
*/
|
|
36
23
|
compare?: Comparator<M>;
|
|
37
|
-
|
|
38
|
-
getPaginationControlProps?: PaginationControlPropsGetter;
|
|
39
|
-
} & DataTablePassThroughProps<M>;
|
|
24
|
+
};
|
|
40
25
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @
|
|
44
|
-
* @param {DataTableColumn<M>[]} columns - The columns to be displayed in this ViewTable
|
|
45
|
-
* @param loading Indicates if the data to be displayed is being loaded yet or not
|
|
46
|
-
* @param pagination Indicates whether to show pagination or not.
|
|
47
|
-
* @param getPaginationControlProps extra attributes for the pagination control buttons
|
|
48
|
-
* @param compare comparison function of the initial order, replaced by the sort of the column chosen in the header
|
|
49
|
-
* @param rest remaining props, passed to the DataTable
|
|
50
|
-
* @return the table with the data, sortable and (optionally) paginated
|
|
26
|
+
* Table that sorts (following the locale) and paginates in the browser all the given records, on top of the
|
|
27
|
+
* mantine-datatable `DataTable`.
|
|
28
|
+
* @template M type of the records, shown one per row
|
|
51
29
|
*/
|
|
52
|
-
declare const ViewTable: <M extends Identifiable>({ data,
|
|
30
|
+
declare const ViewTable: <M extends Identifiable>({ data, pagination, defaultSortStatus, compare, ...rest }: ViewTableProps<M>) => import("react/jsx-runtime").JSX.Element;
|
|
53
31
|
export default ViewTable;
|
|
@@ -1,113 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useKitConfig } from "../../../provider/useKit.js";
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { useEffect, useMemo, useState } from "react";
|
|
3
|
+
import DataTableView from "./DataTableView.js";
|
|
4
|
+
import { useClientTableState } from "./useClientTableState.js";
|
|
6
5
|
import { jsx } from "react/jsx-runtime";
|
|
7
|
-
import { DataTable } from "mantine-datatable";
|
|
8
6
|
// src/component/organism/ViewTable/ViewTable.tsx
|
|
9
|
-
/** Options of records per page. The largest one lets long tables (and end-to-end tests) show every row in one page. */
|
|
10
|
-
var PAGE_SIZES = [
|
|
11
|
-
10,
|
|
12
|
-
20,
|
|
13
|
-
50,
|
|
14
|
-
200
|
|
15
|
-
];
|
|
16
|
-
/** Default sort when neither `defaultSortStatus` nor `compare` is given. */
|
|
17
|
-
var DEFAULT_SORT_STATUS = {
|
|
18
|
-
columnAccessor: "id",
|
|
19
|
-
direction: "asc"
|
|
20
|
-
};
|
|
21
7
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
8
|
+
* Table that sorts (following the locale) and paginates in the browser all the given records, on top of the
|
|
9
|
+
* mantine-datatable `DataTable`.
|
|
10
|
+
* @template M type of the records, shown one per row
|
|
24
11
|
*/
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* The ViewTable component is a wrapper for the Mantine DataTable component.
|
|
31
|
-
* @template M - Model that extends from {@link Identifiable}
|
|
32
|
-
* @param data the data to be displayed in this ViewTable
|
|
33
|
-
* @param {DataTableColumn<M>[]} columns - The columns to be displayed in this ViewTable
|
|
34
|
-
* @param loading Indicates if the data to be displayed is being loaded yet or not
|
|
35
|
-
* @param pagination Indicates whether to show pagination or not.
|
|
36
|
-
* @param getPaginationControlProps extra attributes for the pagination control buttons
|
|
37
|
-
* @param compare comparison function of the initial order, replaced by the sort of the column chosen in the header
|
|
38
|
-
* @param rest remaining props, passed to the DataTable
|
|
39
|
-
* @return the table with the data, sortable and (optionally) paginated
|
|
40
|
-
*/
|
|
41
|
-
var ViewTable = ({ data, columns, loading, pagination = true, showIdColumn = true, defaultSortStatus, compare, getPaginationControlProps, ...rest }) => {
|
|
42
|
-
const { locale, messages } = useKitConfig();
|
|
43
|
-
const [page, setPage] = useState(1);
|
|
44
|
-
const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);
|
|
45
|
-
const [sortStatus, setSortStatus] = useState(defaultSortStatus ?? (compare ? NO_COLUMN_SORT_STATUS : DEFAULT_SORT_STATUS));
|
|
46
|
-
const [compareActive, setCompareActive] = useState(compare !== void 0);
|
|
47
|
-
const sortedData = useMemo(() => {
|
|
48
|
-
const comparator = compareActive && compare ? compare : columnComparator(sortStatus, locale);
|
|
49
|
-
return [...data].sort(comparator);
|
|
50
|
-
}, [
|
|
12
|
+
var ViewTable = ({ data, pagination = true, defaultSortStatus, compare, ...rest }) => {
|
|
13
|
+
const { locale } = useKitConfig();
|
|
14
|
+
const { records, ...state } = useClientTableState({
|
|
51
15
|
data,
|
|
52
|
-
sortStatus,
|
|
53
|
-
compareActive,
|
|
54
|
-
compare,
|
|
55
|
-
locale
|
|
56
|
-
]);
|
|
57
|
-
const records = useMemo(() => {
|
|
58
|
-
if (!pagination) return sortedData;
|
|
59
|
-
const from = (page - 1) * pageSize;
|
|
60
|
-
return sortedData.slice(from, from + pageSize);
|
|
61
|
-
}, [
|
|
62
|
-
sortedData,
|
|
63
16
|
pagination,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
setSortStatus(status);
|
|
71
|
-
}
|
|
72
|
-
const effectiveColumns = [{
|
|
73
|
-
title: "ID",
|
|
74
|
-
accessor: "id",
|
|
75
|
-
hidden: !showIdColumn,
|
|
76
|
-
sortable: true,
|
|
77
|
-
render: (item) => /* @__PURE__ */ jsx("span", { children: item.id })
|
|
78
|
-
}, ...columns];
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
setPage(1);
|
|
81
|
-
}, [pageSize]);
|
|
82
|
-
useEffect(() => {
|
|
83
|
-
const totalPages = Math.ceil(data.length / pageSize);
|
|
84
|
-
setPage((currentPage) => totalPages && currentPage > totalPages ? totalPages : currentPage);
|
|
85
|
-
}, [data.length, pageSize]);
|
|
86
|
-
const paginationProps = pagination ? {
|
|
87
|
-
page,
|
|
88
|
-
onPageChange: (p) => setPage(p),
|
|
89
|
-
totalRecords: data.length,
|
|
90
|
-
recordsPerPage: pageSize,
|
|
91
|
-
recordsPerPageOptions: PAGE_SIZES,
|
|
92
|
-
onRecordsPerPageChange: setPageSize,
|
|
93
|
-
recordsPerPageLabel: messages.table.recordsPerPage,
|
|
94
|
-
paginationText: messages.table.pagination,
|
|
95
|
-
getPaginationControlProps
|
|
96
|
-
} : {};
|
|
97
|
-
return /* @__PURE__ */ jsx(DataTable, {
|
|
98
|
-
minHeight: 200,
|
|
99
|
-
verticalSpacing: "sm",
|
|
100
|
-
striped: true,
|
|
101
|
-
columns: effectiveColumns,
|
|
17
|
+
locale,
|
|
18
|
+
defaultSortStatus,
|
|
19
|
+
compare
|
|
20
|
+
});
|
|
21
|
+
return /* @__PURE__ */ jsx(DataTableView, {
|
|
22
|
+
...rest,
|
|
102
23
|
records,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
fetching: loading,
|
|
106
|
-
sortStatus,
|
|
107
|
-
onSortStatusChange: changeSortStatus,
|
|
108
|
-
customRowAttributes: (record) => ({ "data-testid": `row-${record.id}` }),
|
|
109
|
-
...paginationProps,
|
|
110
|
-
...rest
|
|
24
|
+
state,
|
|
25
|
+
paginated: pagination
|
|
111
26
|
});
|
|
112
27
|
};
|
|
113
28
|
export { ViewTable as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewTable.js","names":[],"sources":["../../../../src/component/organism/ViewTable/ViewTable.tsx"],"sourcesContent":["'use client';\n\nimport {
|
|
1
|
+
{"version":3,"file":"ViewTable.js","names":[],"sources":["../../../../src/component/organism/ViewTable/ViewTable.tsx"],"sourcesContent":["'use client';\n\nimport { DataTableSortStatus } from 'mantine-datatable';\n\nimport { Identifiable } from '../../../model/Identifiable';\nimport { useKitConfig } from '../../../provider/useKit';\nimport { Comparator } from './ColumnComparator';\nimport DataTableView, { DataTableViewBaseProps } from './DataTableView';\nimport { useClientTableState } from './useClientTableState';\n\n/** Props of the {@link ViewTable}. */\ntype ViewTableProps<M extends Identifiable> = DataTableViewBaseProps<M> & {\n /** All records of the table. */\n data: M[];\n\n /** Whether the table is paginated; defaults to true. Without it, every record is shown (e.g. a printed report). */\n pagination?: boolean;\n\n /**\n * Initial sort of the table. Default: by `id`, ascending.\n * Give another value when the natural order of the data should not be by `id` (e.g. when the backend already\n * returns the data in an order to keep). Along with `compare`, it only tells which header shows the sort indicator\n * in the initial order.\n */\n defaultSortStatus?: DataTableSortStatus<M>;\n\n /**\n * Comparison function that defines the initial order, instead of the column of `defaultSortStatus`. It allows\n * sorting by more than one criterion (e.g. city and, in the same city, year descending). After the user clicks the\n * header of a column, the sort of the column applies.\n */\n compare?: Comparator<M>;\n};\n\n/**\n * Table that sorts (following the locale) and paginates in the browser all the given records, on top of the\n * mantine-datatable `DataTable`.\n * @template M type of the records, shown one per row\n */\nconst ViewTable = <M extends Identifiable>({\n data,\n pagination = true,\n defaultSortStatus,\n compare,\n ...rest\n}: ViewTableProps<M>) => {\n const { locale } = useKitConfig();\n const { records, ...state } = useClientTableState({ data, pagination, locale, defaultSortStatus, compare });\n\n return <DataTableView {...rest} records={records} state={state} paginated={pagination} />;\n};\n\nexport default ViewTable;\n"],"mappings":";;;;;;;;;;;AAuCA,IAAM,aAAqC,EACvC,MACA,aAAa,MACb,mBACA,SACA,GAAG,WACkB;CACrB,MAAM,EAAE,WAAW,aAAa;CAChC,MAAM,EAAE,SAAS,GAAG,UAAU,oBAAoB;EAAE;EAAM;EAAY;EAAQ;EAAmB;CAAQ,CAAC;CAE1G,OAAO,oBAAC,eAAD;EAAe,GAAI;EAAe;EAAgB;EAAO,WAAW;CAAa,CAAA;AAC5F"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DataTableSortStatus } from 'mantine-datatable';
|
|
2
|
+
import { Comparator } from './ColumnComparator';
|
|
3
|
+
import { TableState } from './TableState';
|
|
4
|
+
/** Options of {@link useClientTableState}. */
|
|
5
|
+
type ClientTableOptions<M> = {
|
|
6
|
+
/** All records of the table. */
|
|
7
|
+
data: M[];
|
|
8
|
+
/** Whether only the records of the current page are returned. */
|
|
9
|
+
pagination: boolean;
|
|
10
|
+
/** Locale of the text comparison. */
|
|
11
|
+
locale: string;
|
|
12
|
+
/** Initial sort; defaults to {@link DEFAULT_SORT_STATUS}, or to no column when `compare` is given. */
|
|
13
|
+
defaultSortStatus?: DataTableSortStatus<M>;
|
|
14
|
+
/** Comparison function of the initial order, replaced by the sort of the column chosen in the header. */
|
|
15
|
+
compare?: Comparator<M>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Sorts and paginates in the browser all the records of a table.
|
|
19
|
+
* @template M type of the records
|
|
20
|
+
* @return the state of the table and the records to show
|
|
21
|
+
*/
|
|
22
|
+
export declare function useClientTableState<M>({ data, pagination, locale, defaultSortStatus, compare }: ClientTableOptions<M>): TableState<M> & {
|
|
23
|
+
records: M[];
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { columnComparator } from "./ColumnComparator.js";
|
|
3
|
+
import { DEFAULT_SORT_STATUS, PAGE_SIZES } from "./TableState.js";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
// src/component/organism/ViewTable/useClientTableState.ts
|
|
6
|
+
/**
|
|
7
|
+
* Sort used while the `compare` function applies, when `defaultSortStatus` is not given: it matches no column, so no
|
|
8
|
+
* header shows the sort indicator, and the first click on any column sorts it in ascending order.
|
|
9
|
+
*/
|
|
10
|
+
var NO_COLUMN_SORT_STATUS = {
|
|
11
|
+
columnAccessor: "",
|
|
12
|
+
direction: "asc"
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Sorts and paginates in the browser all the records of a table.
|
|
16
|
+
* @template M type of the records
|
|
17
|
+
* @return the state of the table and the records to show
|
|
18
|
+
*/
|
|
19
|
+
function useClientTableState({ data, pagination, locale, defaultSortStatus, compare }) {
|
|
20
|
+
const [page, setPage] = useState(1);
|
|
21
|
+
const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);
|
|
22
|
+
const [sortStatus, setSortStatus] = useState(defaultSortStatus ?? (compare ? NO_COLUMN_SORT_STATUS : DEFAULT_SORT_STATUS));
|
|
23
|
+
const [compareActive, setCompareActive] = useState(compare !== void 0);
|
|
24
|
+
const sortedData = useMemo(() => {
|
|
25
|
+
const comparator = compareActive && compare ? compare : columnComparator(sortStatus, locale);
|
|
26
|
+
return [...data].sort(comparator);
|
|
27
|
+
}, [
|
|
28
|
+
data,
|
|
29
|
+
sortStatus,
|
|
30
|
+
compareActive,
|
|
31
|
+
compare,
|
|
32
|
+
locale
|
|
33
|
+
]);
|
|
34
|
+
const records = useMemo(() => {
|
|
35
|
+
if (!pagination) return sortedData;
|
|
36
|
+
const from = (page - 1) * pageSize;
|
|
37
|
+
return sortedData.slice(from, from + pageSize);
|
|
38
|
+
}, [
|
|
39
|
+
sortedData,
|
|
40
|
+
pagination,
|
|
41
|
+
page,
|
|
42
|
+
pageSize
|
|
43
|
+
]);
|
|
44
|
+
function changeSortStatus(status) {
|
|
45
|
+
setCompareActive(false);
|
|
46
|
+
setSortStatus(status);
|
|
47
|
+
}
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
setPage(1);
|
|
50
|
+
}, [pageSize]);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const totalPages = Math.ceil(data.length / pageSize);
|
|
53
|
+
setPage((currentPage) => totalPages && currentPage > totalPages ? totalPages : currentPage);
|
|
54
|
+
}, [data.length, pageSize]);
|
|
55
|
+
return {
|
|
56
|
+
records,
|
|
57
|
+
page,
|
|
58
|
+
pageSize,
|
|
59
|
+
sortStatus,
|
|
60
|
+
totalRecords: data.length,
|
|
61
|
+
onPageChange: setPage,
|
|
62
|
+
onPageSizeChange: setPageSize,
|
|
63
|
+
onSortStatusChange: changeSortStatus
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export { useClientTableState };
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=useClientTableState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useClientTableState.js","names":[],"sources":["../../../../src/component/organism/ViewTable/useClientTableState.ts"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\n\nimport type { DataTableSortStatus } from 'mantine-datatable';\n\nimport { columnComparator, Comparator } from './ColumnComparator';\nimport { DEFAULT_SORT_STATUS, FIRST_PAGE, PAGE_SIZES, TableState } from './TableState';\n\n/**\n * Sort used while the `compare` function applies, when `defaultSortStatus` is not given: it matches no column, so no\n * header shows the sort indicator, and the first click on any column sorts it in ascending order.\n */\nconst NO_COLUMN_SORT_STATUS = { columnAccessor: '', direction: 'asc' } as const;\n\n/** Options of {@link useClientTableState}. */\ntype ClientTableOptions<M> = {\n /** All records of the table. */\n data: M[];\n\n /** Whether only the records of the current page are returned. */\n pagination: boolean;\n\n /** Locale of the text comparison. */\n locale: string;\n\n /** Initial sort; defaults to {@link DEFAULT_SORT_STATUS}, or to no column when `compare` is given. */\n defaultSortStatus?: DataTableSortStatus<M>;\n\n /** Comparison function of the initial order, replaced by the sort of the column chosen in the header. */\n compare?: Comparator<M>;\n};\n\n/**\n * Sorts and paginates in the browser all the records of a table.\n * @template M type of the records\n * @return the state of the table and the records to show\n */\nexport function useClientTableState<M>({\n data,\n pagination,\n locale,\n defaultSortStatus,\n compare\n}: ClientTableOptions<M>): TableState<M> & { records: M[] } {\n const [page, setPage] = useState(FIRST_PAGE);\n const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);\n const [sortStatus, setSortStatus] = useState<DataTableSortStatus<M>>(\n defaultSortStatus ?? (compare ? NO_COLUMN_SORT_STATUS : DEFAULT_SORT_STATUS)\n );\n // The `compare` function applies until the user chooses a column in the header.\n const [compareActive, setCompareActive] = useState(compare !== undefined);\n\n /*\n * Sorts all records before cutting the page, so each page (including in descending order) shows its part of the\n * whole set. The copy keeps the order of the given array. It is separate from the page cut, so not everything is\n * sorted again on every change of page or page size.\n */\n const sortedData = useMemo(() => {\n const comparator = compareActive && compare ? compare : columnComparator(sortStatus, locale);\n\n return [...data].sort(comparator);\n }, [data, sortStatus, compareActive, compare, locale]);\n\n // Without pagination, shows all records (e.g. a printed report), not only the ones of the first page.\n const records = useMemo(() => {\n if (!pagination) return sortedData;\n\n const from = (page - 1) * pageSize;\n return sortedData.slice(from, from + pageSize);\n }, [sortedData, pagination, page, pageSize]);\n\n function changeSortStatus(status: DataTableSortStatus<M>): void {\n setCompareActive(false);\n setSortStatus(status);\n }\n\n useEffect(() => {\n setPage(FIRST_PAGE);\n }, [pageSize]);\n\n /* If the data shrinks, goes back to the last existing page. The functional update avoids using an outdated `page`\n when the effect above has just gone back to page 1. */\n useEffect(() => {\n const totalPages = Math.ceil(data.length / pageSize);\n setPage(currentPage => (totalPages && currentPage > totalPages ? totalPages : currentPage));\n }, [data.length, pageSize]);\n\n return {\n records,\n page,\n pageSize,\n sortStatus,\n totalRecords: data.length,\n onPageChange: setPage,\n onPageSizeChange: setPageSize,\n onSortStatusChange: changeSortStatus\n };\n}\n"],"mappings":";;;;;;;;;AAWA,IAAM,wBAAwB;CAAE,gBAAgB;CAAI,WAAW;AAAM;;;;;;AAyBrE,SAAgB,oBAAuB,EACnC,MACA,YACA,QACA,mBACA,WACwD;CACxD,MAAM,CAAC,MAAM,WAAW,SAAA,CAAmB;CAC3C,MAAM,CAAC,UAAU,eAAe,SAAS,WAAW,EAAE;CACtD,MAAM,CAAC,YAAY,iBAAiB,SAChC,sBAAsB,UAAU,wBAAwB,oBAC5D;CAEA,MAAM,CAAC,eAAe,oBAAoB,SAAS,YAAY,KAAA,CAAS;CAOxE,MAAM,aAAa,cAAc;EAC7B,MAAM,aAAa,iBAAiB,UAAU,UAAU,iBAAiB,YAAY,MAAM;EAE3F,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,UAAU;CACpC,GAAG;EAAC;EAAM;EAAY;EAAe;EAAS;CAAM,CAAC;CAGrD,MAAM,UAAU,cAAc;EAC1B,IAAI,CAAC,YAAY,OAAO;EAExB,MAAM,QAAQ,OAAO,KAAK;EAC1B,OAAO,WAAW,MAAM,MAAM,OAAO,QAAQ;CACjD,GAAG;EAAC;EAAY;EAAY;EAAM;CAAQ,CAAC;CAE3C,SAAS,iBAAiB,QAAsC;EAC5D,iBAAiB,KAAK;EACtB,cAAc,MAAM;CACxB;CAEA,gBAAgB;EACZ,QAAA,CAAkB;CACtB,GAAG,CAAC,QAAQ,CAAC;CAIb,gBAAgB;EACZ,MAAM,aAAa,KAAK,KAAK,KAAK,SAAS,QAAQ;EACnD,SAAQ,gBAAgB,cAAc,cAAc,aAAa,aAAa,WAAY;CAC9F,GAAG,CAAC,KAAK,QAAQ,QAAQ,CAAC;CAE1B,OAAO;EACH;EACA;EACA;EACA;EACA,cAAc,KAAK;EACnB,cAAc;EACd,kBAAkB;EAClB,oBAAoB;CACxB;AACJ"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { ReactElement, ReactNode } from 'react';
|
|
2
|
-
import { DataTableColumn } from 'mantine-datatable';
|
|
3
|
-
import { ListDataSource } from '../../../data/ListDataSource';
|
|
4
|
-
import { Identifiable } from '../../../model/Identifiable';
|
|
5
2
|
import { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
/** Props of the {@link ListPage}. */
|
|
4
|
+
type ListPageProps = {
|
|
8
5
|
/** Title of the page (e.g. "Regions"). */
|
|
9
6
|
title: string;
|
|
10
7
|
/** Plural name of the records, used in the title of the table card. */
|
|
@@ -12,21 +9,14 @@ interface ListPageProps<T, S> {
|
|
|
12
9
|
breadcrumbItems: BreadcrumbItem[];
|
|
13
10
|
/** Route of the "Add" button; absent for no button. */
|
|
14
11
|
addActionRoute?: string;
|
|
15
|
-
/** Source of the records and of their deletion. */
|
|
16
|
-
service: S;
|
|
17
|
-
tableColumns: DataTableColumn<T>[];
|
|
18
|
-
/** Base path of the pages of the records (e.g. `/region`). */
|
|
19
|
-
resourceBasePath: string;
|
|
20
|
-
actionsSettings?: Partial<ActionsSettings>;
|
|
21
12
|
/** Extra content above the table (e.g. filters). */
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
13
|
+
filters?: ReactNode;
|
|
14
|
+
/** Table of the records (e.g. a `Table`). */
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
};
|
|
27
17
|
/**
|
|
28
|
-
* List page of records: header with the "Add" button, optional
|
|
29
|
-
*
|
|
18
|
+
* List page of records: header with the "Add" button, optional filters and the table of the records, given as
|
|
19
|
+
* children, inside a card.
|
|
30
20
|
*/
|
|
31
|
-
declare function ListPage
|
|
21
|
+
declare function ListPage({ title, titlePlural, breadcrumbItems, addActionRoute, filters, children }: ListPageProps): ReactElement;
|
|
32
22
|
export default ListPage;
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
import { useDocumentTitle, useKitMessages } from "../../../provider/useKit.js";
|
|
3
3
|
import PaperCard from "../../molecule/PaperCard/PaperCard.js";
|
|
4
4
|
import PageHeader from "../../organism/PageHeader/PageHeader.js";
|
|
5
|
-
import Table from "../../organism/Table/Table.js";
|
|
6
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
import { Group, Stack, Text } from "@mantine/core";
|
|
8
7
|
// src/component/template/ListPage/ListPage.tsx
|
|
9
8
|
/**
|
|
10
|
-
* List page of records: header with the "Add" button, optional
|
|
11
|
-
*
|
|
9
|
+
* List page of records: header with the "Add" button, optional filters and the table of the records, given as
|
|
10
|
+
* children, inside a card.
|
|
12
11
|
*/
|
|
13
|
-
function ListPage(
|
|
14
|
-
const { title, titlePlural, breadcrumbItems, addActionRoute, service, tableColumns, resourceBasePath, actionsSettings, children, customFetchMethod, getViewUrl } = props;
|
|
12
|
+
function ListPage({ title, titlePlural, breadcrumbItems, addActionRoute, filters, children }) {
|
|
15
13
|
const documentTitle = useDocumentTitle(title);
|
|
16
14
|
const messages = useKitMessages();
|
|
17
15
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("title", { children: documentTitle }), /* @__PURE__ */ jsxs(Stack, {
|
|
@@ -22,7 +20,7 @@ function ListPage(props) {
|
|
|
22
20
|
breadcrumbItems,
|
|
23
21
|
addActionRoute
|
|
24
22
|
}),
|
|
25
|
-
|
|
23
|
+
filters && /* @__PURE__ */ jsx(Stack, { children: filters }),
|
|
26
24
|
/* @__PURE__ */ jsxs(PaperCard, { children: [/* @__PURE__ */ jsx(Group, {
|
|
27
25
|
justify: "space-between",
|
|
28
26
|
mb: "md",
|
|
@@ -31,14 +29,7 @@ function ListPage(props) {
|
|
|
31
29
|
fw: 600,
|
|
32
30
|
children: messages.table.listTitle(titlePlural)
|
|
33
31
|
})
|
|
34
|
-
}),
|
|
35
|
-
service,
|
|
36
|
-
basePath: resourceBasePath,
|
|
37
|
-
columns: tableColumns,
|
|
38
|
-
customFetchMethod,
|
|
39
|
-
actionsSettings,
|
|
40
|
-
getViewUrl
|
|
41
|
-
})] })
|
|
32
|
+
}), children] })
|
|
42
33
|
]
|
|
43
34
|
})] });
|
|
44
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/ListPage/ListPage.tsx"],"sourcesContent":["import { ReactElement, ReactNode } from 'react';\n\nimport { Group, Stack, Text } from '@mantine/core';\
|
|
1
|
+
{"version":3,"file":"ListPage.js","names":["_Fragment"],"sources":["../../../../src/component/template/ListPage/ListPage.tsx"],"sourcesContent":["import { ReactElement, ReactNode } from 'react';\n\nimport { Group, Stack, Text } from '@mantine/core';\n\nimport { useDocumentTitle, useKitMessages } from '../../../provider/useKit';\nimport { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';\nimport PaperCard from '../../molecule/PaperCard/PaperCard';\nimport PageHeader from '../../organism/PageHeader/PageHeader';\n\n/** Props of the {@link ListPage}. */\ntype ListPageProps = {\n /** Title of the page (e.g. \"Regions\"). */\n title: string;\n\n /** Plural name of the records, used in the title of the table card. */\n titlePlural: string;\n breadcrumbItems: BreadcrumbItem[];\n\n /** Route of the \"Add\" button; absent for no button. */\n addActionRoute?: string;\n\n /** Extra content above the table (e.g. filters). */\n filters?: ReactNode;\n\n /** Table of the records (e.g. a `Table`). */\n children: ReactNode;\n};\n\n/**\n * List page of records: header with the \"Add\" button, optional filters and the table of the records, given as\n * children, inside a card.\n */\nfunction ListPage({\n title,\n titlePlural,\n breadcrumbItems,\n addActionRoute,\n filters,\n children\n}: ListPageProps): ReactElement {\n const documentTitle = useDocumentTitle(title);\n const messages = useKitMessages();\n\n return (\n <>\n <title>{documentTitle}</title>\n <Stack gap=\"lg\">\n <PageHeader title={title} breadcrumbItems={breadcrumbItems} addActionRoute={addActionRoute} />\n {filters && <Stack>{filters}</Stack>}\n <PaperCard>\n <Group justify=\"space-between\" mb=\"md\">\n <Text fz=\"lg\" fw={600}>\n {messages.table.listTitle(titlePlural)}\n </Text>\n </Group>\n {children}\n </PaperCard>\n </Stack>\n </>\n );\n}\n\nexport default ListPage;\n"],"mappings":";;;;;;;;;;;AAgCA,SAAS,SAAS,EACd,OACA,aACA,iBACA,gBACA,SACA,YAC4B;CAC5B,MAAM,gBAAgB,iBAAiB,KAAK;CAC5C,MAAM,WAAW,eAAe;CAEhC,OACI,qBAAAA,UAAA,EAAA,UAAA,CACI,oBAAC,SAAD,EAAA,UAAQ,cAAqB,CAAA,GAC7B,qBAAC,OAAD;EAAO,KAAI;EAAX,UAAA;GACI,oBAAC,YAAD;IAAmB;IAAwB;IAAiC;GAAiB,CAAA;GAC5F,WAAW,oBAAC,OAAD,EAAA,UAAQ,QAAe,CAAA;GACnC,qBAAC,WAAD,EAAA,UAAA,CACI,oBAAC,OAAD;IAAO,SAAQ;IAAgB,IAAG;IAC9B,UAAA,oBAAC,MAAD;KAAM,IAAG;KAAK,IAAI;KACb,UAAA,SAAS,MAAM,UAAU,WAAW;IACnC,CAAA;GACH,CAAA,GACN,QACM,EAAA,CAAA;EACR;CACT,CAAA,CAAA,EAAA,CAAA;AAEV"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PageRequest, PageResult } from './PageRequest';
|
|
2
|
+
/**
|
|
3
|
+
* Source of the pages of a table, sorted and paginated by the backend (e.g. a service that accesses a paginated API).
|
|
4
|
+
* Any object with this method works, without extending a class.
|
|
5
|
+
* @template M type of the records
|
|
6
|
+
*/
|
|
7
|
+
export interface PageDataSource<M> {
|
|
8
|
+
/** Fetches a page of records. */
|
|
9
|
+
findPage(request: PageRequest<M>): Promise<PageResult<M>>;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DataTableSortStatus } from 'mantine-datatable';
|
|
2
|
+
/**
|
|
3
|
+
* Page of records requested from the backend.
|
|
4
|
+
* @template M type of the records
|
|
5
|
+
*/
|
|
6
|
+
export type PageRequest<M> = {
|
|
7
|
+
/** Number of the page, starting at the `firstPage` option of `useServerPagination` (1 by default). */
|
|
8
|
+
page: number;
|
|
9
|
+
/** Maximum number of records of the page. */
|
|
10
|
+
size: number;
|
|
11
|
+
/** Sort to apply. `columnAccessor` holds the `sortKey` of the column, if it has one, or else its `accessor`. */
|
|
12
|
+
sort: DataTableSortStatus<M>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Page of records returned by the backend.
|
|
16
|
+
* @template M type of the records
|
|
17
|
+
*/
|
|
18
|
+
export type PageResult<M> = {
|
|
19
|
+
/** Records of the page, already sorted by the backend. */
|
|
20
|
+
records: M[];
|
|
21
|
+
/** Total of records of all pages. */
|
|
22
|
+
totalRecords: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Fetches a page of records, as the `findPage` of a `PageDataSource`. It must be stable (e.g. with `useCallback`),
|
|
26
|
+
* since a new function means that the filter changed, so the table fetches again from page 1.
|
|
27
|
+
* @template M type of the records
|
|
28
|
+
*/
|
|
29
|
+
export type FetchPage<M> = (request: PageRequest<M>) => Promise<PageResult<M>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/** Values returned by {@link useService}. */
|
|
2
2
|
export type UseService<D> = {
|
|
3
|
-
/** Data of the fetch, or the initial value
|
|
3
|
+
/** Data of the last successful fetch, or the initial value if none has finished yet. */
|
|
4
4
|
data: D;
|
|
5
|
-
/** Error of the fetch; `null` if it has not finished yet or succeeded. */
|
|
5
|
+
/** Error of the current fetch; `null` if it has not finished yet or succeeded. */
|
|
6
6
|
error: unknown | null;
|
|
7
|
-
/** Whether the fetch has not finished yet. */
|
|
7
|
+
/** Whether the current fetch has not finished yet. */
|
|
8
8
|
loading: boolean;
|
|
9
9
|
};
|
|
10
10
|
/**
|