CloudWatch: Fetch Dimension keys correctly from Dimension Picker (#78556)

This commit is contained in:
Isabella Siu 2023-11-29 11:01:44 -05:00 committed by GitHub
parent faa29db241
commit 931c8e99b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 53 deletions

View File

@ -149,7 +149,7 @@ describe('VariableEditor', () => {
// change filter key
const keySelect = screen.getByRole('combobox', { name: 'Dimensions filter key' });
// confirms getDimensionKeys was called with filter and that the element uses keysForDimensionFilter
await select(keySelect, 'v4', {
select(keySelect, 'v4', {
container: document.body,
});
expect(ds.datasource.resources.getDimensionKeys).toHaveBeenCalledWith({
@ -158,14 +158,16 @@ describe('VariableEditor', () => {
metricName: 'i3',
dimensionFilters: undefined,
});
expect(onChange).toHaveBeenCalledWith({
...defaultQuery,
queryType: VariableQueryType.DimensionValues,
namespace: 'z2',
region: 'a1',
metricName: 'i3',
dimensionKey: 's4',
dimensionFilters: { v4: undefined },
await waitFor(() => {
expect(onChange).toHaveBeenCalledWith({
...defaultQuery,
queryType: VariableQueryType.DimensionValues,
namespace: 'z2',
region: 'a1',
metricName: 'i3',
dimensionKey: 's4',
dimensionFilters: { v4: undefined },
});
});
// set filter value

View File

@ -37,12 +37,11 @@ const queryTypes: Array<{ value: string; label: string }> = [
export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
const parsedQuery = migrateVariableQuery(query);
const { region, namespace, metricName, dimensionKey, dimensionFilters } = parsedQuery;
const { region, namespace, metricName, dimensionKey } = parsedQuery;
const [regions, regionIsLoading] = useRegions(datasource);
const namespaces = useNamespaces(datasource);
const metrics = useMetrics(datasource, { region, namespace });
const dimensionKeys = useDimensionKeys(datasource, { region, namespace, metricName });
const keysForDimensionFilter = useDimensionKeys(datasource, { region, namespace, metricName, dimensionFilters });
const accountState = useAccountOptions(datasource.resources, query.region);
const newFormStylingEnabled = config.featureToggles.awsDatasourcesNewFormStyling;
@ -188,7 +187,6 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
onChange={(dimensions) => {
onChange({ ...parsedQuery, dimensionFilters: dimensions });
}}
dimensionKeys={keysForDimensionFilter}
disableExpressions={true}
datasource={datasource}
/>
@ -205,7 +203,6 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
onChange={(dimensions) => {
onChange({ ...parsedQuery, dimensionFilters: dimensions });
}}
dimensionKeys={keysForDimensionFilter}
disableExpressions={true}
datasource={datasource}
/>

View File

@ -43,8 +43,8 @@ describe('Dimensions', () => {
InstanceId: '*',
InstanceGroup: 'Group1',
};
render(<Dimensions {...props} metricStat={props.query} dimensionKeys={[]} />);
const filterItems = screen.getAllByTestId('cloudwatch-dimensions-filter-item');
render(<Dimensions {...props} metricStat={props.query} />);
const filterItems = await screen.findAllByTestId('cloudwatch-dimensions-filter-item');
expect(filterItems.length).toBe(2);
expect(within(filterItems[0]).getByText('InstanceId')).toBeInTheDocument();
@ -61,8 +61,8 @@ describe('Dimensions', () => {
InstanceId: ['*'],
InstanceGroup: ['Group1'],
};
render(<Dimensions {...props} metricStat={props.query} dimensionKeys={[]} />);
const filterItems = screen.getAllByTestId('cloudwatch-dimensions-filter-item');
render(<Dimensions {...props} metricStat={props.query} />);
const filterItems = await screen.findAllByTestId('cloudwatch-dimensions-filter-item');
expect(filterItems.length).toBe(2);
expect(within(filterItems[0]).getByText('InstanceId')).toBeInTheDocument();
@ -77,7 +77,7 @@ describe('Dimensions', () => {
it('it should add the new item but not call onChange', async () => {
props.query.dimensions = {};
const onChange = jest.fn();
render(<Dimensions {...props} metricStat={props.query} onChange={onChange} dimensionKeys={[]} />);
render(<Dimensions {...props} metricStat={props.query} onChange={onChange} />);
await userEvent.click(screen.getByLabelText('Add'));
expect(screen.getByTestId('cloudwatch-dimensions-filter-item')).toBeInTheDocument();
@ -89,9 +89,7 @@ describe('Dimensions', () => {
it('it should add the new item but not call onChange', async () => {
props.query.dimensions = {};
const onChange = jest.fn();
const { container } = render(
<Dimensions {...props} metricStat={props.query} onChange={onChange} dimensionKeys={[]} />
);
const { container } = render(<Dimensions {...props} metricStat={props.query} onChange={onChange} />);
await userEvent.click(screen.getByLabelText('Add'));
const filterItemElement = screen.getByTestId('cloudwatch-dimensions-filter-item');
@ -109,9 +107,7 @@ describe('Dimensions', () => {
it('it should add the new item and trigger onChange', async () => {
props.query.dimensions = {};
const onChange = jest.fn();
const { container } = render(
<Dimensions {...props} metricStat={props.query} onChange={onChange} dimensionKeys={[]} />
);
const { container } = render(<Dimensions {...props} metricStat={props.query} onChange={onChange} />);
const label = await screen.findByLabelText('Add');
await userEvent.click(label);
@ -128,11 +124,8 @@ describe('Dimensions', () => {
expect(valueElement).toBeInTheDocument();
await userEvent.type(valueElement!, 'my-value');
fireEvent.keyDown(valueElement!, { keyCode: 13 });
expect(onChange).not.toHaveBeenCalledWith({
...props.query,
dimensions: {
'my-key': 'my-value',
},
expect(onChange).toHaveBeenCalledWith({
'my-key': 'my-value',
});
});
});

View File

@ -1,7 +1,6 @@
import { isEqual } from 'lodash';
import React, { useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorList } from '@grafana/experimental';
import { CloudWatchDatasource } from '../../../datasource';
@ -13,7 +12,6 @@ export interface Props {
metricStat: MetricStat;
onChange: (dimensions: DimensionsType) => void;
datasource: CloudWatchDatasource;
dimensionKeys: Array<SelectableValue<string>>;
disableExpressions: boolean;
}
@ -62,7 +60,7 @@ const filterConditionsToDimensions = (filters: DimensionFilterCondition[]) => {
}, {});
};
export const Dimensions = ({ metricStat, datasource, dimensionKeys, disableExpressions, onChange }: Props) => {
export const Dimensions = ({ metricStat, datasource, disableExpressions, onChange }: Props) => {
const dimensionFilters = useMemo(() => dimensionsToFilterConditions(metricStat.dimensions), [metricStat.dimensions]);
const [items, setItems] = useState<DimensionFilterCondition[]>(dimensionFilters);
const onDimensionsChange = (newItems: Array<Partial<DimensionFilterCondition>>) => {
@ -80,17 +78,12 @@ export const Dimensions = ({ metricStat, datasource, dimensionKeys, disableExpre
<EditorList
items={items}
onChange={onDimensionsChange}
renderItem={makeRenderFilter(datasource, metricStat, dimensionKeys, disableExpressions)}
renderItem={makeRenderFilter(datasource, metricStat, disableExpressions)}
/>
);
};
function makeRenderFilter(
datasource: CloudWatchDatasource,
metricStat: MetricStat,
dimensionKeys: Array<SelectableValue<string>>,
disableExpressions: boolean
) {
function makeRenderFilter(datasource: CloudWatchDatasource, metricStat: MetricStat, disableExpressions: boolean) {
function renderFilter(
item: DimensionFilterCondition,
onChange: (item: DimensionFilterCondition) => void,
@ -103,7 +96,6 @@ function makeRenderFilter(
datasource={datasource}
metricStat={metricStat}
disableExpressions={disableExpressions}
dimensionKeys={dimensionKeys}
onDelete={onDelete}
/>
);

View File

@ -0,0 +1,53 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { setupMockedDataSource } from '../../../__mocks__/CloudWatchDataSource';
import { CloudWatchMetricsQuery } from '../../../types';
import { FilterItem } from './FilterItem';
const ds = setupMockedDataSource({
variables: [],
});
const q: CloudWatchMetricsQuery = {
id: '',
region: 'us-east-2',
namespace: '',
period: '',
alias: '',
metricName: '',
dimensions: { foo: 'bar', abc: 'xyz' },
matchExact: true,
statistic: '',
expression: '',
refId: '',
};
describe('Dimensions', () => {
it('should call getDimensionKeys without the current key', async () => {
const getDimensionKeys = jest.fn().mockResolvedValue([]);
ds.datasource.resources.getDimensionKeys = getDimensionKeys;
const currFilter = { key: 'foo', value: 'bar' };
render(
<FilterItem
metricStat={q}
datasource={ds.datasource}
filter={currFilter}
disableExpressions={true}
onChange={jest.fn()}
onDelete={jest.fn()}
/>
);
await userEvent.click(screen.getByLabelText('Dimensions filter key'));
expect(getDimensionKeys).toHaveBeenCalledWith({
namespace: q.namespace,
region: q.region,
metricName: q.metricName,
accountId: q.accountId,
dimensionFilters: { abc: ['xyz'] },
});
});
});

View File

@ -7,6 +7,7 @@ import { AccessoryButton, InputGroup } from '@grafana/experimental';
import { Select, useStyles2 } from '@grafana/ui';
import { CloudWatchDatasource } from '../../../datasource';
import { useDimensionKeys } from '../../../hooks';
import { Dimensions, MetricStat } from '../../../types';
import { appendTemplateVariables } from '../../../utils/utils';
@ -16,7 +17,6 @@ export interface Props {
metricStat: MetricStat;
datasource: CloudWatchDatasource;
filter: DimensionFilterCondition;
dimensionKeys: Array<SelectableValue<string>>;
disableExpressions: boolean;
onChange: (value: DimensionFilterCondition) => void;
onDelete: () => void;
@ -32,19 +32,16 @@ const excludeCurrentKey = (dimensions: Dimensions, currentKey: string | undefine
return acc;
}, {});
export const FilterItem = ({
filter,
metricStat: { region, namespace, metricName, dimensions, accountId },
datasource,
dimensionKeys,
disableExpressions,
onChange,
onDelete,
}: Props) => {
export const FilterItem = ({ filter, metricStat, datasource, disableExpressions, onChange, onDelete }: Props) => {
const { region, namespace, metricName, dimensions, accountId } = metricStat;
const dimensionsExcludingCurrentKey = useMemo(
() => excludeCurrentKey(dimensions ?? {}, filter.key),
[dimensions, filter]
);
const dimensionKeys = useDimensionKeys(datasource, {
...metricStat,
dimensionFilters: dimensionsExcludingCurrentKey,
});
const loadDimensionValues = async () => {
if (!filter.key) {

View File

@ -6,7 +6,7 @@ import { config } from '@grafana/runtime';
import { Select } from '@grafana/ui';
import { CloudWatchDatasource } from '../../../datasource';
import { useAccountOptions, useDimensionKeys, useMetrics, useNamespaces } from '../../../hooks';
import { useAccountOptions, useMetrics, useNamespaces } from '../../../hooks';
import { standardStatistics } from '../../../standardStatistics';
import { MetricStat } from '../../../types';
import { appendTemplateVariables, toOption } from '../../../utils/utils';
@ -35,7 +35,6 @@ export const MetricStatEditor = ({
}: React.PropsWithChildren<Props>) => {
const namespaces = useNamespaces(datasource);
const metrics = useMetrics(datasource, metricStat);
const dimensionKeys = useDimensionKeys(datasource, { ...metricStat, dimensionFilters: metricStat.dimensions });
const accountState = useAccountOptions(datasource.resources, metricStat.region);
useEffect(() => {
@ -139,7 +138,6 @@ export const MetricStatEditor = ({
<Dimensions
metricStat={metricStat}
onChange={(dimensions) => onChange({ ...metricStat, dimensions })}
dimensionKeys={dimensionKeys}
disableExpressions={disableExpressions}
datasource={datasource}
/>