Query components unsafe lifecycle methods (#21163)

* Chore: refactor query components unsafe lifecycle methods

* Chore: remove redundant defaults

* Chore: check expression exist while filter targets in query

* Chore: fix broken test

* Chore: adding query filed tests

* pass normalized query to QueryFieldsEditor

Signed-off-by: Boyko Lalov <boiskila@gmail.com>

* Remove introduced strictNullCheck errors and correctly solve merged conficts

* Improve redability and fix strictNullChecks

Co-authored-by: Ivana <ivana.huckova@gmail.com>
This commit is contained in:
Boyko
2020-03-20 14:00:49 +02:00
committed by GitHub
parent aea3929154
commit c600a08524
5 changed files with 91 additions and 85 deletions

View File

@@ -5,7 +5,7 @@ import { act } from 'react-dom/test-utils';
import { DataSourceInstanceSettings } from '@grafana/data';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { CustomVariable } from 'app/features/templating/all';
import { Props, QueryEditor } from './QueryEditor';
import { Props, QueryEditor, normalizeQuery } from './QueryEditor';
import CloudWatchDatasource from '../datasource';
const setup = () => {
@@ -86,26 +86,19 @@ describe('QueryEditor', () => {
});
});
it('should init props correctly', async () => {
// @ts-ignore strict null error TS2345: Argument of type '() => Promise<void>' is not assignable to parameter of type '() => void | undefined'.
await act(async () => {
const props = setup();
props.query.namespace = (null as unknown) as string;
props.query.metricName = (null as unknown) as string;
props.query.expression = (null as unknown) as string;
props.query.dimensions = (null as unknown) as { [key: string]: string | string[] };
props.query.region = (null as unknown) as string;
props.query.statistics = (null as unknown) as string[];
const wrapper = mount(<QueryEditor {...props} />);
const {
query: { namespace, region, metricName, dimensions, statistics, expression },
} = wrapper.props();
expect(namespace).toEqual('');
expect(metricName).toEqual('');
expect(expression).toEqual('');
expect(region).toEqual('default');
expect(statistics).toEqual(['Average']);
expect(dimensions).toEqual({});
it('should normalize query with default values', () => {
expect(normalizeQuery({ refId: '42' } as any)).toEqual({
namespace: '',
metricName: '',
expression: '',
dimensions: {},
region: 'default',
id: '',
alias: '',
statistics: ['Average'],
matchExact: true,
period: '',
refId: '42',
});
});
});

View File

@@ -1,6 +1,7 @@
import React, { PureComponent, ChangeEvent } from 'react';
import { ExploreQueryFieldProps } from '@grafana/data';
import { Input, ValidationEvents, EventsWithValidation, Switch } from '@grafana/ui';
import isEmpty from 'lodash/isEmpty';
import { CloudWatchQuery } from '../types';
import CloudWatchDatasource from '../datasource';
import { QueryField, Alias, QueryFieldsEditor } from './';
@@ -20,51 +21,36 @@ const idValidationEvents: ValidationEvents = {
],
};
export const normalizeQuery = ({
namespace,
metricName,
expression,
dimensions,
region,
id,
alias,
statistics,
period,
...rest
}: CloudWatchQuery): CloudWatchQuery => {
const normalizedQuery = {
namespace: namespace || '',
metricName: metricName || '',
expression: expression || '',
dimensions: dimensions || {},
region: region || 'default',
id: id || '',
alias: alias || '',
statistics: isEmpty(statistics) ? ['Average'] : statistics,
period: period || '',
...rest,
};
return !rest.hasOwnProperty('matchExact') ? { ...normalizedQuery, matchExact: true } : normalizedQuery;
};
export class QueryEditor extends PureComponent<Props, State> {
state: State = { showMeta: false };
static getDerivedStateFromProps(props: Props, state: State) {
const { query } = props;
if (!query.namespace) {
query.namespace = '';
}
if (!query.metricName) {
query.metricName = '';
}
if (!query.expression) {
query.expression = '';
}
if (!query.dimensions) {
query.dimensions = {};
}
if (!query.region) {
query.region = 'default';
}
if (!query.id) {
query.id = '';
}
if (!query.alias) {
query.alias = '';
}
if (!query.statistics || !query.statistics.length) {
query.statistics = ['Average'];
}
if (!query.hasOwnProperty('matchExact')) {
query.matchExact = true;
}
return state;
}
onChange(query: CloudWatchQuery) {
const { onChange, onRunQuery } = this.props;
onChange(query);
@@ -72,12 +58,13 @@ export class QueryEditor extends PureComponent<Props, State> {
}
render() {
const { data, query, onRunQuery } = this.props;
const { data, onRunQuery } = this.props;
const { showMeta } = this.state;
const query = normalizeQuery(this.props.query);
const metaDataExist = data && Object.values(data).length && data.state === 'Done';
return (
<>
<QueryFieldsEditor {...this.props}></QueryFieldsEditor>
<QueryFieldsEditor {...{ ...this.props, query }}></QueryFieldsEditor>
{query.statistics.length <= 1 && (
<div className="gf-form-inline">
<div className="gf-form">
@@ -92,7 +79,7 @@ export class QueryEditor extends PureComponent<Props, State> {
this.onChange({ ...query, id: event.target.value })
}
validationEvents={idValidationEvents}
value={query.id || ''}
value={query.id}
/>
</QueryField>
</div>
@@ -105,7 +92,7 @@ export class QueryEditor extends PureComponent<Props, State> {
<Input
className="gf-form-input"
onBlur={onRunQuery}
value={query.expression || ''}
value={query.expression}
onChange={(event: ChangeEvent<HTMLInputElement>) =>
this.onChange({ ...query, expression: event.target.value })
}
@@ -119,7 +106,7 @@ export class QueryEditor extends PureComponent<Props, State> {
<QueryField label="Period" tooltip="Minimum interval between points in seconds">
<Input
className="gf-form-input width-8"
value={query.period || ''}
value={query.period}
placeholder="auto"
onBlur={onRunQuery}
onChange={(event: ChangeEvent<HTMLInputElement>) =>
@@ -170,7 +157,7 @@ export class QueryEditor extends PureComponent<Props, State> {
</tr>
</thead>
<tbody>
{data.series[0].meta.gmdMeta.map(({ ID, Expression, Period }: any) => (
{data?.series[0]?.meta?.gmdMeta.map(({ ID, Expression, Period }: any) => (
<tr key={ID}>
<td>{ID}</td>
<td>{Expression}</td>