@ifto/mantine-kit 0.3.0 → 0.5.1
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 +85 -10
- package/dist/component/organism/EChart/chart/BarChart.d.ts +3 -0
- package/dist/component/organism/EChart/chart/BarChart.js +5 -0
- package/dist/component/organism/EChart/chart/BarChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/CartesianChart.d.ts +4 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js +5 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/ChartType.d.ts +3 -0
- package/dist/component/organism/EChart/chart/DonutChart.d.ts +4 -0
- package/dist/component/organism/EChart/chart/DonutChart.js +6 -0
- package/dist/component/organism/EChart/chart/DonutChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/LineChart.d.ts +3 -0
- package/dist/component/organism/EChart/chart/LineChart.js +5 -0
- package/dist/component/organism/EChart/chart/LineChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/StackedBarChart.d.ts +3 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js +5 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js.map +1 -1
- 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/package.json +1 -1
|
@@ -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
|
/**
|
package/dist/hook/useService.js
CHANGED
|
@@ -7,6 +7,8 @@ function useService(fetchMethod, initialData) {
|
|
|
7
7
|
const [loading, setLoading] = useState(true);
|
|
8
8
|
useEffect(() => {
|
|
9
9
|
let obsolete = false;
|
|
10
|
+
setLoading(true);
|
|
11
|
+
setError(null);
|
|
10
12
|
fetchMethod().then((responseData) => !obsolete && setData(responseData)).catch((e) => !obsolete && setError(e)).finally(() => !obsolete && setLoading(false));
|
|
11
13
|
return () => {
|
|
12
14
|
obsolete = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useService.js","names":[],"sources":["../../src/hook/useService.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/** Values returned by {@link useService}. */\nexport type UseService<D> = {\n /** Data of the fetch, or the initial value
|
|
1
|
+
{"version":3,"file":"useService.js","names":[],"sources":["../../src/hook/useService.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/** Values returned by {@link useService}. */\nexport type UseService<D> = {\n /** Data of the last successful fetch, or the initial value if none has finished yet. */\n data: D;\n\n /** Error of the current fetch; `null` if it has not finished yet or succeeded. */\n error: unknown | null;\n\n /** Whether the current fetch has not finished yet. */\n loading: boolean;\n};\n\n/**\n * Fetches data when the component mounts and every time `fetchMethod` changes.\n * Without an initial value, `data` is `undefined` while loading (or after a failure), so the caller must handle it.\n * @param fetchMethod function that fetches the data. It must be stable (e.g. with `useCallback`), since a new function\n * triggers a new fetch\n * @return the data (`undefined` until the fetch finishes), the error and whether the fetch is still running\n */\nfunction useService<T>(fetchMethod: () => Promise<T>): UseService<T | undefined>;\n\n/**\n * Fetches data when the component mounts and every time `fetchMethod` changes, starting with the given value (e.g. an\n * empty array for a list), so `data` always has the type of the fetched data.\n * @param fetchMethod function that fetches the data. It must be stable (e.g. with `useCallback`), since a new function\n * triggers a new fetch\n * @param initialData value of `data` until the fetch finishes (and after a failure)\n * @return the data, the error and whether the fetch is still running\n */\nfunction useService<T>(fetchMethod: () => Promise<T>, initialData: T): UseService<T>;\n\nfunction useService<T>(fetchMethod: () => Promise<T>, initialData?: T): UseService<T | undefined> {\n const [data, setData] = useState<T | undefined>(initialData);\n const [error, setError] = useState<unknown | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n /* When fetchMethod changes (e.g. another filter), the previous fetch becomes obsolete. If its response arrives\n after the one of the new fetch, it cannot overwrite the current data. */\n let obsolete = false;\n setLoading(true);\n setError(null);\n fetchMethod()\n .then(responseData => !obsolete && setData(responseData))\n .catch(e => !obsolete && setError(e))\n .finally(() => !obsolete && setLoading(false));\n\n return () => {\n obsolete = true;\n };\n }, [fetchMethod]);\n\n return { data, error, loading };\n}\n\nexport default useService;\n"],"mappings":";;;AAiCA,SAAS,WAAc,aAA+B,aAA4C;CAC9F,MAAM,CAAC,MAAM,WAAW,SAAwB,WAAW;CAC3D,MAAM,CAAC,OAAO,YAAY,SAAyB,IAAI;CACvD,MAAM,CAAC,SAAS,cAAc,SAAS,IAAI;CAE3C,gBAAgB;EAGZ,IAAI,WAAW;EACf,WAAW,IAAI;EACf,SAAS,IAAI;EACb,YAAY,CAAC,CACR,MAAK,iBAAgB,CAAC,YAAY,QAAQ,YAAY,CAAC,CAAC,CACxD,OAAM,MAAK,CAAC,YAAY,SAAS,CAAC,CAAC,CAAC,CACpC,cAAc,CAAC,YAAY,WAAW,KAAK,CAAC;EAEjD,aAAa;GACT,WAAW;EACf;CACJ,GAAG,CAAC,WAAW,CAAC;CAEhB,OAAO;EAAE;EAAM;EAAO;CAAQ;AAClC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifto/mantine-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "General purpose Mantine components for React apps: CRUD tables and forms, layout, ECharts charts, Excel/CSV export, print pages and a REST HTTP client, with i18n (en-US and pt-BR).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "IFTO - Campus Palmas",
|