@@ -7,12 +7,17 @@ import {
77  MetricFindValue , 
88  getDefaultTimeRange , 
99  FieldType , 
10+   CustomVariableSupport , 
11+   DataQueryResponse , 
12+   QueryEditorProps , 
1013}  from  '@grafana/data' ; 
1114import  {  DataSourceWithBackend ,  getTemplateSrv  }  from  '@grafana/runtime' ; 
1215
1316import  {  HaystackQuery ,  OpsQuery ,  HaystackDataSourceOptions ,  HaystackVariableQuery ,  QueryType  }  from  './types' ; 
14- import  {  firstValueFrom  }  from  'rxjs' ; 
17+ import  {  firstValueFrom ,   map ,   Observable  }  from  'rxjs' ; 
1518import  {  isRef ,  parseRef  }  from  'haystack' ; 
19+ import  {  ComponentType  }  from  'react' ; 
20+ import  {  VARIABLE_REF_ID ,  VariableQueryEditor  }  from  'components/VariableQueryEditor' ; 
1621
1722export  const  queryTypes : QueryType [ ]  =  [ 
1823  {  label : 'Eval' ,  value : 'eval' ,  apiRequirements : [ 'eval' ] ,  description : 'Evaluate an Axon expression'  } , 
@@ -29,6 +34,9 @@ export const queryTypes: QueryType[] = [
2934export  class  DataSource  extends  DataSourceWithBackend < HaystackQuery ,  HaystackDataSourceOptions >  { 
3035  constructor ( instanceSettings : DataSourceInstanceSettings < HaystackDataSourceOptions > )  { 
3136    super ( instanceSettings ) ; 
37+     this . variables  =  new  HaystackVariableSupport ( ( request )  =>  { 
38+       return  this . query ( request ) 
39+     } ) ; 
3240  } 
3341
3442  // Queries the available ops from the datasource and returns the queryTypes that are supported. 
@@ -89,48 +97,6 @@ export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDat
8997    } ; 
9098  } 
9199
92-   // This is called when the user is selecting a variable value 
93-   async  metricFindQuery ( variableQuery : HaystackVariableQuery ,  options ?: any )  { 
94-     let  request : HaystackQuery  =  variableQuery ; 
95-     let  observable  =  this . query ( {  targets : [ request ]  }  as  DataQueryRequest < HaystackQuery > ) ; 
96-     let  response  =  await  firstValueFrom ( observable ) ; 
97- 
98-     if  ( response  ===  undefined  ||  response . data  ===  undefined )  { 
99-       return  [ ] ; 
100-     } 
101- 
102-     return  response . data . reduce ( ( acc : MetricFindValue [ ] ,  frame : DataFrame )  =>  { 
103-       // Default to the first field 
104-       let  column  =  frame . fields [ 0 ] ; 
105-       if  ( variableQuery . column  !==  undefined  &&  variableQuery . column  !==  '' )  { 
106-         // If a column was input, match the column name 
107-         column  =  frame . fields . find ( ( field : Field )  =>  field . name  ===  variableQuery . column )  ??  column ; 
108-       }  else  if  ( frame . fields . some ( ( field : Field )  =>  field . name  ===  'id' ) )  { 
109-         // If there is an id column, use that 
110-         column  =  frame . fields . find ( ( field : Field )  =>  field . name  ===  'id' )  ??  column ; 
111-       } 
112- 
113-       // Default to the selected column 
114-       let  displayColumn  =  column ; 
115-       if  ( variableQuery . displayColumn  !==  undefined  &&  variableQuery . displayColumn  !==  '' )  { 
116-         // If a column was input, match the column name 
117-         displayColumn  = 
118-           frame . fields . find ( ( field : Field )  =>  field . name  ===  variableQuery . displayColumn )  ??  displayColumn ; 
119-       } 
120- 
121-       let  variableValues  =  column . values . map ( ( value ,  index )  =>  { 
122-         let  variableValue  =  variableValueFromCell ( value ,  column . type ) ; 
123- 
124-         let  displayValue  =  displayColumn . values [ index ] ; 
125-         let  variableText  =  variableTextFromCell ( displayValue ,  displayColumn . type ) ; 
126- 
127-         return  {  text : variableText ,  value : variableValue  } ; 
128-       } ) ; 
129- 
130-       return  acc . concat ( variableValues ) ; 
131-     } ,  [ ] ) ; 
132-   } 
133- 
134100  // Returns a DataQueryRequest that gets the available ops from the datasource 
135101  // This applies a bunch of defaults because it's not a time series query 
136102  private  opsRequest ( refId : string ) : DataQueryRequest < HaystackQuery >  { 
@@ -150,6 +116,65 @@ export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDat
150116  } 
151117} 
152118
119+ export  class  HaystackVariableSupport  extends  CustomVariableSupport < DataSource ,  HaystackVariableQuery ,  HaystackQuery ,  HaystackDataSourceOptions >  { 
120+   editor : ComponentType < QueryEditorProps < DataSource ,  HaystackQuery ,  HaystackDataSourceOptions ,  HaystackVariableQuery > > ; 
121+ 
122+   // Requests data from the backend. This allows this class to reuse the DataSource.query method to get data. 
123+   onQuery : ( request : DataQueryRequest < HaystackVariableQuery > )  =>  Observable < DataQueryResponse > ; 
124+ 
125+   constructor ( onQuery : ( request : DataQueryRequest < HaystackVariableQuery > )  =>  Observable < DataQueryResponse > )  { 
126+     super ( ) ; 
127+     this . editor  =  VariableQueryEditor ; 
128+     this . onQuery  =  onQuery ; 
129+   } 
130+ 
131+   query ( request : DataQueryRequest < HaystackVariableQuery > ) : Observable < DataQueryResponse >  { 
132+     let  variableQuery  =  request . targets [ 0 ] ; 
133+     variableQuery . refId  =  VARIABLE_REF_ID ; 
134+     let  observable  =  this . onQuery ( request ) ; 
135+     return  observable . pipe ( 
136+       map ( ( response )  =>  { 
137+         if  ( response  ===  undefined  ||  response . errors  !==  undefined  ||  response . data  ===  undefined )  { 
138+           return  response 
139+         } 
140+ 
141+         let  variableValues  =  response . data . reduce ( ( acc : MetricFindValue [ ] ,  frame : DataFrame )  =>  { 
142+           // Default to the first field 
143+           let  column  =  frame . fields [ 0 ] ; 
144+           if  ( variableQuery . column  !==  undefined  &&  variableQuery . column  !==  '' )  { 
145+             // If a column was input, match the column name 
146+             column  =  frame . fields . find ( ( field : Field )  =>  field . name  ===  variableQuery . column )  ??  column ; 
147+           }  else  if  ( frame . fields . some ( ( field : Field )  =>  field . name  ===  'id' ) )  { 
148+             // If there is an id column, use that 
149+             column  =  frame . fields . find ( ( field : Field )  =>  field . name  ===  'id' )  ??  column ; 
150+           } 
151+ 
152+           // Default to the selected column 
153+           let  displayColumn  =  column ; 
154+           if  ( variableQuery . displayColumn  !==  undefined  &&  variableQuery . displayColumn  !==  '' )  { 
155+             // If a column was input, match the column name 
156+             displayColumn  =  frame . fields . find ( ( field : Field )  =>  { 
157+               return  field . name  ===  variableQuery . displayColumn 
158+             } )  ??  displayColumn ; 
159+           } 
160+ 
161+           let  variableValues  =  column . values . map ( ( value ,  index )  =>  { 
162+             let  variableValue  =  variableValueFromCell ( value ,  column . type ) ; 
163+ 
164+             let  displayValue  =  displayColumn . values [ index ] ; 
165+             let  variableText  =  variableTextFromCell ( displayValue ,  displayColumn . type ) ; 
166+ 
167+             return  {  text : variableText ,  value : variableValue  } ; 
168+           } ) ; 
169+           return  acc . concat ( variableValues ) ; 
170+         } ,  [ ] ) ; 
171+         return  {  ...response ,  data : variableValues  } ; 
172+       } ) 
173+     ) ; 
174+   } 
175+ } 
176+ 
177+ 
153178function  variableValueFromCell ( value : string ,  columnType : FieldType ) : string  { 
154179  switch  ( columnType )  { 
155180    case  FieldType . string :
0 commit comments