Skip to content

Commit 479f58c

Browse files
authored
feat(webui): Move timestamp key selector in guided Presto UI into date picker. (#1631)
1 parent 0f276e5 commit 479f58c

File tree

9 files changed

+160
-95
lines changed

9 files changed

+160
-95
lines changed

components/webui/client/src/pages/SearchPage/SearchControls/Presto/GuidedControls/TimestampKey/index.tsx

Lines changed: 0 additions & 24 deletions
This file was deleted.

components/webui/client/src/pages/SearchPage/SearchControls/Presto/GuidedControls/index.module.css

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515
display: flex;
1616
}
1717

18-
.timestampKey {
19-
width: 300px;
20-
display: flex;
21-
}
22-
2318
.where {
2419
grid-column: span 2;
2520
display: flex;
Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import useTimestampKeyInit from "../../../SearchState/Presto/useTimestampKeyInit";
12
import searchStyles from "../../index.module.css";
23
import QueryStatus from "../../QueryStatus";
34
import TimeRangeInput from "../../TimeRangeInput";
@@ -7,7 +8,6 @@ import From from "./From";
78
import guidedGrid from "./index.module.css";
89
import OrderBy from "./OrderBy";
910
import Select from "./Select";
10-
import TimestampKey from "./TimestampKey";
1111
import Where from "./Where";
1212

1313

@@ -16,28 +16,32 @@ import Where from "./Where";
1616
*
1717
* @return
1818
*/
19-
const GuidedControls = () => (
20-
<div className={searchStyles["searchControlsContainer"]}>
21-
<div className={searchStyles["runRow"]}>
22-
<div>
23-
<SqlInterfaceButton/>
19+
const GuidedControls = () => {
20+
const {contextHolder} = useTimestampKeyInit();
21+
22+
return (
23+
<div className={searchStyles["searchControlsContainer"]}>
24+
{contextHolder}
25+
<div className={searchStyles["runRow"]}>
26+
<div>
27+
<SqlInterfaceButton/>
28+
</div>
29+
<div className={searchStyles["buttons"]}>
30+
<TimeRangeInput/>
31+
<SqlSearchButton/>
32+
</div>
2433
</div>
25-
<div className={searchStyles["buttons"]}>
26-
<TimestampKey/>
27-
<TimeRangeInput/>
28-
<SqlSearchButton/>
34+
<div className={guidedGrid["gridContainer"]}>
35+
<Select/>
36+
<From/>
37+
<Where/>
38+
<OrderBy/>
39+
</div>
40+
<div className={searchStyles["status"]}>
41+
<QueryStatus/>
2942
</div>
3043
</div>
31-
<div className={guidedGrid["gridContainer"]}>
32-
<Select/>
33-
<From/>
34-
<Where/>
35-
<OrderBy/>
36-
</div>
37-
<div className={searchStyles["status"]}>
38-
<QueryStatus/>
39-
</div>
40-
</div>
41-
);
44+
);
45+
};
4246

4347
export default GuidedControls;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {useQuery} from "@tanstack/react-query";
2+
import {
3+
Select,
4+
SelectProps,
5+
} from "antd";
6+
7+
import useSearchStore from "../../../../../SearchState";
8+
import usePrestoSearchState from "../../../../../SearchState/Presto";
9+
import {fetchTimestampColumns} from "../../../../../SearchState/Presto/useTimestampKeyInit/sql";
10+
import {SEARCH_UI_STATE} from "../../../../../SearchState/typings";
11+
12+
13+
/**
14+
* Renders a timestamp key selector component.
15+
*
16+
* @param selectProps
17+
* @return
18+
*/
19+
const TimestampKeySelect = (selectProps: SelectProps<string>) => {
20+
const dataset = useSearchStore((state) => state.selectDataset);
21+
const timestampKey = usePrestoSearchState((state) => state.timestampKey);
22+
const updateTimestampKey = usePrestoSearchState((state) => state.updateTimestampKey);
23+
const searchUiState = useSearchStore((state) => state.searchUiState);
24+
25+
// Access cached timestamp keys fetched by useTimestampKeyInit hook in GuidedControls.
26+
const {data: timestampKeys} = useQuery({
27+
queryKey: [
28+
"timestampColumns",
29+
dataset,
30+
],
31+
queryFn: () => (dataset ?
32+
fetchTimestampColumns(dataset) :
33+
[]),
34+
enabled: null !== dataset,
35+
});
36+
37+
const handleTimestampKeyChange = (value: string) => {
38+
updateTimestampKey(value);
39+
};
40+
41+
return (
42+
<Select<string>
43+
options={(timestampKeys || []).map((option) => ({label: option, value: option}))}
44+
value={timestampKey}
45+
disabled={
46+
null === dataset ||
47+
searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING ||
48+
searchUiState === SEARCH_UI_STATE.QUERYING
49+
}
50+
onChange={handleTimestampKeyChange}
51+
{...selectProps}/>
52+
);
53+
};
54+
55+
export default TimestampKeySelect;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.footerContainer {
2+
display: flex;
3+
align-items: center;
4+
padding-top: 8px;
5+
padding-bottom: 8px;
6+
gap: 8px;
7+
}
8+
9+
.footerSelect {
10+
flex: 1;
11+
min-width: 0;
12+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {Typography} from "antd";
2+
3+
import styles from "./index.module.css";
4+
import TimestampKeySelect from "./TimestampKeySelect";
5+
6+
7+
const {Text} = Typography;
8+
9+
/**
10+
* Renders the footer for the time range picker when in guided mode. Includes the timestamp key
11+
* selector.
12+
*
13+
* @return
14+
*/
15+
const TimeRangeFooter = () => {
16+
return (
17+
<div className={styles["footerContainer"]}>
18+
<Text>Timestamp key:</Text>
19+
<TimestampKeySelect
20+
className={styles["footerSelect"] || ""}
21+
size={"small"}/>
22+
</div>
23+
);
24+
};
25+
26+
export default TimeRangeFooter;

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
import {useCallback} from "react";
2+
3+
import {CLP_QUERY_ENGINES} from "@webui/common/config";
14
import {
25
DatePicker,
36
Select,
47
} from "antd";
58
import dayjs from "dayjs";
69

10+
import {SETTINGS_QUERY_ENGINE} from "../../../../config";
711
import useSearchStore from "../../SearchState/index";
12+
import usePrestoSearchState from "../../SearchState/Presto";
13+
import {PRESTO_SQL_INTERFACE} from "../../SearchState/Presto/typings";
814
import {SEARCH_UI_STATE} from "../../SearchState/typings";
915
import styles from "./index.module.css";
16+
import TimeRangeFooter from "./Presto/TimeRangeFooter";
1017
import {
1118
isValidDateRange,
1219
TIME_RANGE_OPTION,
@@ -30,6 +37,10 @@ const TimeRangeInput = () => {
3037
searchUiState,
3138
} = useSearchStore();
3239

40+
const sqlInterface = usePrestoSearchState((state) => state.sqlInterface);
41+
const isPrestoGuided = SETTINGS_QUERY_ENGINE === CLP_QUERY_ENGINES.PRESTO &&
42+
sqlInterface === PRESTO_SQL_INTERFACE.GUIDED;
43+
3344
const handleSelectChange = (newTimeRangeOption: TIME_RANGE_OPTION) => {
3445
updateTimeRangeOption(newTimeRangeOption);
3546
};
@@ -48,6 +59,14 @@ const TimeRangeInput = () => {
4859
]);
4960
};
5061

62+
const renderFooter = useCallback(() => {
63+
if (false === isPrestoGuided) {
64+
return null;
65+
}
66+
67+
return <TimeRangeFooter/>;
68+
}, [isPrestoGuided]);
69+
5170
return (
5271
<div
5372
className={styles["timeRangeInputContainer"]}
@@ -69,6 +88,7 @@ const TimeRangeInput = () => {
6988
<DatePicker.RangePicker
7089
allowClear={true}
7190
className={styles["rangePicker"] || ""}
91+
renderExtraFooter={renderFooter}
7292
showTime={true}
7393
size={"middle"}
7494
value={timeRange}
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
11
import {useEffect} from "react";
22

33
import {useQuery} from "@tanstack/react-query";
4-
import {
5-
message,
6-
Select,
7-
SelectProps,
8-
} from "antd";
4+
import {message} from "antd";
95

10-
import useSearchStore from "../../../../SearchState";
11-
import usePrestoSearchState from "../../../../SearchState/Presto";
12-
import {SEARCH_UI_STATE} from "../../../../SearchState/typings";
6+
import useSearchStore from "../../";
7+
import usePrestoSearchState from "..";
138
import {fetchTimestampColumns} from "./sql";
149

1510

1611
/**
17-
* Renders a timestamp key selector component
12+
* Hook to initialize timestamp key. Fetches timestamp columns and sets a default if none is
13+
* selected. Shows messages for errors or warnings with data fetching.
1814
*
19-
* @param selectProps
2015
* @return
2116
*/
22-
const TimestampKeySelect = (selectProps: SelectProps<string>) => {
17+
const useTimestampKeyInit = () => {
2318
const dataset = useSearchStore((state) => state.selectDataset);
2419
const timestampKey = usePrestoSearchState((state) => state.timestampKey);
2520
const updateTimestampKey = usePrestoSearchState((state) => state.updateTimestampKey);
26-
const searchUiState = useSearchStore((state) => state.searchUiState);
2721

2822
const [messageApi, contextHolder] = message.useMessage();
2923

30-
const {data: timestampKeys, isPending, isSuccess, isError} = useQuery({
24+
const {data: timestampKeys, isSuccess, isError} = useQuery({
3125
queryKey: [
3226
"timestampColumns",
3327
dataset,
@@ -38,6 +32,14 @@ const TimestampKeySelect = (selectProps: SelectProps<string>) => {
3832
enabled: null !== dataset,
3933
});
4034

35+
// Reset timestamp key when dataset changes.
36+
useEffect(() => {
37+
updateTimestampKey(null);
38+
}, [
39+
dataset,
40+
updateTimestampKey,
41+
]);
42+
4143
useEffect(() => {
4244
if (isSuccess) {
4345
if ("undefined" !== typeof timestampKeys[0] && null === timestampKey) {
@@ -51,6 +53,7 @@ const TimestampKeySelect = (selectProps: SelectProps<string>) => {
5153
updateTimestampKey,
5254
]);
5355

56+
// Show error message if fetch fails
5457
useEffect(() => {
5558
if (isError) {
5659
messageApi.error({
@@ -63,6 +66,7 @@ const TimestampKeySelect = (selectProps: SelectProps<string>) => {
6366
messageApi,
6467
]);
6568

69+
// Show warning if no timestamp columns found
6670
useEffect(() => {
6771
if (isSuccess && 0 === timestampKeys.length) {
6872
messageApi.warning({
@@ -79,34 +83,7 @@ const TimestampKeySelect = (selectProps: SelectProps<string>) => {
7983
updateTimestampKey,
8084
]);
8185

82-
// Reset timestamp key when dataset changes
83-
useEffect(() => {
84-
updateTimestampKey(null);
85-
}, [
86-
dataset,
87-
updateTimestampKey,
88-
]);
89-
90-
const handleTimestampKeyChange = (value: string) => {
91-
updateTimestampKey(value);
92-
};
93-
94-
return (
95-
<>
96-
{contextHolder}
97-
<Select<string>
98-
loading={isPending}
99-
options={(timestampKeys || []).map((option) => ({label: option, value: option}))}
100-
value={timestampKey}
101-
disabled={
102-
null === dataset ||
103-
searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING ||
104-
searchUiState === SEARCH_UI_STATE.QUERYING
105-
}
106-
onChange={handleTimestampKeyChange}
107-
{...selectProps}/>
108-
</>
109-
);
86+
return {contextHolder};
11087
};
11188

112-
export default TimestampKeySelect;
89+
export default useTimestampKeyInit;
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import {querySql} from "../../../../../../api/sql";
2-
import {SqlTableSuffix} from "../../../../../../config/sql-table-suffix";
3-
import {settings} from "../../../../../../settings";
1+
import {querySql} from "../../../../../api/sql";
2+
import {SqlTableSuffix} from "../../../../../config/sql-table-suffix";
3+
import {settings} from "../../../../../settings";
44

55

66
/**

0 commit comments

Comments
 (0)