diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx index 7791a248702..f98a203a575 100644 --- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx +++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx @@ -1,6 +1,7 @@ import { css } from '@emotion/css'; import React, { useRef, useEffect } from 'react'; import { useLatest } from 'react-use'; +import { v4 as uuidv4 } from 'uuid'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; @@ -78,10 +79,10 @@ const getStyles = (theme: GrafanaTheme2) => { }; const MonacoQueryField = ({ languageProvider, history, onBlur, onRunQuery, initialValue }: Props) => { + const id = uuidv4(); // we need only one instance of `overrideServices` during the lifetime of the react component const overrideServicesRef = useRef(getOverrideServices()); const containerRef = useRef(null); - const langProviderRef = useLatest(languageProvider); const historyRef = useLatest(history); const onRunQueryRef = useLatest(onRunQuery); @@ -115,8 +116,11 @@ const MonacoQueryField = ({ languageProvider, history, onBlur, onRunQuery, initi ensureLogQL(monaco); }} onMount={(editor, monaco) => { + // Monaco has a bug where it runs actions on all instances (https://github.com/microsoft/monaco-editor/issues/2947), so we ensure actions are executed on instance-level with this ContextKey. + const isEditorFocused = editor.createContextKey('isEditorFocused' + id, false); // we setup on-blur editor.onDidBlurEditorWidget(() => { + isEditorFocused.set(false); onBlurRef.current(editor.getValue()); }); const dataProvider = new CompletionDataProvider(langProviderRef.current, historyRef.current); @@ -162,14 +166,18 @@ const MonacoQueryField = ({ languageProvider, history, onBlur, onRunQuery, initi editor.onDidContentSizeChange(updateElementHeight); updateElementHeight(); - // handle: shift + enter // FIXME: maybe move this functionality into CodeEditor? - editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => { - onRunQueryRef.current(editor.getValue()); - }); + editor.addCommand( + monaco.KeyMod.Shift | monaco.KeyCode.Enter, + () => { + onRunQueryRef.current(editor.getValue()); + }, + 'isEditorFocused' + id + ); editor.onDidFocusEditorText(() => { + isEditorFocused.set(true); if (editor.getValue().trim() === '') { editor.trigger('', 'editor.action.triggerSuggest', {}); } diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx b/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx index 5c26a5682d2..13878664886 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import { promLanguageDefinition } from 'monaco-promql'; import React, { useRef, useEffect } from 'react'; import { useLatest } from 'react-use'; +import { v4 as uuidv4 } from 'uuid'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; @@ -87,6 +88,8 @@ const getStyles = (theme: GrafanaTheme2, placeholder: string) => { }; const MonacoQueryField = (props: Props) => { + const id = uuidv4(); + // we need only one instance of `overrideServices` during the lifetime of the react component const overrideServicesRef = useRef(getOverrideServices()); const containerRef = useRef(null); @@ -126,10 +129,15 @@ const MonacoQueryField = (props: Props) => { ensurePromQL(monaco); }} onMount={(editor, monaco) => { + const isEditorFocused = editor.createContextKey('isEditorFocused' + id, false); // we setup on-blur editor.onDidBlurEditorWidget(() => { + isEditorFocused.set(false); onBlurRef.current(editor.getValue()); }); + editor.onDidFocusEditorText(() => { + isEditorFocused.set(true); + }); // we construct a DataProvider object const getSeries = (selector: string) => lpRef.current.getSeries(selector); @@ -213,9 +221,13 @@ const MonacoQueryField = (props: Props) => { // handle: shift + enter // FIXME: maybe move this functionality into CodeEditor? - editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => { - onRunQueryRef.current(editor.getValue()); - }); + editor.addCommand( + monaco.KeyMod.Shift | monaco.KeyCode.Enter, + () => { + onRunQueryRef.current(editor.getValue()); + }, + 'isEditorFocused' + id + ); /* Something in this configuration of monaco doesn't bubble up [mod]+K, which the command palette uses. Pass the event out of monaco manually