Skip to content

Commit 619392f

Browse files
authored
feat(webui): Add a progress bar to the Presto search page. (#1206)
1 parent e087603 commit 619392f

File tree

7 files changed

+170
-65
lines changed

7 files changed

+170
-65
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.prestoProgress {
2+
position: absolute;
3+
line-height: 0;
4+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {useEffect} from "react";
2+
3+
import {Progress} from "antd";
4+
5+
import useSearchStore from "../../SearchState";
6+
import {SEARCH_UI_STATE} from "../../SearchState/typings";
7+
import {usePseudoProgress} from "../../SearchState/usePseudoProgress";
8+
import styles from "./index.module.css";
9+
10+
11+
/**
12+
* Renders a pseudo progress bar that listens for changes in `searchUiState`.
13+
*
14+
* @return
15+
*/
16+
const ProgressBar = () => {
17+
const {searchUiState} = useSearchStore.getState();
18+
const {
19+
progress,
20+
start,
21+
stop,
22+
} = usePseudoProgress();
23+
24+
useEffect(() => {
25+
if (searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING) {
26+
start();
27+
} else if (
28+
searchUiState === SEARCH_UI_STATE.DONE ||
29+
searchUiState === SEARCH_UI_STATE.FAILED
30+
) {
31+
stop();
32+
}
33+
}, [searchUiState,
34+
start,
35+
stop]);
36+
37+
return (
38+
<Progress
39+
className={styles["prestoProgress"] || ""}
40+
percent={progress ?? 0}
41+
showInfo={false}
42+
size={"small"}
43+
status={"active"}
44+
strokeLinecap={"butt"}
45+
style={{display: null === progress ?
46+
"none" :
47+
"block"}}/>
48+
);
49+
};
50+
51+
export {ProgressBar};

components/webui/client/src/pages/SearchPage/SearchControls/QueryInput/index.tsx

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,14 @@ import {
33
useCallback,
44
useEffect,
55
useRef,
6-
useState,
76
} from "react";
87

98
import type {InputRef} from "antd";
10-
import {Nullable} from "src/typings/common";
119

1210
import QueryBox from "../../../../components/QueryBox";
1311
import useSearchStore from "../../SearchState/index";
1412
import {SEARCH_UI_STATE} from "../../SearchState/typings";
15-
import {
16-
PROGRESS_INCREMENT,
17-
PROGRESS_INTERVAL_MILLIS,
18-
} from "./typings";
13+
import {usePseudoProgress} from "../../SearchState/usePseudoProgress";
1914

2015

2116
/**
@@ -27,8 +22,7 @@ const QueryInput = () => {
2722
const queryIsCaseSensitive = useSearchStore((state) => state.queryIsCaseSensitive);
2823
const queryString = useSearchStore((state) => state.queryString);
2924
const searchUiState = useSearchStore((state) => state.searchUiState);
30-
const [pseudoProgress, setPseudoProgress] = useState<Nullable<number>>(null);
31-
const intervalIdRef = useRef<number>(0);
25+
const {progress: pseudoProgress, start, stop} = usePseudoProgress();
3226
const inputRef = useRef<InputRef>(null);
3327

3428
const handleCaseSensitiveChange = useCallback((newValue: boolean) => {
@@ -43,34 +37,16 @@ const QueryInput = () => {
4337

4438
useEffect(() => {
4539
if (searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING) {
46-
if (0 !== intervalIdRef.current) {
47-
console.warn("Interval already set for submitted query");
48-
49-
return;
50-
}
51-
intervalIdRef.current = window.setInterval(() => {
52-
setPseudoProgress((v) => {
53-
if (100 <= (v ?? 0) + PROGRESS_INCREMENT) {
54-
return 100;
55-
}
56-
57-
return (v ?? 0) + PROGRESS_INCREMENT;
58-
});
59-
}, PROGRESS_INTERVAL_MILLIS);
40+
start();
6041
} else if (
6142
searchUiState === SEARCH_UI_STATE.DONE ||
6243
searchUiState === SEARCH_UI_STATE.FAILED
6344
) {
64-
clearInterval(intervalIdRef.current);
65-
intervalIdRef.current = 0;
66-
setPseudoProgress(null);
45+
stop();
6746
}
68-
}, [searchUiState]);
69-
70-
// Clear the interval if the component unmounts.
71-
useEffect(() => {
72-
clearInterval(intervalIdRef.current);
73-
}, []);
47+
}, [searchUiState,
48+
start,
49+
stop]);
7450

7551
useEffect(() => {
7652
if (

components/webui/client/src/pages/SearchPage/SearchControls/QueryInput/typings.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import {
2+
useCallback,
3+
useEffect,
4+
useRef,
5+
useState,
6+
} from "react";
7+
8+
import {Nullable} from "../../../typings/common";
9+
10+
11+
/**
12+
* Pseudo progress bar increment on each interval tick.
13+
*/
14+
const PROGRESS_INCREMENT = 5;
15+
16+
/**
17+
* The interval for updating the pseudo progress bar.
18+
*/
19+
const PROGRESS_INTERVAL_MILLIS = 100;
20+
21+
/**
22+
* A custom hook to manage a pseudo progress value.
23+
* The progress increases gradually and can be reset.
24+
*
25+
* @return
26+
*/
27+
const usePseudoProgress = (): {
28+
progress: Nullable<number>;
29+
start: () => void;
30+
stop: () => void;
31+
} => {
32+
const [progress, setProgress] = useState<Nullable<number>>(null);
33+
const intervalIdRef = useRef<number>(0);
34+
35+
const start = useCallback(() => {
36+
if (0 !== intervalIdRef.current) {
37+
console.warn("Interval already set for submitted query");
38+
39+
return;
40+
}
41+
intervalIdRef.current = window.setInterval(() => {
42+
setProgress((v) => {
43+
if (100 <= (v ?? 0) + PROGRESS_INCREMENT) {
44+
return 100;
45+
}
46+
47+
return (v ?? 0) + PROGRESS_INCREMENT;
48+
});
49+
}, PROGRESS_INTERVAL_MILLIS);
50+
}, []);
51+
52+
const stop = useCallback(() => {
53+
clearInterval(intervalIdRef.current);
54+
intervalIdRef.current = 0;
55+
setProgress(null);
56+
}, []);
57+
58+
useEffect(() => {
59+
return () => {
60+
if (0 !== intervalIdRef.current) {
61+
clearInterval(intervalIdRef.current);
62+
intervalIdRef.current = 0;
63+
}
64+
};
65+
}, []);
66+
67+
return {
68+
progress,
69+
start,
70+
stop,
71+
};
72+
};
73+
74+
export {usePseudoProgress};

components/webui/client/src/pages/SearchPage/SearchState/useUpdateStateWithMetadata.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,25 @@ const useUiUpdateOnDoneSignal = () => {
2424
return;
2525
}
2626

27-
if (resultsMetadata.lastSignal === SEARCH_SIGNAL.RESP_DONE) {
28-
updateSearchUiState(SEARCH_UI_STATE.DONE);
29-
} else if (resultsMetadata.lastSignal === PRESTO_SEARCH_SIGNAL.FAILED) {
30-
updateSearchUiState(SEARCH_UI_STATE.FAILED);
31-
notification.error({
32-
description: resultsMetadata.errorMsg || "An error occurred during search",
33-
duration: 15,
34-
key: `search-failed-${resultsMetadata._id}`,
35-
message: resultsMetadata.errorName || "Search Failed",
36-
pauseOnHover: true,
37-
placement: "bottomRight",
38-
showProgress: true,
39-
});
27+
switch (resultsMetadata.lastSignal) {
28+
case SEARCH_SIGNAL.RESP_DONE:
29+
case PRESTO_SEARCH_SIGNAL.FINISHED:
30+
updateSearchUiState(SEARCH_UI_STATE.DONE);
31+
break;
32+
case PRESTO_SEARCH_SIGNAL.FAILED:
33+
updateSearchUiState(SEARCH_UI_STATE.FAILED);
34+
notification.error({
35+
description: resultsMetadata.errorMsg || "An error occurred during search",
36+
duration: 15,
37+
key: `search-failed-${resultsMetadata._id}`,
38+
message: resultsMetadata.errorName || "Search Failed",
39+
pauseOnHover: true,
40+
placement: "bottomRight",
41+
showProgress: true,
42+
});
43+
break;
44+
default:
45+
break;
4046
}
4147
}, [
4248
resultsMetadata,

components/webui/client/src/pages/SearchPage/index.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
import {
2+
CLP_QUERY_ENGINES,
3+
SETTINGS_QUERY_ENGINE,
4+
} from "../../config";
15
import styles from "./index.module.css";
6+
import {ProgressBar} from "./Presto/ProgressBar";
27
import SearchControls from "./SearchControls";
38
import SearchQueryStatus from "./SearchQueryStatus";
49
import SearchResultsTable from "./SearchResults/SearchResultsTable";
@@ -15,14 +20,17 @@ const SearchPage = () => {
1520
useUiUpdateOnDoneSignal();
1621

1722
return (
18-
<div className={styles["searchPageContainer"]}>
19-
<div>
20-
<SearchControls/>
21-
<SearchQueryStatus/>
23+
<>
24+
{SETTINGS_QUERY_ENGINE === CLP_QUERY_ENGINES.PRESTO && <ProgressBar/>}
25+
<div className={styles["searchPageContainer"]}>
26+
<div>
27+
<SearchControls/>
28+
<SearchQueryStatus/>
29+
</div>
30+
<SearchResultsTimeline/>
31+
<SearchResultsTable/>
2232
</div>
23-
<SearchResultsTimeline/>
24-
<SearchResultsTable/>
25-
</div>
33+
</>
2634
);
2735
};
2836

0 commit comments

Comments
 (0)