Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
useEffect,
useMemo,
} from "react";

import VirtualTable from "../../../../../../components/VirtualTable";
import useSearchStore from "../../../../SearchState/index";
import {PrestoSearchResult} from "./typings";
import {usePrestoSearchResults} from "./usePrestoSearchResults";
import {getPrestoSearchResultsTableColumns} from "./utils";


interface PrestoResultsVirtualTableProps {
tableHeight: number;
}

/**
* Renders Presto search results in a virtual table.
*
* @param props
* @param props.tableHeight
* @return
*/
const PrestoResultsVirtualTable = ({tableHeight}: PrestoResultsVirtualTableProps) => {
const {updateNumSearchResultsTable} = useSearchStore();
const prestoSearchResults = usePrestoSearchResults();

const columns = useMemo(
() => getPrestoSearchResultsTableColumns(prestoSearchResults || []),
[prestoSearchResults]
);

useEffect(() => {
const num = prestoSearchResults ?
prestoSearchResults.length :
0;

updateNumSearchResultsTable(num);
}, [
prestoSearchResults,
updateNumSearchResultsTable,
]);

return (
<VirtualTable<PrestoSearchResult>
columns={columns}
dataSource={prestoSearchResults || []}
pagination={false}
rowKey={(record) => record._id}
scroll={{y: tableHeight}}/>
);
};

export default PrestoResultsVirtualTable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {PRESTO_DATA_PROPERTY} from "../../../../../../../../common";


/**
* Structure of dynamic Presto search results data.
*/
interface PrestoSearchResult {
_id: string;
[PRESTO_DATA_PROPERTY]: Record<string, unknown>;
}

export type {PrestoSearchResult};
export {getPrestoSearchResultsTableColumns} from "./utils";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consider renaming the file to .ts (no JSX).

This file contains only types; using .ts improves clarity and avoids unnecessary TSX processing.

Would you like me to generate a follow-up patch to rename the file and update imports?

🤖 Prompt for AI Agents
In
components/webui/client/src/pages/SearchPage/SearchResults/SearchResultsTable/Presto/PrestoResultsVirtualTable/typings.tsx
around lines 12-13, this file only exports types and utilities so rename the
file from .tsx to .ts to reflect that it contains no JSX; after renaming, update
all import sites to reference typings.ts (or use type-only imports where
appropriate, e.g. import type {...} from './typings') and run a quick
project-wide search to fix any stale .tsx references; no code changes within the
file are required beyond the filename change, but ensure build/tsconfig include
patterns still capture the new .ts file if you rely on explicit globs.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import MongoSocketCollection from "../../../../../../api/socket/MongoSocketCollection";
import {useCursor} from "../../../../../../api/socket/useCursor";
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../../../SearchState/index";
import {SEARCH_MAX_NUM_RESULTS} from "../../typings";
import {PrestoSearchResult} from "./typings";


/**
* Custom hook to get Presto search results for the current searchJobId.
*
* @return
*/
const usePrestoSearchResults = () => {
const searchJobId = useSearchStore((state) => state.searchJobId);

const searchResultsCursor = useCursor<PrestoSearchResult>(
() => {
// If there is no active search job, there are no results to fetch. The cursor will
// return null.
if (searchJobId === SEARCH_STATE_DEFAULT.searchJobId) {
return null;
}

console.log(
`Subscribing to updates to Presto search results with job ID: ${searchJobId}`
);

// Retrieve 1k most recent results.
const options = {
sort: [
[
"_id",
"desc",
],
],
limit: SEARCH_MAX_NUM_RESULTS,
};

const collection = new MongoSocketCollection(searchJobId);
return collection.find({}, options);
},
[searchJobId]
);

return searchResultsCursor;
};

export {usePrestoSearchResults};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {TableProps} from "antd";

import {PRESTO_DATA_PROPERTY} from "../../../../../../../../common";
import {PrestoSearchResult} from "./typings";


/**
* Generates dynamic columns configuration for Presto query engine.
*
* @param data Array of Presto search results
* @return
*/
const getPrestoSearchResultsTableColumns = (
data: PrestoSearchResult[]
): NonNullable<TableProps<PrestoSearchResult>["columns"]> => {
if (0 === data.length || "undefined" === typeof data[0] || "undefined" === typeof data[0].row) {
return [];
}

return Object.keys(data[0].row)
.map((key) => ({
dataIndex: [PRESTO_DATA_PROPERTY,
key],
key: key,
title: key,
}));
};

export {getPrestoSearchResultsTableColumns};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {useEffect} from "react";

import VirtualTable from "../../../../../components/VirtualTable";
import useSearchStore from "../../../SearchState/index";
import {
SearchResult,
searchResultsTableColumns,
} from "./typings";
import {useSearchResults} from "./useSearchResults";


interface SearchResultsVirtualTableProps {
tableHeight: number;
}

/**
* Renders search results in a virtual table.
*
* @param props
* @param props.tableHeight
* @return
*/
const SearchResultsVirtualTable = ({tableHeight}: SearchResultsVirtualTableProps) => {
const {updateNumSearchResultsTable} = useSearchStore();
const searchResults = useSearchResults();

useEffect(() => {
const num = searchResults ?
searchResults.length :
0;

updateNumSearchResultsTable(num);
}, [
searchResults,
updateNumSearchResultsTable,
]);

return (
<VirtualTable<SearchResult>
columns={searchResultsTableColumns}
dataSource={searchResults || []}
pagination={false}
rowKey={(record) => record._id.toString()}
scroll={{y: tableHeight}}/>
);
};

export default SearchResultsVirtualTable;
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {TableProps} from "antd";
import dayjs from "dayjs";

