Skip to content

Commit 3964565

Browse files
authored
feat(webui): Display search results in Presto UI. (#1179)
1 parent 1fe0224 commit 3964565

File tree

13 files changed

+249
-59
lines changed

13 files changed

+249
-59
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {
2+
useEffect,
3+
useMemo,
4+
} from "react";
5+
6+
import type {PrestoSearchResult} from "../../../../../../../../common/index.js";
7+
import VirtualTable from "../../../../../../components/VirtualTable";
8+
import useSearchStore from "../../../../SearchState/index";
9+
import {usePrestoSearchResults} from "./usePrestoSearchResults";
10+
import {getPrestoSearchResultsTableColumns} from "./utils";
11+
12+
13+
interface PrestoResultsVirtualTableProps {
14+
tableHeight: number;
15+
}
16+
17+
/**
18+
* Renders Presto search results in a virtual table.
19+
*
20+
* @param props
21+
* @param props.tableHeight
22+
* @return
23+
*/
24+
const PrestoResultsVirtualTable = ({tableHeight}: PrestoResultsVirtualTableProps) => {
25+
const {updateNumSearchResultsTable} = useSearchStore();
26+
const prestoSearchResults = usePrestoSearchResults();
27+
28+
const columns = useMemo(
29+
() => getPrestoSearchResultsTableColumns(prestoSearchResults || []),
30+
[prestoSearchResults]
31+
);
32+
33+
useEffect(() => {
34+
const num = prestoSearchResults ?
35+
prestoSearchResults.length :
36+
0;
37+
38+
updateNumSearchResultsTable(num);
39+
}, [
40+
prestoSearchResults,
41+
updateNumSearchResultsTable,
42+
]);
43+
44+
return (
45+
<VirtualTable<PrestoSearchResult>
46+
columns={columns}
47+
dataSource={prestoSearchResults || []}
48+
pagination={false}
49+
rowKey={(record) => record._id}
50+
scroll={{y: tableHeight}}/>
51+
);
52+
};
53+
54+
export default PrestoResultsVirtualTable;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type {PrestoSearchResult} from "../../../../../../../../common/index.js";
2+
import MongoSocketCollection from "../../../../../../api/socket/MongoSocketCollection";
3+
import {useCursor} from "../../../../../../api/socket/useCursor";
4+
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../../../SearchState/index";
5+
import {SEARCH_MAX_NUM_RESULTS} from "../../typings";
6+
7+
8+
/**
9+
* Custom hook to get Presto search results for the current searchJobId.
10+
*
11+
* @return
12+
*/
13+
const usePrestoSearchResults = () => {
14+
const searchJobId = useSearchStore((state) => state.searchJobId);
15+
16+
const searchResultsCursor = useCursor<PrestoSearchResult>(
17+
() => {
18+
// If there is no active search job, there are no results to fetch. The cursor will
19+
// return null.
20+
if (searchJobId === SEARCH_STATE_DEFAULT.searchJobId) {
21+
return null;
22+
}
23+
24+
console.log(
25+
`Subscribing to updates to Presto search results with job ID: ${searchJobId}`
26+
);
27+
28+
// Retrieve 1k most recent results.
29+
const options = {
30+
sort: [
31+
[
32+
"_id",
33+
"desc",
34+
],
35+
],
36+
limit: SEARCH_MAX_NUM_RESULTS,
37+
};
38+
39+
const collection = new MongoSocketCollection(searchJobId);
40+
return collection.find({}, options);
41+
},
42+
[searchJobId]
43+
);
44+
45+
return searchResultsCursor;
46+
};
47+
48+
export {usePrestoSearchResults};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {TableProps} from "antd";
2+
3+
import type {PrestoSearchResult} from "../../../../../../../../common/index.js";
4+
5+
6+
/**
7+
* Generates dynamic columns configuration for Presto query engine.
8+
*
9+
* @param data Array of Presto search results
10+
* @return
11+
*/
12+
const getPrestoSearchResultsTableColumns = (
13+
data: PrestoSearchResult[]
14+
): NonNullable<TableProps<PrestoSearchResult>["columns"]> => {
15+
if (0 === data.length ||
16+
"undefined" === typeof data[0] ||
17+
"undefined" === typeof data[0].row
18+
) {
19+
return [];
20+
}
21+
22+
return Object.keys(data[0].row)
23+
.map((key) => ({
24+
dataIndex: [
25+
"row",
26+
key,
27+
],
28+
key: key,
29+
title: key,
30+
}));
31+
};
32+
33+
export {getPrestoSearchResultsTableColumns};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {useEffect} from "react";
2+
3+
import VirtualTable from "../../../../../components/VirtualTable";
4+
import useSearchStore from "../../../SearchState/index";
5+
import {
6+
SearchResult,
7+
searchResultsTableColumns,
8+
} from "./typings";
9+
import {useSearchResults} from "./useSearchResults";
10+
11+
12+
interface SearchResultsVirtualTableProps {
13+
tableHeight: number;
14+
}
15+
16+
/**
17+
* Renders search results in a virtual table.
18+
*
19+
* @param props
20+
* @param props.tableHeight
21+
* @return
22+
*/
23+
const SearchResultsVirtualTable = ({tableHeight}: SearchResultsVirtualTableProps) => {
24+
const {updateNumSearchResultsTable} = useSearchStore();
25+
const searchResults = useSearchResults();
26+
27+
useEffect(() => {
28+
const num = searchResults ?
29+
searchResults.length :
30+
0;
31+
32+
updateNumSearchResultsTable(num);
33+
}, [
34+
searchResults,
35+
updateNumSearchResultsTable,
36+
]);
37+
38+
return (
39+
<VirtualTable<SearchResult>
40+
columns={searchResultsTableColumns}
41+
dataSource={searchResults || []}
42+
pagination={false}
43+
rowKey={(record) => record._id.toString()}
44+
scroll={{y: tableHeight}}/>
45+
);
46+
};
47+
48+
export default SearchResultsVirtualTable;

components/webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/typings.tsx renamed to components/webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/SearchResultsVirtualTable/typings.tsx

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import {TableProps} from "antd";
22
import dayjs from "dayjs";
33

4-
import {DATETIME_FORMAT_TEMPLATE} from "../../../../typings/datetime";
54
import {
65
CLP_STORAGE_ENGINES,
76
SETTINGS_STORAGE_ENGINE,
8-
} from ".././../../../config";
9-
import Message from "./Message";
10-
import {getStreamId} from "./utils";
7+
} from "../../../../../config";
8+
import {DATETIME_FORMAT_TEMPLATE} from "../../../../../typings/datetime";
9+
import Message from "../Message";
10+
import {getStreamId} from "../utils";
1111

