Cloudwatch: Use new annotation API (#48102)

* use new annotation api

* fix bad merge
This commit is contained in:
Erik Sundell
2022-04-27 12:41:48 +02:00
committed by GitHub
parent 25e153e4e7
commit f58a2d879e
27 changed files with 530 additions and 378 deletions

View File

@@ -1,8 +1,12 @@
import { render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import '@testing-library/jest-dom';
import { QueryEditorProps } from '@grafana/data';
import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource';
import { CloudWatchAnnotationQuery } from '../types';
import { CloudWatchDatasource } from '../datasource';
import { CloudWatchAnnotationQuery, CloudWatchJsonData, CloudWatchMetricsQuery, CloudWatchQuery } from '../types';
import { AnnotationQueryEditor } from './AnnotationQueryEditor';
@@ -10,21 +14,16 @@ const ds = setupMockedDataSource({
variables: [],
});
const q: CloudWatchAnnotationQuery = {
id: '',
const q: CloudWatchQuery = {
queryMode: 'Annotations',
region: 'us-east-2',
namespace: '',
period: '',
alias: '',
metricName: '',
dimensions: {},
matchExact: true,
statistic: '',
expression: '',
refId: '',
enable: true,
name: '',
iconColor: '',
prefixMatching: false,
actionPrefix: '',
alarmNamePrefix: '',
@@ -36,7 +35,7 @@ ds.datasource.getMetrics = jest.fn().mockResolvedValue([]);
ds.datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
const props = {
const props: QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData> = {
datasource: ds.datasource,
query: q,
onChange: jest.fn(),
@@ -51,11 +50,18 @@ describe('AnnotationQueryEditor', () => {
});
});
it('should return an error component in case CloudWatchQuery is not CloudWatchAnnotationQuery', async () => {
ds.datasource.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
render(
<AnnotationQueryEditor {...props} query={{ ...props.query, queryMode: 'Metrics' } as CloudWatchMetricsQuery} />
);
await waitFor(() => expect(screen.getByText('Invalid annotation query')).toBeInTheDocument());
});
it('should not display wildcard option in dimension value dropdown', async () => {
ds.datasource.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
props.query.dimensions = { instanceId: 'instance-123' };
(props.query as CloudWatchAnnotationQuery).dimensions = { instanceId: 'instance-123' };
render(<AnnotationQueryEditor {...props} />);
const valueElement = screen.getByText('instance-123');
expect(valueElement).toBeInTheDocument();
expect(screen.queryByText('*')).toBeNull();

View File

@@ -1,27 +1,30 @@
import React, { ChangeEvent } from 'react';
import { PanelData } from '@grafana/data';
import { EditorField, EditorHeader, EditorRow, EditorSwitch, InlineSelect, Space } from '@grafana/experimental';
import { Input } from '@grafana/ui';
import { QueryEditorProps } from '@grafana/data';
import { EditorField, EditorHeader, EditorRow, InlineSelect, Space, EditorSwitch } from '@grafana/experimental';
import { Alert, Input } from '@grafana/ui';
import { CloudWatchDatasource } from '../datasource';
import { isCloudWatchAnnotationQuery } from '../guards';
import { useRegions } from '../hooks';
import { CloudWatchAnnotationQuery, CloudWatchMetricsQuery } from '../types';
import { CloudWatchJsonData, CloudWatchQuery, MetricStat } from '../types';
import { MetricStatEditor } from './MetricStatEditor';
export type Props = {
query: CloudWatchAnnotationQuery;
datasource: CloudWatchDatasource;
onChange: (value: CloudWatchAnnotationQuery) => void;
data?: PanelData;
};
export type Props = QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData>;
export function AnnotationQueryEditor(props: React.PropsWithChildren<Props>) {
export const AnnotationQueryEditor = (props: Props) => {
const { query, onChange, datasource } = props;
const [regions, regionIsLoading] = useRegions(datasource);
if (!isCloudWatchAnnotationQuery(query)) {
return (
<Alert severity="error" title="Invalid annotation query" topSpacing={2}>
{JSON.stringify(query, null, 4)}
</Alert>
);
}
return (
<>
<EditorHeader>
@@ -38,8 +41,10 @@ export function AnnotationQueryEditor(props: React.PropsWithChildren<Props>) {
<Space v={0.5} />
<MetricStatEditor
{...props}
refId={query.refId}
metricStat={query}
disableExpressions={true}
onChange={(editorQuery: CloudWatchMetricsQuery) => onChange({ ...query, ...editorQuery })}
onChange={(metricStat: MetricStat) => onChange({ ...query, ...metricStat })}
onRunQuery={() => {}}
></MetricStatEditor>
<Space v={0.5} />
@@ -81,4 +86,4 @@ export function AnnotationQueryEditor(props: React.PropsWithChildren<Props>) {
</EditorRow>
</>
);
}
};

View File

@@ -43,7 +43,7 @@ describe('Dimensions', () => {
InstanceId: '*',
InstanceGroup: 'Group1',
};
render(<Dimensions {...props} query={props.query} dimensionKeys={[]} />);
render(<Dimensions {...props} metricStat={props.query} dimensionKeys={[]} />);
const filterItems = screen.getAllByTestId('cloudwatch-dimensions-filter-item');
expect(filterItems.length).toBe(2);
@@ -59,7 +59,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} query={props.query} onChange={onChange} dimensionKeys={[]} />);
render(<Dimensions {...props} metricStat={props.query} onChange={onChange} dimensionKeys={[]} />);
await userEvent.click(screen.getByLabelText('Add'));
expect(screen.getByTestId('cloudwatch-dimensions-filter-item')).toBeInTheDocument();
@@ -72,7 +72,7 @@ describe('Dimensions', () => {
props.query.dimensions = {};
const onChange = jest.fn();
const { container } = render(
<Dimensions {...props} query={props.query} onChange={onChange} dimensionKeys={[]} />
<Dimensions {...props} metricStat={props.query} onChange={onChange} dimensionKeys={[]} />
);
await userEvent.click(screen.getByLabelText('Add'));
@@ -92,7 +92,7 @@ describe('Dimensions', () => {
props.query.dimensions = {};
const onChange = jest.fn();
const { container } = render(
<Dimensions {...props} query={props.query} onChange={onChange} dimensionKeys={[]} />
<Dimensions {...props} metricStat={props.query} onChange={onChange} dimensionKeys={[]} />
);
const label = await screen.findByLabelText('Add');

View File

@@ -1,16 +1,16 @@
import { isEqual } from 'lodash';
import React, { useEffect, useState } from 'react';
import React, { useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorList } from '@grafana/experimental';
import { CloudWatchDatasource } from '../../datasource';
import { Dimensions as DimensionsType, DimensionsQuery } from '../../types';
import { Dimensions as DimensionsType, MetricStat } from '../../types';
import { FilterItem } from './FilterItem';
export interface Props {
query: DimensionsQuery;
metricStat: MetricStat;
onChange: (dimensions: DimensionsType) => void;
datasource: CloudWatchDatasource;
dimensionKeys: Array<SelectableValue<string>>;
@@ -45,16 +45,22 @@ const filterConditionsToDimensions = (filters: DimensionFilterCondition[]) => {
}, {});
};
export const Dimensions: React.FC<Props> = ({ query, datasource, dimensionKeys, disableExpressions, onChange }) => {
const [items, setItems] = useState<DimensionFilterCondition[]>([]);
useEffect(() => setItems(dimensionsToFilterConditions(query.dimensions)), [query.dimensions]);
export const Dimensions: React.FC<Props> = ({
metricStat,
datasource,
dimensionKeys,
disableExpressions,
onChange,
}) => {
const dimensionFilters = useMemo(() => dimensionsToFilterConditions(metricStat.dimensions), [metricStat.dimensions]);
const [items, setItems] = useState<DimensionFilterCondition[]>(dimensionFilters);
const onDimensionsChange = (newItems: Array<Partial<DimensionFilterCondition>>) => {
setItems(newItems);
// The onChange event should only be triggered in the case there is a complete dimension object.
// So when a new key is added that does not yet have a value, it should not trigger an onChange event.
const newDimensions = filterConditionsToDimensions(newItems);
if (!isEqual(newDimensions, query.dimensions)) {
if (!isEqual(newDimensions, metricStat.dimensions)) {
onChange(newDimensions);
}
};
@@ -63,14 +69,14 @@ export const Dimensions: React.FC<Props> = ({ query, datasource, dimensionKeys,
<EditorList
items={items}
onChange={onDimensionsChange}
renderItem={makeRenderFilter(datasource, query, dimensionKeys, disableExpressions)}
renderItem={makeRenderFilter(datasource, metricStat, dimensionKeys, disableExpressions)}
/>
);
};
function makeRenderFilter(
datasource: CloudWatchDatasource,
query: DimensionsQuery,
metricStat: MetricStat,
dimensionKeys: Array<SelectableValue<string>>,
disableExpressions: boolean
) {
@@ -84,7 +90,7 @@ function makeRenderFilter(
filter={item}
onChange={(item) => onChange(item)}
datasource={datasource}
query={query}
metricStat={metricStat}
disableExpressions={disableExpressions}
dimensionKeys={dimensionKeys}
onDelete={onDelete}

View File

@@ -3,17 +3,17 @@ import React, { FunctionComponent, useMemo } from 'react';
import { useAsyncFn } from 'react-use';
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
import { InputGroup, AccessoryButton } from '@grafana/experimental';
import { AccessoryButton, InputGroup } from '@grafana/experimental';
import { Select, stylesFactory, useTheme2 } from '@grafana/ui';
import { CloudWatchDatasource } from '../../datasource';
import { Dimensions, DimensionsQuery } from '../../types';
import { Dimensions, MetricStat } from '../../types';
import { appendTemplateVariables } from '../../utils/utils';
import { DimensionFilterCondition } from './Dimensions';
export interface Props {
query: DimensionsQuery;
metricStat: MetricStat;
datasource: CloudWatchDatasource;
filter: DimensionFilterCondition;
dimensionKeys: Array<SelectableValue<string>>;
@@ -34,7 +34,7 @@ const excludeCurrentKey = (dimensions: Dimensions, currentKey: string | undefine
export const FilterItem: FunctionComponent<Props> = ({
filter,
query: { region, namespace, metricName, dimensions },
metricStat: { region, namespace, metricName, dimensions },
datasource,
dimensionKeys,
disableExpressions,

View File

@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
import { intersectionBy, debounce, unionBy } from 'lodash';
import { debounce, intersectionBy, unionBy } from 'lodash';
import { LanguageMap, languages as prismLanguages } from 'prismjs';
import React, { ReactNode } from 'react';
import { Editor, Node, Plugin } from 'slate';
@@ -19,6 +19,8 @@ import { notifyApp } from 'app/core/actions';
import { createErrorNotification } from 'app/core/copy/appNotification';
import { dispatch } from 'app/store/store';
import { ExploreId } from 'app/types';
// Utils & Services
// dom also includes Element polyfills
import { CloudWatchDatasource } from '../datasource';
import { CloudWatchLanguageProvider } from '../language_provider';
@@ -339,7 +341,7 @@ export class CloudWatchLogsQueryField extends React.PureComponent<CloudWatchLogs
<div className="gf-form gf-form--grow flex-shrink-1">
<QueryField
additionalPlugins={this.plugins}
query={query.expression ?? ''}
query={(query as CloudWatchLogsQuery).expression ?? ''}
onChange={this.onChangeQuery}
onClick={this.onQueryFieldClick}
onRunQuery={this.props.onRunQuery}

View File

@@ -1,11 +1,11 @@
import { fireEvent, render, screen, act, waitFor } from '@testing-library/react';
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import selectEvent from 'react-select-event';
import { MetricStatEditor } from '..';
import { setupMockedDataSource } from '../../__mocks__/CloudWatchDataSource';
import { CloudWatchMetricsQuery } from '../../types';
import { MetricStat } from '../../types';
const ds = setupMockedDataSource({
variables: [],
@@ -15,23 +15,19 @@ ds.datasource.getNamespaces = jest.fn().mockResolvedValue([]);
ds.datasource.getMetrics = jest.fn().mockResolvedValue([]);
ds.datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
const q: CloudWatchMetricsQuery = {
id: '',
const metricStat: MetricStat = {
region: 'us-east-2',
namespace: '',
period: '',
alias: '',
metricName: '',
dimensions: {},
matchExact: true,
statistic: '',
expression: '',
refId: '',
matchExact: true,
};
const props = {
refId: 'A',
datasource: ds.datasource,
query: q,
metricStat,
onChange: jest.fn(),
onRunQuery: jest.fn(),
};
@@ -50,7 +46,7 @@ describe('MetricStatEditor', () => {
await userEvent.type(statisticElement, statistic);
fireEvent.keyDown(statisticElement, { keyCode: 13 });
expect(onChange).toHaveBeenCalledWith({ ...props.query, statistic });
expect(onChange).toHaveBeenCalledWith({ ...props.metricStat, statistic });
expect(onRunQuery).toHaveBeenCalled();
});
@@ -96,7 +92,13 @@ describe('MetricStatEditor', () => {
});
it('should be unchecked when value is false', async () => {
render(<MetricStatEditor {...props} query={{ ...props.query, matchExact: false }} disableExpressions={false} />);
render(
<MetricStatEditor
{...props}
metricStat={{ ...props.metricStat, matchExact: false }}
disableExpressions={false}
/>
);
expect(await screen.findByLabelText('Match exact - optional')).not.toBeChecked();
});
});
@@ -139,24 +141,24 @@ describe('MetricStatEditor', () => {
await selectEvent.select(metricsSelect, 'm1');
expect(onChange.mock.calls).toEqual([
[{ ...propsNamespaceMetrics.query, namespace: 'n1' }], // First call, namespace select
[{ ...propsNamespaceMetrics.query, metricName: 'm1' }], // Second call, metric select
[{ ...propsNamespaceMetrics.metricStat, namespace: 'n1' }], // First call, namespace select
[{ ...propsNamespaceMetrics.metricStat, metricName: 'm1' }], // Second call, metric select
]);
expect(onRunQuery).toHaveBeenCalledTimes(2);
});
it('should remove metricName from query if it does not exist in new namespace', async () => {
it('should remove metricName from metricStat if it does not exist in new namespace', async () => {
propsNamespaceMetrics.datasource.getMetrics = jest
.fn()
.mockImplementation((namespace: string, region: string) => {
let mockMetrics =
namespace === 'n1' && region === props.query.region
namespace === 'n1' && region === props.metricStat.region
? metrics
: [{ value: 'oldNamespaceMetric', label: 'oldNamespaceMetric', text: 'oldNamespaceMetric' }];
return Promise.resolve(mockMetrics);
});
propsNamespaceMetrics.query.metricName = 'oldNamespaceMetric';
propsNamespaceMetrics.query.namespace = 'n2';
propsNamespaceMetrics.metricStat.metricName = 'oldNamespaceMetric';
propsNamespaceMetrics.metricStat.namespace = 'n2';
await act(async () => {
render(<MetricStatEditor {...propsNamespaceMetrics} />);
@@ -167,12 +169,12 @@ describe('MetricStatEditor', () => {
await selectEvent.select(namespaceSelect, 'n1');
expect(onChange.mock.calls).toEqual([[{ ...propsNamespaceMetrics.query, metricName: '', namespace: 'n1' }]]);
expect(onChange.mock.calls).toEqual([[{ ...propsNamespaceMetrics.metricStat, metricName: '', namespace: 'n1' }]]);
});
it('should not remove metricName from query if it does exist in new namespace', async () => {
propsNamespaceMetrics.query.namespace = 'n1';
propsNamespaceMetrics.query.metricName = 'm1';
it('should not remove metricName from metricStat if it does exist in new namespace', async () => {
propsNamespaceMetrics.metricStat.namespace = 'n1';
propsNamespaceMetrics.metricStat.metricName = 'm1';
await act(async () => {
render(<MetricStatEditor {...propsNamespaceMetrics} />);
@@ -184,7 +186,9 @@ describe('MetricStatEditor', () => {
await selectEvent.select(namespaceSelect, 'n2');
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange.mock.calls).toEqual([[{ ...propsNamespaceMetrics.query, metricName: 'm1', namespace: 'n2' }]]);
expect(onChange.mock.calls).toEqual([
[{ ...propsNamespaceMetrics.metricStat, metricName: 'm1', namespace: 'n2' }],
]);
});
});
});

View File

@@ -7,50 +7,52 @@ import { Select } from '@grafana/ui';
import { Dimensions } from '..';
import { CloudWatchDatasource } from '../../datasource';
import { useDimensionKeys, useMetrics, useNamespaces } from '../../hooks';
import { CloudWatchMetricsQuery } from '../../types';
import { MetricStat } from '../../types';
import { appendTemplateVariables, toOption } from '../../utils/utils';
export type Props = {
query: CloudWatchMetricsQuery;
refId: string;
metricStat: MetricStat;
datasource: CloudWatchDatasource;
disableExpressions?: boolean;
onChange: (value: CloudWatchMetricsQuery) => void;
onChange: (value: MetricStat) => void;
onRunQuery: () => void;
};
export function MetricStatEditor({
query,
refId,
metricStat,
datasource,
disableExpressions = false,
onChange,
onRunQuery,
}: React.PropsWithChildren<Props>) {
const { region, namespace, metricName, dimensions } = query;
const { region, namespace, metricName, dimensions } = metricStat;
const namespaces = useNamespaces(datasource);
const metrics = useMetrics(datasource, region, namespace);
const dimensionKeys = useDimensionKeys(datasource, region, namespace, metricName, dimensions ?? {});
const onQueryChange = (query: CloudWatchMetricsQuery) => {
onChange(query);
const onMetricStatChange = (metricStat: MetricStat) => {
onChange(metricStat);
onRunQuery();
};
const onNamespaceChange = async (query: CloudWatchMetricsQuery) => {
const validatedQuery = await validateMetricName(query);
onQueryChange(validatedQuery);
const onNamespaceChange = async (metricStat: MetricStat) => {
const validatedQuery = await validateMetricName(metricStat);
onMetricStatChange(validatedQuery);
};
const validateMetricName = async (query: CloudWatchMetricsQuery) => {
let { metricName, namespace, region } = query;
const validateMetricName = async (metricStat: MetricStat) => {
let { metricName, namespace, region } = metricStat;
if (!metricName) {
return query;
return metricStat;
}
await datasource.getMetrics(namespace, region).then((result: Array<SelectableValue<string>>) => {
if (!result.find((metric) => metric.value === metricName)) {
metricName = '';
}
});
return { ...query, metricName };
return { ...metricStat, metricName };
};
return (
@@ -60,12 +62,12 @@ export function MetricStatEditor({
<EditorField label="Namespace" width={26}>
<Select
aria-label="Namespace"
value={query.namespace}
value={metricStat.namespace}
allowCustomValue
options={namespaces}
onChange={({ value: namespace }) => {
if (namespace) {
onNamespaceChange({ ...query, namespace });
onNamespaceChange({ ...metricStat, namespace });
}
}}
/>
@@ -73,12 +75,12 @@ export function MetricStatEditor({
<EditorField label="Metric name" width={16}>
<Select
aria-label="Metric name"
value={query.metricName || null}
value={metricStat.metricName || null}
allowCustomValue
options={metrics}
onChange={({ value: metricName }) => {
if (metricName) {
onQueryChange({ ...query, metricName });
onMetricStatChange({ ...metricStat, metricName });
}
}}
/>
@@ -86,12 +88,12 @@ export function MetricStatEditor({
<EditorField label="Statistic" width={16}>
<Select
inputId={`${query.refId}-metric-stat-editor-select-statistic`}
inputId={`${refId}-metric-stat-editor-select-statistic`}
allowCustomValue
value={toOption(query.statistic ?? datasource.standardStatistics[0])}
value={toOption(metricStat.statistic ?? datasource.standardStatistics[0])}
options={appendTemplateVariables(
datasource,
datasource.standardStatistics.filter((s) => s !== query.statistic).map(toOption)
datasource.standardStatistics.filter((s) => s !== metricStat.statistic).map(toOption)
)}
onChange={({ value: statistic }) => {
if (
@@ -103,7 +105,7 @@ export function MetricStatEditor({
return;
}
onQueryChange({ ...query, statistic });
onMetricStatChange({ ...metricStat, statistic });
}}
/>
</EditorField>
@@ -113,8 +115,8 @@ export function MetricStatEditor({
<EditorRow>
<EditorField label="Dimensions">
<Dimensions
query={query}
onChange={(dimensions) => onQueryChange({ ...query, dimensions })}
metricStat={metricStat}
onChange={(dimensions) => onMetricStatChange({ ...metricStat, dimensions })}
dimensionKeys={dimensionKeys}
disableExpressions={disableExpressions}
datasource={datasource}
@@ -129,11 +131,11 @@ export function MetricStatEditor({
tooltip="Only show metrics that exactly match all defined dimension names."
>
<EditorSwitch
id={`${query.refId}-cloudwatch-match-exact`}
value={!!query.matchExact}
id={`${refId}-cloudwatch-match-exact`}
value={!!metricStat.matchExact}
onChange={(e) => {
onQueryChange({
...query,
onMetricStatChange({
...metricStat,
matchExact: e.currentTarget.checked,
});
}}

View File

@@ -5,13 +5,14 @@ import { EditorField, EditorRow, Space } from '@grafana/experimental';
import { Input } from '@grafana/ui';
import { CloudWatchDatasource } from '../datasource';
import { isMetricsQuery } from '../guards';
import { isCloudWatchMetricsQuery } from '../guards';
import {
CloudWatchJsonData,
CloudWatchMetricsQuery,
CloudWatchQuery,
MetricEditorMode,
MetricQueryType,
MetricStat,
} from '../types';
import QueryHeader from './QueryHeader';
@@ -87,7 +88,7 @@ export class MetricsQueryEditor extends PureComponent<Props, State> {
onRunQuery={onRunQuery}
datasource={datasource}
onChange={(newQuery) => {
if (isMetricsQuery(newQuery) && newQuery.metricEditorMode !== query.metricEditorMode) {
if (isCloudWatchMetricsQuery(newQuery) && newQuery.metricEditorMode !== query.metricEditorMode) {
this.setState({ sqlCodeEditorIsDirty: false });
}
this.onChange(newQuery);
@@ -99,7 +100,12 @@ export class MetricsQueryEditor extends PureComponent<Props, State> {
{query.metricQueryType === MetricQueryType.Search && (
<>
{query.metricEditorMode === MetricEditorMode.Builder && (
<MetricStatEditor {...{ ...this.props, query }}></MetricStatEditor>
<MetricStatEditor
{...this.props}
refId={query.refId}
metricStat={query}
onChange={(metricStat: MetricStat) => this.props.onChange({ ...query, ...metricStat })}
></MetricStatEditor>
)}
{query.metricEditorMode === MetricEditorMode.Code && (
<MathExpressionQueryField

View File

@@ -1,4 +1,4 @@
import { render, screen, waitFor, act } from '@testing-library/react';
import { act, render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource';
@@ -14,7 +14,7 @@ ds.datasource.getRegions = jest.fn().mockResolvedValue([]);
describe('QueryHeader', () => {
it('should display metric options for metrics', async () => {
const query: CloudWatchMetricsQuery = {
queryType: 'Metrics',
queryMode: 'Metrics',
id: '',
region: 'us-east-2',
namespace: '',

View File

@@ -1,7 +1,7 @@
import { pick } from 'lodash';
import React from 'react';
import { ExploreMode, SelectableValue } from '@grafana/data';
import { SelectableValue, ExploreMode } from '@grafana/data';
import { EditorHeader, InlineSelect } from '@grafana/experimental';
import { CloudWatchDatasource } from '../datasource';
@@ -70,7 +70,7 @@ const QueryHeader: React.FC<QueryHeaderProps> = ({
<InlineSelect aria-label="Query mode" value={queryMode} options={apiModes} onChange={onQueryModeChange} />
{queryMode !== ExploreMode.Logs && (
{queryMode === ExploreMode.Metrics && (
<MetricsQueryHeader
query={query}
datasource={datasource}

View File

@@ -139,7 +139,7 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
/>
<InlineField label="Dimensions" labelWidth={20} tooltip="Dimensions to filter the returned values on">
<Dimensions
query={{ ...parsedQuery, dimensions: parsedQuery.dimensionFilters }}
metricStat={{ ...parsedQuery, dimensions: parsedQuery.dimensionFilters }}
onChange={(dimensions) => {
onChange({ ...parsedQuery, dimensionFilters: dimensions });
}}