Azure Monitor: Add current value to editor options (#60726)

This commit is contained in:
Andres Martinez Gotor 2022-12-23 18:43:43 +01:00 committed by GitHub
parent bb5ac924ae
commit 7a679db08b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 167 additions and 19 deletions

View File

@ -0,0 +1,45 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
import { AzureMonitorOption } from '../../types';
import AggregationField from './AggregationField';
const props = {
aggregationOptions: [],
query: createMockQuery(),
datasource: createMockDatasource(),
variableOptionGroup: { label: 'Templates', options: [] },
onQueryChange: jest.fn(),
setError: jest.fn(),
isLoading: false,
};
describe('AggregationField', () => {
it('should render the current value', async () => {
const aggregationOptions: AzureMonitorOption[] = [{ label: 'foo', value: 'foo' }];
const query = {
...props.query,
azureMonitor: {
aggregation: 'foo',
},
};
render(<AggregationField {...props} aggregationOptions={aggregationOptions} query={query} />);
expect(screen.queryByText('foo')).toBeInTheDocument();
});
it('should render the current value even if it is not in the list of options', async () => {
const aggregationOptions: AzureMonitorOption[] = [{ label: 'foo', value: 'foo' }];
const query = {
...props.query,
azureMonitor: {
aggregation: 'bar',
},
};
render(<AggregationField {...props} aggregationOptions={aggregationOptions} query={query} />);
expect(screen.queryByText('bar')).toBeInTheDocument();
expect(screen.queryByText('foo')).not.toBeInTheDocument();
});
});

View File

@ -1,9 +1,10 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
import { addValueToOptions } from '../../utils/common';
import { Field } from '../Field';
import { setAggregation } from './setQueryValue';
@ -32,10 +33,7 @@ const AggregationField: React.FC<AggregationFieldProps> = ({
[onQueryChange, query]
);
const options = useMemo(
() => [...aggregationOptions, variableOptionGroup],
[aggregationOptions, variableOptionGroup]
);
const options = addValueToOptions(aggregationOptions, variableOptionGroup, query.azureMonitor?.aggregation);
return (
<Field label="Aggregation">

View File

@ -0,0 +1,44 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
import { AzureMonitorOption } from '../../types';
import MetricNameField from './MetricNameField';
const props = {
metricNames: [],
query: createMockQuery(),
datasource: createMockDatasource(),
variableOptionGroup: { label: 'Templates', options: [] },
onQueryChange: jest.fn(),
setError: jest.fn(),
};
describe('MetricNameField', () => {
it('should render the current value', async () => {
const metricNames: AzureMonitorOption[] = [{ label: 'foo', value: 'foo' }];
const query = {
...props.query,
azureMonitor: {
metricName: 'foo',
},
};
render(<MetricNameField {...props} metricNames={metricNames} query={query} />);
expect(screen.queryByText('foo')).toBeInTheDocument();
});
it('should render the current value even if it is not in the list of options', async () => {
const metricNames: AzureMonitorOption[] = [{ label: 'foo', value: 'foo' }];
const query = {
...props.query,
azureMonitor: {
metricName: 'bar',
},
};
render(<MetricNameField {...props} metricNames={metricNames} query={query} />);
expect(screen.queryByText('bar')).toBeInTheDocument();
expect(screen.queryByText('foo')).not.toBeInTheDocument();
});
});

View File

@ -1,10 +1,11 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
import { selectors } from '../../e2e/selectors';
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
import { addValueToOptions } from '../../utils/common';
import { Field } from '../Field';
import { setMetricName } from './setQueryValue';
@ -26,7 +27,7 @@ const MetricNameField: React.FC<MetricNameProps> = ({ metricNames, query, variab
[onQueryChange, query]
);
const options = useMemo(() => [...metricNames, variableOptionGroup], [metricNames, variableOptionGroup]);
const options = addValueToOptions(metricNames, variableOptionGroup, query.azureMonitor?.metricName);
return (
<Field label="Metric" data-testid={selectors.components.queryEditor.metricsQueryEditor.metricName.input}>

View File

@ -1,9 +1,10 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
import { addValueToOptions } from '../../utils/common';
import { Field } from '../Field';
import { setCustomNamespace } from './setQueryValue';
@ -30,14 +31,8 @@ const MetricNamespaceField: React.FC<MetricNamespaceFieldProps> = ({
[onQueryChange, query]
);
const options = useMemo(() => [...metricNamespaces, variableOptionGroup], [metricNamespaces, variableOptionGroup]);
const optionValues = metricNamespaces
.map((m) => m.value.toLowerCase())
.concat(variableOptionGroup.options.map((p) => p.value));
const value = query.azureMonitor?.customNamespace || query.azureMonitor?.metricNamespace;
if (value && !optionValues.includes(value.toLowerCase())) {
options.push({ label: value, value });
}
const options = addValueToOptions(metricNamespaces, variableOptionGroup, value);
return (
<Field label="Metric namespace">

View File

@ -0,0 +1,45 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
import { AzureMonitorOption } from '../../types';
import TimeGrainField from './TimeGrainField';
const props = {
timeGrainOptions: [],
query: createMockQuery(),
datasource: createMockDatasource(),
variableOptionGroup: { label: 'Templates', options: [] },
onQueryChange: jest.fn(),
setError: jest.fn(),
isLoading: false,
};
describe('TimeGrainField', () => {
it('should render the current value', async () => {
const timeGrainOptions: AzureMonitorOption[] = [{ label: '15m', value: '15m' }];
const query = {
...props.query,
azureMonitor: {
timeGrain: '15m',
},
};
render(<TimeGrainField {...props} timeGrainOptions={timeGrainOptions} query={query} />);
expect(screen.queryByText('15m')).toBeInTheDocument();
});
it('should render the current value even if it is not in the list of options', async () => {
const timeGrainOptions: AzureMonitorOption[] = [{ label: '15m', value: '15m' }];
const query = {
...props.query,
azureMonitor: {
timeGrain: '1h',
},
};
render(<TimeGrainField {...props} timeGrainOptions={timeGrainOptions} query={query} />);
expect(screen.queryByText('1h')).toBeInTheDocument();
expect(screen.queryByText('15m')).not.toBeInTheDocument();
});
});

View File

@ -5,6 +5,7 @@ import { Select } from '@grafana/ui';
import TimegrainConverter from '../../time_grain_converter';
import { AzureQueryEditorFieldProps, AzureMonitorOption } from '../../types';
import { addValueToOptions } from '../../utils/common';
import { Field } from '../Field';
import { setTimeGrain } from './setQueryValue';
@ -48,8 +49,10 @@ const TimeGrainField: React.FC<TimeGrainFieldProps> = ({
const baseTimeGrains = timeGrainOptions.map((v) => (v.value === 'auto' ? { ...v, description: autoInterval } : v));
return [...baseTimeGrains, variableOptionGroup];
}, [timeGrainOptions, variableOptionGroup]);
const options = addValueToOptions(baseTimeGrains, variableOptionGroup, query.azureMonitor?.timeGrain);
return options;
}, [timeGrainOptions, variableOptionGroup, query.azureMonitor?.timeGrain]);
return (
<Field label="Time grain">

View File

@ -158,12 +158,14 @@ export interface AzureMonitorOption<T = string> {
options?: AzureMonitorOption[];
}
export type VariableOptionGroup = { label: string; options: AzureMonitorOption[] };
export interface AzureQueryEditorFieldProps {
data?: PanelData;
query: AzureMonitorQuery;
datasource: Datasource;
subscriptionId?: string;
variableOptionGroup: { label: string; options: AzureMonitorOption[] };
variableOptionGroup: VariableOptionGroup;
onQueryChange: (newQuery: AzureMonitorQuery) => void;
setError: (source: string, error: AzureMonitorErrorish | undefined) => void;

View File

@ -4,7 +4,7 @@ import { rangeUtil } from '@grafana/data';
import { VariableWithMultiSupport } from 'app/features/variables/types';
import TimegrainConverter from '../time_grain_converter';
import { AzureMonitorOption } from '../types';
import { AzureMonitorOption, VariableOptionGroup } from '../types';
export const hasOption = (options: AzureMonitorOption[], value: string): boolean =>
options.some((v) => (v.options ? hasOption(v.options, value) : v.value === value));
@ -22,6 +22,21 @@ export const findOptions = (options: AzureMonitorOption[], values: string[] = []
export const toOption = (v: { text: string; value: string }) => ({ value: v.value, label: v.text });
export const addValueToOptions = (
values: AzureMonitorOption[],
variableOptionGroup: VariableOptionGroup,
value?: string
) => {
const options = [...values, variableOptionGroup];
const optionValues = values.map((m) => m.value.toLowerCase()).concat(variableOptionGroup.options.map((p) => p.value));
if (value && !optionValues.includes(value.toLowerCase())) {
options.push({ label: value, value });
}
return options;
};
export function convertTimeGrainsToMs<T extends { value: string }>(timeGrains: T[]) {
const allowedTimeGrainsMs: number[] = [];
timeGrains.forEach((tg: any) => {