import {DATETIME_FORMAT_TEMPLATE} from "../../../../typings/datetime";
import {
CLP_STORAGE_ENGINES,
SETTINGS_STORAGE_ENGINE,
} from ".././../../../config";
import Message from "./Message";
import {getStreamId} from "./utils";
} from "../../../../../config";
import {DATETIME_FORMAT_TEMPLATE} from "../../../../../typings/datetime";
import Message from "../Message";
import {getStreamId} from "../utils";


/**
Expand All @@ -25,7 +25,7 @@ interface SearchResult {
}

/**
* Columns configuration for the seach results table.
* Columns configuration for the search results table.
*/
const searchResultsTableColumns: NonNullable<TableProps<SearchResult>["columns"]> = [
{
Expand Down Expand Up @@ -70,20 +70,5 @@ const searchResultsTableColumns: NonNullable<TableProps<SearchResult>["columns"]
},
];

/**
* Padding for the table to the bottom of the page.
*/
const TABLE_BOTTOM_PADDING = 75;

/**
* The maximum number of results to retrieve for a search.
*/
const SEARCH_MAX_NUM_RESULTS = 1000;


export type {SearchResult};
export {
SEARCH_MAX_NUM_RESULTS,
searchResultsTableColumns,
TABLE_BOTTOM_PADDING,
};
export {searchResultsTableColumns};
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import MongoSocketCollection from "../../../../api/socket/MongoSocketCollection";
import {useCursor} from "../../../../api/socket/useCursor";
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../SearchState/index";
import {
SEARCH_MAX_NUM_RESULTS,
SearchResult,
} from "./typings";
import MongoSocketCollection from "../../../../../api/socket/MongoSocketCollection";
import {useCursor} from "../../../../../api/socket/useCursor";
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../../SearchState/index";
import {SEARCH_MAX_NUM_RESULTS} from "../typings";
import {SearchResult} from "./typings";


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import {
useState,
} from "react";

import VirtualTable from "../../../../components/VirtualTable";
import useSearchStore from "../../SearchState/index";
import {
SearchResult,
searchResultsTableColumns,
TABLE_BOTTOM_PADDING,
} from "./typings";
import {useSearchResults} from "./useSearchResults";
CLP_QUERY_ENGINES,
SETTINGS_QUERY_ENGINE,
} from "../../../../config";
import PrestoResultsVirtualTable from "./Presto/PrestoResultsVirtualTable";
import SearchResultsVirtualTable from "./SearchResultsVirtualTable";
import {TABLE_BOTTOM_PADDING} from "./typings";


/**
Expand All @@ -20,22 +19,9 @@ import {useSearchResults} from "./useSearchResults";
* @return
*/
const SearchResultsTable = () => {
const {updateNumSearchResultsTable} = useSearchStore();
const searchResults = useSearchResults();
const [tableHeight, setTableHeight] = useState<number>(0);
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const num = searchResults ?
searchResults.length :
0;

updateNumSearchResultsTable(num);
}, [
searchResults,
updateNumSearchResultsTable,
]);

// Antd table requires a fixed height for virtual scrolling. The effect sets a fixed height
// based on the window height, container top, and fixed padding.
useEffect(() => {
Expand All @@ -60,12 +46,13 @@ const SearchResultsTable = () => {
ref={containerRef}
style={{outline: "none"}}
>
<VirtualTable<SearchResult>
columns={searchResultsTableColumns}
dataSource={searchResults || []}
pagination={false}
rowKey={(record) => record._id.toString()}
scroll={{y: tableHeight}}/>
{CLP_QUERY_ENGINES.PRESTO === SETTINGS_QUERY_ENGINE ?
(
<PrestoResultsVirtualTable tableHeight={tableHeight}/>
) :
(
<SearchResultsVirtualTable tableHeight={tableHeight}/>
)}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Padding for the table to the bottom of the page.
*/
const TABLE_BOTTOM_PADDING = 75;

/**
* The maximum number of results to retrieve for a search.
*/
const SEARCH_MAX_NUM_RESULTS = 1000;

export {
SEARCH_MAX_NUM_RESULTS,
TABLE_BOTTOM_PADDING,
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
CLP_STORAGE_ENGINES,
SETTINGS_STORAGE_ENGINE,
} from "../../../../config";
import type {SearchResult} from "./typings";
import type {SearchResult} from "./SearchResultsVirtualTable/typings";


/**
Expand Down
6 changes: 6 additions & 0 deletions components/webui/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ type PRESTO_SEARCH_SIGNAL =
| "CANCELED"
| "FAILED";

/**
* Property name used to wrap result objects to prevent conflicts with MongoDB's _id field.
*/
const PRESTO_DATA_PROPERTY = "row";

/**
* CLP query engines.
*/
Expand All @@ -131,6 +136,7 @@ interface SearchResultsMetadataDocument {
}
export {
CLP_QUERY_ENGINES,
PRESTO_DATA_PROPERTY,
SEARCH_SIGNAL,
};
export type {
Expand Down
5 changes: 3 additions & 2 deletions components/webui/server/src/plugins/app/Presto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ClientOptions,
} from "presto-client";

import {CLP_QUERY_ENGINES} from "../../../../common/index.js";
import settings from "../../../settings.json" with {type: "json"};


Expand All @@ -29,7 +30,7 @@ declare module "fastify" {

export default fp(
(fastify) => {
if ("presto" !== settings.ClpQueryEngine) {
if (CLP_QUERY_ENGINES.PRESTO !== settings.ClpQueryEngine as CLP_QUERY_ENGINES) {
return;
}

Expand All @@ -40,7 +41,7 @@ export default fp(

fastify.log.info(
clientOptions,
"Initializing Presto"
"Initializing Presto client"
);
fastify.decorate("Presto", new Presto(clientOptions));
},
Expand Down
Loading