@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.
@@ -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,9 @@
1
+ import { GridLoaderStates } from "@etsoo/react";
2
+ /**
3
+ * Grid data cache type
4
+ */
5
+ export type GridDataCacheType<T> = {
6
+ rows: T[];
7
+ state: GridLoaderStates<T>;
8
+ creation: number;
9
+ };
@@ -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
+ }
@@ -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 { GridDataGet, ReactUtils, useCombinedRefs, useDimensions } from "@etsoo/react";
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
- const data = GridDataGet(props, fieldTemplate);
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 = sessionStorage.getItem(cacheKey);
80
+ const cacheData = GridUtils.getCacheData(cacheKey, cacheMinutes);
87
81
  if (cacheData) {
88
- const { rows, state, creation } = JSON.parse(cacheData);
89
- // 120 minutes
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: onUpdateRows, onInitLoad: onInitLoad, ...rest })),
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: onUpdateRows, onInitLoad: onInitLoad, mRef: mRefs, onClick: (event, data) => quickAction && ReactUtils.isSafeClick(event) && quickAction(data), oRef: (element) => {
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 { GridDataGet, useCombinedRefs, useDimensions } from "@etsoo/react";
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
- const data = GridDataGet(props, fieldTemplate);
36
- return loadData(data);
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: fields, onSubmit: onSubmit })),
107
+ React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
77
108
  list)));
78
109
  }
@@ -1,10 +1,11 @@
1
- import { GridDataGet, useCombinedRefs, useDimensions } from "@etsoo/react";
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
- const data = GridDataGet(props, fieldTemplate);
42
- return loadData(data);
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: fields, onSubmit: onSubmit })),
98
+ React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
68
99
  list)));
69
100
  }
@@ -1,6 +1,6 @@
1
- import { DataTypes, IdDefaultType } from '@etsoo/shared';
2
- import React from 'react';
3
- import { ListPageProps } from './ListPageProps';
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
@@ -1,10 +1,11 @@
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';
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
- const data = GridDataGet(props, fieldTemplate);
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: fields, onSubmit: onSubmit })),
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 '@etsoo/shared';
2
- import { ScrollerListExProps } from '../ScrollerListEx';
3
- import { SearchPageProps } from './SearchPageProps';
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>, 'loadData'>;
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
  */
@@ -1,6 +1,6 @@
1
- import { DataTypes, IdDefaultType } from '@etsoo/shared';
2
- import React from 'react';
3
- import { TablePageProps } from './TablePageProps';
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
@@ -1,10 +1,11 @@
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';
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
- const data = GridDataGet(props, fieldTemplate);
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: fields, onSubmit: onSubmit })),
69
+ React.createElement(SearchBar, { fields: f, onSubmit: onSubmit })),
68
70
  list)));
69
71
  }