1- import  React ,  {  ChangeEvent ,   ReactNode  }  from  'react' ; 
2- import  {  AsyncSelect ,   Button ,  Form ,   Icon ,   InlineField ,   Input ,  VerticalGroup  }  from  '@grafana/ui' ; 
3- import  {  DataFrame ,   DataQueryRequest ,   Field ,   getDefaultTimeRange ,   QueryEditorProps ,   SelectableValue ,   Vector  }  from  '@grafana/data' ; 
1+ import  React ,  {   }  from  'react' ; 
2+ import  {  Button ,  Form ,  VerticalGroup  }  from  '@grafana/ui' ; 
3+ import  {  QueryEditorProps  }  from  '@grafana/data' ; 
44import  {  DataSource  }  from  '../datasource' ; 
5- import  {  DEFAULT_QUERY ,  HaystackDataSourceOptions ,  HaystackQuery  }  from  '../types' ; 
5+ import  {  HaystackDataSourceOptions ,  HaystackQuery  }  from  '../types' ; 
6+ import  {  HaystackQueryTypeSelector  }  from  './HaystackQueryTypeSelector' ; 
7+ import  {  HaystackQueryInput  }  from  './HaystackQueryInput' ; 
68
79type  Props  =  QueryEditorProps < DataSource ,  HaystackQuery ,  HaystackDataSourceOptions > ; 
810
9- export  function  QueryEditor ( {  datasource,  query,  onChange,  onRunQuery,  range ,  app  } : Props )  { 
10-   const  onTypeChange  =  ( event :  SelectableValue < string > )  =>  { 
11-     onChange ( {  ...query ,  type : event . value   ??   queryTypeDefault . value !  } ) ; 
11+ export  function  QueryEditor ( {  datasource,  query,  onChange,  onRunQuery } : Props )  { 
12+   const  onTypeChange  =  ( newType :  string )  =>  { 
13+     onChange ( {  ...query ,  type : newType  } ) ; 
1214  } ; 
13-   const  onEvalChange  =  ( event : ChangeEvent < HTMLInputElement > )  =>  { 
14-     onChange ( {  ...query ,  type : 'eval' ,  eval : event . target . value  } ) ; 
15-   } ; 
16-   const  onHisReadChange  =  ( event : ChangeEvent < HTMLInputElement > )  =>  { 
17-     onChange ( {  ...query ,  type : 'hisRead' ,  hisRead : event . target . value  } ) ; 
18-   } ; 
19-   const  onReadChange  =  ( event : ChangeEvent < HTMLInputElement > )  =>  { 
20-     onChange ( {  ...query ,  type : 'read' ,  read : event . target . value  } ) ; 
21-   } ; 
22- 
23-   interface  QueryType  extends  SelectableValue < string >  { 
24-     apiRequirements : string [ ] ; 
25-   }  
26- 
27-   const  queryTypes : QueryType [ ]  =  [ 
28-     {  label : 'Read' ,  value : "read" ,  apiRequirements : [ "read" ] ,  description : 'Read the records matched by a filter'  } , 
29-     {  label : 'HisRead' ,  value : "hisRead" ,  apiRequirements : [ "hisRead" ] ,  description : 'Read the history of a point'  } , 
30-     {  label : 'Eval' ,  value : "eval" ,  apiRequirements : [ "eval" ] ,  description : 'Evaluate an Axon expression'  } , 
31-   ] ; 
32-   const  queryTypeDefault  =  queryTypes [ 0 ] ; 
33-   function  queryTypeFromLabel ( label : string )  { 
34-     return  queryTypes . find ( ( queryType )  =>  queryType . value  ===  label ) ; 
35-   } 
36- 
37-   const  SelectComponent  =  ( )  =>  { 
38-     return  ( 
39-       < InlineField  label = "Type" > 
40-         < AsyncSelect 
41-           loadOptions = { loadOps } 
42-           defaultOptions 
43-           value = { queryTypeFromLabel ( query . type ) } 
44-           width = { 30 } 
45-           onChange = { ( queryType )  =>  { 
46-             onTypeChange ( queryType ) ; 
47-           } } 
48-         /> 
49-       </ InlineField > 
50-     ) ; 
51-   } ; 
52- 
53-   // Queries the available ops from the datasource on only returns the ones that are supported. 
54-   const  loadOps  =  ( )  =>  { 
55-     let  opsRequest : DataQueryRequest < HaystackQuery >  =  { 
56-       requestId : 'ops' , 
57-       dashboardId : 0 , 
58-       interval : '0' , 
59-       intervalMs : 0 , 
60-       panelId : 0 , 
61-       range : range  ??  getDefaultTimeRange ( ) , 
62-       scopedVars : { } , 
63-       targets : [ {  type : 'ops'  ,  eval : "" ,  read : "" ,  hisRead : "" ,  refId : query . refId } ] , 
64-       timezone : 'UTC' , 
65-       app : 'ops' , 
66-       startTime : 0 , 
15+   const  onQueryChange  =  ( newQuery : string )  =>  { 
16+     if  ( query . type  ===  "hisRead" )  { 
17+       onChange ( {  ...query ,  hisRead : newQuery  } ) ; 
18+     }  else  if  ( query . type  ===  "eval" )  { 
19+       onChange ( {  ...query ,  eval : newQuery  } ) ; 
20+     }  else  if  ( query . type  ===  "read" )  { 
21+       onChange ( {  ...query ,  read : newQuery  } ) ; 
6722    } 
68-     return  datasource . query ( opsRequest ) . toPromise ( ) . then ( ( result )  =>  { 
69-       if ( result ?. state  ===  'Error' )  { 
70-         return  [ ] ; 
71-       } 
72-       let  frame  =  result ?. data ?. find ( ( frame : DataFrame )  =>  { 
73-         return  frame . refId  ===  query . refId 
74-       } ) 
75-       let  opSymbols  =  frame ?. fields ?. find ( ( field : Field < any ,  Vector < string > > )  =>  { 
76-         return  field . name  ===  'def' 
77-       } ) . values  ??  [ ] ; 
78-       let  ops : string [ ]  =  opSymbols . map ( ( opSymbol : string )  =>  { 
79-         if  ( opSymbol . startsWith ( '^op:' ) )  { 
80-           return  opSymbol . substring ( 4 ) ; 
81-         }  else  { 
82-           return  opSymbol ; 
83-         } 
84-       } ) ; 
85- 
86-       return  queryTypes . filter ( ( queryType )  =>  { 
87-         return  queryType . apiRequirements . every ( ( apiRequirement )  =>  { 
88-           return  ops . find ( ( op )  =>  { 
89-             return  op  ===  apiRequirement 
90-           } )  !==  undefined ; 
91-         } ) ; 
92-       } ) ; 
93-     } ) ; 
94-   } 
95- 
96-   function  renderQuery ( ) : ReactNode  { 
97-     let  width  =  100 ; 
98-     let  queryType  =  queryTypeFromLabel ( query . type ) ; 
99-     switch  ( queryType ?. value )  { 
100-       case  "eval" :
101-         return  ( 
102-           < InlineField > 
103-             < Input 
104-               width = { width } 
105-               prefix = { < Icon  name = "angle-right"  /> } 
106-               onChange = { onEvalChange } 
107-               value = { query . eval } 
108-               placeholder = { DEFAULT_QUERY . eval } 
109-             /> 
110-           </ InlineField > 
111-         ) ; 
112-       case  "hisRead" :
113-         return  ( 
114-           < InlineField > 
115-             < Input 
116-               width = { width } 
117-               prefix = { '@' } 
118-               onChange = { onHisReadChange } 
119-               value = { query . hisRead } 
120-               placeholder = { DEFAULT_QUERY . hisRead } 
121-             /> 
122-           </ InlineField > 
123-         ) ; 
124-       case  "read" :
125-         return  ( 
126-           < InlineField > 
127-             < Input 
128-               width = { width } 
129-               prefix = { < Icon  name = "filter"  /> } 
130-               onChange = { onReadChange } 
131-               value = { query . read } 
132-               placeholder = { DEFAULT_QUERY . read } 
133-             /> 
134-           </ InlineField > 
135-         ) ; 
136-     } 
137-     return  < p > Select a query type</ p > ; 
138-   } 
23+   } ; 
13924
14025  function  onSubmit ( newQuery : Partial < HaystackQuery > )  { 
14126    query  =  {  ...query ,  ...newQuery  } ; 
@@ -149,8 +34,16 @@ export function QueryEditor({ datasource, query, onChange, onRunQuery, range, ap
14934        { ( {  register,  errors } )  =>  { 
15035          return  ( 
15136            < VerticalGroup > 
152-               < SelectComponent  /> 
153-               { renderQuery ( ) } 
37+               < HaystackQueryTypeSelector 
38+                 datasource = { datasource } 
39+                 type = { query . type } 
40+                 refId = { query . refId } 
41+                 onChange = { onTypeChange } 
42+               /> 
43+               < HaystackQueryInput 
44+                 query = { query } 
45+                 onChange = { onQueryChange } 
46+               /> 
15447              < Button  type = "submit"  > Run</ Button > 
15548            </ VerticalGroup > 
15649          ) ; 
0 commit comments