1
- import React from 'react' ;
2
- import { ChangeEvent , useState } from 'react' ;
1
+ import React , { ChangeEvent , useState } from 'react' ;
3
2
import {
4
3
Button ,
5
4
InlineField ,
@@ -9,17 +8,15 @@ import {
9
8
InlineSwitch ,
10
9
Modal ,
11
10
useTheme2 ,
12
- Tooltip ,
13
11
} from '@grafana/ui' ;
14
12
import { EditorHeader , InlineSelect , FlexItem } from '@grafana/plugin-ui' ;
15
- import { CoreApp , QueryEditorProps , SelectableValue } from '@grafana/data' ;
13
+ import { CoreApp , QueryEditorProps , SelectableValue , LoadingState } from '@grafana/data' ;
16
14
import { DataSource } from '../datasource' ;
17
15
import { MongoDataSourceOptions , MongoQuery , QueryLanguage , QueryType , DEFAULT_QUERY } from '../types' ;
18
16
import { parseJsQuery , parseJsQueryLegacy } from '../utils' ;
19
17
import { QueryEditorRaw } from './QueryEditorRaw' ;
20
18
import { QueryToolbox } from './QueryToolbox' ;
21
19
import validator from 'validator' ;
22
- import './QueryEditor.css' ;
23
20
24
21
type Props = QueryEditorProps < DataSource , MongoQuery , MongoDataSourceOptions > ;
25
22
@@ -43,32 +40,14 @@ const languageOptions: Array<SelectableValue<string>> = [
43
40
] ;
44
41
45
42
export function QueryEditor ( props : Props ) {
46
- const { query, app, onRunQuery } = props ;
43
+ const { query, app, data , onRunQuery } = props ;
47
44
48
45
const theme = useTheme2 ( ) ;
49
46
50
47
const [ queryTextError , setQueryTextError ] = useState < string | null > ( null ) ;
51
48
const [ isAggregateOptionExpanded , setIsAggregateOptionExpanded ] = useState ( false ) ;
52
49
const [ isEditorExpanded , setIsEditorExpanded ] = useState ( false ) ;
53
50
54
-
55
- const renderRunButton = ( isQueryRunnable : boolean ) => {
56
- if ( isQueryRunnable ) {
57
- return (
58
- < Button icon = "play" variant = "primary" size = "sm" onClick = { ( ) => onRunQuery ( ) } >
59
- Run query
60
- </ Button >
61
- ) ;
62
- }
63
- return (
64
- < Tooltip theme = "error" content = { < > Your query is invalid. Check below for details.</ > } placement = "top" >
65
- < Button icon = "exclamation-triangle" variant = "secondary" size = "sm" onClick = { onRunQuery } >
66
- Run query
67
- </ Button >
68
- </ Tooltip >
69
- ) ;
70
- } ;
71
-
72
51
const renderCodeEditor = ( showTools : boolean , width ?: number , height ?: number ) => {
73
52
return (
74
53
< >
@@ -88,21 +67,34 @@ export function QueryEditor(props: Props) {
88
67
placeholder = "Select query language"
89
68
options = { languageOptions }
90
69
value = { query . queryLanguage }
91
- onChange = { val => props . onChange ( { ...query , queryLanguage : val . value } ) }
70
+ onChange = { ( val ) => props . onChange ( { ...query , queryLanguage : val . value } ) }
92
71
/>
93
72
< FlexItem grow = { 1 } />
94
- { renderRunButton ( true ) }
73
+ { ! query . isStreaming && (
74
+ < Button
75
+ icon = "play"
76
+ variant = "primary"
77
+ size = "sm"
78
+ onClick = { ( ) => onRunQuery ( ) }
79
+ disabled = { data ?. state === LoadingState . Loading }
80
+ >
81
+ Run query
82
+ </ Button >
83
+ ) }
95
84
</ EditorHeader >
96
85
) }
97
86
< QueryEditorRaw
98
- query = { query . queryText || '' }
87
+ query = { query . queryText ?? '' }
99
88
language = {
100
89
query . queryLanguage === QueryLanguage . JAVASCRIPT || query . queryLanguage === QueryLanguage . JAVASCRIPT_SHADOW
101
90
? 'javascript'
102
91
: 'json'
103
92
}
104
93
onBlur = { ( queryText : string ) => {
105
- if ( query . queryLanguage === QueryLanguage . JAVASCRIPT || query . queryLanguage === QueryLanguage . JAVASCRIPT_SHADOW ) {
94
+ if (
95
+ query . queryLanguage === QueryLanguage . JAVASCRIPT ||
96
+ query . queryLanguage === QueryLanguage . JAVASCRIPT_SHADOW
97
+ ) {
106
98
// parse the JavaScript query
107
99
const { error, collection } =
108
100
query . queryLanguage === QueryLanguage . JAVASCRIPT_SHADOW
@@ -114,7 +106,7 @@ export function QueryEditor(props: Props) {
114
106
} else {
115
107
props . onChange ( { ...query , queryText : queryText } ) ;
116
108
if ( ! validator . isJSON ( queryText ) ) {
117
- setQueryTextError ( " Query should be a valid JSON" )
109
+ setQueryTextError ( ' Query should be a valid JSON' ) ;
118
110
} else {
119
111
setQueryTextError ( null ) ;
120
112
}
@@ -163,25 +155,30 @@ export function QueryEditor(props: Props) {
163
155
< >
164
156
< InlineFieldRow >
165
157
< InlineField
166
- label = "Collection" error = "Collection is required"
158
+ label = "Collection"
159
+ error = "Collection is required"
167
160
invalid = { query . queryLanguage !== QueryLanguage . JAVASCRIPT && ! query . collection }
168
161
tooltip = "Name of MongoDB collection to query"
169
162
>
170
163
< Input
171
- width = { 25 } id = "query-editor-collection" value = { query . collection }
172
- onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => props . onChange ( { ...query , collection : evt . target . value } ) }
164
+ width = { 25 }
165
+ id = "query-editor-collection"
166
+ value = { query . collection }
167
+ onChange = { ( evt : ChangeEvent < HTMLInputElement > ) =>
168
+ props . onChange ( { ...query , collection : evt . target . value } )
169
+ }
173
170
disabled = { query . queryLanguage === QueryLanguage . JAVASCRIPT }
174
171
/>
175
172
</ InlineField >
176
- { app !== CoreApp . Explore && < InlineField label = "Streaming" tooltip = "Watch MongoDB change streams" >
177
- < InlineSwitch
178
- id = "query-editor-collection-streaming"
179
- value = { query . isStreaming === true }
180
- onChange = { evt => props . onChange ( { ... query , isStreaming : evt . currentTarget . checked } ) }
181
- />
182
- </ InlineField >
183
- }
184
-
173
+ { app !== CoreApp . Explore && (
174
+ < InlineField label = "Streaming" tooltip = "(Experimental) Watch MongoDB change streams" >
175
+ < InlineSwitch
176
+ id = "query-editor-collection-streaming"
177
+ value = { query . isStreaming === true }
178
+ onChange = { ( evt ) => props . onChange ( { ... query , isStreaming : evt . currentTarget . checked } ) }
179
+ / >
180
+ </ InlineField >
181
+ ) }
185
182
</ InlineFieldRow >
186
183
{ isEditorExpanded ? renderPlaceholder ( ) : renderCodeEditor ( true , undefined , 300 ) }
187
184
@@ -196,7 +193,8 @@ export function QueryEditor(props: Props) {
196
193
tooltip = "The maximum amount of time that the query can run on the server. The default value is nil, meaning that there is no time limit for query execution."
197
194
>
198
195
< Input
199
- id = "query-editor-max-time-ms" value = { query . aggregateMaxTimeMS }
196
+ id = "query-editor-max-time-ms"
197
+ value = { query . aggregateMaxTimeMS }
200
198
onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => {
201
199
if ( ! evt . target . value ) {
202
200
props . onChange ( { ...query , aggregateMaxTimeMS : undefined } ) ;
@@ -210,33 +208,41 @@ export function QueryEditor(props: Props) {
210
208
label = "Max await time(ms)"
211
209
tooltip = "The maximum amount of time that the server should wait for new documents to satisfy a tailable cursor query."
212
210
>
213
- < Input id = "query-editor-max-await-time-ms" value = { query . aggregateMaxAwaitTime }
211
+ < Input
212
+ id = "query-editor-max-await-time-ms"
213
+ value = { query . aggregateMaxAwaitTime }
214
214
onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => {
215
215
if ( ! evt . target . value ) {
216
216
props . onChange ( { ...query , aggregateMaxAwaitTime : undefined } ) ;
217
217
} else if ( validator . isInt ( evt . target . value , { gt : 0 } ) ) {
218
218
props . onChange ( { ...query , aggregateMaxAwaitTime : parseInt ( evt . target . value , 10 ) } ) ;
219
219
}
220
- } } />
220
+ } }
221
+ />
221
222
</ InlineField >
222
223
</ InlineFieldRow >
223
224
< InlineFieldRow >
224
225
< InlineField
225
226
label = "Comment"
226
227
tooltip = "A string that will be included in server logs, profiling logs, and currentOp queries to help trace the operation."
227
228
>
228
- < Input id = "query-editor-comment" value = { query . aggregateComment }
229
+ < Input
230
+ id = "query-editor-comment"
231
+ value = { query . aggregateComment }
229
232
onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => {
230
233
if ( evt . target . value ) {
231
234
props . onChange ( { ...query , aggregateComment : evt . target . value } ) ;
232
235
}
233
- } } />
236
+ } }
237
+ />
234
238
</ InlineField >
235
239
< InlineField
236
240
label = "Batch size"
237
241
tooltip = "The maximum number of documents to be included in each batch returned by the server."
238
242
>
239
- < Input id = "query-editor-batch-size" value = { query . aggregateBatchSize }
243
+ < Input
244
+ id = "query-editor-batch-size"
245
+ value = { query . aggregateBatchSize }
240
246
onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => {
241
247
if ( validator . isInt ( evt . target . value , { gt : 0 } ) ) {
242
248
props . onChange ( { ...query , aggregateBatchSize : parseInt ( evt . target . value , 10 ) } ) ;
@@ -251,17 +257,23 @@ export function QueryEditor(props: Props) {
251
257
tooltip = "If true, the operation can write to temporary files in the _tmp subdirectory of the database directory path on the server. The default value is false."
252
258
>
253
259
< InlineSwitch
254
- id = "query-editor-allow-disk-use" value = { query . aggregateAllowDiskUse }
255
- onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => props . onChange ( { ...query , aggregateAllowDiskUse : evt . target . checked } ) }
260
+ id = "query-editor-allow-disk-use"
261
+ value = { query . aggregateAllowDiskUse }
262
+ onChange = { ( evt : ChangeEvent < HTMLInputElement > ) =>
263
+ props . onChange ( { ...query , aggregateAllowDiskUse : evt . target . checked } )
264
+ }
256
265
/>
257
266
</ InlineField >
258
267
< InlineField
259
268
label = "Bypass document validation"
260
269
tooltip = "If true, writes executed as part of the operation will opt out of document-level validation on the server. This option is valid for MongoDB versions >= 3.2 and is ignored for previous server versions. The default value is false."
261
270
>
262
271
< InlineSwitch
263
- id = "query-editor-bypass-document-validation" value = { query . aggregateBypassDocumentValidation }
264
- onChange = { ( evt : ChangeEvent < HTMLInputElement > ) => props . onChange ( { ...query , aggregateBypassDocumentValidation : evt . target . checked } ) }
272
+ id = "query-editor-bypass-document-validation"
273
+ value = { query . aggregateBypassDocumentValidation }
274
+ onChange = { ( evt : ChangeEvent < HTMLInputElement > ) =>
275
+ props . onChange ( { ...query , aggregateBypassDocumentValidation : evt . target . checked } )
276
+ }
265
277
/>
266
278
</ InlineField >
267
279
</ InlineFieldRow >
0 commit comments