Skip to content

Commit 6b540b5

Browse files
authored
Speed up pagination / Clean query cache (indirect variables) / The page is loading display / "Finished in" correct elapsed time (#196)
1 parent e3e21d8 commit 6b540b5

File tree

7 files changed

+63
-26
lines changed

7 files changed

+63
-26
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- A favicon (#188).
13+
- A cache to remember the entire result table (useful when scrolling through pages of a lengthy result table) (#193).
1314

1415
### Changed
1516

@@ -23,7 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2324
- Solved console warning when hovering over source verification question mark (#128).
2425
- ASK query is working now (#22).
2526
- "Finished in" now shows effective query execution time (#130).
26-
- "Clean query cache" button's functionality works as expected now (#190).
27+
- "Clean query cache" button's functionality works as expected now (also for templated queries with indirect variables) (#190).
28+
- "The page is loading." type of prompt is back (now "The list is loading." and "The options for the variables in this query are loading.") (#194).
2729

2830
## [1.6.0] - 2025-03-17
2931

main/src/components/ActionBar/ActionBar.jsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,26 @@ import configManager from "../../configManager/configManager.js";
2727
*/
2828
function ActionBar() {
2929
const { total, isLoading, resource } = useListContext();
30-
const [time, setTime] = useState(0);
30+
const now = Date.now();
31+
const [timeStart, setTimeStart] = useState(now);
32+
const [timeNow, setTimeNow] = useState(now);
3133
const [sourceInfoOpen, setSourceInfoOpen] = useState(false);
3234

3335
useEffect(() => {
3436
if (isLoading) {
35-
setTime(0);
37+
const now = Date.now();
38+
setTimeStart(now);
39+
setTimeNow(now);
3640
}
3741
}, [isLoading]);
3842

3943
useEffect(() => {
4044
let intervalId;
4145
if (isLoading) {
42-
intervalId = setInterval(() => setTime(time + 1), 10);
46+
intervalId = setInterval(() => setTimeNow(Date.now()), 100);
4347
}
4448
return () => clearInterval(intervalId);
45-
}, [time, isLoading]);
49+
}, [timeNow, isLoading]);
4650

4751
const config = configManager.getConfig();
4852
const query = configManager.getQueryWorkingCopyById(resource);
@@ -58,7 +62,7 @@ function ActionBar() {
5862
<div className="information-box">
5963
{isLoading && <strong>Runtime: </strong>}
6064
{!isLoading && <strong>Finished in: </strong>}
61-
<Time time={time} showMilliseconds={config.showMilliseconds} />
65+
<Time elapsedMilliseconds={timeNow - timeStart} showMilliseconds={config.showMilliseconds} />
6266
</div>
6367
<div className="information-box">
6468
<strong>Sources: </strong>

main/src/components/ActionBar/Time.jsx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,15 @@ import { Component } from "react";
66
* @returns {Component} a component that displays the time in seconds and milliseconds (if configured to do so)
77
*/
88
function Time(props) {
9-
const time = props.time;
10-
const minutes =
11-
Math.floor((time % 360000) / 6000) + 60 * Math.floor(time / 360000);
12-
const seconds = Math.floor((time % 6000) / 100) + 60 * minutes;
13-
const milliseconds = time % 100;
14-
15-
let display = seconds.toString();
169
if (props.showMilliseconds) {
17-
display = `${display}.${milliseconds}`;
10+
return <>{`${(props.elapsedMilliseconds / 1000).toFixed(3)} s`}</>;
11+
} else {
12+
return <>{`${Math.round(props.elapsedMilliseconds / 1000)} s`}</>;
1813
}
19-
20-
display += "s";
21-
22-
return <>{display}</>;
2314
}
2415

2516
Time.propTypes = {
26-
time: PropTypes.number,
17+
elapsedMilliseconds: PropTypes.number,
2718
showMilliseconds: PropTypes.bool,
2819
};
2920

main/src/components/InteractionLayout/NavigationBar/NavigationBar.jsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { AppBar, TitlePortal, useRefresh } from "react-admin";
1+
import { AppBar, TitlePortal } from "react-admin";
22
import "./NavigationBar.css";
33
import AuthenticationMenu from "../AuthenticationMenu/AuthenticationMenu";
44
import { Component, useState } from "react";
5+
import { useNavigate } from 'react-router-dom';
56
import CleaningServicesIcon from '@mui/icons-material/CleaningServices';
67
import { IconButton } from '@mui/material';
78
import { Tooltip } from '@mui/material';
@@ -10,6 +11,7 @@ import AboutDialog from "./AboutDialog";
1011

1112
import configManager from "../../../configManager/configManager";
1213
import comunicaEngineWrapper from "../../../comunicaEngineWrapper/comunicaEngineWrapper";
14+
import SparqlDataProvider from "../../../dataProvider/SparqlDataProvider";
1315

1416
function AboutButton(props) {
1517
return (
@@ -22,10 +24,12 @@ function AboutButton(props) {
2224
}
2325

2426
function InvalidateButton() {
25-
const refresh = useRefresh();
27+
const navigate = useNavigate();
2628
const handleClick = async () => {
2729
await comunicaEngineWrapper.reset();
28-
refresh();
30+
SparqlDataProvider.clearListCache();
31+
// navigate! (refresh is not enough to clear status in case of templated queries with indirect variables)
32+
navigate('/');
2933
}
3034
return (
3135
<Tooltip title="Clean Query Cache">

main/src/components/ListResultTable/QueryResultList/QueryResultList.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component } from "react";
2-
import { Datagrid, List, Title, useListContext, useResourceDefinition } from "react-admin";
2+
import { Datagrid, List, Title, Loading, useListContext, useResourceDefinition } from "react-admin";
33
import ActionBar from "../../ActionBar/ActionBar";
44
import GenericField from "../../../representationProvider/GenericField";
55
import TableHeader from "./TableHeader/TableHeader";
@@ -92,6 +92,11 @@ const NoValuesDisplay = () => {
9292
const MyDatagrid = (props) => {
9393
const { query } = props;
9494
const { data, isLoading } = useListContext(props);
95+
96+
if (isLoading) {
97+
return <Loading loadingSecondary={"The list is loading. Just a moment please."} />;
98+
}
99+
95100
let values = {};
96101
if (!isLoading && data && data.length > 0) {
97102
data.forEach((record) => {

main/src/components/ListResultTable/TemplatedListResultTable.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ const TemplatedListResultTable = (props) => {
4040
useEffect(() => {
4141
(async () => {
4242
if (query.variables || query.indirectVariables) {
43+
// LOG console.log('start waiting for variable options');
4344
setVariableOptions(await dataProvider.getVariableOptions(query));
45+
// LOG console.log('done waiting for variable options');
4446
setWaitingForVariableOptions(false);
4547
}
4648
})();
@@ -55,7 +57,7 @@ const TemplatedListResultTable = (props) => {
5557

5658
if (waitingForVariableOptions) {
5759
// LOG console.log('TemplatedListResultTable waiting for variable options.');
58-
return <Loading loadingSecondary={"Loading variable options. Just a moment please."} />;
60+
return <Loading sx={{ height: "auto" }} loadingSecondary={"The options for the variables in this query are loading. Just a moment please."} />;
5961
}
6062

6163
if (isTemplatedQuery) {

main/src/dataProvider/SparqlDataProvider.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ const onConfigChanged = (newConfig) => {
2626

2727
configManager.on('configChanged', onConfigChanged);
2828

29+
// simple cache to save time while scrolling through pages of a list
30+
// results = the result of executeQuery, totalItems
31+
const listCache = {
32+
hash: "",
33+
results: {}
34+
};
35+
2936
// LOG let getListCounter = 0;
3037
// LOG let getVariableOptionsCounter = 0;
3138

@@ -58,7 +65,19 @@ export default {
5865
query.variableValues = meta.variableValues;
5966
}
6067

61-
let results = await executeQuery(query);
68+
let results;
69+
const hash = JSON.stringify({ resource, variableValues: query.variableValues });
70+
// LOG console.log(`hash: ${hash}`);
71+
if (hash == listCache.hash) {
72+
// LOG console.log(`reusing listCache.results: ${JSON.stringify(listCache.results, null, 2)}`);
73+
results = listCache.results;
74+
} else {
75+
results = await executeQuery(query);
76+
listCache.hash = hash;
77+
listCache.results = results;
78+
// LOG console.log(`new listCache.results: ${JSON.stringify(listCache.results, null, 2)}`);
79+
}
80+
6281
let totalItems = results.length;
6382
results = results.slice(offset, offset + limit);
6483

@@ -101,7 +120,8 @@ export default {
101120
deleteMany: async function deleteMany() {
102121
throw new NotImplementedError();
103122
},
104-
getVariableOptions
123+
getVariableOptions,
124+
clearListCache
105125
};
106126

107127
/**
@@ -427,3 +447,12 @@ async function getVariableOptions(query) {
427447
}
428448
return variableOptions;
429449
}
450+
451+
/**
452+
* Clears the list cache
453+
*/
454+
function clearListCache() {
455+
// LOG console.log('Clearing listCache');
456+
listCache.hash = "";
457+
}
458+

0 commit comments

Comments
 (0)