1111// See the License for the specific language governing permissions and
1212// limitations under the License.
1313
14- import React , { useEffect , useMemo , useRef , useState } from 'react' ;
14+ import React , { useMemo , useRef , useState } from 'react' ;
1515
16- import { useQuery } from '@tanstack/react-query' ;
1716import cx from 'classnames' ;
1817import TextareaAutosize from 'react-textarea-autosize' ;
1918
20- import { LabelsRequest , LabelsResponse , QueryServiceClient , ValuesRequest } from '@parca/client' ;
21- import { useGrpcMetadata } from '@parca/components' ;
2219import { Query } from '@parca/parser' ;
2320import { TEST_IDS , testId } from '@parca/test-utils' ;
24- import { millisToProtoTimestamp , sanitizeLabelValue } from '@parca/utilities' ;
2521
26- import { UtilizationLabels } from '../ProfileSelector' ;
27- import { LabelsProvider , useLabels } from '../contexts/MatchersInputLabelsContext' ;
28- import useGrpcQuery from '../useGrpcQuery' ;
22+ import { useUnifiedLabels } from '../contexts/UnifiedLabelsContext' ;
23+ import { useQueryState } from '../hooks/useQueryState' ;
2924import SuggestionsList , { Suggestion , Suggestions } from './SuggestionsList' ;
3025
31- interface MatchersInputProps {
32- queryClient : QueryServiceClient ;
33- setMatchersString : ( arg : string ) => void ;
34- runQuery : ( ) => void ;
35- currentQuery : Query ;
36- profileType : string ;
37- start ?: number ;
38- end ?: number ;
39- }
40-
41- export interface ILabelNamesResult {
42- response ?: LabelsResponse ;
43- error ?: Error ;
44- }
45-
46- interface UseLabelNames {
47- result : ILabelNamesResult ;
48- loading : boolean ;
49- refetch : ( ) => Promise < void > ;
50- }
51-
52- export const useLabelNames = (
53- client : QueryServiceClient ,
54- profileType : string ,
55- start ?: number ,
56- end ?: number ,
57- match ?: string [ ]
58- ) : UseLabelNames => {
59- const metadata = useGrpcMetadata ( ) ;
60-
61- const { data, isLoading, error, refetch} = useGrpcQuery < LabelsResponse > ( {
62- key : [ 'labelNames' , profileType , match ?. join ( ',' ) , start , end ] ,
63- queryFn : async signal => {
64- const request : LabelsRequest = { match : match !== undefined ? match : [ ] } ;
65- if ( start !== undefined && end !== undefined ) {
66- request . start = millisToProtoTimestamp ( start ) ;
67- request . end = millisToProtoTimestamp ( end ) ;
68- }
69- if ( profileType !== undefined ) {
70- request . profileType = profileType ;
71- }
72- const { response} = await client . labels ( request , { meta : metadata , abort : signal } ) ;
73- return response ;
74- } ,
75- options : {
76- enabled : profileType !== undefined && profileType !== '' ,
77- keepPreviousData : false ,
78- } ,
79- } ) ;
80-
81- useEffect ( ( ) => {
82- console . log ( 'Label names query result:' , { data, error, isLoading} ) ;
83- } , [ data , error , isLoading ] ) ;
84-
85- return {
86- result : { response : data , error : error as Error } ,
87- loading : isLoading ,
88- refetch : async ( ) => {
89- await refetch ( ) ;
90- } ,
91- } ;
92- } ;
93-
94- interface UseLabelValues {
95- result : {
96- response : string [ ] ;
97- error ?: Error ;
98- } ;
99- loading : boolean ;
100- refetch : ( ) => Promise < void > ;
101- }
102-
103- export const useLabelValues = (
104- client : QueryServiceClient ,
105- labelName : string ,
106- profileType : string ,
107- start ?: number ,
108- end ?: number
109- ) : UseLabelValues => {
110- const metadata = useGrpcMetadata ( ) ;
111-
112- const { data, isLoading, error, refetch} = useGrpcQuery < string [ ] > ( {
113- key : [ 'labelValues' , labelName , profileType , start , end ] ,
114- queryFn : async signal => {
115- const request : ValuesRequest = { labelName, match : [ ] , profileType} ;
116- if ( start !== undefined && end !== undefined ) {
117- request . start = millisToProtoTimestamp ( start ) ;
118- request . end = millisToProtoTimestamp ( end ) ;
119- }
120- const { response} = await client . values ( request , { meta : metadata , abort : signal } ) ;
121- return sanitizeLabelValue ( response . labelValues ) ;
122- } ,
123- options : {
124- enabled :
125- profileType !== undefined &&
126- profileType !== '' &&
127- labelName !== undefined &&
128- labelName !== '' ,
129- keepPreviousData : false ,
130- } ,
131- } ) ;
132-
133- console . log ( 'Label values query result:' , { data, error, isLoading, labelName} ) ;
134-
135- return {
136- result : { response : data ?? [ ] , error : error as Error } ,
137- loading : isLoading ,
138- refetch : async ( ) => {
139- await refetch ( ) ;
140- } ,
141- } ;
142- } ;
143-
144- export const useFetchUtilizationLabelValues = (
145- labelName : string ,
146- utilizationLabels ?: UtilizationLabels
147- ) : string [ ] => {
148- const { data} = useQuery ( {
149- queryKey : [ 'utilizationLabelValues' , labelName ] ,
150- queryFn : async ( ) => {
151- const result = await utilizationLabels ?. utilizationFetchLabelValues ?.( labelName ) ;
152- return result ?? [ ] ;
153- } ,
154- enabled : utilizationLabels ?. utilizationFetchLabelValues != null && labelName !== '' ,
155- } ) ;
156-
157- return data ?? [ ] ;
158- } ;
159-
160- const MatchersInput = ( {
161- setMatchersString,
162- runQuery,
163- currentQuery,
164- } : MatchersInputProps ) : JSX . Element => {
26+ const MatchersInput = ( ) : JSX . Element => {
16527 const inputRef = useRef < HTMLTextAreaElement | null > ( null ) ;
16628 const [ focusedInput , setFocusedInput ] = useState ( false ) ;
16729 const [ lastCompleted , setLastCompleted ] = useState < Suggestion > ( new Suggestion ( '' , '' , '' ) ) ;
16830
16931 const {
17032 labelNames,
17133 labelValues,
172- labelNameMappings,
34+ labelNameMappingsForMatchersInput : labelNameMappings ,
17335 isLabelNamesLoading,
17436 isLabelValuesLoading,
17537 currentLabelName,
17638 setCurrentLabelName,
17739 shouldHandlePrefixes,
17840 refetchLabelValues,
17941 refetchLabelNames,
180- } = useLabels ( ) ;
42+ suffix,
43+ } = useUnifiedLabels ( ) ;
44+
45+ const { setDraftMatchers, commitDraft, draftParsedQuery} = useQueryState ( { suffix} ) ;
18146
182- const value = currentQuery . matchersString ( ) ;
47+ const value = draftParsedQuery != null ? draftParsedQuery . matchersString ( ) : '' ;
18348
18449 const suggestionSections = useMemo ( ( ) => {
18550 const suggestionSections = new Suggestions ( ) ;
186- Query . suggest ( `${ currentQuery . profileName ( ) } {${ value } ` ) . forEach ( function ( s ) {
51+ Query . suggest ( `${ draftParsedQuery ? .profileName ( ) as string } {${ value } ` ) . forEach ( function ( s ) {
18752 // Skip suggestions that we just completed. This really only works,
18853 // because we know the language is not repetitive. For a language that
18954 // has a repeating word, this would not work.
@@ -256,7 +121,7 @@ const MatchersInput = ({
256121 } ) ;
257122 return suggestionSections ;
258123 } , [
259- currentQuery ,
124+ draftParsedQuery ,
260125 lastCompleted ,
261126 labelNames ,
262127 labelValues ,
@@ -271,7 +136,7 @@ const MatchersInput = ({
271136
272137 const onChange = ( e : React . ChangeEvent < HTMLTextAreaElement > ) : void => {
273138 const newValue = e . target . value ;
274- setMatchersString ( newValue ) ;
139+ setDraftMatchers ( newValue ) ;
275140 resetLastCompleted ( ) ;
276141 } ;
277142
@@ -294,7 +159,7 @@ const MatchersInput = ({
294159 const applySuggestion = ( suggestion : Suggestion ) : void => {
295160 const newValue = complete ( suggestion ) ;
296161 setLastCompleted ( suggestion ) ;
297- setMatchersString ( newValue ) ;
162+ setDraftMatchers ( newValue ) ;
298163 if ( inputRef . current !== null ) {
299164 inputRef . current . value = newValue ;
300165 inputRef . current . focus ( ) ;
@@ -309,7 +174,7 @@ const MatchersInput = ({
309174 setFocusedInput ( false ) ;
310175 } ;
311176
312- const profileSelected = currentQuery . profileName ( ) === '' ;
177+ const profileSelected = draftParsedQuery ? .profileName ( ) === '' ;
313178
314179 return (
315180 < div
@@ -345,7 +210,7 @@ const MatchersInput = ({
345210 suggestions = { suggestionSections }
346211 applySuggestion = { applySuggestion }
347212 inputRef = { inputRef . current }
348- runQuery = { runQuery }
213+ runQuery = { commitDraft }
349214 focusedInput = { focusedInput }
350215 isLabelValuesLoading = {
351216 isLabelValuesLoading && lastCompleted . type === 'literal' && lastCompleted . value !== ','
@@ -358,15 +223,4 @@ const MatchersInput = ({
358223 ) ;
359224} ;
360225
361- export default function MatchersInputWithProvider ( props : MatchersInputProps ) : JSX . Element {
362- return (
363- < LabelsProvider
364- queryClient = { props . queryClient }
365- profileType = { props . profileType }
366- start = { props . start }
367- end = { props . end }
368- >
369- < MatchersInput { ...props } />
370- </ LabelsProvider >
371- ) ;
372- }
226+ export default MatchersInput ;
0 commit comments