Alerting: app specific query editors for Loki and Prometheus (#34365)

* Adding simplified version of query editor based on app flag.

* cleaned up the absolute time range.

* changing placeholder text.

* updated snapshot.

* added some tests.

* adding loki query editor tests.

* updating snapshots.
This commit is contained in:
Marcus Andersson
2021-05-19 16:24:27 +02:00
committed by GitHub
parent f48708bb9e
commit 8ddf6de6e7
23 changed files with 333 additions and 68 deletions

View File

@@ -3,18 +3,16 @@ import React, { PureComponent } from 'react';
// Types
import { InlineFormLabel, LegacyForms, Select } from '@grafana/ui';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { PrometheusDatasource } from '../datasource';
import { PromOptions, PromQuery } from '../types';
import { SelectableValue } from '@grafana/data';
import { PromQuery } from '../types';
import PromQueryField from './PromQueryField';
import PromLink from './PromLink';
import { PromExemplarField } from './PromExemplarField';
import { PromQueryEditorProps } from './types';
const { Switch } = LegacyForms;
export type Props = QueryEditorProps<PrometheusDatasource, PromQuery, PromOptions>;
const FORMAT_OPTIONS: Array<SelectableValue<string>> = [
{ label: 'Time series', value: 'time_series' },
{ label: 'Table', value: 'table' },
@@ -35,11 +33,11 @@ interface State {
exemplar: boolean;
}
export class PromQueryEditor extends PureComponent<Props, State> {
export class PromQueryEditor extends PureComponent<PromQueryEditorProps, State> {
// Query target to be modified and used for queries
query: PromQuery;
constructor(props: Props) {
constructor(props: PromQueryEditorProps) {
super(props);
// Use default query to prevent undefined input values
const defaultQuery: Partial<PromQuery> = { expr: '', legendFormat: '', interval: '', exemplar: true };
@@ -118,6 +116,7 @@ export class PromQueryEditor extends PureComponent<Props, State> {
onChange={this.onFieldChange}
history={[]}
data={data}
data-testid={testIds.editor}
ExtraFieldElement={
<div className="gf-form-inline">
<div className="gf-form">
@@ -198,3 +197,7 @@ export class PromQueryEditor extends PureComponent<Props, State> {
);
}
}
export const testIds = {
editor: 'prom-editor',
};

View File

@@ -0,0 +1,64 @@
import React from 'react';
import { render, RenderResult } from '@testing-library/react';
import { PromQueryEditorByApp } from './PromQueryEditorByApp';
import { CoreApp } from '@grafana/data';
import { noop } from 'lodash';
import { Observable } from 'rxjs';
import { first } from 'rxjs/operators';
import { PrometheusDatasource } from '../datasource';
import { testIds as alertingTestIds } from './PromQueryEditorForAlerting';
import { testIds as regularTestIds } from './PromQueryEditor';
function setup(app: CoreApp): RenderResult {
const dataSource = ({
createQuery: jest.fn((q) => q),
getPrometheusTime: jest.fn((date, roundup) => 123),
languageProvider: {
start: () => Promise.resolve([]),
syntax: () => {},
getLabelKeys: () => [],
metrics: [],
},
exemplarErrors: new Observable().pipe(first()),
} as unknown) as PrometheusDatasource;
return render(
<PromQueryEditorByApp
app={app}
onChange={noop}
onRunQuery={noop}
datasource={dataSource}
query={{ refId: 'A', expr: '' }}
/>
);
}
describe('PromQueryEditorByApp', () => {
it('should render simplified query editor for cloud alerting', () => {
const { getByTestId, queryByTestId } = setup(CoreApp.CloudAlerting);
expect(getByTestId(alertingTestIds.editor)).toBeInTheDocument();
expect(queryByTestId(regularTestIds.editor)).toBeNull();
});
it('should render regular query editor for unkown apps', () => {
const { getByTestId, queryByTestId } = setup(CoreApp.Unknown);
expect(getByTestId(regularTestIds.editor)).toBeInTheDocument();
expect(queryByTestId(alertingTestIds.editor)).toBeNull();
});
it('should render regular query editor for explore', () => {
const { getByTestId, queryByTestId } = setup(CoreApp.Explore);
expect(getByTestId(regularTestIds.editor)).toBeInTheDocument();
expect(queryByTestId(alertingTestIds.editor)).toBeNull();
});
it('should render regular query editor for dashboard', () => {
const { getByTestId, queryByTestId } = setup(CoreApp.Dashboard);
expect(getByTestId(regularTestIds.editor)).toBeInTheDocument();
expect(queryByTestId(alertingTestIds.editor)).toBeNull();
});
});

View File

@@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { CoreApp } from '@grafana/data';
import { PromQueryEditorProps } from './types';
import { PromQueryEditor } from './PromQueryEditor';
import { PromQueryEditorForAlerting } from './PromQueryEditorForAlerting';
export function PromQueryEditorByApp(props: PromQueryEditorProps) {
const { app } = props;
switch (app) {
case CoreApp.CloudAlerting:
return <PromQueryEditorForAlerting {...props} />;
default:
return <PromQueryEditor {...props} />;
}
}
export default memo(PromQueryEditorByApp);

View File

@@ -0,0 +1,25 @@
import React from 'react';
import PromQueryField from './PromQueryField';
import { PromQueryEditorProps } from './types';
export function PromQueryEditorForAlerting(props: PromQueryEditorProps) {
const { datasource, query, range, data, onChange, onRunQuery } = props;
return (
<PromQueryField
datasource={datasource}
query={query}
onRunQuery={onRunQuery}
onChange={onChange}
history={[]}
range={range}
data={data}
placeholder="Enter a PromQL query"
data-testid={testIds.editor}
/>
);
}
export const testIds = {
editor: 'prom-editor-cloud-alerting',
};

View File

@@ -77,6 +77,8 @@ export function willApplySuggestion(suggestion: string, { typeaheadContext, type
interface PromQueryFieldProps extends ExploreQueryFieldProps<PrometheusDatasource, PromQuery, PromOptions> {
history: Array<HistoryItem<PromQuery>>;
ExtraFieldElement?: ReactNode;
placeholder?: string;
'data-testid'?: string;
}
interface PromQueryFieldState {
@@ -271,7 +273,9 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
datasource: { languageProvider },
query,
ExtraFieldElement,
placeholder = 'Enter a PromQL query (run with Shift+Enter)',
} = this.props;
const { labelBrowserVisible, syntaxLoaded, hint } = this.state;
const cleanText = languageProvider ? languageProvider.cleanText : undefined;
const hasMetrics = languageProvider.metrics.length > 0;
@@ -280,7 +284,10 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
return (
<>
<div className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1">
<div
className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1"
data-testid={this.props['data-testid']}
>
<button
className="gf-form-label query-keyword pointer"
onClick={this.onClickChooserButton}
@@ -300,7 +307,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
onBlur={this.props.onBlur}
onChange={this.onChangeQuery}
onRunQuery={this.props.onRunQuery}
placeholder="Enter a PromQL query (run with Shift+Enter)"
placeholder={placeholder}
portalOrigin="prometheus"
syntaxLoaded={syntaxLoaded}
/>

View File

@@ -178,6 +178,7 @@ exports[`Render PromQueryEditor with basic options should render 1`] = `
/>
</div>
}
data-testid="prom-editor"
datasource={
Object {
"createQuery": [MockFunction],

View File

@@ -0,0 +1,5 @@
import { QueryEditorProps } from '@grafana/data';
import { PrometheusDatasource } from '../datasource';
import { PromOptions, PromQuery } from '../types';
export type PromQueryEditorProps = QueryEditorProps<PrometheusDatasource, PromQuery, PromOptions>;