11import { css } from '@emotion/css' ;
22
33import React , { createContext } from 'react' ;
4+ import { debounceTime , throttleTime } from 'rxjs' ;
5+ import { useObservableCallback , useSubscription } from 'observable-hooks'
46
57import { CoreApp , Field , getDefaultTimeRange , GrafanaTheme2 , QueryEditorProps } from '@grafana/data' ;
68import { InlineLabel , useStyles2 } from '@grafana/ui' ;
@@ -34,7 +36,7 @@ export const QueryEditor = ({ query, onChange, onRunQuery, datasource, range, ap
3436 query = { query }
3537 range = { range || getDefaultTimeRange ( ) }
3638 >
37- < QueryEditorForm value = { query } />
39+ < QueryEditorForm value = { query } onRunQuery = { onRunQuery } />
3840 </ ElasticsearchProvider >
3941 ) ;
4042} ;
@@ -54,21 +56,33 @@ export const useSearchableFields = getHook(SearchableFieldsContext)
5456
5557interface Props {
5658 value : ElasticsearchQuery ;
59+ onRunQuery : ( ) => void
5760}
5861
59- export const ElasticSearchQueryField = ( { value, onChange } : { value ?: string ; onChange : ( v : string ) => void } ) => {
62+ type ElasticSearchQueryFieldProps = {
63+ value ?: string ;
64+ onChange : ( v : string ) => void
65+ onSubmit : ( v : string ) => void
66+ }
67+ export const ElasticSearchQueryField = ( { value, onChange, onSubmit } : ElasticSearchQueryFieldProps ) => {
6068 const styles = useStyles2 ( getStyles ) ;
6169 const datasource = useDatasource ( )
6270 const { getSuggestions } = useDatasourceFields ( datasource ) ;
6371
6472 return (
6573 < div className = { styles . queryItem } >
66- < LuceneQueryEditor placeholder = "Enter a lucene query" value = { value || '' } autocompleter = { getSuggestions } onChange = { onChange } />
74+ < LuceneQueryEditor
75+ placeholder = "Enter a lucene query - Type Shift-Enter to run query, Ctrl-Space to autocomplete"
76+ value = { value || '' }
77+ autocompleter = { getSuggestions }
78+ onChange = { onChange }
79+ onSubmit = { onSubmit }
80+ />
6781 </ div >
6882 ) ;
6983} ;
7084
71- const QueryEditorForm = ( { value } : Props ) => {
85+ const QueryEditorForm = ( { value, onRunQuery } : Props ) => {
7286 const dispatch = useDispatch ( ) ;
7387 const nextId = useNextId ( ) ;
7488 const styles = useStyles2 ( getStyles ) ;
@@ -77,6 +91,20 @@ const QueryEditorForm = ({ value }: Props) => {
7791 ( metric ) => metricAggregationConfig [ metric . type ] . impliedQueryType === 'metrics'
7892 ) ;
7993
94+ const onChange = ( query : string ) => {
95+ dispatch ( changeQuery ( query ) )
96+ }
97+ const onSubmit = ( query : string ) => {
98+ onChange ( query )
99+ onRunQuery ( )
100+ }
101+
102+ const [ onChangeCB , textChanged$ ] = useObservableCallback < string > ( event$ => event$ . pipe ( debounceTime ( 1000 ) ) )
103+ const [ onSubmitCB , submitted$ ] = useObservableCallback < string > ( event$ => event$ . pipe ( throttleTime ( 500 ) ) )
104+
105+ useSubscription ( textChanged$ , onChange )
106+ useSubscription ( submitted$ , onSubmit )
107+
80108 return (
81109 < >
82110 < div className = { styles . root } >
@@ -87,7 +115,10 @@ const QueryEditorForm = ({ value }: Props) => {
87115 </ div >
88116 < div className = { styles . root } >
89117 < InlineLabel width = { 17 } > Lucene Query</ InlineLabel >
90- < ElasticSearchQueryField onChange = { ( query ) => dispatch ( changeQuery ( query ) ) } value = { value ?. query } />
118+ < ElasticSearchQueryField
119+ onChange = { onChangeCB }
120+ value = { value ?. query }
121+ onSubmit = { onSubmitCB } />
91122 </ div >
92123
93124 < MetricAggregationsEditor nextId = { nextId } />
0 commit comments