1212

1313
/**
@@ -25,7 +25,7 @@ interface SearchResult {
2525
}
2626

2727
/**
28-
* Columns configuration for the seach results table.
28+
* Columns configuration for the search results table.
2929
*/
3030
const searchResultsTableColumns: NonNullable<TableProps<SearchResult>["columns"]> = [
3131
{
@@ -70,20 +70,5 @@ const searchResultsTableColumns: NonNullable<TableProps<SearchResult>["columns"]
7070
},
7171
];
7272

73-
/**
74-
* Padding for the table to the bottom of the page.
75-
*/
76-
const TABLE_BOTTOM_PADDING = 75;
77-
78-
/**
79-
* The maximum number of results to retrieve for a search.
80-
*/
81-
const SEARCH_MAX_NUM_RESULTS = 1000;
82-
83-
8473
export type {SearchResult};
85-
export {
86-
SEARCH_MAX_NUM_RESULTS,
87-
searchResultsTableColumns,
88-
TABLE_BOTTOM_PADDING,
89-
};
74+
export {searchResultsTableColumns};

components/webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/useSearchResults.ts renamed to components/webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/SearchResultsVirtualTable/useSearchResults.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import MongoSocketCollection from "../../../../api/socket/MongoSocketCollection";
2-
import {useCursor} from "../../../../api/socket/useCursor";
3-
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../SearchState/index";
4-
import {
5-
SEARCH_MAX_NUM_RESULTS,
6-
SearchResult,
7-
} from "./typings";
1+
import MongoSocketCollection from "../../../../../api/socket/MongoSocketCollection";
2+
import {useCursor} from "../../../../../api/socket/useCursor";
3+
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../../SearchState/index";
4+
import {SEARCH_MAX_NUM_RESULTS} from "../typings";
5+
import {SearchResult} from "./typings";
86

