Prometheus/Loki: Run query explicitly instead of onblur in panel edit (#64815)

* Prometheus: Run query explicitly instead of onblur in panel edit, and highlight Run qqueries when query changed

* Update loki to do the same

* Cleanup unused prop

* Remove test
This commit is contained in:
Torkel Ödegaard 2023-03-21 07:55:34 +01:00 committed by GitHub
parent 126c4a106e
commit 395890c357
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 20 additions and 53 deletions

View File

@ -1,3 +1,4 @@
import { isEqual } from 'lodash';
import React, { SyntheticEvent, useCallback, useEffect, useState } from 'react';
import { usePrevious } from 'react-use';
@ -76,7 +77,9 @@ export const LokiQueryEditor = React.memo<LokiQueryEditorProps>((props) => {
}, [data]);
const onChangeInternal = (query: LokiQuery) => {
setDataIsStale(true);
if (!isEqual(query, props.query)) {
setDataIsStale(true);
}
onChange(query);
};

View File

@ -1,6 +1,6 @@
import React, { ReactNode } from 'react';
import { CoreApp, QueryEditorProps } from '@grafana/data';
import { QueryEditorProps } from '@grafana/data';
import { LokiDatasource } from '../datasource';
import { shouldRefreshLabels } from '../languageUtils';
@ -66,7 +66,7 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
};
render() {
const { ExtraFieldElement, query, app, datasource, history, onRunQuery, onQueryType } = this.props;
const { ExtraFieldElement, query, datasource, history, onRunQuery, onQueryType } = this.props;
const placeholder = this.props.placeholder ?? 'Enter a Loki query (run with Shift+Enter)';
return (
@ -77,7 +77,6 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
>
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
<MonacoQueryFieldWrapper
runQueryOnBlur={app !== CoreApp.Explore}
datasource={datasource}
history={history ?? []}
onChange={this.onChangeQuery}

View File

@ -5,12 +5,7 @@ import { createLokiDatasource } from '../../mocks';
import { MonacoQueryFieldWrapper, Props } from './MonacoQueryFieldWrapper';
function renderComponent({
initialValue = '',
onChange = jest.fn(),
onRunQuery = jest.fn(),
runQueryOnBlur = false,
}: Partial<Props> = {}) {
function renderComponent({ initialValue = '', onChange = jest.fn(), onRunQuery = jest.fn() }: Partial<Props> = {}) {
const datasource = createLokiDatasource();
render(
@ -20,7 +15,6 @@ function renderComponent({
initialValue={initialValue}
onChange={onChange}
onRunQuery={onRunQuery}
runQueryOnBlur={runQueryOnBlur}
placeholder="Enter a Loki query (run with Shift+Enter)"
/>
);

View File

@ -6,13 +6,12 @@ import { Props as MonacoProps } from './MonacoQueryFieldProps';
export type Props = Omit<MonacoProps, 'onRunQuery' | 'onBlur'> & {
onChange: (query: string) => void;
onRunQuery: () => void;
runQueryOnBlur: boolean;
onQueryType?: (query: string) => void;
};
export const MonacoQueryFieldWrapper = (props: Props) => {
const lastRunValueRef = useRef<string | null>(null);
const { runQueryOnBlur, onRunQuery, onChange, ...rest } = props;
const { onRunQuery, onChange, ...rest } = props;
const handleRunQuery = (value: string) => {
lastRunValueRef.current = value;
@ -21,14 +20,7 @@ export const MonacoQueryFieldWrapper = (props: Props) => {
};
const handleBlur = (value: string) => {
if (runQueryOnBlur) {
// run handleRunQuery only if the current value is different from the last-time-executed value
if (value !== lastRunValueRef.current) {
handleRunQuery(value);
}
} else {
onChange(value);
}
onChange(value);
};
return <MonacoQueryFieldLazy onRunQuery={handleRunQuery} onBlur={handleBlur} {...rest} />;

View File

@ -148,7 +148,7 @@ describe('PromQueryField', () => {
expect(labelBrowser.textContent).toContain('Metrics browser');
});
it('should not run query onBlur in explore', async () => {
it('should not run query onBlur', async () => {
const onRunQuery = jest.fn();
const { container } = render(<PromQueryField {...defaultProps} app={CoreApp.Explore} onRunQuery={onRunQuery} />);
@ -163,22 +163,6 @@ describe('PromQueryField', () => {
await userEvent.click(document.body);
expect(onRunQuery).not.toHaveBeenCalled();
});
it('should run query onBlur in dashboard', async () => {
const onRunQuery = jest.fn();
const { container } = render(<PromQueryField {...defaultProps} app={CoreApp.Dashboard} onRunQuery={onRunQuery} />);
// wait for component to rerender
await screen.findByRole('button');
const input = getByTestId(container, 'dummy-code-input');
expect(input).toBeInTheDocument();
await userEvent.type(input, 'metric');
// blur element
await userEvent.click(document.body);
expect(onRunQuery).toHaveBeenCalled();
});
});
function makeLanguageProvider(options: { metrics: string[][] }) {

View File

@ -4,7 +4,7 @@ import React, { ReactNode } from 'react';
import { Plugin } from 'slate';
import { Editor } from 'slate-react';
import { CoreApp, isDataFrame, QueryEditorProps, QueryHint, TimeRange, toLegacyResponseData } from '@grafana/data';
import { isDataFrame, QueryEditorProps, QueryHint, TimeRange, toLegacyResponseData } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime/src';
import {
BracesPlugin,
@ -310,7 +310,6 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
<MonacoQueryFieldWrapper
runQueryOnBlur={this.props.app !== CoreApp.Explore}
languageProvider={languageProvider}
history={history}
onChange={this.onChangeQuery}

View File

@ -6,12 +6,11 @@ import { Props as MonacoProps } from './MonacoQueryFieldProps';
type Props = Omit<MonacoProps, 'onRunQuery' | 'onBlur'> & {
onChange: (query: string) => void;
onRunQuery: () => void;
runQueryOnBlur: boolean;
};
export const MonacoQueryFieldWrapper = (props: Props) => {
const lastRunValueRef = useRef<string | null>(null);
const { runQueryOnBlur, onRunQuery, onChange, ...rest } = props;
const { onRunQuery, onChange, ...rest } = props;
const handleRunQuery = (value: string) => {
lastRunValueRef.current = value;
@ -20,14 +19,7 @@ export const MonacoQueryFieldWrapper = (props: Props) => {
};
const handleBlur = (value: string) => {
if (runQueryOnBlur) {
// run handleRunQuery only if the current value is different from the last-time-executed value
if (value !== lastRunValueRef.current) {
handleRunQuery(value);
}
} else {
onChange(value);
}
onChange(value);
};
/**

View File

@ -1,4 +1,4 @@
import { map } from 'lodash';
import { isEqual, map } from 'lodash';
import React, { SyntheticEvent, useCallback, useEffect, useState } from 'react';
import { CoreApp, LoadingState, SelectableValue } from '@grafana/data';
@ -82,7 +82,9 @@ export const PromQueryEditorSelector = React.memo<Props>((props) => {
}, [data]);
const onChangeInternal = (query: PromQuery) => {
setDataIsStale(true);
if (!isEqual(query, props.query)) {
setDataIsStale(true);
}
onChange(query);
};
@ -138,7 +140,9 @@ export const PromQueryEditorSelector = React.memo<Props>((props) => {
</EditorHeader>
<Space v={0.5} />
<EditorRows>
{editorMode === QueryEditorMode.Code && <PromQueryCodeEditor {...props} query={query} showExplain={explain} />}
{editorMode === QueryEditorMode.Code && (
<PromQueryCodeEditor {...props} query={query} showExplain={explain} onChange={onChangeInternal} />
)}
{editorMode === QueryEditorMode.Builder && (
<PromQueryBuilderContainer
query={query}