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 3f30dafc36c..f62b079a35b 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 @@ -6,6 +6,7 @@ import { useLatest } from 'react-use'; import { promLanguageDefinition } from 'monaco-promql'; import { getCompletionProvider } from './monaco-completion-provider'; import { Props } from './MonacoQueryFieldProps'; +import { getOverrideServices } from './getOverrideServices'; const options: monacoTypes.editor.IStandaloneEditorConstructionOptions = { codeLens: false, @@ -75,6 +76,8 @@ const getStyles = (theme: GrafanaTheme2) => { }; const MonacoQueryField = (props: Props) => { + // we need only one instance of `overrideServices` during the lifetime of the react component + const overrideServicesRef = useRef(getOverrideServices()); const containerRef = useRef(null); const { languageProvider, history, onBlur, onRunQuery, initialValue } = props; @@ -102,6 +105,7 @@ const MonacoQueryField = (props: Props) => { ref={containerRef} > (); + + // we want this to be true by default + strings.set('expandSuggestionDocs', true.toString()); + + return { + // we do not implement the on* handlers + onDidChangeValue: (data: unknown): void => undefined, + onDidChangeTarget: (data: unknown): void => undefined, + onWillSaveState: (data: unknown): void => undefined, + + get: (key: string, scope: unknown, fallbackValue?: string): string | undefined => { + return strings.get(key) ?? fallbackValue; + }, + + getBoolean: (key: string, scope: unknown, fallbackValue?: boolean): boolean | undefined => { + const val = strings.get(key); + if (val !== undefined) { + // the interface-docs say the value will be converted + // to a boolean but do not specify how, so we improvise + return val === 'true'; + } else { + return fallbackValue; + } + }, + + getNumber: (key: string, scope: unknown, fallbackValue?: number): number | undefined => { + const val = strings.get(key); + if (val !== undefined) { + return parseInt(val, 10); + } else { + return fallbackValue; + } + }, + + store: ( + key: string, + value: string | boolean | number | undefined | null, + scope: unknown, + target: unknown + ): void => { + // the interface-docs say if the value is nullish, it should act as delete + if (value === null || value === undefined) { + strings.delete(key); + } else { + strings.set(key, value.toString()); + } + }, + + remove: (key: string, scope: unknown): void => { + strings.delete(key); + }, + + keys: (scope: unknown, target: unknown): string[] => { + return Array.from(strings.keys()); + }, + + logStorage: (): void => { + console.log('logStorage: not implemented'); + }, + + migrate: (): Promise => { + // we do not implement this + return Promise.resolve(undefined); + }, + + isNew: (scope: unknown): boolean => { + // we create a new storage for every session, we do not persist it, + // so we return `true`. + return true; + }, + + flush: (reason?: unknown): Promise => { + // we do not implement this + return Promise.resolve(undefined); + }, + }; +} + +let overrideServices: monacoTypes.editor.IEditorOverrideServices | null = null; + +export function getOverrideServices(): monacoTypes.editor.IEditorOverrideServices { + // only have one instance of this for every query editor + if (overrideServices === null) { + overrideServices = { + storageService: makeStorageService(), + }; + } + + return overrideServices; +}