-
Notifications
You must be signed in to change notification settings - Fork 92
feat(new-webui): Integrate aggregation results into query timeline UI. #941
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
206f755
8a00cc7
592f5e4
c93574e
f22304e
14c2f00
4a74063
3be40ca
4ba04b3
a4548c5
50e2ce7
45e623c
c9dea3b
8dc3883
440b674
8dd1341
23d3f4d
32b8d19
87e2313
7ccda94
99d9612
028835b
624b205
5d77bb1
7fdc18a
d585c96
3cb8f92
343766f
bb0235d
5149ea0
37b0e36
cab5b3a
a071ae0
5a5f1cc
4390c80
3a76904
eb98287
ea803b2
4a2b527
b29e66a
89dc988
5882b75
bce8841
79dfa0b
665d589
35ef34a
0a2dcde
80c0632
d44b888
f11754c
a28860e
239773d
f7d2695
86f3a40
13247d7
ae8ebaa
340073b
9215797
9d4691e
b944ea4
d56f0c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,78 +1,67 @@ | ||||||||||||||||||||||||||||||
| import {Card} from "antd"; | ||||||||||||||||||||||||||||||
| import dayjs from "dayjs"; | ||||||||||||||||||||||||||||||
| import {Dayjs} from "dayjs"; | ||||||||||||||||||||||||||||||
| import {TimelineConfig} from "src/components/ResultsTimeline/typings"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| import {TimeRange} from "../../../../components/ResultsTimeline/datetime/typings"; | ||||||||||||||||||||||||||||||
| import ResultsTimeline from "../../../../components/ResultsTimeline/index"; | ||||||||||||||||||||||||||||||
| import {TimelineBucket} from "../../../../components/ResultsTimeline/typings"; | ||||||||||||||||||||||||||||||
| import {handleQuerySubmit} from "../../SearchControls/search-requests"; | ||||||||||||||||||||||||||||||
| import {TIME_RANGE_OPTION} from "../../SearchControls/TimeRangeInput/utils"; | ||||||||||||||||||||||||||||||
| import useSearchStore from "../../SearchState"; | ||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||
| computeTimelineConfig, | ||||||||||||||||||||||||||||||
| expandTimeRangeToDurationMultiple, | ||||||||||||||||||||||||||||||
| } from "./utils"; | ||||||||||||||||||||||||||||||
| import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../SearchState/index"; | ||||||||||||||||||||||||||||||
| import {SEARCH_UI_STATE} from "../../SearchState/typings"; | ||||||||||||||||||||||||||||||
| import {useAggregationResults} from "./useAggregationResults"; | ||||||||||||||||||||||||||||||
| import {computeTimelineConfig} from "./utils"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // eslint-disable-next-line no-warning-comments | ||||||||||||||||||||||||||||||
| // TODO: Replace with values from database once api implemented. | ||||||||||||||||||||||||||||||
| const DUMMY_BUCKETS: TimelineBucket[] = [ | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| count: 2, | ||||||||||||||||||||||||||||||
| timestamp: dayjs().subtract(10, "day") | ||||||||||||||||||||||||||||||
| .valueOf(), | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| count: 3, | ||||||||||||||||||||||||||||||
| // eslint-disable-next-line no-magic-numbers | ||||||||||||||||||||||||||||||
| timestamp: dayjs().subtract(5, "day") | ||||||||||||||||||||||||||||||
| .valueOf(), | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| count: 5, | ||||||||||||||||||||||||||||||
| timestamp: dayjs().valueOf(), | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||
| * Renders timeline visualization of search results. | ||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||
| * @return | ||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||
| const SearchResultsTimeline = () => { | ||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto - see the Zustand state / action retrieval styling sugguestion
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do this also in future PR |
||||||||||||||||||||||||||||||
| queryString, | ||||||||||||||||||||||||||||||
| updateTimeRange, | ||||||||||||||||||||||||||||||
| timeRange: [beginTime, endTime], | ||||||||||||||||||||||||||||||
| updateTimeRangeOption, | ||||||||||||||||||||||||||||||
| timelineConfig, | ||||||||||||||||||||||||||||||
| searchUiState, | ||||||||||||||||||||||||||||||
| updateTimelineConfig, | ||||||||||||||||||||||||||||||
| } = useSearchStore(); | ||||||||||||||||||||||||||||||
| const timestampBeginUnixMillis = beginTime.utc().valueOf(); | ||||||||||||||||||||||||||||||
| const timestampEndUnixMillis = endTime.utc().valueOf(); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const timelineConfig = computeTimelineConfig(timestampBeginUnixMillis, timestampEndUnixMillis); | ||||||||||||||||||||||||||||||
| const aggregationResults = useAggregationResults(); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const handleTimelineZoom = (newTimeRange: TimeRange) => { | ||||||||||||||||||||||||||||||
| // Expand the time range to the granularity of buckets so if the user | ||||||||||||||||||||||||||||||
| // pans across at least one bar in the graph, we will zoom into a region | ||||||||||||||||||||||||||||||
| // that still contains log events. | ||||||||||||||||||||||||||||||
| const expandedTimeRange = expandTimeRangeToDurationMultiple( | ||||||||||||||||||||||||||||||
| timelineConfig.bucketDuration, | ||||||||||||||||||||||||||||||
| newTimeRange, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| const handleTimelineZoom = (newTimeRange: [Dayjs, Dayjs]) => { | ||||||||||||||||||||||||||||||
| const newTimelineConfig: TimelineConfig = computeTimelineConfig(newTimeRange); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| updateTimeRange([expandedTimeRange.begin, | ||||||||||||||||||||||||||||||
| expandedTimeRange.end]); | ||||||||||||||||||||||||||||||
| // Update range picker selection to match zoomed range. | ||||||||||||||||||||||||||||||
| updateTimeRange(newTimeRange); | ||||||||||||||||||||||||||||||
| updateTimeRangeOption(TIME_RANGE_OPTION.CUSTOM); | ||||||||||||||||||||||||||||||
| updateTimelineConfig(newTimelineConfig); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const isQueryStringEmpty = queryString === SEARCH_STATE_DEFAULT.queryString; | ||||||||||||||||||||||||||||||
| if (isQueryStringEmpty) { | ||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // eslint-disable-next-line no-warning-comments | ||||||||||||||||||||||||||||||
| // TODO: submit query based on timelineConfig. | ||||||||||||||||||||||||||||||
| handleQuerySubmit({ | ||||||||||||||||||||||||||||||
| ignoreCase: false, | ||||||||||||||||||||||||||||||
| queryString: queryString, | ||||||||||||||||||||||||||||||
| timeRangeBucketSizeMillis: newTimelineConfig.bucketDuration.asMilliseconds(), | ||||||||||||||||||||||||||||||
| timestampBegin: newTimeRange[0].valueOf(), | ||||||||||||||||||||||||||||||
| timestampEnd: newTimeRange[1].valueOf(), | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
+51
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainConsider using the actual case sensitivity preference. The Let me check if there's a case sensitivity setting in the search state: 🏁 Script executed: #!/bin/bash
# Description: Check for case sensitivity settings in the search state and UI
# Search for ignoreCase or case sensitivity related state
rg -A 5 "ignoreCase|caseSensitive|caseInsensitive" --glob "**/*SearchState*" --glob "**/*Search*"Length of output: 1987 Use actual case sensitivity preference for timeline zoom queries The call to • Ensure this component receives the Suggested diff: --- a/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTimeline/index.tsx
+++ b/components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTimeline/index.tsx
@@ 47,7
- handleQuerySubmit({
- ignoreCase: false,
+ handleQuerySubmit({
+ ignoreCase: ignoreCase,
queryString: queryString,
timeRangeBucketSizeMillis: newTimelineConfig.bucketDuration.asMilliseconds(),
timestampBegin: newTimeRange[0].valueOf(),This will align the timeline-zoom search with the UI’s case-sensitivity setting. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // eslint-disable-next-line no-warning-comments | ||||||||||||||||||||||||||||||
| // TODO: fix `isInputDisabled` . | ||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||
| <Card> | ||||||||||||||||||||||||||||||
| <ResultsTimeline | ||||||||||||||||||||||||||||||
| isInputDisabled={false} | ||||||||||||||||||||||||||||||
| timelineBuckets={DUMMY_BUCKETS} | ||||||||||||||||||||||||||||||
| timelineConfig={timelineConfig} | ||||||||||||||||||||||||||||||
| isInputDisabled={ | ||||||||||||||||||||||||||||||
| searchUiState === SEARCH_UI_STATE.QUERYING || | ||||||||||||||||||||||||||||||
| searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| timelineBuckets={aggregationResults ? | ||||||||||||||||||||||||||||||
| aggregationResults : | ||||||||||||||||||||||||||||||
| []} | ||||||||||||||||||||||||||||||
| onTimelineZoom={handleTimelineZoom}/> | ||||||||||||||||||||||||||||||
| </Card> | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import MongoCollectionSocket from "../../../../api/socket/MongoCollectionSocket"; | ||
| import {useCursor} from "../../../../api/socket/useCursor"; | ||
| import {TimelineBucket} from "../../../../components/ResultsTimeline/typings"; | ||
| import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../SearchState/index"; | ||
|
|
||
|
|
||
| /** | ||
| * Custom hook to get aggregation results for the current aggregationJobId. | ||
| * | ||
| * @return | ||
| */ | ||
| const useAggregationResults = () => { | ||
| const {aggregationJobId} = useSearchStore(); | ||
|
|
||
| const aggregationResultsCursor = useCursor<TimelineBucket>( | ||
| () => { | ||
| // If there is no active aggregation job, there are no results to fetch. The cursor will | ||
| // return null. | ||
| if (aggregationJobId === SEARCH_STATE_DEFAULT.aggregationJobId) { | ||
| return null; | ||
| } | ||
|
|
||
| const collection = new MongoCollectionSocket(aggregationJobId.toString()); | ||
| return collection.find({}, {}); | ||
| }, | ||
| [aggregationJobId] | ||
| ); | ||
|
|
||
| return aggregationResultsCursor; | ||
| }; | ||
|
|
||
| export {useAggregationResults}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
purely stylish - we can address all in another PR
instead of retrieving the states / actions here, we can write
so the definition of handleSubmitButtonClick won't change at all
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k i will do in later PR