orc-shared 5.10.0-dev.7 → 5.10.0-dev.9
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/dist/components/AppFrame/Preferences.js +46 -45
- package/dist/components/MaterialUI/DataDisplay/PredefinedElements/Placeholder.js +15 -3
- package/dist/components/MaterialUI/DataDisplay/Table.js +15 -8
- package/dist/hocs/withScrollBox.js +9 -3
- package/dist/hooks/useInMemoryPaging.js +139 -0
- package/dist/utils/ListHelper.js +271 -0
- package/dist/utils/comparisonHelper.js +176 -0
- package/package.json +1 -1
- package/src/components/AppFrame/Preferences.js +30 -29
- package/src/components/AppFrame/Preferences.test.js +108 -123
- package/src/components/MaterialUI/DataDisplay/PredefinedElements/Placeholder.js +17 -2
- package/src/components/MaterialUI/DataDisplay/PredefinedElements/Placeholder.test.js +3 -1
- package/src/components/MaterialUI/DataDisplay/Table.js +121 -121
- package/src/components/MaterialUI/DataDisplay/Table.test.js +115 -1
- package/src/hocs/withScrollBox.js +10 -5
- package/src/hocs/withScrollBox.test.js +12 -0
- package/src/hooks/useInMemoryPaging.js +85 -0
- package/src/hooks/useInMemoryPaging.test.js +551 -0
- package/src/utils/ListHelper.js +203 -0
- package/src/utils/ListHelper.test.js +710 -0
- package/src/utils/comparisonHelper.js +124 -0
- package/src/utils/comparisonHelper.test.js +324 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
2
|
import ReactDOM from "react-dom";
|
|
3
3
|
import { act } from "react-dom/test-utils";
|
|
4
4
|
import sinon from "sinon";
|
|
@@ -1244,4 +1244,118 @@ describe("Table", () => {
|
|
|
1244
1244
|
const scrollableDiv = mountedComponent.find({ "data-qa": "scrollable-table-div" });
|
|
1245
1245
|
expect(scrollableDiv?.getElement()?.ref?.current?.scrollTop, "to equal", 800);
|
|
1246
1246
|
});
|
|
1247
|
+
|
|
1248
|
+
it("should scroll to top", () => {
|
|
1249
|
+
const { headers, rows } = buildHeaderAndRowFromConfig(config, elements);
|
|
1250
|
+
|
|
1251
|
+
state = state.setIn(
|
|
1252
|
+
["view", "testScrollbarPosition"],
|
|
1253
|
+
Immutable.fromJS({
|
|
1254
|
+
scrollBarPosition: 800,
|
|
1255
|
+
}),
|
|
1256
|
+
);
|
|
1257
|
+
|
|
1258
|
+
const tableProps = new TableProps();
|
|
1259
|
+
|
|
1260
|
+
tableProps.set(TableProps.propNames.selectMode, true);
|
|
1261
|
+
tableProps.set(TableProps.propNames.tableName, "test");
|
|
1262
|
+
tableProps.set(TableProps.propNames.saveScrollbarPosition, true);
|
|
1263
|
+
|
|
1264
|
+
const scrollLoader = sinon.spy().named("scrollLoader");
|
|
1265
|
+
|
|
1266
|
+
const CustomTable = () => {
|
|
1267
|
+
const ref = useRef(null);
|
|
1268
|
+
|
|
1269
|
+
const clickToTop = () => {
|
|
1270
|
+
ref.current && ref.current.scrollToTop();
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
return (
|
|
1274
|
+
<>
|
|
1275
|
+
<input type="button" onClick={clickToTop} data-qa="scroll-btn" />
|
|
1276
|
+
<Table
|
|
1277
|
+
ref={ref}
|
|
1278
|
+
rows={rows}
|
|
1279
|
+
headers={headers}
|
|
1280
|
+
pageLength={2}
|
|
1281
|
+
latestPage={1}
|
|
1282
|
+
tableProps={tableProps}
|
|
1283
|
+
scrollLoader={scrollLoader}
|
|
1284
|
+
/>
|
|
1285
|
+
</>
|
|
1286
|
+
);
|
|
1287
|
+
};
|
|
1288
|
+
|
|
1289
|
+
const component = (
|
|
1290
|
+
<TestWrapper provider={{ store }}>
|
|
1291
|
+
<CustomTable />
|
|
1292
|
+
</TestWrapper>
|
|
1293
|
+
);
|
|
1294
|
+
|
|
1295
|
+
const mountedComponent = mount(component);
|
|
1296
|
+
const scrollableDiv = mountedComponent.find({ "data-qa": "scrollable-table-div" });
|
|
1297
|
+
expect(scrollableDiv?.getElement()?.ref?.current?.scrollTop, "to equal", 800);
|
|
1298
|
+
|
|
1299
|
+
const scrollBtn = mountedComponent.find({ "data-qa": "scroll-btn" });
|
|
1300
|
+
scrollBtn.simulate("click");
|
|
1301
|
+
|
|
1302
|
+
expect(scrollableDiv?.getElement()?.ref?.current?.scrollTop, "to equal", 0);
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
it("should not scroll to top because already at the top", () => {
|
|
1306
|
+
const { headers, rows } = buildHeaderAndRowFromConfig(config, elements);
|
|
1307
|
+
|
|
1308
|
+
state = state.setIn(
|
|
1309
|
+
["view", "testScrollbarPosition"],
|
|
1310
|
+
Immutable.fromJS({
|
|
1311
|
+
scrollBarPosition: 0,
|
|
1312
|
+
}),
|
|
1313
|
+
);
|
|
1314
|
+
|
|
1315
|
+
const tableProps = new TableProps();
|
|
1316
|
+
|
|
1317
|
+
tableProps.set(TableProps.propNames.selectMode, true);
|
|
1318
|
+
tableProps.set(TableProps.propNames.tableName, "test");
|
|
1319
|
+
tableProps.set(TableProps.propNames.saveScrollbarPosition, true);
|
|
1320
|
+
|
|
1321
|
+
const scrollLoader = sinon.spy().named("scrollLoader");
|
|
1322
|
+
|
|
1323
|
+
const CustomTable = () => {
|
|
1324
|
+
const ref = useRef(null);
|
|
1325
|
+
|
|
1326
|
+
const clickToTop = () => {
|
|
1327
|
+
ref.current && ref.current.scrollToTop();
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1330
|
+
return (
|
|
1331
|
+
<>
|
|
1332
|
+
<input type="button" onClick={clickToTop} data-qa="scroll-btn" />
|
|
1333
|
+
<Table
|
|
1334
|
+
ref={ref}
|
|
1335
|
+
rows={rows}
|
|
1336
|
+
headers={headers}
|
|
1337
|
+
pageLength={2}
|
|
1338
|
+
latestPage={1}
|
|
1339
|
+
tableProps={tableProps}
|
|
1340
|
+
scrollLoader={scrollLoader}
|
|
1341
|
+
/>
|
|
1342
|
+
</>
|
|
1343
|
+
);
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1346
|
+
const component = (
|
|
1347
|
+
<TestWrapper provider={{ store }}>
|
|
1348
|
+
<CustomTable />
|
|
1349
|
+
</TestWrapper>
|
|
1350
|
+
);
|
|
1351
|
+
|
|
1352
|
+
const mountedComponent = mount(component);
|
|
1353
|
+
const scrollableDiv = mountedComponent.find({ "data-qa": "scrollable-table-div" });
|
|
1354
|
+
expect(scrollableDiv?.getElement()?.ref?.current?.scrollTop, "to equal", 0);
|
|
1355
|
+
|
|
1356
|
+
const scrollBtn = mountedComponent.find({ "data-qa": "scroll-btn" });
|
|
1357
|
+
scrollBtn.simulate("click");
|
|
1358
|
+
|
|
1359
|
+
expect(scrollableDiv?.getElement()?.ref?.current?.scrollTop, "to equal", 0);
|
|
1360
|
+
});
|
|
1247
1361
|
});
|
|
@@ -11,15 +11,20 @@ const useStyles = makeStyles({
|
|
|
11
11
|
},
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
const withScrollBox =
|
|
15
|
-
|
|
16
|
-
({ onScroll, ...otherProps }) => {
|
|
14
|
+
const withScrollBox = WrappedComp =>
|
|
15
|
+
React.forwardRef(({ onScroll, ...otherProps }, externalRef) => {
|
|
17
16
|
const classes = useStyles();
|
|
18
17
|
|
|
18
|
+
const mergeRef = (node, measureRef) => {
|
|
19
|
+
measureRef(node);
|
|
20
|
+
|
|
21
|
+
if (externalRef) externalRef.current = node;
|
|
22
|
+
};
|
|
23
|
+
|
|
19
24
|
return (
|
|
20
25
|
<Measure bounds>
|
|
21
26
|
{({ measureRef, contentRect }) => (
|
|
22
|
-
<div className={classes.scrollbox} onScroll={onScroll} ref={measureRef}>
|
|
27
|
+
<div className={classes.scrollbox} onScroll={onScroll} ref={node => mergeRef(node, measureRef)}>
|
|
23
28
|
<WrappedComp
|
|
24
29
|
{...otherProps}
|
|
25
30
|
height={safeGet(contentRect, "bounds", "height")}
|
|
@@ -29,6 +34,6 @@ const withScrollBox =
|
|
|
29
34
|
)}
|
|
30
35
|
</Measure>
|
|
31
36
|
);
|
|
32
|
-
};
|
|
37
|
+
});
|
|
33
38
|
|
|
34
39
|
export default withScrollBox;
|
|
@@ -22,4 +22,16 @@ describe("withScrollBox", () => {
|
|
|
22
22
|
</div>,
|
|
23
23
|
),
|
|
24
24
|
));
|
|
25
|
+
|
|
26
|
+
it("forwards the ref to the scroll box div", () => {
|
|
27
|
+
const ref = React.createRef();
|
|
28
|
+
|
|
29
|
+
return expect(withScrollBox, "when called with", [TestComp]).then(EnhComp => {
|
|
30
|
+
const element = <EnhComp ref={ref} />;
|
|
31
|
+
return expect(() => expect(element, "when mounted", "to be truthy"), "not to throw").then(() => {
|
|
32
|
+
expect(ref.current, "to be defined");
|
|
33
|
+
expect(ref.current.nodeType, "to equal", 1);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
25
37
|
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
2
|
+
import { unwrapImmutable } from "../utils";
|
|
3
|
+
import useViewState from "./useViewState";
|
|
4
|
+
|
|
5
|
+
const scrollTableRef = tableRef => {
|
|
6
|
+
if (!tableRef?.current) {
|
|
7
|
+
console.error("[useInMemoryPaging]: tableRef was not specified or tableRef.current is null.");
|
|
8
|
+
} else {
|
|
9
|
+
tableRef.current.scrollToTop();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const useInMemoryPaging = ({
|
|
14
|
+
viewStateName,
|
|
15
|
+
tableRef,
|
|
16
|
+
records,
|
|
17
|
+
pageSize,
|
|
18
|
+
initialSort = {},
|
|
19
|
+
initialFilters = {},
|
|
20
|
+
sortAndFilterFn,
|
|
21
|
+
}) => {
|
|
22
|
+
const [viewState, updateViewState] = useViewState(viewStateName);
|
|
23
|
+
const internalSortAndFilterFn = useRef(sortAndFilterFn);
|
|
24
|
+
const internalInitialSort = useRef(initialSort);
|
|
25
|
+
const internalInitialFilters = useRef(initialFilters);
|
|
26
|
+
|
|
27
|
+
const filters = viewState.filters ?? internalInitialFilters.current;
|
|
28
|
+
const sorting = viewState.sorting ?? internalInitialSort.current;
|
|
29
|
+
const currentPage = viewState.currentPage ?? 1;
|
|
30
|
+
const nextPageToLoad = viewState.nextPageToLoad ?? 1;
|
|
31
|
+
|
|
32
|
+
if (internalSortAndFilterFn.current !== sortAndFilterFn) {
|
|
33
|
+
console.warn(
|
|
34
|
+
"[useInMemoryPaging]: a different value for sortAndFilterFn was detected between renders, ensure that it never changes (define it outside of your component).",
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const setFilter = filters => {
|
|
39
|
+
scrollTableRef(tableRef);
|
|
40
|
+
updateViewState("filters", filters);
|
|
41
|
+
updateViewState("currentPage", 1);
|
|
42
|
+
updateViewState("nextPageToLoad", 1);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const setSort = sorting => {
|
|
46
|
+
scrollTableRef(tableRef);
|
|
47
|
+
updateViewState("sorting", sorting);
|
|
48
|
+
updateViewState("currentPage", 1);
|
|
49
|
+
updateViewState("nextPageToLoad", 1);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const scrollLoader = useCallback(
|
|
53
|
+
page => {
|
|
54
|
+
if (page > nextPageToLoad) {
|
|
55
|
+
updateViewState("currentPage", page);
|
|
56
|
+
updateViewState("nextPageToLoad", page);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
[nextPageToLoad, updateViewState],
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const [rows, totalCount] = useMemo(() => {
|
|
63
|
+
let list = internalSortAndFilterFn.current({
|
|
64
|
+
list: unwrapImmutable(records),
|
|
65
|
+
filters: filters,
|
|
66
|
+
sorting: sorting,
|
|
67
|
+
});
|
|
68
|
+
return [unwrapImmutable(list.slice(0, currentPage * pageSize)), list.length];
|
|
69
|
+
}, [currentPage, pageSize, records, filters, sorting, internalSortAndFilterFn]);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
rows,
|
|
73
|
+
scrollLoader,
|
|
74
|
+
currentPage,
|
|
75
|
+
|
|
76
|
+
filters,
|
|
77
|
+
sorting,
|
|
78
|
+
|
|
79
|
+
setFilter,
|
|
80
|
+
setSort,
|
|
81
|
+
totalCount,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default useInMemoryPaging;
|