From e467b1719271f89e98a97d942f7d6a0f0db9ddc6 Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Tue, 29 Jul 2025 16:06:03 -0700 Subject: [PATCH 1/7] fix commas --- static/app/views/explore/utils.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/static/app/views/explore/utils.tsx b/static/app/views/explore/utils.tsx index fb6c8f5003b82f..4010eb867305ba 100644 --- a/static/app/views/explore/utils.tsx +++ b/static/app/views/explore/utils.tsx @@ -618,18 +618,26 @@ export function formatQueryToNaturalLanguage(query: string): string { return formattedTokens.reduce((result, token, index) => { if (index === 0) return token; - const prevToken = formattedTokens[index - 1]; - if (!prevToken) return `${result}, ${token}`; + const currentOriginalToken = tokens[index] || ''; + const prevOriginalToken = tokens[index - 1] || ''; const isLogicalOp = token.toUpperCase() === 'AND' || token.toUpperCase() === 'OR'; const prevIsLogicalOp = - prevToken.toUpperCase() === 'AND' || prevToken.toUpperCase() === 'OR'; + formattedTokens[index - 1]?.toUpperCase() === 'AND' || + formattedTokens[index - 1]?.toUpperCase() === 'OR'; if (isLogicalOp || prevIsLogicalOp) { return `${result} ${token}`; } - return `${result}, ${token}`; + const isCurrentFilter = /[:>== Date: Tue, 29 Jul 2025 16:45:15 -0700 Subject: [PATCH 2/7] use initialquery as well so that we dont lose context --- .../components/searchQueryBuilder/context.tsx | 7 +++++++ .../searchQueryBuilder/tokens/freeText.tsx | 13 ++++++++----- .../components/seerComboBox/seerComboBox.tsx | 2 ++ static/app/views/explore/spans/spansTab.tsx | 17 +++++++++++++++-- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/static/app/components/searchQueryBuilder/context.tsx b/static/app/components/searchQueryBuilder/context.tsx index d9db39fa687166..a9309a125fc718 100644 --- a/static/app/components/searchQueryBuilder/context.tsx +++ b/static/app/components/searchQueryBuilder/context.tsx @@ -30,6 +30,7 @@ import useOrganization from 'sentry/utils/useOrganization'; interface SearchQueryBuilderContextData { actionBarRef: React.RefObject; committedQuery: string; + currentInputValue: string; disabled: boolean; disallowFreeText: boolean; disallowWildcard: boolean; @@ -49,6 +50,7 @@ interface SearchQueryBuilderContextData { parsedQuery: ParseResult | null; query: string; searchSource: string; + setCurrentInputValue: (value: string) => void; setDisplaySeerResults: (enabled: boolean) => void; size: 'small' | 'normal'; wrapperRef: React.RefObject; @@ -108,6 +110,7 @@ export function SearchQueryBuilderProvider({ const {setupAcknowledgement} = useOrganizationSeerSetup({enabled: enableAISearch}); const [displaySeerResults, setDisplaySeerResults] = useState(false); + const [currentInputValue, setCurrentInputValue] = useState(''); const {state, dispatch} = useQueryBuilderState({ initialQuery, @@ -194,6 +197,8 @@ export function SearchQueryBuilderProvider({ replaceRawSearchKeys, filterKeyAliases, gaveSeerConsent: setupAcknowledgement.orgHasAcknowledged, + currentInputValue, + setCurrentInputValue, }; }, [ disabled, @@ -220,6 +225,8 @@ export function SearchQueryBuilderProvider({ stableFilterKeys, stableGetSuggestedFilterKey, state, + currentInputValue, + setCurrentInputValue, ]); return ( diff --git a/static/app/components/searchQueryBuilder/tokens/freeText.tsx b/static/app/components/searchQueryBuilder/tokens/freeText.tsx index ea5ea1909b2709..e65d8f87d1eece 100644 --- a/static/app/components/searchQueryBuilder/tokens/freeText.tsx +++ b/static/app/components/searchQueryBuilder/tokens/freeText.tsx @@ -253,11 +253,6 @@ function SearchQueryBuilderInputInternal({ setSelectionIndex(inputRef.current?.selectionStart ?? 0); }, []); - const resetInputValue = useCallback(() => { - setInputValue(trimmedTokenValue); - updateSelectionIndex(); - }, [trimmedTokenValue, updateSelectionIndex]); - const filterValue = getWordAtCursorPosition(inputValue, selectionIndex); const { @@ -270,8 +265,15 @@ function SearchQueryBuilderInputInternal({ placeholder, searchSource, recentSearches, + setCurrentInputValue, } = useSearchQueryBuilder(); + const resetInputValue = useCallback(() => { + setInputValue(trimmedTokenValue); + setCurrentInputValue(trimmedTokenValue); + updateSelectionIndex(); + }, [trimmedTokenValue, updateSelectionIndex, setCurrentInputValue]); + const {customMenu, sectionItems, maxOptions, onKeyDownCapture, handleOptionSelected} = useFilterKeyListBox({ filterValue, @@ -617,6 +619,7 @@ function SearchQueryBuilderInputInternal({ } setInputValue(e.target.value); + setCurrentInputValue(e.target.value); setSelectionIndex(e.target.selectionStart ?? 0); }} onKeyDown={onKeyDown} diff --git a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx index 24a12d8f258829..f38cdea132ebd0 100644 --- a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx +++ b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx @@ -94,6 +94,8 @@ function isNoneOfTheseItem(item: SeerSearchItems): item is NoneOfTheseItem { type SeerSearchItems = SeerSearchItem | NoneOfTheseItem; export function SeerComboBox({initialQuery, ...props}: SeerComboBoxProps) { + // console.log('initialQuery', initialQuery); + // console.log('props', props); const buttonRef = useRef(null); const listBoxRef = useRef(null); const popoverRef = useRef(null); diff --git a/static/app/views/explore/spans/spansTab.tsx b/static/app/views/explore/spans/spansTab.tsx index 11c96fb293cbdf..5b193a4dd24d69 100644 --- a/static/app/views/explore/spans/spansTab.tsx +++ b/static/app/views/explore/spans/spansTab.tsx @@ -173,10 +173,23 @@ function SpansSearchBar({ }: { eapSpanSearchQueryBuilderProps: EAPSpanSearchQueryBuilderProps; }) { - const {displaySeerResults, query} = useSearchQueryBuilder(); + const {displaySeerResults, query, currentInputValue} = useSearchQueryBuilder(); + + const initialSeerQuery = (() => { + const committedQuery = query.trim(); + const inputValue = currentInputValue.trim(); + + if (!inputValue) return committedQuery; + + if (!committedQuery) return inputValue; + + if (committedQuery.includes(inputValue)) return committedQuery; + + return `${committedQuery} ${inputValue}`; + })(); return displaySeerResults ? ( - + ) : ( ); From 7e788792ac38ef71fe3ba7829c11e2d638148047 Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Tue, 29 Jul 2025 18:02:24 -0700 Subject: [PATCH 3/7] auto submit only if selected during free text --- .../components/searchQueryBuilder/context.tsx | 6 ++++++ .../filterKeyListBox/useFilterKeyListBox.tsx | 17 ++++++++++++++++- .../components/seerComboBox/seerComboBox.tsx | 16 +++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/static/app/components/searchQueryBuilder/context.tsx b/static/app/components/searchQueryBuilder/context.tsx index a9309a125fc718..c71169aabd3871 100644 --- a/static/app/components/searchQueryBuilder/context.tsx +++ b/static/app/components/searchQueryBuilder/context.tsx @@ -29,6 +29,7 @@ import useOrganization from 'sentry/utils/useOrganization'; interface SearchQueryBuilderContextData { actionBarRef: React.RefObject; + autoSubmitSeer: boolean; committedQuery: string; currentInputValue: string; disabled: boolean; @@ -50,6 +51,7 @@ interface SearchQueryBuilderContextData { parsedQuery: ParseResult | null; query: string; searchSource: string; + setAutoSubmitSeer: (enabled: boolean) => void; setCurrentInputValue: (value: string) => void; setDisplaySeerResults: (enabled: boolean) => void; size: 'small' | 'normal'; @@ -110,6 +112,7 @@ export function SearchQueryBuilderProvider({ const {setupAcknowledgement} = useOrganizationSeerSetup({enabled: enableAISearch}); const [displaySeerResults, setDisplaySeerResults] = useState(false); + const [autoSubmitSeer, setAutoSubmitSeer] = useState(false); const [currentInputValue, setCurrentInputValue] = useState(''); const {state, dispatch} = useQueryBuilderState({ @@ -194,6 +197,8 @@ export function SearchQueryBuilderProvider({ portalTarget, displaySeerResults, setDisplaySeerResults, + autoSubmitSeer, + setAutoSubmitSeer, replaceRawSearchKeys, filterKeyAliases, gaveSeerConsent: setupAcknowledgement.orgHasAcknowledged, @@ -206,6 +211,7 @@ export function SearchQueryBuilderProvider({ disallowWildcard, dispatch, displaySeerResults, + autoSubmitSeer, enableAISearch, filterKeyAliases, filterKeyMenuWidth, diff --git a/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx b/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx index 9fffc720daeaec..f4cf5714bcb5f6 100644 --- a/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx +++ b/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx @@ -168,8 +168,10 @@ export function useFilterKeyListBox({filterValue}: {filterValue: string}) { filterKeys, getFieldDefinition, setDisplaySeerResults, + setAutoSubmitSeer, enableAISearch, gaveSeerConsent, + currentInputValue, } = useSearchQueryBuilder(); const {sectionedItems} = useFilterKeyItems(); const recentFilters = useRecentSearchFilters(); @@ -391,6 +393,13 @@ export function useFilterKeyListBox({filterValue}: {filterValue: string}) { action: 'opened', }); setDisplaySeerResults(true); + + // Set flag to auto-submit if there's text in the input + if (currentInputValue?.trim()) { + setAutoSubmitSeer(true); + } else { + setAutoSubmitSeer(false); + } return; } @@ -403,7 +412,13 @@ export function useFilterKeyListBox({filterValue}: {filterValue: string}) { return; } }, - [organization, seerAcknowledgeMutate, setDisplaySeerResults] + [ + organization, + seerAcknowledgeMutate, + setDisplaySeerResults, + setAutoSubmitSeer, + currentInputValue, + ] ); return { diff --git a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx index f38cdea132ebd0..a0c2c3baa271f9 100644 --- a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx +++ b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx @@ -108,7 +108,8 @@ export function SeerComboBox({initialQuery, ...props}: SeerComboBoxProps) { ); const openForm = useFeedbackForm(); - const {setDisplaySeerResults} = useSearchQueryBuilder(); + const {setDisplaySeerResults, autoSubmitSeer, setAutoSubmitSeer} = + useSearchQueryBuilder(); const {rawResult, submitQuery, isPending} = useSeerSearch(); const applySeerSearchQuery = useApplySeerSearchQuery(); const organization = useOrganization(); @@ -323,6 +324,19 @@ export function SeerComboBox({initialQuery, ...props}: SeerComboBoxProps) { } }, [state]); + // Auto-submit search when autoSubmitSeer flag is true + useLayoutEffect(() => { + if (autoSubmitSeer && searchQuery.trim()) { + trackAnalytics('trace.explorer.ai_query_submitted', { + organization, + natural_language_query: searchQuery.trim(), + }); + submitQuery(searchQuery.trim()); + // Reset the flag after submitting + setAutoSubmitSeer(false); + } + }, [autoSubmitSeer, searchQuery, organization, submitQuery, setAutoSubmitSeer]); + return ( From 5b8dd1319e272c9f171313b160e78ac7fa6885cf Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Tue, 29 Jul 2025 18:20:49 -0700 Subject: [PATCH 4/7] clean --- .../tokens/filterKeyListBox/useFilterKeyListBox.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx b/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx index f4cf5714bcb5f6..784b60aef7c136 100644 --- a/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx +++ b/static/app/components/searchQueryBuilder/tokens/filterKeyListBox/useFilterKeyListBox.tsx @@ -394,7 +394,6 @@ export function useFilterKeyListBox({filterValue}: {filterValue: string}) { }); setDisplaySeerResults(true); - // Set flag to auto-submit if there's text in the input if (currentInputValue?.trim()) { setAutoSubmitSeer(true); } else { From bcbabac987111d6d57abe28be648007b4750487f Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Wed, 30 Jul 2025 22:38:17 -0700 Subject: [PATCH 5/7] clean comments --- .../app/views/explore/components/seerComboBox/seerComboBox.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx index a0c2c3baa271f9..7d786d6d8e90d2 100644 --- a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx +++ b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx @@ -94,8 +94,6 @@ function isNoneOfTheseItem(item: SeerSearchItems): item is NoneOfTheseItem { type SeerSearchItems = SeerSearchItem | NoneOfTheseItem; export function SeerComboBox({initialQuery, ...props}: SeerComboBoxProps) { - // console.log('initialQuery', initialQuery); - // console.log('props', props); const buttonRef = useRef(null); const listBoxRef = useRef(null); const popoverRef = useRef(null); From 49854c3e58bffbba8d9e9e00989f874ef19ab764 Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Wed, 30 Jul 2025 22:50:13 -0700 Subject: [PATCH 6/7] remo comment --- .../app/views/explore/components/seerComboBox/seerComboBox.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx index 7d786d6d8e90d2..5b8145ff828195 100644 --- a/static/app/views/explore/components/seerComboBox/seerComboBox.tsx +++ b/static/app/views/explore/components/seerComboBox/seerComboBox.tsx @@ -322,7 +322,6 @@ export function SeerComboBox({initialQuery, ...props}: SeerComboBoxProps) { } }, [state]); - // Auto-submit search when autoSubmitSeer flag is true useLayoutEffect(() => { if (autoSubmitSeer && searchQuery.trim()) { trackAnalytics('trace.explorer.ai_query_submitted', { @@ -330,7 +329,6 @@ export function SeerComboBox({initialQuery, ...props}: SeerComboBoxProps) { natural_language_query: searchQuery.trim(), }); submitQuery(searchQuery.trim()); - // Reset the flag after submitting setAutoSubmitSeer(false); } }, [autoSubmitSeer, searchQuery, organization, submitQuery, setAutoSubmitSeer]); From 4e60780712fc00ac1f8c79a9d21f81d054d3d3da Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Wed, 30 Jul 2025 22:55:06 -0700 Subject: [PATCH 7/7] dont remove if equal --- static/app/views/explore/spans/spansTab.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/app/views/explore/spans/spansTab.tsx b/static/app/views/explore/spans/spansTab.tsx index 5b193a4dd24d69..98f9341ba33706 100644 --- a/static/app/views/explore/spans/spansTab.tsx +++ b/static/app/views/explore/spans/spansTab.tsx @@ -183,8 +183,6 @@ function SpansSearchBar({ if (!committedQuery) return inputValue; - if (committedQuery.includes(inputValue)) return committedQuery; - return `${committedQuery} ${inputValue}`; })();