@etsoo/materialui 1.2.42 → 1.2.44
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/lib/DataGridEx.d.ts +8 -0
- package/lib/GridDataCacheType.d.ts +9 -0
- package/lib/GridDataCacheType.js +1 -0
- package/lib/GridUtils.d.ts +46 -0
- package/lib/GridUtils.js +85 -0
- package/lib/ResponsibleContainer.d.ts +0 -8
- package/lib/ResponsibleContainer.js +11 -24
- package/lib/pages/DataGridPage.js +37 -6
- package/lib/pages/FixedListPage.js +37 -6
- package/lib/pages/ListPage.d.ts +3 -3
- package/lib/pages/ListPage.js +43 -12
- package/lib/pages/ListPageProps.d.ts +4 -4
- package/lib/pages/SearchPageProps.d.ts +9 -1
- package/lib/pages/TablePage.d.ts +3 -3
- package/lib/pages/TablePage.js +15 -13
- package/package.json +2 -2
- package/src/DataGridEx.tsx +10 -0
- package/src/GridDataCacheType.ts +10 -0
- package/src/GridUtils.ts +99 -0
- package/src/ResponsibleContainer.tsx +11 -43
- package/src/pages/DataGridPage.tsx +56 -4
- package/src/pages/FixedListPage.tsx +53 -4
- package/src/pages/ListPage.tsx +129 -80
- package/src/pages/ListPageProps.ts +7 -7
- package/src/pages/SearchPageProps.ts +13 -1
- package/src/pages/TablePage.tsx +121 -116
package/lib/DataGridEx.d.ts
CHANGED
|
@@ -20,6 +20,14 @@ export type DataGridExProps<T extends object, D extends DataTypes.Keys<T>> = Omi
|
|
|
20
20
|
* Alternating colors for odd/even rows
|
|
21
21
|
*/
|
|
22
22
|
alternatingColors?: [string?, string?];
|
|
23
|
+
/**
|
|
24
|
+
* Cache key
|
|
25
|
+
*/
|
|
26
|
+
cacheKey?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Cache minutes
|
|
29
|
+
*/
|
|
30
|
+
cacheMinutes?: number;
|
|
23
31
|
/**
|
|
24
32
|
* Checkable to choose multiple items
|
|
25
33
|
* @default false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { GridLoadDataProps, GridLoaderStates } from "@etsoo/react";
|
|
2
|
+
import { DataTypes } from "@etsoo/shared";
|
|
3
|
+
import { GridDataCacheType } from "./GridDataCacheType";
|
|
4
|
+
/**
|
|
5
|
+
* Grid utilities
|
|
6
|
+
*/
|
|
7
|
+
export declare namespace GridUtils {
|
|
8
|
+
/**
|
|
9
|
+
* Create data loader
|
|
10
|
+
* @param props Props
|
|
11
|
+
* @param template Field template
|
|
12
|
+
* @param cacheKey Cache key
|
|
13
|
+
* @returns Request data
|
|
14
|
+
*/
|
|
15
|
+
function createLoader<F extends DataTypes.BasicTemplate>(props: GridLoadDataProps, template?: F, cacheKey?: string): DataTypes.BasicTemplateType<F> & {
|
|
16
|
+
currentPage: number;
|
|
17
|
+
batchSize: number;
|
|
18
|
+
orderBy?: string | undefined;
|
|
19
|
+
orderByAsc?: boolean | undefined;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get cache data
|
|
23
|
+
* @param cacheKey Cache key
|
|
24
|
+
* @param cacheMinutes Cache minutes
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
27
|
+
function getCacheData<T>(cacheKey: string, cacheMinutes: number): GridDataCacheType<T> | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Get search data
|
|
30
|
+
* @param cacheKey Cache key
|
|
31
|
+
* @returns Result
|
|
32
|
+
*/
|
|
33
|
+
function getSearchData<F extends DataTypes.BasicTemplate>(cacheKey?: string): DataTypes.BasicTemplateType<F> | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Get update rows handler
|
|
36
|
+
* @param cacheKey Cache key
|
|
37
|
+
* @returns Handler
|
|
38
|
+
*/
|
|
39
|
+
function getUpdateRowsHandler<T extends object>(cacheKey?: string): (rows: T[], state: GridLoaderStates<T>) => void;
|
|
40
|
+
/**
|
|
41
|
+
* Merget search date to state
|
|
42
|
+
* @param state State
|
|
43
|
+
* @param searchData Search data
|
|
44
|
+
*/
|
|
45
|
+
function mergeSearchData<T, F extends DataTypes.BasicTemplate>(state: GridLoaderStates<T>, searchData?: DataTypes.BasicTemplateType<F>): void;
|
|
46
|
+
}
|
package/lib/GridUtils.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { GridDataGetData } from "@etsoo/react";
|
|
2
|
+
/**
|
|
3
|
+
* Grid utilities
|
|
4
|
+
*/
|
|
5
|
+
export var GridUtils;
|
|
6
|
+
(function (GridUtils) {
|
|
7
|
+
/**
|
|
8
|
+
* Create data loader
|
|
9
|
+
* @param props Props
|
|
10
|
+
* @param template Field template
|
|
11
|
+
* @param cacheKey Cache key
|
|
12
|
+
* @returns Request data
|
|
13
|
+
*/
|
|
14
|
+
function createLoader(props, template, cacheKey) {
|
|
15
|
+
const { data, ...rest } = props;
|
|
16
|
+
const formData = GridDataGetData(data, template);
|
|
17
|
+
if (cacheKey)
|
|
18
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(formData));
|
|
19
|
+
return { ...formData, ...rest };
|
|
20
|
+
}
|
|
21
|
+
GridUtils.createLoader = createLoader;
|
|
22
|
+
/**
|
|
23
|
+
* Get cache data
|
|
24
|
+
* @param cacheKey Cache key
|
|
25
|
+
* @param cacheMinutes Cache minutes
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
function getCacheData(cacheKey, cacheMinutes) {
|
|
29
|
+
const cacheSource = sessionStorage.getItem(cacheKey);
|
|
30
|
+
if (cacheSource) {
|
|
31
|
+
const cacheData = JSON.parse(cacheSource);
|
|
32
|
+
if (new Date().valueOf() - cacheData.creation > cacheMinutes * 60000) {
|
|
33
|
+
sessionStorage.removeItem(cacheKey);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
return cacheData;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
GridUtils.getCacheData = getCacheData;
|
|
40
|
+
/**
|
|
41
|
+
* Get search data
|
|
42
|
+
* @param cacheKey Cache key
|
|
43
|
+
* @returns Result
|
|
44
|
+
*/
|
|
45
|
+
function getSearchData(cacheKey) {
|
|
46
|
+
if (cacheKey) {
|
|
47
|
+
const data = sessionStorage.getItem(`${cacheKey}-searchbar`);
|
|
48
|
+
if (data) {
|
|
49
|
+
return JSON.parse(data);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
GridUtils.getSearchData = getSearchData;
|
|
54
|
+
/**
|
|
55
|
+
* Get update rows handler
|
|
56
|
+
* @param cacheKey Cache key
|
|
57
|
+
* @returns Handler
|
|
58
|
+
*/
|
|
59
|
+
function getUpdateRowsHandler(cacheKey) {
|
|
60
|
+
return (rows, state) => {
|
|
61
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
62
|
+
const data = {
|
|
63
|
+
rows,
|
|
64
|
+
state,
|
|
65
|
+
creation: new Date().valueOf()
|
|
66
|
+
};
|
|
67
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
GridUtils.getUpdateRowsHandler = getUpdateRowsHandler;
|
|
72
|
+
/**
|
|
73
|
+
* Merget search date to state
|
|
74
|
+
* @param state State
|
|
75
|
+
* @param searchData Search data
|
|
76
|
+
*/
|
|
77
|
+
function mergeSearchData(state, searchData) {
|
|
78
|
+
var _a;
|
|
79
|
+
if (searchData == null)
|
|
80
|
+
return;
|
|
81
|
+
(_a = state.data) !== null && _a !== void 0 ? _a : (state.data = {});
|
|
82
|
+
Object.assign(state.data, searchData);
|
|
83
|
+
}
|
|
84
|
+
GridUtils.mergeSearchData = mergeSearchData;
|
|
85
|
+
})(GridUtils || (GridUtils = {}));
|
|
@@ -22,14 +22,6 @@ export type ResponsibleContainerProps<T extends object, F extends DataTypes.Basi
|
|
|
22
22
|
* @returns Adjusted height
|
|
23
23
|
*/
|
|
24
24
|
adjustFabHeight?: (height: number, isGrid: boolean) => number;
|
|
25
|
-
/**
|
|
26
|
-
* Cache key
|
|
27
|
-
*/
|
|
28
|
-
cacheKey?: string;
|
|
29
|
-
/**
|
|
30
|
-
* Cache minutes
|
|
31
|
-
*/
|
|
32
|
-
cacheMinutes?: number;
|
|
33
25
|
/**
|
|
34
26
|
* Columns
|
|
35
27
|
*/
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Box, Stack } from "@mui/material";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { ReactUtils, useCombinedRefs, useDimensions } from "@etsoo/react";
|
|
4
4
|
import { DataGridEx, DataGridExCalColumns } from "./DataGridEx";
|
|
5
5
|
import { MUGlobal } from "./MUGlobal";
|
|
6
6
|
import { PullToRefreshUI } from "./PullToRefreshUI";
|
|
7
7
|
import { ScrollerListEx } from "./ScrollerListEx";
|
|
8
8
|
import { SearchBar } from "./SearchBar";
|
|
9
9
|
import { Labels } from "./app/Labels";
|
|
10
|
+
import { GridUtils } from "./GridUtils";
|
|
10
11
|
function defaultContainerBoxSx(paddings, hasField, _dataGrid) {
|
|
11
12
|
const half = MUGlobal.half(paddings);
|
|
12
13
|
return {
|
|
@@ -44,11 +45,10 @@ export function ResponsibleContainer(props) {
|
|
|
44
45
|
// Load data
|
|
45
46
|
const localLoadData = (props) => {
|
|
46
47
|
state.mounted = true;
|
|
47
|
-
|
|
48
|
-
if (cacheKey)
|
|
49
|
-
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
50
|
-
return loadData(data);
|
|
48
|
+
return loadData(GridUtils.createLoader(props, fieldTemplate, cacheKey));
|
|
51
49
|
};
|
|
50
|
+
// Search data
|
|
51
|
+
const searchData = GridUtils.getSearchData(cacheKey);
|
|
52
52
|
// On submit callback
|
|
53
53
|
const onSubmit = (data, _reset) => {
|
|
54
54
|
if (data == null || state.ref == null)
|
|
@@ -72,25 +72,15 @@ export function ResponsibleContainer(props) {
|
|
|
72
72
|
state.rect = rect;
|
|
73
73
|
return false;
|
|
74
74
|
});
|
|
75
|
-
const onUpdateRows = (rows, state) => {
|
|
76
|
-
if (state.currentPage > 0 && cacheKey) {
|
|
77
|
-
const data = { rows, state, creation: new Date().valueOf() };
|
|
78
|
-
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
75
|
const onInitLoad = (ref) => {
|
|
82
76
|
// Avoid repeatedly load from cache
|
|
83
77
|
if (refs.current.initLoaded || !cacheKey)
|
|
84
78
|
return undefined;
|
|
85
79
|
// Cache data
|
|
86
|
-
const cacheData =
|
|
80
|
+
const cacheData = GridUtils.getCacheData(cacheKey, cacheMinutes);
|
|
87
81
|
if (cacheData) {
|
|
88
|
-
const { rows, state
|
|
89
|
-
|
|
90
|
-
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
91
|
-
sessionStorage.removeItem(cacheKey);
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
82
|
+
const { rows, state } = cacheData;
|
|
83
|
+
GridUtils.mergeSearchData(state, searchData);
|
|
94
84
|
// Scroll position
|
|
95
85
|
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
96
86
|
if (scrollData) {
|
|
@@ -157,7 +147,7 @@ export function ResponsibleContainer(props) {
|
|
|
157
147
|
React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data), outerRef: (element) => {
|
|
158
148
|
if (element != null && elementReady)
|
|
159
149
|
elementReady(element, true);
|
|
160
|
-
}, onScroll: onGridScroll, columns: columns, onUpdateRows:
|
|
150
|
+
}, onScroll: onGridScroll, columns: columns, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, ...rest })),
|
|
161
151
|
true
|
|
162
152
|
];
|
|
163
153
|
}
|
|
@@ -172,7 +162,7 @@ export function ResponsibleContainer(props) {
|
|
|
172
162
|
delete rest.selectable;
|
|
173
163
|
return [
|
|
174
164
|
React.createElement(Box, { className: "ListBox", sx: { height: heightLocal } },
|
|
175
|
-
React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, onUpdateRows:
|
|
165
|
+
React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, mRef: mRefs, onClick: (event, data) => quickAction && ReactUtils.isSafeClick(event) && quickAction(data), oRef: (element) => {
|
|
176
166
|
if (element != null && elementReady)
|
|
177
167
|
elementReady(element, false);
|
|
178
168
|
}, onScroll: onListScroll, ...rest })),
|
|
@@ -180,12 +170,9 @@ export function ResponsibleContainer(props) {
|
|
|
180
170
|
];
|
|
181
171
|
})();
|
|
182
172
|
const searchBar = React.useMemo(() => {
|
|
183
|
-
var _a;
|
|
184
173
|
if (!hasFields || showDataGrid == null)
|
|
185
174
|
return;
|
|
186
|
-
const f = typeof fields == "function"
|
|
187
|
-
? fields(JSON.parse((_a = sessionStorage.getItem(`${cacheKey}-searchbar`)) !== null && _a !== void 0 ? _a : "{}"))
|
|
188
|
-
: fields;
|
|
175
|
+
const f = typeof fields == "function" ? fields(searchData !== null && searchData !== void 0 ? searchData : {}) : fields;
|
|
189
176
|
return (React.createElement(SearchBar, { fields: f, onSubmit: onSubmit, className: `searchBar${showDataGrid ? "Grid" : "List"}` }));
|
|
190
177
|
}, [showDataGrid, hasFields, searchBarHeight]);
|
|
191
178
|
// Pull container
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCombinedRefs, useDimensions } from "@etsoo/react";
|
|
2
2
|
import { Box, Stack } from "@mui/material";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { DataGridEx } from "../DataGridEx";
|
|
5
5
|
import { MUGlobal } from "../MUGlobal";
|
|
6
6
|
import { SearchBar } from "../SearchBar";
|
|
7
7
|
import { CommonPage } from "./CommonPage";
|
|
8
|
+
import { GridUtils } from "../GridUtils";
|
|
8
9
|
/**
|
|
9
10
|
* DataGrid page
|
|
10
11
|
* @param props Props
|
|
@@ -13,7 +14,7 @@ import { CommonPage } from "./CommonPage";
|
|
|
13
14
|
export function DataGridPage(props) {
|
|
14
15
|
var _a;
|
|
15
16
|
// Destruct
|
|
16
|
-
const { adjustHeight, fields, fieldTemplate, height, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, ...rest } = props;
|
|
17
|
+
const { adjustHeight, fields, fieldTemplate, height, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
18
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
19
|
// States
|
|
19
20
|
const [states, setStates] = React.useReducer((currentState, newState) => {
|
|
@@ -27,13 +28,42 @@ export function DataGridPage(props) {
|
|
|
27
28
|
states.ref = ref;
|
|
28
29
|
//setStates({ ref });
|
|
29
30
|
});
|
|
31
|
+
const initLoadedRef = React.useRef();
|
|
30
32
|
// On submit callback
|
|
31
33
|
const onSubmit = (data, _reset) => {
|
|
32
34
|
setStates({ data });
|
|
33
35
|
};
|
|
34
36
|
const localLoadData = (props) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
return loadData(GridUtils.createLoader(props, fieldTemplate, cacheKey));
|
|
38
|
+
};
|
|
39
|
+
// Search data
|
|
40
|
+
const searchData = GridUtils.getSearchData(cacheKey);
|
|
41
|
+
const onInitLoad = (ref) => {
|
|
42
|
+
// Avoid repeatedly load from cache
|
|
43
|
+
if (initLoadedRef.current || !cacheKey)
|
|
44
|
+
return undefined;
|
|
45
|
+
// Cache data
|
|
46
|
+
const cacheData = GridUtils.getCacheData(cacheKey, cacheMinutes);
|
|
47
|
+
if (cacheData) {
|
|
48
|
+
const { rows, state } = cacheData;
|
|
49
|
+
GridUtils.mergeSearchData(state, searchData);
|
|
50
|
+
// Scroll position
|
|
51
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
52
|
+
if (scrollData) {
|
|
53
|
+
const { scrollLeft, scrollTop } = JSON.parse(scrollData);
|
|
54
|
+
globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
|
|
55
|
+
}
|
|
56
|
+
// Update flag value
|
|
57
|
+
initLoadedRef.current = true;
|
|
58
|
+
// Return cached rows and state
|
|
59
|
+
return [rows, state];
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
};
|
|
63
|
+
const onGridScroll = (props) => {
|
|
64
|
+
if (!cacheKey || !initLoadedRef.current)
|
|
65
|
+
return;
|
|
66
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
37
67
|
};
|
|
38
68
|
// Watch container
|
|
39
69
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
@@ -56,7 +86,7 @@ export function DataGridPage(props) {
|
|
|
56
86
|
const gridHeight = states.height;
|
|
57
87
|
if (gridHeight == null)
|
|
58
88
|
return;
|
|
59
|
-
return (React.createElement(DataGridEx, { autoLoad: false, height: gridHeight, loadData: localLoadData, mRef: refs, outerRef: (element) => {
|
|
89
|
+
return (React.createElement(DataGridEx, { autoLoad: false, height: gridHeight, loadData: localLoadData, mRef: refs, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, onScroll: onGridScroll, outerRef: (element) => {
|
|
60
90
|
if (element != null)
|
|
61
91
|
setStates({ element });
|
|
62
92
|
}, ...rest }));
|
|
@@ -67,12 +97,13 @@ export function DataGridPage(props) {
|
|
|
67
97
|
return;
|
|
68
98
|
ref.reset({ data });
|
|
69
99
|
}, [ref, data]);
|
|
100
|
+
const f = typeof fields == "function" ? fields(searchData !== null && searchData !== void 0 ? searchData : {}) : fields;
|
|
70
101
|
// Layout
|
|
71
102
|
return (React.createElement(CommonPage, { ...pageProps, scrollContainer: states.element },
|
|
72
103
|
React.createElement(Stack, null,
|
|
73
104
|
React.createElement(Box, { ref: dimensions[0][0], sx: {
|
|
74
105
|
paddingBottom: pageProps.paddings
|
|
75
106
|
} },
|
|
76
|
-
React.createElement(SearchBar, { fields:
|
|
107
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
77
108
|
list)));
|
|
78
109
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCombinedRefs, useDimensions } from "@etsoo/react";
|
|
2
2
|
import { Box, Stack } from "@mui/material";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { MUGlobal } from "../MUGlobal";
|
|
5
5
|
import { ScrollerListEx } from "../ScrollerListEx";
|
|
6
6
|
import { SearchBar } from "../SearchBar";
|
|
7
7
|
import { CommonPage } from "./CommonPage";
|
|
8
|
+
import { GridUtils } from "../GridUtils";
|
|
8
9
|
/**
|
|
9
10
|
* Fixed height list page
|
|
10
11
|
* @param props Props
|
|
@@ -13,10 +14,11 @@ import { CommonPage } from "./CommonPage";
|
|
|
13
14
|
export function FixedListPage(props) {
|
|
14
15
|
var _a;
|
|
15
16
|
// Destruct
|
|
16
|
-
const { adjustHeight, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, ...rest } = props;
|
|
17
|
+
const { adjustHeight, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
18
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
19
|
// States
|
|
19
20
|
const [states] = React.useState({});
|
|
21
|
+
const initLoadedRef = React.useRef();
|
|
20
22
|
// Scroll container
|
|
21
23
|
const [scrollContainer, updateScrollContainer] = React.useState();
|
|
22
24
|
const refs = useCombinedRefs(mRef, (ref) => {
|
|
@@ -38,8 +40,36 @@ export function FixedListPage(props) {
|
|
|
38
40
|
reset();
|
|
39
41
|
};
|
|
40
42
|
const localLoadData = (props) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
return loadData(GridUtils.createLoader(props, fieldTemplate, cacheKey));
|
|
44
|
+
};
|
|
45
|
+
// Search data
|
|
46
|
+
const searchData = GridUtils.getSearchData(cacheKey);
|
|
47
|
+
const onInitLoad = (ref) => {
|
|
48
|
+
// Avoid repeatedly load from cache
|
|
49
|
+
if (initLoadedRef.current || !cacheKey)
|
|
50
|
+
return undefined;
|
|
51
|
+
// Cache data
|
|
52
|
+
const cacheData = GridUtils.getCacheData(cacheKey, cacheMinutes);
|
|
53
|
+
if (cacheData) {
|
|
54
|
+
const { rows, state } = cacheData;
|
|
55
|
+
GridUtils.mergeSearchData(state, searchData);
|
|
56
|
+
// Scroll position
|
|
57
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
58
|
+
if (scrollData) {
|
|
59
|
+
const { scrollOffset } = JSON.parse(scrollData);
|
|
60
|
+
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
61
|
+
}
|
|
62
|
+
// Update flag value
|
|
63
|
+
initLoadedRef.current = true;
|
|
64
|
+
// Return cached rows and state
|
|
65
|
+
return [rows, state];
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
};
|
|
69
|
+
const onListScroll = (props) => {
|
|
70
|
+
if (!cacheKey || !initLoadedRef.current)
|
|
71
|
+
return;
|
|
72
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
43
73
|
};
|
|
44
74
|
// Watch container
|
|
45
75
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
@@ -53,17 +83,18 @@ export function FixedListPage(props) {
|
|
|
53
83
|
return (React.createElement(Box, { id: "list-container", sx: {
|
|
54
84
|
height: height + "px"
|
|
55
85
|
} },
|
|
56
|
-
React.createElement(ScrollerListEx, { autoLoad: false, height: height, loadData: localLoadData, mRef: refs, oRef: (element) => {
|
|
86
|
+
React.createElement(ScrollerListEx, { autoLoad: false, height: height, loadData: localLoadData, mRef: refs, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, onScroll: onListScroll, oRef: (element) => {
|
|
57
87
|
if (element != null)
|
|
58
88
|
updateScrollContainer(element);
|
|
59
89
|
}, ...rest })));
|
|
60
90
|
}
|
|
61
91
|
}, [rect]);
|
|
92
|
+
const f = typeof fields == "function" ? fields(searchData !== null && searchData !== void 0 ? searchData : {}) : fields;
|
|
62
93
|
const { paddings, ...pageRest } = pageProps;
|
|
63
94
|
// Layout
|
|
64
95
|
return (React.createElement(CommonPage, { ...pageRest, paddings: {}, scrollContainer: scrollContainer },
|
|
65
96
|
React.createElement(Stack, null,
|
|
66
97
|
React.createElement(Box, { ref: dimensions[0][0], sx: { padding: paddings } },
|
|
67
|
-
React.createElement(SearchBar, { fields:
|
|
98
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
68
99
|
list)));
|
|
69
100
|
}
|
package/lib/pages/ListPage.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DataTypes, IdDefaultType } from
|
|
2
|
-
import React from
|
|
3
|
-
import { ListPageProps } from
|
|
1
|
+
import { DataTypes, IdDefaultType } from "@etsoo/shared";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { ListPageProps } from "./ListPageProps";
|
|
4
4
|
/**
|
|
5
5
|
* List page
|
|
6
6
|
* @param props Props
|
package/lib/pages/ListPage.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Box, Stack } from
|
|
3
|
-
import React from
|
|
4
|
-
import { MUGlobal } from
|
|
5
|
-
import { ScrollerListEx } from
|
|
6
|
-
import { SearchBar } from
|
|
7
|
-
import { CommonPage, CommonPageScrollContainer } from
|
|
1
|
+
import { useCombinedRefs } from "@etsoo/react";
|
|
2
|
+
import { Box, Stack } from "@mui/material";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { MUGlobal } from "../MUGlobal";
|
|
5
|
+
import { ScrollerListEx } from "../ScrollerListEx";
|
|
6
|
+
import { SearchBar } from "../SearchBar";
|
|
7
|
+
import { CommonPage, CommonPageScrollContainer } from "./CommonPage";
|
|
8
|
+
import { GridUtils } from "../GridUtils";
|
|
8
9
|
/**
|
|
9
10
|
* List page
|
|
10
11
|
* @param props Props
|
|
@@ -13,7 +14,7 @@ import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
|
13
14
|
export function ListPage(props) {
|
|
14
15
|
var _a;
|
|
15
16
|
// Destruct
|
|
16
|
-
const { fields, fieldTemplate, loadData, mRef, pageProps = {}, ...rest } = props;
|
|
17
|
+
const { fields, fieldTemplate, loadData, mRef, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
18
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
19
|
// States
|
|
19
20
|
const [states] = React.useState({});
|
|
@@ -25,6 +26,7 @@ export function ListPage(props) {
|
|
|
25
26
|
if (first)
|
|
26
27
|
reset();
|
|
27
28
|
});
|
|
29
|
+
const initLoadedRef = React.useRef();
|
|
28
30
|
const reset = () => {
|
|
29
31
|
if (states.data == null || states.ref == null)
|
|
30
32
|
return;
|
|
@@ -36,15 +38,44 @@ export function ListPage(props) {
|
|
|
36
38
|
reset();
|
|
37
39
|
};
|
|
38
40
|
const localLoadData = (props) => {
|
|
39
|
-
|
|
40
|
-
return loadData(data);
|
|
41
|
+
return loadData(GridUtils.createLoader(props, fieldTemplate, cacheKey));
|
|
41
42
|
};
|
|
43
|
+
// Search data
|
|
44
|
+
const searchData = GridUtils.getSearchData(cacheKey);
|
|
45
|
+
const onInitLoad = (ref) => {
|
|
46
|
+
// Avoid repeatedly load from cache
|
|
47
|
+
if (initLoadedRef.current || !cacheKey)
|
|
48
|
+
return undefined;
|
|
49
|
+
// Cache data
|
|
50
|
+
const cacheData = GridUtils.getCacheData(cacheKey, cacheMinutes);
|
|
51
|
+
if (cacheData) {
|
|
52
|
+
const { rows, state } = cacheData;
|
|
53
|
+
GridUtils.mergeSearchData(state, searchData);
|
|
54
|
+
// Scroll position
|
|
55
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
56
|
+
if (scrollData) {
|
|
57
|
+
const { scrollOffset } = JSON.parse(scrollData);
|
|
58
|
+
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
59
|
+
}
|
|
60
|
+
// Update flag value
|
|
61
|
+
initLoadedRef.current = true;
|
|
62
|
+
// Return cached rows and state
|
|
63
|
+
return [rows, state];
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
};
|
|
67
|
+
const onListScroll = (props) => {
|
|
68
|
+
if (!cacheKey || !initLoadedRef.current)
|
|
69
|
+
return;
|
|
70
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
71
|
+
};
|
|
72
|
+
const f = typeof fields == "function" ? fields(searchData !== null && searchData !== void 0 ? searchData : {}) : fields;
|
|
42
73
|
// Layout
|
|
43
74
|
return (React.createElement(CommonPage, { ...pageProps, scrollContainer: CommonPageScrollContainer },
|
|
44
75
|
React.createElement(Stack, null,
|
|
45
76
|
React.createElement(Box, { sx: {
|
|
46
77
|
paddingBottom: pageProps.paddings
|
|
47
78
|
} },
|
|
48
|
-
React.createElement(SearchBar, { fields:
|
|
49
|
-
React.createElement(ScrollerListEx, { autoLoad: false, loadData: localLoadData, mRef: refs, ...rest }))));
|
|
79
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
80
|
+
React.createElement(ScrollerListEx, { autoLoad: false, loadData: localLoadData, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, onScroll: onListScroll, mRef: refs, ...rest }))));
|
|
50
81
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DataTypes } from
|
|
2
|
-
import { ScrollerListExProps } from
|
|
3
|
-
import { SearchPageProps } from
|
|
1
|
+
import { DataTypes } from "@etsoo/shared";
|
|
2
|
+
import { ScrollerListExProps } from "../ScrollerListEx";
|
|
3
|
+
import { SearchPageProps } from "./SearchPageProps";
|
|
4
4
|
/**
|
|
5
5
|
* List page props
|
|
6
6
|
*/
|
|
7
|
-
export type ListPageProps<T extends object, F extends DataTypes.BasicTemplate, D extends DataTypes.Keys<T>> = SearchPageProps<T, F> & Omit<ScrollerListExProps<T, D>,
|
|
7
|
+
export type ListPageProps<T extends object, F extends DataTypes.BasicTemplate, D extends DataTypes.Keys<T>> = SearchPageProps<T, F> & Omit<ScrollerListExProps<T, D>, "loadData">;
|
|
@@ -6,10 +6,18 @@ import { CommonPageProps } from "./CommonPageProps";
|
|
|
6
6
|
* Search page props
|
|
7
7
|
*/
|
|
8
8
|
export type SearchPageProps<T extends object, F extends DataTypes.BasicTemplate> = Omit<GridLoader<T>, "loadData"> & {
|
|
9
|
+
/**
|
|
10
|
+
* Cache key
|
|
11
|
+
*/
|
|
12
|
+
cacheKey?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Cache minutes
|
|
15
|
+
*/
|
|
16
|
+
cacheMinutes?: number;
|
|
9
17
|
/**
|
|
10
18
|
* Search fields
|
|
11
19
|
*/
|
|
12
|
-
fields: React.ReactElement[];
|
|
20
|
+
fields: React.ReactElement[] | ((data: DataTypes.BasicTemplateType<F>) => React.ReactElement[]);
|
|
13
21
|
/**
|
|
14
22
|
* Search field template
|
|
15
23
|
*/
|
package/lib/pages/TablePage.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DataTypes, IdDefaultType } from
|
|
2
|
-
import React from
|
|
3
|
-
import { TablePageProps } from
|
|
1
|
+
import { DataTypes, IdDefaultType } from "@etsoo/shared";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TablePageProps } from "./TablePageProps";
|
|
4
4
|
/**
|
|
5
5
|
* Table page
|
|
6
6
|
* @param props Props
|
package/lib/pages/TablePage.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Box, Stack } from
|
|
3
|
-
import React from
|
|
4
|
-
import { MUGlobal } from
|
|
5
|
-
import { SearchBar } from
|
|
6
|
-
import { TableEx, TableExMinWidth } from
|
|
7
|
-
import { CommonPage, CommonPageScrollContainer } from
|
|
1
|
+
import { useCombinedRefs, useDimensions } from "@etsoo/react";
|
|
2
|
+
import { Box, Stack } from "@mui/material";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { MUGlobal } from "../MUGlobal";
|
|
5
|
+
import { SearchBar } from "../SearchBar";
|
|
6
|
+
import { TableEx, TableExMinWidth } from "../TableEx";
|
|
7
|
+
import { CommonPage, CommonPageScrollContainer } from "./CommonPage";
|
|
8
|
+
import { GridUtils } from "../GridUtils";
|
|
8
9
|
/**
|
|
9
10
|
* Table page
|
|
10
11
|
* @param props Props
|
|
@@ -13,7 +14,7 @@ import { CommonPage, CommonPageScrollContainer } from './CommonPage';
|
|
|
13
14
|
export function TablePage(props) {
|
|
14
15
|
var _a;
|
|
15
16
|
// Destruct
|
|
16
|
-
const { columns, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, ...rest } = props;
|
|
17
|
+
const { columns, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
18
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
19
|
// States
|
|
19
20
|
const [states] = React.useState({});
|
|
@@ -36,9 +37,10 @@ export function TablePage(props) {
|
|
|
36
37
|
reset();
|
|
37
38
|
};
|
|
38
39
|
const localLoadData = (props) => {
|
|
39
|
-
|
|
40
|
-
return loadData(data);
|
|
40
|
+
return loadData(GridUtils.createLoader(props, fieldTemplate, cacheKey));
|
|
41
41
|
};
|
|
42
|
+
// Search data
|
|
43
|
+
const searchData = GridUtils.getSearchData(cacheKey);
|
|
42
44
|
// Total width
|
|
43
45
|
const totalWidth = React.useMemo(() => columns.reduce((previousValue, { width, minWidth }) => {
|
|
44
46
|
var _a;
|
|
@@ -49,8 +51,7 @@ export function TablePage(props) {
|
|
|
49
51
|
const rect = dimensions[0][2];
|
|
50
52
|
const list = React.useMemo(() => {
|
|
51
53
|
if (rect != null && rect.height > 50 && rect.width >= totalWidth) {
|
|
52
|
-
let maxHeight = document.documentElement.clientHeight -
|
|
53
|
-
(rect.top + rect.height + 1);
|
|
54
|
+
let maxHeight = document.documentElement.clientHeight - (rect.top + rect.height + 1);
|
|
54
55
|
const style = window.getComputedStyle(dimensions[0][1]);
|
|
55
56
|
const paddingBottom = parseFloat(style.paddingBottom);
|
|
56
57
|
if (!isNaN(paddingBottom))
|
|
@@ -58,12 +59,13 @@ export function TablePage(props) {
|
|
|
58
59
|
return (React.createElement(TableEx, { autoLoad: false, columns: columns, loadData: localLoadData, maxHeight: maxHeight, mRef: refs, ...rest }));
|
|
59
60
|
}
|
|
60
61
|
}, [rect]);
|
|
62
|
+
const f = typeof fields == "function" ? fields(searchData !== null && searchData !== void 0 ? searchData : {}) : fields;
|
|
61
63
|
// Layout
|
|
62
64
|
return (React.createElement(CommonPage, { ...pageProps, scrollContainer: CommonPageScrollContainer },
|
|
63
65
|
React.createElement(Stack, null,
|
|
64
66
|
React.createElement(Box, { ref: dimensions[0][0], sx: {
|
|
65
67
|
paddingBottom: pageProps.paddings
|
|
66
68
|
} },
|
|
67
|
-
React.createElement(SearchBar, { fields:
|
|
69
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
68
70
|
list)));
|
|
69
71
|
}
|