Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import SubmitButton from "./SubmitButton";
* @return
*/
const SearchButton = () => {
const store = useSearchStore();
const {searchUiState} = useSearchStore();
Comment thread
davemarco marked this conversation as resolved.
Resolved

return (
(store.searchUiState === SEARCH_UI_STATE.QUERYING) ?
(searchUiState === SEARCH_UI_STATE.QUERYING) ?
<CancelButton/> :
<SubmitButton/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const handleClearResults = () => {
const handleQuerySubmit = (payload: QueryJobCreationSchema) => {
const store = useSearchStore.getState();

// Buttons to submit a query should be disabled while an existing query is in progress.
// User should be unable to submit a new query while an existing query is in progress.
Comment thread
davemarco marked this conversation as resolved.
Resolved
if (
store.searchUiState !== SEARCH_UI_STATE.DEFAULT &&
store.searchUiState !== SEARCH_UI_STATE.DONE
Expand All @@ -59,6 +59,8 @@ const handleQuerySubmit = (payload: QueryJobCreationSchema) => {

handleClearResults();

store.updateNumSearchResultsTable(0);
store.updateNumSearchResultsTimeline(0);
Comment thread
davemarco marked this conversation as resolved.
Resolved
store.updateSearchUiState(SEARCH_UI_STATE.QUERY_ID_PENDING);

submitQuery(payload)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {useMemo} from "react";

import {
GetProps,
Typography,
} from "antd";

import useSearchStore from "../SearchState/index";
import {SEARCH_UI_STATE} from "../SearchState/typings";


const {Text} = Typography;
type TextTypes = GetProps<typeof Text>["type"];


/**
* Displays the number of search results.
*
* @return
*/
const Results = () => {
const {
numSearchResultsTimeline,
numSearchResultsTable,
searchUiState,
} = useSearchStore();
Comment thread
davemarco marked this conversation as resolved.
Resolved

// Number of results is the maximum of the number of results in the timeline and table. The
// timeline may have more results since the table results are capped. Having two sources may
// be provide more timely update to the user.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
const numResults = useMemo(
() => Math.max(numSearchResultsTimeline, numSearchResultsTable),
[
numSearchResultsTimeline,
numSearchResultsTable,
]
);

let textType: TextTypes;
switch (searchUiState) {
case SEARCH_UI_STATE.QUERYING:
textType = "warning";
break;
case SEARCH_UI_STATE.DEFAULT:
case SEARCH_UI_STATE.QUERY_ID_PENDING:
textType = "secondary";
break;
case SEARCH_UI_STATE.DONE:
textType = "success";
break;
default:
textType = "secondary";
}

return (
<Text
strong={true}
type={textType}
>
{numResults}
</Text>
);
};

export default Results;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.status {
margin-left: 2px;
margin-top: 4px;
}

.badge {
padding-bottom: 4px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {Typography} from "antd";

import useSearchStore from "../SearchState/index";
import {SEARCH_UI_STATE} from "../SearchState/typings";
import styles from "./index.module.css";
import Results from "./Results";


const {Text} = Typography;

/**
* Displays the search job ID and the number of results found.
*
* @return
*/
const SearchQueryStatus = () => {
const {
searchJobId,
searchUiState,
} = useSearchStore();

return (
<div className={styles["status"]}>
{(searchUiState === SEARCH_UI_STATE.QUERYING ||
searchUiState === SEARCH_UI_STATE.DONE) && (
<Text type={"secondary"}>
Search job #
{searchJobId}
{" "}
found
{" "}
</Text>
)}
<Results/>
<Text type={"secondary"}> results</Text>
</div>
);
};


export default SearchQueryStatus;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {

import {Table} from "antd";

import useSearchStore from "../../SearchState/index";
import {
SearchResult,
searchResultsTableColumns,
Expand All @@ -20,10 +21,22 @@ 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 Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {useEffect} from "react";

import {Card} from "antd";
import {Dayjs} from "dayjs";
import {TimelineConfig} from "src/components/ResultsTimeline/typings";
Expand All @@ -24,10 +26,22 @@ const SearchResultsTimeline = () => {
timelineConfig,
searchUiState,
updateTimelineConfig,
updateNumSearchResultsTimeline,
} = useSearchStore();

const aggregationResults = useAggregationResults();

useEffect(() => {
const numSearchResultsTimeline = aggregationResults?.reduce(
(acc, curr) => acc + curr.count,
0
) ?? 0;

updateNumSearchResultsTimeline(numSearchResultsTimeline);
}, [
aggregationResults,
updateNumSearchResultsTimeline,
]);

const handleTimelineZoom = (newTimeRange: [Dayjs, Dayjs]) => {
const newTimelineConfig: TimelineConfig = computeTimelineConfig(newTimeRange);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {SEARCH_UI_STATE} from "./typings";
*/
const SEARCH_STATE_DEFAULT = Object.freeze({
aggregationJobId: null,
numSearchResultsTable: 0,
numSearchResultsTimeline: 0,
queryIsCaseSensitive: false,
queryString: "",
searchJobId: null,
Expand All @@ -32,6 +34,16 @@ interface SearchState {
*/
aggregationJobId: string | null;

/**
* The number of search table results.
*/
numSearchResultsTable: number;

/**
* The number of timeline results.
*/
numSearchResultsTimeline: number;

/**
* Whether the query is case sensitive.
*/
Expand Down Expand Up @@ -70,6 +82,8 @@ interface SearchState {
timelineConfig: TimelineConfig;

updateAggregationJobId: (id: string | null) => void;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

following our latest (undocumented yet - sorry!) Zustand practices, Zustand actions that do not perform more actions than state settings should be prefixed with set instead of update. This is fine to leave in the current PR, but we should address such in a future Zustand refactoring PR.

updateNumSearchResultsTable: (num: number) => void;
updateNumSearchResultsTimeline: (num: number) => void;
updateQueryIsCaseSensitive: (newValue: boolean) => void;
updateQueryString: (query: string) => void;
updateSearchJobId: (id: string | null) => void;
Expand All @@ -84,6 +98,12 @@ const useSearchStore = create<SearchState>((set) => ({
updateAggregationJobId: (id) => {
set({aggregationJobId: id});
},
updateNumSearchResultsTable: (num) => {
set({numSearchResultsTable: num});
},
updateNumSearchResultsTimeline: (num) => {
set({numSearchResultsTimeline: num});
},
updateQueryIsCaseSensitive: (newValue: boolean) => {
set({queryIsCaseSensitive: newValue});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ const useResultsMetadata = () => {
return resultsMetadata;
};


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Remove unnecessary blank line before export

The blank line added at line 51 serves no functional purpose and may introduce trailing whitespace. Please remove it to keep formatting consistent.

🤖 Prompt for AI Agents
In
components/log-viewer-webui/client/src/pages/SearchPage/SearchState/useResultsMetadata.ts
at line 51, remove the unnecessary blank line before the export statement to
avoid trailing whitespace and maintain consistent formatting.

export {useResultsMetadata};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styles from "./index.module.css";
import SearchControls from "./SearchControls";
import SearchQueryStatus from "./SearchQueryStatus";
import SearchResultsTable from "./SearchResults/SearchResultsTable";
import SearchResultsTimeline from "./SearchResults/SearchResultsTimeline";
import {useUiUpdateOnDoneSignal} from "./SearchState/useUpdateStateWithMetadata";
Expand All @@ -15,7 +16,10 @@ const SearchPage = () => {

return (
<div className={styles["searchPageContainer"]}>
<SearchControls/>
<div>
<SearchControls/>
<SearchQueryStatus/>
</div>
<SearchResultsTimeline/>
<SearchResultsTable/>
</div>
Expand Down