@etsoo/materialui 1.2.42 → 1.2.43
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/ResponsibleContainer.d.ts +0 -8
- package/lib/pages/DataGridPage.js +47 -4
- package/lib/pages/FixedListPage.js +47 -4
- package/lib/pages/ListPage.d.ts +3 -3
- package/lib/pages/ListPage.js +52 -11
- 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 +16 -12
- package/package.json +1 -1
- package/src/DataGridEx.tsx +10 -0
- package/src/GridDataCacheType.ts +10 -0
- package/src/ResponsibleContainer.tsx +2 -11
- package/src/pages/DataGridPage.tsx +76 -1
- package/src/pages/FixedListPage.tsx +73 -1
- package/src/pages/ListPage.tsx +148 -80
- package/src/pages/ListPageProps.ts +7 -7
- package/src/pages/SearchPageProps.ts +13 -1
- package/src/pages/TablePage.tsx +130 -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 {};
|
|
@@ -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
|
*/
|
|
@@ -11,9 +11,9 @@ import { CommonPage } from "./CommonPage";
|
|
|
11
11
|
* @returns Component
|
|
12
12
|
*/
|
|
13
13
|
export function DataGridPage(props) {
|
|
14
|
-
var _a;
|
|
14
|
+
var _a, _b;
|
|
15
15
|
// Destruct
|
|
16
|
-
const { adjustHeight, fields, fieldTemplate, height, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, ...rest } = props;
|
|
16
|
+
const { adjustHeight, fields, fieldTemplate, height, loadData, mRef, sizeReadyMiliseconds = 100, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
17
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
18
|
// States
|
|
19
19
|
const [states, setStates] = React.useReducer((currentState, newState) => {
|
|
@@ -27,14 +27,54 @@ export function DataGridPage(props) {
|
|
|
27
27
|
states.ref = ref;
|
|
28
28
|
//setStates({ ref });
|
|
29
29
|
});
|
|
30
|
+
const initLoadedRef = React.useRef();
|
|
30
31
|
// On submit callback
|
|
31
32
|
const onSubmit = (data, _reset) => {
|
|
32
33
|
setStates({ data });
|
|
33
34
|
};
|
|
34
35
|
const localLoadData = (props) => {
|
|
35
36
|
const data = GridDataGet(props, fieldTemplate);
|
|
37
|
+
if (cacheKey)
|
|
38
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
36
39
|
return loadData(data);
|
|
37
40
|
};
|
|
41
|
+
const onUpdateRows = (rows, state) => {
|
|
42
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
43
|
+
const data = { rows, state, creation: new Date().valueOf() };
|
|
44
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const onInitLoad = (ref) => {
|
|
48
|
+
// Avoid repeatedly load from cache
|
|
49
|
+
if (initLoadedRef.current || !cacheKey)
|
|
50
|
+
return undefined;
|
|
51
|
+
// Cache data
|
|
52
|
+
const cacheData = sessionStorage.getItem(cacheKey);
|
|
53
|
+
if (cacheData) {
|
|
54
|
+
const { rows, state, creation } = JSON.parse(cacheData);
|
|
55
|
+
// 120 minutes
|
|
56
|
+
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
57
|
+
sessionStorage.removeItem(cacheKey);
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
// Scroll position
|
|
61
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
62
|
+
if (scrollData) {
|
|
63
|
+
const { scrollLeft, scrollTop } = JSON.parse(scrollData);
|
|
64
|
+
globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
|
|
65
|
+
}
|
|
66
|
+
// Update flag value
|
|
67
|
+
initLoadedRef.current = true;
|
|
68
|
+
// Return cached rows and state
|
|
69
|
+
return [rows, state];
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
};
|
|
73
|
+
const onGridScroll = (props) => {
|
|
74
|
+
if (!cacheKey || !initLoadedRef.current)
|
|
75
|
+
return;
|
|
76
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
77
|
+
};
|
|
38
78
|
// Watch container
|
|
39
79
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
40
80
|
const rect = dimensions[0][2];
|
|
@@ -56,7 +96,7 @@ export function DataGridPage(props) {
|
|
|
56
96
|
const gridHeight = states.height;
|
|
57
97
|
if (gridHeight == null)
|
|
58
98
|
return;
|
|
59
|
-
return (React.createElement(DataGridEx, { autoLoad: false, height: gridHeight, loadData: localLoadData, mRef: refs, outerRef: (element) => {
|
|
99
|
+
return (React.createElement(DataGridEx, { autoLoad: false, height: gridHeight, loadData: localLoadData, mRef: refs, onUpdateRows: onUpdateRows, onInitLoad: onInitLoad, onScroll: onGridScroll, outerRef: (element) => {
|
|
60
100
|
if (element != null)
|
|
61
101
|
setStates({ element });
|
|
62
102
|
}, ...rest }));
|
|
@@ -67,12 +107,15 @@ export function DataGridPage(props) {
|
|
|
67
107
|
return;
|
|
68
108
|
ref.reset({ data });
|
|
69
109
|
}, [ref, data]);
|
|
110
|
+
const f = typeof fields == "function"
|
|
111
|
+
? fields(JSON.parse((_b = sessionStorage.getItem(`${cacheKey}-searchbar`)) !== null && _b !== void 0 ? _b : "{}"))
|
|
112
|
+
: fields;
|
|
70
113
|
// Layout
|
|
71
114
|
return (React.createElement(CommonPage, { ...pageProps, scrollContainer: states.element },
|
|
72
115
|
React.createElement(Stack, null,
|
|
73
116
|
React.createElement(Box, { ref: dimensions[0][0], sx: {
|
|
74
117
|
paddingBottom: pageProps.paddings
|
|
75
118
|
} },
|
|
76
|
-
React.createElement(SearchBar, { fields:
|
|
119
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
77
120
|
list)));
|
|
78
121
|
}
|
|
@@ -11,12 +11,13 @@ import { CommonPage } from "./CommonPage";
|
|
|
11
11
|
* @returns Component
|
|
12
12
|
*/
|
|
13
13
|
export function FixedListPage(props) {
|
|
14
|
-
var _a;
|
|
14
|
+
var _a, _b;
|
|
15
15
|
// Destruct
|
|
16
|
-
const { adjustHeight, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, ...rest } = props;
|
|
16
|
+
const { adjustHeight, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
17
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
18
|
// States
|
|
19
19
|
const [states] = React.useState({});
|
|
20
|
+
const initLoadedRef = React.useRef();
|
|
20
21
|
// Scroll container
|
|
21
22
|
const [scrollContainer, updateScrollContainer] = React.useState();
|
|
22
23
|
const refs = useCombinedRefs(mRef, (ref) => {
|
|
@@ -39,8 +40,47 @@ export function FixedListPage(props) {
|
|
|
39
40
|
};
|
|
40
41
|
const localLoadData = (props) => {
|
|
41
42
|
const data = GridDataGet(props, fieldTemplate);
|
|
43
|
+
if (cacheKey)
|
|
44
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
42
45
|
return loadData(data);
|
|
43
46
|
};
|
|
47
|
+
const onUpdateRows = (rows, state) => {
|
|
48
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
49
|
+
const data = { rows, state, creation: new Date().valueOf() };
|
|
50
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const onInitLoad = (ref) => {
|
|
54
|
+
// Avoid repeatedly load from cache
|
|
55
|
+
if (initLoadedRef.current || !cacheKey)
|
|
56
|
+
return undefined;
|
|
57
|
+
// Cache data
|
|
58
|
+
const cacheData = sessionStorage.getItem(cacheKey);
|
|
59
|
+
if (cacheData) {
|
|
60
|
+
const { rows, state, creation } = JSON.parse(cacheData);
|
|
61
|
+
// 120 minutes
|
|
62
|
+
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
63
|
+
sessionStorage.removeItem(cacheKey);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
// Scroll position
|
|
67
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
68
|
+
if (scrollData) {
|
|
69
|
+
const { scrollOffset } = JSON.parse(scrollData);
|
|
70
|
+
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
71
|
+
}
|
|
72
|
+
// Update flag value
|
|
73
|
+
initLoadedRef.current = true;
|
|
74
|
+
// Return cached rows and state
|
|
75
|
+
return [rows, state];
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
};
|
|
79
|
+
const onListScroll = (props) => {
|
|
80
|
+
if (!cacheKey || !initLoadedRef.current)
|
|
81
|
+
return;
|
|
82
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
83
|
+
};
|
|
44
84
|
// Watch container
|
|
45
85
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
46
86
|
const rect = dimensions[0][2];
|
|
@@ -53,17 +93,20 @@ export function FixedListPage(props) {
|
|
|
53
93
|
return (React.createElement(Box, { id: "list-container", sx: {
|
|
54
94
|
height: height + "px"
|
|
55
95
|
} },
|
|
56
|
-
React.createElement(ScrollerListEx, { autoLoad: false, height: height, loadData: localLoadData, mRef: refs, oRef: (element) => {
|
|
96
|
+
React.createElement(ScrollerListEx, { autoLoad: false, height: height, loadData: localLoadData, mRef: refs, onUpdateRows: onUpdateRows, onInitLoad: onInitLoad, onScroll: onListScroll, oRef: (element) => {
|
|
57
97
|
if (element != null)
|
|
58
98
|
updateScrollContainer(element);
|
|
59
99
|
}, ...rest })));
|
|
60
100
|
}
|
|
61
101
|
}, [rect]);
|
|
102
|
+
const f = typeof fields == "function"
|
|
103
|
+
? fields(JSON.parse((_b = sessionStorage.getItem(`${cacheKey}-searchbar`)) !== null && _b !== void 0 ? _b : "{}"))
|
|
104
|
+
: fields;
|
|
62
105
|
const { paddings, ...pageRest } = pageProps;
|
|
63
106
|
// Layout
|
|
64
107
|
return (React.createElement(CommonPage, { ...pageRest, paddings: {}, scrollContainer: scrollContainer },
|
|
65
108
|
React.createElement(Stack, null,
|
|
66
109
|
React.createElement(Box, { ref: dimensions[0][0], sx: { padding: paddings } },
|
|
67
|
-
React.createElement(SearchBar, { fields:
|
|
110
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
68
111
|
list)));
|
|
69
112
|
}
|
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,19 +1,19 @@
|
|
|
1
|
-
import { GridDataGet, useCombinedRefs } from
|
|
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 { GridDataGet, 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
8
|
/**
|
|
9
9
|
* List page
|
|
10
10
|
* @param props Props
|
|
11
11
|
* @returns Component
|
|
12
12
|
*/
|
|
13
13
|
export function ListPage(props) {
|
|
14
|
-
var _a;
|
|
14
|
+
var _a, _b;
|
|
15
15
|
// Destruct
|
|
16
|
-
const { fields, fieldTemplate, loadData, mRef, pageProps = {}, ...rest } = props;
|
|
16
|
+
const { fields, fieldTemplate, loadData, mRef, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
17
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
18
|
// States
|
|
19
19
|
const [states] = React.useState({});
|
|
@@ -25,6 +25,7 @@ export function ListPage(props) {
|
|
|
25
25
|
if (first)
|
|
26
26
|
reset();
|
|
27
27
|
});
|
|
28
|
+
const initLoadedRef = React.useRef();
|
|
28
29
|
const reset = () => {
|
|
29
30
|
if (states.data == null || states.ref == null)
|
|
30
31
|
return;
|
|
@@ -39,12 +40,52 @@ export function ListPage(props) {
|
|
|
39
40
|
const data = GridDataGet(props, fieldTemplate);
|
|
40
41
|
return loadData(data);
|
|
41
42
|
};
|
|
43
|
+
const onUpdateRows = (rows, state) => {
|
|
44
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
45
|
+
const data = { rows, state, creation: new Date().valueOf() };
|
|
46
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const onInitLoad = (ref) => {
|
|
50
|
+
// Avoid repeatedly load from cache
|
|
51
|
+
if (initLoadedRef.current || !cacheKey)
|
|
52
|
+
return undefined;
|
|
53
|
+
// Cache data
|
|
54
|
+
const cacheData = sessionStorage.getItem(cacheKey);
|
|
55
|
+
if (cacheData) {
|
|
56
|
+
const { rows, state, creation } = JSON.parse(cacheData);
|
|
57
|
+
// 120 minutes
|
|
58
|
+
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
59
|
+
sessionStorage.removeItem(cacheKey);
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
// Scroll position
|
|
63
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
64
|
+
if (scrollData) {
|
|
65
|
+
const { scrollOffset } = JSON.parse(scrollData);
|
|
66
|
+
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
67
|
+
}
|
|
68
|
+
// Update flag value
|
|
69
|
+
initLoadedRef.current = true;
|
|
70
|
+
// Return cached rows and state
|
|
71
|
+
return [rows, state];
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
};
|
|
75
|
+
const onListScroll = (props) => {
|
|
76
|
+
if (!cacheKey || !initLoadedRef.current)
|
|
77
|
+
return;
|
|
78
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
79
|
+
};
|
|
80
|
+
const f = typeof fields == "function"
|
|
81
|
+
? fields(JSON.parse((_b = sessionStorage.getItem(`${cacheKey}-searchbar`)) !== null && _b !== void 0 ? _b : "{}"))
|
|
82
|
+
: fields;
|
|
42
83
|
// Layout
|
|
43
84
|
return (React.createElement(CommonPage, { ...pageProps, scrollContainer: CommonPageScrollContainer },
|
|
44
85
|
React.createElement(Stack, null,
|
|
45
86
|
React.createElement(Box, { sx: {
|
|
46
87
|
paddingBottom: pageProps.paddings
|
|
47
88
|
} },
|
|
48
|
-
React.createElement(SearchBar, { fields:
|
|
49
|
-
React.createElement(ScrollerListEx, { autoLoad: false, loadData: localLoadData, mRef: refs, ...rest }))));
|
|
89
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
90
|
+
React.createElement(ScrollerListEx, { autoLoad: false, loadData: localLoadData, onUpdateRows: onUpdateRows, onInitLoad: onInitLoad, onScroll: onListScroll, mRef: refs, ...rest }))));
|
|
50
91
|
}
|
|
@@ -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,19 +1,19 @@
|
|
|
1
|
-
import { GridDataGet, useCombinedRefs, useDimensions } from
|
|
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 { GridDataGet, 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
8
|
/**
|
|
9
9
|
* Table page
|
|
10
10
|
* @param props Props
|
|
11
11
|
* @returns Component
|
|
12
12
|
*/
|
|
13
13
|
export function TablePage(props) {
|
|
14
|
-
var _a;
|
|
14
|
+
var _a, _b;
|
|
15
15
|
// Destruct
|
|
16
|
-
const { columns, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, ...rest } = props;
|
|
16
|
+
const { columns, fields, fieldTemplate, loadData, mRef, sizeReadyMiliseconds = 0, pageProps = {}, cacheKey, cacheMinutes = 120, ...rest } = props;
|
|
17
17
|
(_a = pageProps.paddings) !== null && _a !== void 0 ? _a : (pageProps.paddings = MUGlobal.pagePaddings);
|
|
18
18
|
// States
|
|
19
19
|
const [states] = React.useState({});
|
|
@@ -37,6 +37,8 @@ export function TablePage(props) {
|
|
|
37
37
|
};
|
|
38
38
|
const localLoadData = (props) => {
|
|
39
39
|
const data = GridDataGet(props, fieldTemplate);
|
|
40
|
+
if (cacheKey)
|
|
41
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
40
42
|
return loadData(data);
|
|
41
43
|
};
|
|
42
44
|
// Total width
|
|
@@ -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,15 @@ 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"
|
|
63
|
+
? fields(JSON.parse((_b = sessionStorage.getItem(`${cacheKey}-searchbar`)) !== null && _b !== void 0 ? _b : "{}"))
|
|
64
|
+
: fields;
|
|
61
65
|
// Layout
|
|
62
66
|
return (React.createElement(CommonPage, { ...pageProps, scrollContainer: CommonPageScrollContainer },
|
|
63
67
|
React.createElement(Stack, null,
|
|
64
68
|
React.createElement(Box, { ref: dimensions[0][0], sx: {
|
|
65
69
|
paddingBottom: pageProps.paddings
|
|
66
70
|
} },
|
|
67
|
-
React.createElement(SearchBar, { fields:
|
|
71
|
+
React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
|
|
68
72
|
list)));
|
|
69
73
|
}
|
package/package.json
CHANGED
package/src/DataGridEx.tsx
CHANGED
|
@@ -51,6 +51,16 @@ export type DataGridExProps<
|
|
|
51
51
|
*/
|
|
52
52
|
alternatingColors?: [string?, string?];
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Cache key
|
|
56
|
+
*/
|
|
57
|
+
cacheKey?: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Cache minutes
|
|
61
|
+
*/
|
|
62
|
+
cacheMinutes?: number;
|
|
63
|
+
|
|
54
64
|
/**
|
|
55
65
|
* Checkable to choose multiple items
|
|
56
66
|
* @default false
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "./ScrollerListEx";
|
|
34
34
|
import { SearchBar } from "./SearchBar";
|
|
35
35
|
import { Labels } from "./app/Labels";
|
|
36
|
+
import { GridDataCacheType } from "./GridDataCacheType";
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* ResponsibleContainer props
|
|
@@ -67,16 +68,6 @@ export type ResponsibleContainerProps<
|
|
|
67
68
|
*/
|
|
68
69
|
adjustFabHeight?: (height: number, isGrid: boolean) => number;
|
|
69
70
|
|
|
70
|
-
/**
|
|
71
|
-
* Cache key
|
|
72
|
-
*/
|
|
73
|
-
cacheKey?: string;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Cache minutes
|
|
77
|
-
*/
|
|
78
|
-
cacheMinutes?: number;
|
|
79
|
-
|
|
80
71
|
/**
|
|
81
72
|
* Columns
|
|
82
73
|
*/
|
|
@@ -293,7 +284,7 @@ export function ResponsibleContainer<
|
|
|
293
284
|
}
|
|
294
285
|
);
|
|
295
286
|
|
|
296
|
-
type DataType =
|
|
287
|
+
type DataType = GridDataCacheType<T>;
|
|
297
288
|
|
|
298
289
|
const onUpdateRows = (rows: T[], state: GridLoaderStates<T>) => {
|
|
299
290
|
if (state.currentPage > 0 && cacheKey) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GridDataGet,
|
|
3
3
|
GridLoadDataProps,
|
|
4
|
+
GridLoaderStates,
|
|
5
|
+
GridOnScrollProps,
|
|
4
6
|
ScrollerGridForwardRef,
|
|
7
|
+
VariableSizeGrid,
|
|
5
8
|
useCombinedRefs,
|
|
6
9
|
useDimensions
|
|
7
10
|
} from "@etsoo/react";
|
|
@@ -13,6 +16,7 @@ import { MUGlobal } from "../MUGlobal";
|
|
|
13
16
|
import { SearchBar } from "../SearchBar";
|
|
14
17
|
import { CommonPage } from "./CommonPage";
|
|
15
18
|
import { DataGridPageProps } from "./DataGridPageProps";
|
|
19
|
+
import { GridDataCacheType } from "../GridDataCacheType";
|
|
16
20
|
|
|
17
21
|
interface LocalStates<T> {
|
|
18
22
|
data?: FormData;
|
|
@@ -41,6 +45,8 @@ export function DataGridPage<
|
|
|
41
45
|
mRef,
|
|
42
46
|
sizeReadyMiliseconds = 100,
|
|
43
47
|
pageProps = {},
|
|
48
|
+
cacheKey,
|
|
49
|
+
cacheMinutes = 120,
|
|
44
50
|
...rest
|
|
45
51
|
} = props;
|
|
46
52
|
|
|
@@ -65,6 +71,8 @@ export function DataGridPage<
|
|
|
65
71
|
}
|
|
66
72
|
);
|
|
67
73
|
|
|
74
|
+
const initLoadedRef = React.useRef<boolean>();
|
|
75
|
+
|
|
68
76
|
// On submit callback
|
|
69
77
|
const onSubmit = (data: FormData, _reset: boolean) => {
|
|
70
78
|
setStates({ data });
|
|
@@ -72,9 +80,64 @@ export function DataGridPage<
|
|
|
72
80
|
|
|
73
81
|
const localLoadData = (props: GridLoadDataProps) => {
|
|
74
82
|
const data = GridDataGet(props, fieldTemplate);
|
|
83
|
+
|
|
84
|
+
if (cacheKey)
|
|
85
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
86
|
+
|
|
75
87
|
return loadData(data);
|
|
76
88
|
};
|
|
77
89
|
|
|
90
|
+
type DataType = GridDataCacheType<T>;
|
|
91
|
+
|
|
92
|
+
const onUpdateRows = (rows: T[], state: GridLoaderStates<T>) => {
|
|
93
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
94
|
+
const data: DataType = { rows, state, creation: new Date().valueOf() };
|
|
95
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const onInitLoad = (
|
|
100
|
+
ref: VariableSizeGrid<T>
|
|
101
|
+
): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
|
|
102
|
+
// Avoid repeatedly load from cache
|
|
103
|
+
if (initLoadedRef.current || !cacheKey) return undefined;
|
|
104
|
+
|
|
105
|
+
// Cache data
|
|
106
|
+
const cacheData = sessionStorage.getItem(cacheKey);
|
|
107
|
+
if (cacheData) {
|
|
108
|
+
const { rows, state, creation } = JSON.parse(cacheData) as DataType;
|
|
109
|
+
|
|
110
|
+
// 120 minutes
|
|
111
|
+
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
112
|
+
sessionStorage.removeItem(cacheKey);
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Scroll position
|
|
117
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
118
|
+
if (scrollData) {
|
|
119
|
+
const { scrollLeft, scrollTop } = JSON.parse(
|
|
120
|
+
scrollData
|
|
121
|
+
) as GridOnScrollProps;
|
|
122
|
+
|
|
123
|
+
globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Update flag value
|
|
127
|
+
initLoadedRef.current = true;
|
|
128
|
+
|
|
129
|
+
// Return cached rows and state
|
|
130
|
+
return [rows, state];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return undefined;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const onGridScroll = (props: GridOnScrollProps) => {
|
|
137
|
+
if (!cacheKey || !initLoadedRef.current) return;
|
|
138
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
139
|
+
};
|
|
140
|
+
|
|
78
141
|
// Watch container
|
|
79
142
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
80
143
|
const rect = dimensions[0][2];
|
|
@@ -105,6 +168,9 @@ export function DataGridPage<
|
|
|
105
168
|
height={gridHeight}
|
|
106
169
|
loadData={localLoadData}
|
|
107
170
|
mRef={refs}
|
|
171
|
+
onUpdateRows={onUpdateRows}
|
|
172
|
+
onInitLoad={onInitLoad}
|
|
173
|
+
onScroll={onGridScroll}
|
|
108
174
|
outerRef={(element?: HTMLDivElement) => {
|
|
109
175
|
if (element != null) setStates({ element });
|
|
110
176
|
}}
|
|
@@ -119,6 +185,15 @@ export function DataGridPage<
|
|
|
119
185
|
ref.reset({ data });
|
|
120
186
|
}, [ref, data]);
|
|
121
187
|
|
|
188
|
+
const f =
|
|
189
|
+
typeof fields == "function"
|
|
190
|
+
? fields(
|
|
191
|
+
JSON.parse(
|
|
192
|
+
sessionStorage.getItem(`${cacheKey}-searchbar`) ?? "{}"
|
|
193
|
+
) as DataTypes.BasicTemplateType<F>
|
|
194
|
+
)
|
|
195
|
+
: fields;
|
|
196
|
+
|
|
122
197
|
// Layout
|
|
123
198
|
return (
|
|
124
199
|
<CommonPage {...pageProps} scrollContainer={states.element}>
|
|
@@ -129,7 +204,7 @@ export function DataGridPage<
|
|
|
129
204
|
paddingBottom: pageProps.paddings
|
|
130
205
|
}}
|
|
131
206
|
>
|
|
132
|
-
<SearchBar fields={
|
|
207
|
+
<SearchBar fields={f} onSubmit={onSubmit} />
|
|
133
208
|
</Box>
|
|
134
209
|
{list}
|
|
135
210
|
</Stack>
|