From 5c05a3deb9730cee7f8eaca5a77ab6d21e095e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 2 Mar 2022 16:16:19 +0100 Subject: [PATCH] Prometheus: Save query editor mode default (#46074) --- .../PromQueryBuilderOptions.test.tsx | 2 +- .../components/PromQueryEditorSelector.tsx | 7 +-- .../prometheus/querybuilder/shared/types.ts | 6 +- .../prometheus/querybuilder/state.test.ts | 34 +++++++++++ .../prometheus/querybuilder/state.ts | 60 +++++++++++++++++++ .../prometheus/querybuilder/types.ts | 33 +--------- 6 files changed, 102 insertions(+), 40 deletions(-) create mode 100644 public/app/plugins/datasource/prometheus/querybuilder/state.test.ts create mode 100644 public/app/plugins/datasource/prometheus/querybuilder/state.ts diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx index 153a72ce5ee..dcc03f3e4aa 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { PromQuery } from '../../types'; -import { getQueryWithDefaults } from '../types'; +import { getQueryWithDefaults } from '../state'; import { CoreApp } from '@grafana/data'; import { PromQueryBuilderOptions } from './PromQueryBuilderOptions'; import { selectOptionInTest } from '@grafana/ui'; diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx index 2062f6a71e4..49a98f1b025 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx @@ -13,7 +13,7 @@ import { buildVisualQueryFromString } from '../parsing'; import { PromQueryCodeEditor } from './PromQueryCodeEditor'; import { PromQueryBuilderContainer } from './PromQueryBuilderContainer'; import { PromQueryBuilderOptions } from './PromQueryBuilderOptions'; -import { getQueryWithDefaults } from '../types'; +import { changeEditorMode, getQueryWithDefaults } from '../state'; export const PromQueryEditorSelector = React.memo((props) => { const { onChange, onRunQuery, data } = props; @@ -24,7 +24,6 @@ export const PromQueryEditorSelector = React.memo((props) const onEditorModeChange = useCallback( (newMetricEditorMode: QueryEditorMode) => { - const change = { ...query, editorMode: newMetricEditorMode }; if (newMetricEditorMode === QueryEditorMode.Builder) { const result = buildVisualQueryFromString(query.expr || ''); // If there are errors, give user a chance to decide if they want to go to builder as that can loose some data. @@ -33,7 +32,7 @@ export const PromQueryEditorSelector = React.memo((props) return; } } - onChange(change); + changeEditorMode(query, newMetricEditorMode, onChange); }, [onChange, query] ); @@ -52,7 +51,7 @@ export const PromQueryEditorSelector = React.memo((props) body="There were errors while trying to parse the query. Continuing to visual builder may loose some parts of the query." confirmText="Continue" onConfirm={() => { - onChange({ ...query, editorMode: QueryEditorMode.Builder }); + changeEditorMode(query, QueryEditorMode.Builder, onChange); setParseModalOpen(false); }} onDismiss={() => setParseModalOpen(false)} diff --git a/public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts b/public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts index eec8fb91fe5..e86988500f8 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts @@ -87,9 +87,9 @@ export interface QueryBuilderOperationParamEditorProps { } export enum QueryEditorMode { - Builder, - Code, - Explain, + Code = 'code', + Builder = 'builder', + Explain = 'explain', } export interface VisualQueryModeller { diff --git a/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts b/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts new file mode 100644 index 00000000000..46d056845bd --- /dev/null +++ b/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts @@ -0,0 +1,34 @@ +import { CoreApp } from '@grafana/data'; +import { QueryEditorMode } from './shared/types'; +import { changeEditorMode, getQueryWithDefaults } from './state'; + +describe('getQueryWithDefaults(', () => { + it('should set defaults', () => { + expect(getQueryWithDefaults({ refId: 'A' } as any, CoreApp.Dashboard)).toEqual({ + editorMode: 'builder', + expr: '', + legendFormat: '__auto', + range: true, + refId: 'A', + }); + }); + + it('should set both range and instant to true when in Explore', () => { + expect(getQueryWithDefaults({ refId: 'A' } as any, CoreApp.Explore)).toEqual({ + editorMode: 'builder', + expr: '', + legendFormat: '__auto', + range: true, + instant: true, + refId: 'A', + }); + }); + + it('Changing editor mode with blank query should change default', () => { + changeEditorMode({ refId: 'A', expr: '' }, QueryEditorMode.Code, (query) => { + expect(query.editorMode).toBe(QueryEditorMode.Code); + }); + + expect(getQueryWithDefaults({ refId: 'A' } as any, CoreApp.Dashboard).editorMode).toEqual(QueryEditorMode.Code); + }); +}); diff --git a/public/app/plugins/datasource/prometheus/querybuilder/state.ts b/public/app/plugins/datasource/prometheus/querybuilder/state.ts new file mode 100644 index 00000000000..9a69b6ab11d --- /dev/null +++ b/public/app/plugins/datasource/prometheus/querybuilder/state.ts @@ -0,0 +1,60 @@ +import { CoreApp } from '@grafana/data'; +import store from 'app/core/store'; +import { LegendFormatMode, PromQuery } from '../types'; +import { QueryEditorMode } from './shared/types'; + +const queryEditorModeDefaultLocalStorageKey = 'PrometheusQueryEditorModeDefault'; + +export function changeEditorMode(query: PromQuery, editorMode: QueryEditorMode, onChange: (query: PromQuery) => void) { + // If empty query store new mode as default + if (query.expr === '') { + store.set(queryEditorModeDefaultLocalStorageKey, editorMode); + } + + onChange({ ...query, editorMode }); +} + +export function getDefaultEditorMode(expr: string) { + // If we already have an expression default to code view + if (expr != null && expr !== '') { + return QueryEditorMode.Code; + } + + const value = store.get(queryEditorModeDefaultLocalStorageKey) as QueryEditorMode; + switch (value) { + case QueryEditorMode.Builder: + case QueryEditorMode.Code: + case QueryEditorMode.Explain: + return value; + default: + return QueryEditorMode.Builder; + } +} + +/** + * Returns query with defaults, and boolean true/false depending on change was required + */ +export function getQueryWithDefaults(query: PromQuery, app: CoreApp | undefined): PromQuery { + // If no expr (ie new query) then default to builder + let result = query; + + if (!query.editorMode) { + result = { ...query, editorMode: getDefaultEditorMode(query.expr) }; + } + + if (query.expr == null) { + result = { ...result, expr: '', legendFormat: LegendFormatMode.Auto }; + } + + if (query.range == null && query.instant == null) { + // Default to range query + result = { ...result, range: true }; + + // In explore we default to both instant & range + if (app === CoreApp.Explore) { + result.instant = true; + } + } + + return result; +} diff --git a/public/app/plugins/datasource/prometheus/querybuilder/types.ts b/public/app/plugins/datasource/prometheus/querybuilder/types.ts index e51ad1ff144..e621313dd1e 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/types.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/types.ts @@ -1,7 +1,5 @@ -import { CoreApp } from '@grafana/data'; -import { LegendFormatMode, PromQuery } from '../types'; import { VisualQueryBinary } from './shared/LokiAndPromQueryModellerBase'; -import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryEditorMode } from './shared/types'; +import { QueryBuilderLabelFilter, QueryBuilderOperation } from './shared/types'; /** * Visual query model @@ -114,32 +112,3 @@ export interface PromQueryPattern { name: string; operations: QueryBuilderOperation[]; } - -/** - * Returns query with defaults, and boolean true/false depending on change was required - */ -export function getQueryWithDefaults(query: PromQuery, app: CoreApp | undefined): PromQuery { - // If no expr (ie new query) then default to builder - let result = query; - const editorMode = query.editorMode ?? (query.expr ? QueryEditorMode.Code : QueryEditorMode.Builder); - - if (result.editorMode !== editorMode) { - result = { ...result, editorMode }; - } - - if (query.expr == null) { - result = { ...result, expr: '', legendFormat: LegendFormatMode.Auto }; - } - - if (query.range == null && query.instant == null) { - // Default to range query - result = { ...result, range: true }; - - // In explore we default to both instant & range - if (app === CoreApp.Explore) { - result.instant = true; - } - } - - return result; -}