97

108
/**

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

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import {
44
useState,
55
} from "react";
66

7-
import VirtualTable from "../../../../components/VirtualTable";
8-
import useSearchStore from "../../SearchState/index";
97
import {
10-
SearchResult,
11-
searchResultsTableColumns,
12-
TABLE_BOTTOM_PADDING,
13-
} from "./typings";
14-
import {useSearchResults} from "./useSearchResults";
8+
CLP_QUERY_ENGINES,
9+
SETTINGS_QUERY_ENGINE,
10+
} from "../../../../config";
11+
import PrestoResultsVirtualTable from "./Presto/PrestoResultsVirtualTable";
12+
import SearchResultsVirtualTable from "./SearchResultsVirtualTable";
13+
import {TABLE_BOTTOM_PADDING} from "./typings";
1514

1615

1716
/**
@@ -20,22 +19,9 @@ import {useSearchResults} from "./useSearchResults";
2019
* @return
2120
*/
2221
const SearchResultsTable = () => {
23-
const {updateNumSearchResultsTable} = useSearchStore();
24-
const searchResults = useSearchResults();
2522
const [tableHeight, setTableHeight] = useState<number>(0);
2623
const containerRef = useRef<HTMLDivElement>(null);
2724

28-
useEffect(() => {
29-
const num = searchResults ?
30-
searchResults.length :
31-
0;
32-
33-
updateNumSearchResultsTable(num);
34-
}, [
35-
searchResults,
36-
updateNumSearchResultsTable,
37-
]);
38-
3925
// Antd table requires a fixed height for virtual scrolling. The effect sets a fixed height
4026
// based on the window height, container top, and fixed padding.
4127
useEffect(() => {
@@ -60,12 +46,13 @@ const SearchResultsTable = () => {
6046
ref={containerRef}
6147
style={{outline: "none"}}
6248
>
63-
<VirtualTable<SearchResult>
64-
columns={searchResultsTableColumns}
65-
dataSource={searchResults || []}
66-
pagination={false}
67-
rowKey={(record) => record._id.toString()}
68-
scroll={{y: tableHeight}}/>
49+
{CLP_QUERY_ENGINES.PRESTO === SETTINGS_QUERY_ENGINE ?
50+
(
51+
<PrestoResultsVirtualTable tableHeight={tableHeight}/>
52+
) :
53+
(
54+
<SearchResultsVirtualTable tableHeight={tableHeight}/>
55+
)}
6956
</div>
7057
);
7158
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Padding for the table to the bottom of the page.
3+
*/
4+
const TABLE_BOTTOM_PADDING = 75;
5+
6+
/**
7+
* The maximum number of results to retrieve for a search.
8+
*/
9+
const SEARCH_MAX_NUM_RESULTS = 1000;
10+
11+
export {
12+
SEARCH_MAX_NUM_RESULTS,
13+
TABLE_BOTTOM_PADDING,
14+
};

components/webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
CLP_STORAGE_ENGINES,
33
SETTINGS_STORAGE_ENGINE,
44
} from "../../../../config";
5-
import type {SearchResult} from "./typings";
5+
import type {SearchResult} from "./SearchResultsVirtualTable/typings";
66

77

88
/**

components/webui/common/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,29 @@ interface SearchResultsMetadataDocument {
129129
numTotalResults?: number;
130130
queryEngine: CLP_QUERY_ENGINES;
131131
}
132+
133+
/**
134+
* Presto row wrapped in a `row` property to prevent conflicts with MongoDB's `_id` field.
135+
*/
136+
interface PrestoRowObject {
137+
row: Record<string, unknown>;
138+
}
139+
140+
/**
141+
* Presto search result in MongoDB.
142+
*/
143+
interface PrestoSearchResult extends PrestoRowObject {
144+
_id: string;
145+
}
146+
132147
export {
133148
CLP_QUERY_ENGINES,
134149
PRESTO_SEARCH_SIGNAL,
135150
SEARCH_SIGNAL,
136151
};
137152
export type {
153+
PrestoRowObject,
154+
PrestoSearchResult,
138155
SearchResultsMetadataDocument,
139156
ClientToServerEvents,
140157
Err,

0 commit comments

Comments
 (0)