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
1616import cx from 'classnames' ;
1717import TextareaAutosize from 'react-textarea-autosize' ;
1818
19- import { LabelsRequest , LabelsResponse , QueryServiceClient } from '@parca/client' ;
19+ import { LabelsRequest , LabelsResponse , QueryServiceClient , ValuesRequest } from '@parca/client' ;
2020import { useGrpcMetadata } from '@parca/components' ;
2121import { Query } from '@parca/parser' ;
2222import { millisToProtoTimestamp , sanitizeLabelValue } from '@parca/utilities' ;
@@ -75,6 +75,42 @@ export const useLabelNames = (
7575 return { result : { response : data , error : error as Error } , loading : isLoading } ;
7676} ;
7777
78+ interface UseLabelValues {
79+ result : {
80+ response : string [ ] ;
81+ error ?: Error ;
82+ } ;
83+ loading : boolean ;
84+ }
85+
86+ export const useLabelValues = (
87+ client : QueryServiceClient ,
88+ labelName : string ,
89+ profileType : string
90+ ) : UseLabelValues => {
91+ const metadata = useGrpcMetadata ( ) ;
92+
93+ const { data, isLoading, error} = useGrpcQuery < string [ ] > ( {
94+ key : [ 'labelValues' , labelName , profileType ] ,
95+ queryFn : async ( ) => {
96+ const request : ValuesRequest = { labelName, match : [ ] , profileType} ;
97+ const { response} = await client . values ( request , { meta : metadata } ) ;
98+ return sanitizeLabelValue ( response . labelValues ) ;
99+ } ,
100+ options : {
101+ enabled :
102+ profileType !== undefined &&
103+ profileType !== '' &&
104+ labelName !== undefined &&
105+ labelName !== '' ,
106+ staleTime : 1000 * 60 * 5 , // 5 minutes
107+ keepPreviousData : false ,
108+ } ,
109+ } ) ;
110+
111+ return { result : { response : data ?? [ ] , error : error as Error } , loading : isLoading } ;
112+ } ;
113+
78114const MatchersInput = ( {
79115 queryClient,
80116 setMatchersString,
@@ -84,34 +120,16 @@ const MatchersInput = ({
84120} : MatchersInputProps ) : JSX . Element => {
85121 const inputRef = useRef < HTMLTextAreaElement | null > ( null ) ;
86122 const [ focusedInput , setFocusedInput ] = useState ( false ) ;
87- const [ labelValuesLoading , setLabelValuesLoading ] = useState ( false ) ;
88123 const [ lastCompleted , setLastCompleted ] = useState < Suggestion > ( new Suggestion ( '' , '' , '' ) ) ;
89- const [ labelValues , setLabelValues ] = useState < string [ ] | null > ( null ) ;
90124 const [ currentLabelName , setCurrentLabelName ] = useState < string | null > ( null ) ;
91- const metadata = useGrpcMetadata ( ) ;
92125
93126 const { loading : labelNamesLoading , result} = useLabelNames ( queryClient , profileType ) ;
94127 const { response : labelNamesResponse , error : labelNamesError } = result ;
95128
96- useEffect ( ( ) => {
97- if ( currentLabelName !== null ) {
98- const call = queryClient . values (
99- { labelName : currentLabelName , match : [ ] , profileType} ,
100- { meta : metadata }
101- ) ;
102- setLabelValuesLoading ( true ) ;
103-
104- call . response
105- . then ( response => {
106- // replace single `\` in the `labelValues` string with doubles `\\` if available.
107- const newValues = sanitizeLabelValue ( response . labelValues ) ;
108-
109- return setLabelValues ( newValues ) ;
110- } )
111- . catch ( ( ) => setLabelValues ( null ) )
112- . finally ( ( ) => setLabelValuesLoading ( false ) ) ;
113- }
114- } , [ currentLabelName , metadata , profileType , queryClient ] ) ;
129+ const {
130+ loading : labelValuesLoading ,
131+ result : { response : labelValues } ,
132+ } = useLabelValues ( queryClient , currentLabelName ?? '' , profileType ) ;
115133
116134 const labelNames = useMemo ( ( ) => {
117135 return ( labelNamesError === undefined || labelNamesError == null ) &&
0 commit comments