Prometheus/Loki: Show raw query by default in the builder(#50007)

This commit is contained in:
Andrej Ocenas 2022-06-02 13:50:10 +02:00 committed by GitHub
parent ace5b2058d
commit c63071f519
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 103 additions and 40 deletions

View File

@ -30,6 +30,7 @@ describe('LokiQueryBuilderContainer', () => {
),
onChange: jest.fn(),
onRunQuery: () => {},
showRawQuery: true,
};
render(<LokiQueryBuilderContainer {...props} />);
expect(screen.getByText('testjob')).toBeInTheDocument();

View File

@ -15,6 +15,7 @@ export interface Props {
datasource: LokiDatasource;
onChange: (update: LokiQuery) => void;
onRunQuery: () => void;
showRawQuery: boolean;
}
export interface State {
@ -26,7 +27,7 @@ export interface State {
* This component is here just to contain the translation logic between string query and the visual query builder model.
*/
export function LokiQueryBuilderContainer(props: Props) {
const { query, onChange, onRunQuery, datasource } = props;
const { query, onChange, onRunQuery, datasource, showRawQuery } = props;
const [state, dispatch] = useReducer(stateSlice.reducer, {
expr: query.expr,
// Use initial visual query only if query.expr is empty string
@ -62,7 +63,7 @@ export function LokiQueryBuilderContainer(props: Props) {
onChange={onVisQueryChange}
onRunQuery={onRunQuery}
/>
{query.rawQuery && <QueryPreview query={query.expr} />}
{showRawQuery && <QueryPreview query={query.expr} />}
</>
);
}

View File

@ -10,6 +10,18 @@ import { LokiQuery, LokiQueryType } from '../../types';
import { LokiQueryEditorSelector } from './LokiQueryEditorSelector';
jest.mock('app/core/store', () => {
return {
get() {
return undefined;
},
set() {},
getObject(key: string, defaultValue: any) {
return defaultValue;
},
};
});
const defaultQuery = {
refId: 'A',
expr: '{label1="foo", label2="bar"}',
@ -86,23 +98,14 @@ describe('LokiQueryEditorSelector', () => {
});
it('Can enable raw query', async () => {
const { onChange } = renderWithMode(QueryEditorMode.Builder);
expect(screen.queryByLabelText('selector')).not.toBeInTheDocument();
renderWithMode(QueryEditorMode.Builder);
expect(screen.queryByLabelText('selector')).toBeInTheDocument();
screen.getByLabelText('Raw query').click();
expect(onChange).toBeCalledWith({
refId: 'A',
expr: defaultQuery.expr,
queryType: 'range',
editorMode: QueryEditorMode.Builder,
rawQuery: true,
});
expect(screen.queryByLabelText('selector')).not.toBeInTheDocument();
});
it('Should show raw query', async () => {
it('Should show raw query by default', async () => {
renderWithProps({
rawQuery: true,
editorMode: QueryEditorMode.Builder,
expr: '{job="grafana"}',
});

View File

@ -11,7 +11,7 @@ import { LokiQueryEditorProps } from '../../components/types';
import { LokiQuery } from '../../types';
import { lokiQueryModeller } from '../LokiQueryModeller';
import { buildVisualQueryFromString } from '../parsing';
import { changeEditorMode, getQueryWithDefaults } from '../state';
import { changeEditorMode, getQueryWithDefaults, useRawQuery } from '../state';
import { LokiQueryBuilderContainer } from './LokiQueryBuilderContainer';
import { LokiQueryBuilderExplained } from './LokiQueryBuilderExplained';
@ -24,6 +24,7 @@ export const LokiQueryEditorSelector = React.memo<LokiQueryEditorProps>((props)
const [dataIsStale, setDataIsStale] = useState(false);
const query = getQueryWithDefaults(props.query);
const [rawQuery, setRawQuery] = useRawQuery();
// This should be filled in from the defaults by now.
const editorMode = query.editorMode!;
@ -53,7 +54,7 @@ export const LokiQueryEditorSelector = React.memo<LokiQueryEditorProps>((props)
const onQueryPreviewChange = (event: SyntheticEvent<HTMLInputElement>) => {
const isEnabled = event.currentTarget.checked;
onChange({ ...query, rawQuery: isEnabled });
setRawQuery(isEnabled);
};
return (
@ -86,7 +87,7 @@ export const LokiQueryEditorSelector = React.memo<LokiQueryEditorProps>((props)
}}
options={lokiQueryModeller.getQueryPatterns().map((x) => ({ label: x.name, value: x }))}
/>
<QueryHeaderSwitch label="Raw query" value={query.rawQuery} onChange={onQueryPreviewChange} />
<QueryHeaderSwitch label="Raw query" value={rawQuery} onChange={onQueryPreviewChange} />
</>
)}
<FlexItem grow={1} />
@ -110,6 +111,7 @@ export const LokiQueryEditorSelector = React.memo<LokiQueryEditorProps>((props)
query={query}
onChange={onChangeInternal}
onRunQuery={props.onRunQuery}
showRawQuery={rawQuery}
/>
)}
{editorMode === QueryEditorMode.Explain && <LokiQueryBuilderExplained query={query.expr} />}

View File

@ -1,3 +1,5 @@
import { useCallback, useState } from 'react';
import store from 'app/core/store';
import { QueryEditorMode } from '../../prometheus/querybuilder/shared/types';
@ -53,3 +55,28 @@ export function getQueryWithDefaults(query: LokiQuery): LokiQuery {
return result;
}
const queryEditorRawQueryLocalStorageKey = 'LokiQueryEditorRawQueryDefault';
function getRawQueryVisibility(): boolean {
const val = store.get(queryEditorRawQueryLocalStorageKey);
return val === undefined ? true : Boolean(parseInt(val, 10));
}
function setRawQueryVisibility(value: boolean) {
store.set(queryEditorRawQueryLocalStorageKey, value ? '1' : '0');
}
/**
* Use and store value of raw query switch in local storage.
* Needs to be a hook with local state to trigger rerenders.
*/
export function useRawQuery(): [boolean, (val: boolean) => void] {
const [rawQuery, setRawQuery] = useState(getRawQueryVisibility());
const setter = useCallback((value: boolean) => {
setRawQueryVisibility(value);
setRawQuery(value);
}, []);
return [rawQuery, setter];
}

View File

@ -49,8 +49,6 @@ export interface LokiQuery extends DataQuery {
/* @deprecated now use queryType */
instant?: boolean;
editorMode?: QueryEditorMode;
/** Controls if the raw query text is shown */
rawQuery?: boolean;
}
export interface LokiOptions extends DataSourceJsonData {

View File

@ -18,6 +18,7 @@ export interface Props {
onChange: (update: PromQuery) => void;
onRunQuery: () => void;
data?: PanelData;
showRawQuery?: boolean;
}
export interface State {
@ -29,7 +30,7 @@ export interface State {
* This component is here just to contain the translation logic between string query and the visual query builder model.
*/
export function PromQueryBuilderContainer(props: Props) {
const { query, onChange, onRunQuery, datasource, data } = props;
const { query, onChange, onRunQuery, datasource, data, showRawQuery } = props;
const [state, dispatch] = useReducer(stateSlice.reducer, { expr: query.expr });
// Only rebuild visual query if expr changes from outside
@ -56,7 +57,7 @@ export function PromQueryBuilderContainer(props: Props) {
onRunQuery={onRunQuery}
data={data}
/>
{query.rawQuery && <QueryPreview query={query.expr} />}
{showRawQuery && <QueryPreview query={query.expr} />}
</>
);
}

View File

@ -20,6 +20,18 @@ jest.mock('../../components/monaco-query-field/MonacoQueryFieldWrapper', () => {
};
});
jest.mock('app/core/store', () => {
return {
get() {
return undefined;
},
set() {},
getObject(key: string, defaultValue: any) {
return defaultValue;
},
};
});
jest.mock('@grafana/runtime', () => {
return {
...jest.requireActual('@grafana/runtime'),
@ -87,23 +99,14 @@ describe('PromQueryEditorSelector', () => {
});
it('Can enable raw query', async () => {
const { onChange } = renderWithMode(QueryEditorMode.Builder);
expect(screen.queryByLabelText('selector')).not.toBeInTheDocument();
renderWithMode(QueryEditorMode.Builder);
expect(screen.queryByLabelText('selector')).toBeInTheDocument();
screen.getByLabelText('Raw query').click();
expect(onChange).toBeCalledWith({
refId: 'A',
expr: defaultQuery.expr,
range: true,
editorMode: QueryEditorMode.Builder,
rawQuery: true,
});
expect(screen.queryByLabelText('selector')).not.toBeInTheDocument();
});
it('Should show raw query', async () => {
it('Should show raw query by default', async () => {
renderWithProps({
rawQuery: true,
editorMode: QueryEditorMode.Builder,
expr: 'my_metric',
});

View File

@ -13,7 +13,7 @@ import { FeedbackLink } from '../shared/FeedbackLink';
import { QueryEditorModeToggle } from '../shared/QueryEditorModeToggle';
import { QueryHeaderSwitch } from '../shared/QueryHeaderSwitch';
import { QueryEditorMode } from '../shared/types';
import { changeEditorMode, getQueryWithDefaults } from '../state';
import { changeEditorMode, getQueryWithDefaults, useRawQuery } from '../state';
import { PromQueryBuilderContainer } from './PromQueryBuilderContainer';
import { PromQueryBuilderExplained } from './PromQueryBuilderExplained';
@ -28,6 +28,7 @@ export const PromQueryEditorSelector = React.memo<Props>((props) => {
const [dataIsStale, setDataIsStale] = useState(false);
const query = getQueryWithDefaults(props.query, app);
const [rawQuery, setRawQuery] = useRawQuery();
// This should be filled in from the defaults by now.
const editorMode = query.editorMode!;
@ -59,7 +60,7 @@ export const PromQueryEditorSelector = React.memo<Props>((props) => {
const onQueryPreviewChange = (event: SyntheticEvent<HTMLInputElement>) => {
const isEnabled = event.currentTarget.checked;
onChange({ ...query, rawQuery: isEnabled });
setRawQuery(isEnabled);
};
const onChangeInternal = (query: PromQuery) => {
@ -99,7 +100,7 @@ export const PromQueryEditorSelector = React.memo<Props>((props) => {
}}
options={promQueryModeller.getQueryPatterns().map((x) => ({ label: x.name, value: x }))}
/>
<QueryHeaderSwitch label="Raw query" value={query.rawQuery} onChange={onQueryPreviewChange} />
<QueryHeaderSwitch label="Raw query" value={rawQuery} onChange={onQueryPreviewChange} />
</>
)}
{editorMode === QueryEditorMode.Builder && (
@ -127,6 +128,7 @@ export const PromQueryEditorSelector = React.memo<Props>((props) => {
onChange={onChangeInternal}
onRunQuery={props.onRunQuery}
data={data}
showRawQuery={rawQuery}
/>
)}
{editorMode === QueryEditorMode.Explain && <PromQueryBuilderExplained query={query.expr} />}

View File

@ -1,3 +1,5 @@
import { useCallback, useState } from 'react';
import { CoreApp } from '@grafana/data';
import store from 'app/core/store';
@ -59,3 +61,28 @@ export function getQueryWithDefaults(query: PromQuery, app: CoreApp | undefined)
return result;
}
const queryEditorRawQueryLocalStorageKey = 'PrometheusQueryEditorRawQueryDefault';
function getRawQueryVisibility(): boolean {
const val = store.get(queryEditorRawQueryLocalStorageKey);
return val === undefined ? true : Boolean(parseInt(val, 10));
}
function setRawQueryVisibility(value: boolean) {
store.set(queryEditorRawQueryLocalStorageKey, value ? '1' : '0');
}
/**
* Use and store value of raw query switch in local storage.
* Needs to be a hook with local state to trigger rerenders.
*/
export function useRawQuery(): [boolean, (val: boolean) => void] {
const [rawQuery, setRawQuery] = useState(getRawQueryVisibility());
const setter = useCallback((value: boolean) => {
setRawQueryVisibility(value);
setRawQuery(value);
}, []);
return [rawQuery, setter];
}

View File

@ -20,8 +20,6 @@ export interface PromQuery extends DataQuery {
showingTable?: boolean;
/** Code, Builder or Explain */
editorMode?: QueryEditorMode;
/** Controls if the raw query text is shown */
rawQuery?: boolean;
}
export interface PromOptions extends DataSourceJsonData {