diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx index 254318e4960..d8b2087cca9 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx @@ -124,7 +124,7 @@ export function getQueryTypeOptions(includeBoth: boolean) { export function getQueryTypeChangeHandler(query: PromQuery, onChange: (update: PromQuery) => void) { return (queryType: string) => { if (queryType === 'instant') { - onChange({ ...query, instant: true, range: false }); + onChange({ ...query, instant: true, range: false, exemplar: false }); } else if (queryType === 'range') { onChange({ ...query, instant: false, range: true }); } else { diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx index 4426a77c69b..5de3e7b3358 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx @@ -19,7 +19,7 @@ export const FORMAT_OPTIONS: Array> = [ { label: 'Heatmap', value: 'heatmap' }, ]; -const INTERVAL_FACTOR_OPTIONS: Array> = map([1, 2, 3, 4, 5, 10], (value: number) => ({ +export const INTERVAL_FACTOR_OPTIONS: Array> = map([1, 2, 3, 4, 5, 10], (value: number) => ({ value, label: '1/' + value, })); diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx index 9d900fe9d3c..791678c860f 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx @@ -6,7 +6,6 @@ import { PromQuery } from '../../types'; import { buildVisualQueryFromString } from '../parsing'; import { promQueryModeller } from '../PromQueryModeller'; import { PromQueryBuilder } from './PromQueryBuilder'; -import { PromQueryBuilderOptions } from './PromQueryBuilderOptions'; import { QueryPreview } from './QueryPreview'; import { PromVisualQuery } from '../types'; @@ -24,7 +23,7 @@ export interface Props { * @constructor */ export function PromQueryBuilderContainer(props: Props) { - const { query, onChange, onRunQuery, datasource, app } = props; + const { query, onChange, onRunQuery, datasource } = props; const visQuery = buildVisualQueryFromString(query.expr || '').query; @@ -37,7 +36,6 @@ export function PromQueryBuilderContainer(props: Props) { <> {query.editorPreview && } - ); } diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx index 775b76c733e..64f1a5ea653 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx @@ -4,7 +4,7 @@ import { CoreApp, SelectableValue } from '@grafana/data'; import { Input, RadioButtonGroup, Select, Switch } from '@grafana/ui'; import { QueryOptionGroup } from '../shared/QueryOptionGroup'; import { PromQuery } from '../../types'; -import { FORMAT_OPTIONS } from '../../components/PromQueryEditor'; +import { FORMAT_OPTIONS, INTERVAL_FACTOR_OPTIONS } from '../../components/PromQueryEditor'; import { getQueryTypeChangeHandler, getQueryTypeOptions } from '../../components/PromExploreExtraField'; export interface Props { @@ -32,7 +32,7 @@ export const PromQueryBuilderOptions = React.memo(({ query, app, onChange onRunQuery(); }; - const queryTypeOptions = getQueryTypeOptions(false); + const queryTypeOptions = getQueryTypeOptions(app === CoreApp.Explore); const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange); const onExemplarChange = (event: SyntheticEvent) => { @@ -41,15 +41,17 @@ export const PromQueryBuilderOptions = React.memo(({ query, app, onChange onRunQuery(); }; - const showExemplarSwitch = app !== CoreApp.UnifiedAlerting && !query.instant; + const onIntervalFactorChange = (value: SelectableValue) => { + onChange({ ...query, intervalFactor: value.value }); + onRunQuery(); + }; return ( @@ -76,22 +78,42 @@ export const PromQueryBuilderOptions = React.memo(({ query, app, onChange option.value === query.intervalFactor)} + /> + + )} ); }); +function shouldShowExemplarSwitch(query: PromQuery, app?: CoreApp) { + if (app === CoreApp.UnifiedAlerting || !query.range) { + return false; + } + + return true; +} + +function getQueryTypeValue(query: PromQuery) { + return query.range && query.instant ? 'both' : query.instant ? 'instant' : 'range'; +} + function getCollapsedInfo(query: PromQuery, formatOption: SelectableValue): string[] { const items: string[] = []; @@ -105,9 +127,7 @@ function getCollapsedInfo(query: PromQuery, formatOption: SelectableValue + ); +} diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx index 8ec6d21737e..16c73bfe641 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx @@ -71,7 +71,6 @@ describe('PromQueryEditorSelector', () => { it('shows builder when builder mode is set', async () => { renderWithMode(QueryEditorMode.Builder); - screen.debug(undefined, 20000); expectBuilder(); }); @@ -86,6 +85,8 @@ describe('PromQueryEditorSelector', () => { expect(onChange).toBeCalledWith({ refId: 'A', expr: defaultQuery.expr, + instant: false, + range: true, editorMode: QueryEditorMode.Builder, }); }); @@ -99,6 +100,8 @@ describe('PromQueryEditorSelector', () => { expect(onChange).toBeCalledWith({ refId: 'A', expr: defaultQuery.expr, + instant: false, + range: true, editorMode: QueryEditorMode.Builder, editorPreview: true, }); @@ -119,6 +122,8 @@ describe('PromQueryEditorSelector', () => { expect(onChange).toBeCalledWith({ refId: 'A', expr: defaultQuery.expr, + instant: false, + range: true, editorMode: QueryEditorMode.Code, }); }); @@ -129,6 +134,8 @@ describe('PromQueryEditorSelector', () => { expect(onChange).toBeCalledWith({ refId: 'A', expr: defaultQuery.expr, + instant: false, + range: true, editorMode: QueryEditorMode.Explain, }); }); diff --git a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx index 3044361779f..94f65d8f025 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx @@ -1,10 +1,8 @@ +import React, { SyntheticEvent, useCallback, useState } from 'react'; import { css } from '@emotion/css'; import { GrafanaTheme2, LoadingState } from '@grafana/data'; import { EditorHeader, EditorRows, FlexItem, InlineSelect, Space } from '@grafana/experimental'; import { Button, ConfirmModal, useStyles2 } from '@grafana/ui'; -import React, { SyntheticEvent, useCallback, useEffect, useState } from 'react'; - -import { PromQueryEditor } from '../../components/PromQueryEditor'; import { PromQueryEditorProps } from '../../components/types'; import { promQueryModeller } from '../PromQueryModeller'; import { QueryEditorModeToggle } from '../shared/QueryEditorModeToggle'; @@ -12,13 +10,17 @@ import { QueryHeaderSwitch } from '../shared/QueryHeaderSwitch'; import { QueryEditorMode } from '../shared/types'; import { PromQueryBuilderExplained } from './PromQueryBuilderExplained'; import { buildVisualQueryFromString } from '../parsing'; +import { PromQueryCodeEditor } from './PromQueryCodeEditor'; import { PromQueryBuilderContainer } from './PromQueryBuilderContainer'; +import { PromQueryBuilderOptions } from './PromQueryBuilderOptions'; +import { getQueryWithDefaults } from '../types'; export const PromQueryEditorSelector = React.memo((props) => { - const { query, onChange, onRunQuery, data } = props; + const { onChange, onRunQuery, data } = props; const styles = useStyles2(getStyles); - const [parseModalOpen, setParseModalOpen] = useState(false); + const query = getQueryWithDefaults(props.query, props.app); + const editorMode = query.editorMode!; const onEditorModeChange = useCallback( (newMetricEditorMode: QueryEditorMode) => { @@ -42,15 +44,6 @@ export const PromQueryEditorSelector = React.memo((props) onRunQuery(); }; - // If no expr (ie new query) then default to builder - const editorMode = query.editorMode ?? (query.expr ? QueryEditorMode.Code : QueryEditorMode.Builder); - - useEffect(() => { - if (query.editorMode === undefined) { - onChange({ ...query, editorMode }); - } - }, [editorMode, onChange, query]); - return ( <> ((props) - {editorMode === QueryEditorMode.Code && } + {editorMode === QueryEditorMode.Code && } {editorMode === QueryEditorMode.Builder && ( ((props) /> )} {editorMode === QueryEditorMode.Explain && } + {editorMode !== QueryEditorMode.Explain && ( + + )} ); diff --git a/public/app/plugins/datasource/prometheus/querybuilder/types.ts b/public/app/plugins/datasource/prometheus/querybuilder/types.ts index 0a7780625e5..5b284d635db 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/types.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/types.ts @@ -1,5 +1,7 @@ +import { CoreApp } from '@grafana/data'; +import { PromQuery } from '../types'; import { VisualQueryBinary } from './shared/LokiAndPromQueryModellerBase'; -import { QueryBuilderLabelFilter, QueryBuilderOperation } from './shared/types'; +import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryEditorMode } from './shared/types'; /** * Visual query model @@ -54,12 +56,35 @@ export interface PromQueryPattern { operations: QueryBuilderOperation[]; } -export function getDefaultEmptyQuery() { - const model: PromVisualQuery = { - metric: '', - labels: [], - operations: [], - }; +/** + * 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); - return model; + if (result.editorMode !== editorMode) { + result = { ...result, editorMode }; + } + + if (query.expr == null) { + result = { ...result, expr: '' }; + } + + // Default to range query + if (query.range == null) { + result = { ...result, range: true }; + } + + // In explore we default to both instant & range + if (query.instant == null && query.range == null) { + if (app === CoreApp.Explore) { + result = { ...result, instant: true }; + } else { + result = { ...result, instant: false, range: true }; + } + } + + return result; }