diff --git a/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx b/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx index ae954c17260..544520f378e 100644 --- a/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx @@ -42,9 +42,9 @@ export default class CloudWatchLink extends Component { start, timeType: 'ABSOLUTE', tz: 'UTC', - editorString: query.expression, + editorString: query.expression ?? '', isLiveTail: false, - source: query.logGroupNames, + source: query.logGroupNames ?? [], }; return encodeUrl(urlProps, datasource.getActualRegion(query.region)); diff --git a/public/app/plugins/datasource/cloudwatch/components/LogsCheatSheet.tsx b/public/app/plugins/datasource/cloudwatch/components/LogsCheatSheet.tsx index 5cfd2af5e93..0f6e6231961 100644 --- a/public/app/plugins/datasource/cloudwatch/components/LogsCheatSheet.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/LogsCheatSheet.tsx @@ -220,18 +220,12 @@ export default class LogsCheatSheet extends PureComponent { const { onClickExample, exploreId } = this.props; - const nextQuery: CloudWatchLogsQuery = { - ...(query as CloudWatchLogsQuery), - apiMode: 'Logs', - queryMode: 'Logs', - }; - dispatch(changeModeAction({ exploreId, mode: ExploreMode.Metrics })); - onClickExample(nextQuery); + onClickExample(query); }; onClickExample(query: CloudWatchLogsQuery) { - if (query.expression.includes('stats')) { + if (query.expression?.includes('stats')) { this.switchToMetrics(query); } else { this.props.onClickExample(query); @@ -243,7 +237,9 @@ export default class LogsCheatSheet extends PureComponent this.onClickExample({ refId: 'A', expression: expr } as CloudWatchLogsQuery)} + onClick={e => + this.onClickExample({ refId: 'A', expression: expr, queryMode: 'Logs', region: 'default', id: 'A' }) + } >
{renderHighlightedMarkup(expr, keyPrefix)}
diff --git a/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx index e28b21a1a15..9570f3f27fc 100644 --- a/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx @@ -275,16 +275,7 @@ export class CloudWatchLogsQueryField extends React.PureComponent { - const { query, onChange, exploreId } = this.props; - - if (onChange) { - const nextQuery: CloudWatchLogsQuery = { - ...(query as CloudWatchLogsQuery), - apiMode: 'Logs', - }; - onChange(nextQuery); - } - + const { exploreId } = this.props; dispatch(changeModeAction({ exploreId, mode: ExploreMode.Metrics })); }; @@ -409,7 +400,7 @@ export class CloudWatchLogsQueryField extends React.PureComponent { const props: Props = { query: { queryMode: 'Metrics', - apiMode: 'Metrics', refId: '', id: '', region: 'us-east-1', diff --git a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx index c01d25c61ea..79f7e8a9c2a 100644 --- a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx @@ -1,15 +1,15 @@ import React, { useState, useEffect } from 'react'; import { SelectableValue } from '@grafana/data'; import { Segment, SegmentAsync } from '@grafana/ui'; -import { CloudWatchQuery, SelectableStrings, CloudWatchMetricsQuery } from '../types'; +import { SelectableStrings, CloudWatchMetricsQuery } from '../types'; import { CloudWatchDatasource } from '../datasource'; import { Stats, Dimensions, QueryInlineField } from '.'; export type Props = { - query: CloudWatchQuery; + query: CloudWatchMetricsQuery; datasource: CloudWatchDatasource; onRunQuery?: () => void; - onChange: (value: CloudWatchQuery) => void; + onChange: (value: CloudWatchMetricsQuery) => void; }; interface State { @@ -66,7 +66,7 @@ export function MetricsQueryFieldsEditor({ const toOption = (value: any) => ({ label: value, value }); - const onQueryChange = (query: CloudWatchQuery) => { + const onQueryChange = (query: CloudWatchMetricsQuery) => { onChange(query); onRunQuery(); }; @@ -98,7 +98,7 @@ export function MetricsQueryFieldsEditor({ /> - {query.expression.length === 0 && ( + {query.expression?.length === 0 && ( <> { render() { const { query } = this.props; - const apiMode = query.apiMode ?? query.queryMode ?? 'Metrics'; + const apiMode = query.queryMode ?? 'Metrics'; return ( <> @@ -25,9 +26,27 @@ export class PanelQueryEditor extends PureComponent { - this.props.onChange({ ...query, apiMode: (value as 'Metrics' | 'Logs') ?? 'Metrics' }) - } + onChange={({ value }) => { + const newMode = (value as 'Metrics' | 'Logs') ?? 'Metrics'; + if (newMode !== apiModes[apiMode].value) { + const commonProps = pick( + query, + 'id', + 'region', + 'namespace', + 'refId', + 'hide', + 'key', + 'queryType', + 'datasource' + ); + + this.props.onChange({ + ...commonProps, + queryMode: newMode, + } as CloudWatchQuery); + } + }} /> {apiMode === ExploreMode.Logs ? ( diff --git a/public/app/plugins/datasource/cloudwatch/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/datasource.test.ts index 8c8c88f067b..f6b030ae711 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.test.ts @@ -7,26 +7,30 @@ describe('datasource', () => { describe('query', () => { it('should return error if log query and log groups is not specified', async () => { const { datasource } = setup(); - const response: DataQueryResponse = (await datasource.query({ - targets: [ - { - queryMode: 'Logs' as 'Logs', - }, - ], - } as any)) as any; + const response: DataQueryResponse = (await datasource + .query({ + targets: [ + { + queryMode: 'Logs' as 'Logs', + }, + ], + } as any) + .toPromise()) as any; expect(response.error?.message).toBe('Log group is required'); }); it('should return empty response if queries are hidden', async () => { const { datasource } = setup(); - const response: DataQueryResponse = (await datasource.query({ - targets: [ - { - queryMode: 'Logs' as 'Logs', - hide: true, - }, - ], - } as any)) as any; + const response: DataQueryResponse = (await datasource + .query({ + targets: [ + { + queryMode: 'Logs' as 'Logs', + hide: true, + }, + ], + } as any) + .toPromise()) as any; expect(response.data).toEqual([]); }); }); diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index eed9553b2f6..21670fc1f3b 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -39,7 +39,7 @@ import { MetricRequest, TSDBResponse, } from './types'; -import { empty, from, Observable } from 'rxjs'; +import { empty, from, Observable, of, merge } from 'rxjs'; import { catchError, delay, expand, finalize, map, mergeMap, tap } from 'rxjs/operators'; import { CloudWatchLanguageProvider } from './language_provider'; @@ -101,55 +101,78 @@ export class CloudWatchDatasource extends DataSourceApi): Promise | Observable { + query(options: DataQueryRequest): Observable { options = angular.copy(options); - const firstTarget = options.targets[0]; - let queries = options.targets.filter(item => item.id !== '' || item.hide !== true); + const { logQueries, metricsQueries } = this.getTargetsByQueryMode(queries); - if (firstTarget.queryMode === 'Logs') { - const logQueries: CloudWatchLogsQuery[] = queries.filter(item => item.queryMode === 'Logs') as any; - - const validLogQueries = logQueries.filter(item => item.logGroupNames?.length); - if (logQueries.length > validLogQueries.length) { - return Promise.resolve({ data: [], error: { message: 'Log group is required' } }); - } - - // No valid targets, return the empty result to save a round trip. - if (_.isEmpty(validLogQueries)) { - return Promise.resolve({ data: [] }); - } - - const queryParams = validLogQueries.map((target: CloudWatchLogsQuery) => ({ - queryString: target.expression, - refId: target.refId, - logGroupNames: target.logGroupNames, - region: this.replace(this.getActualRegion(target.region), options.scopedVars, true, 'region'), - })); - - return this.makeLogActionRequest('StartQuery', queryParams, options.scopedVars).pipe( - mergeMap(dataFrames => - this.logsQuery( - dataFrames.map(dataFrame => ({ - queryId: dataFrame.fields[0].values.get(0), - region: dataFrame.meta?.custom?.['Region'] ?? 'default', - refId: dataFrame.refId!, - statsGroups: (options.targets.find(target => target.refId === dataFrame.refId)! as CloudWatchLogsQuery) - .statsGroups, - })) - ) - ), - map(response => this.addDataLinksToLogsResponse(response, options)) - ); + const dataQueryResponses: Array> = []; + if (logQueries.length > 0) { + dataQueryResponses.push(this.handleLogQueries(logQueries, options)); } - const metricQueries: MetricQuery[] = options.targets + if (metricsQueries.length > 0) { + dataQueryResponses.push(this.handleMetricQueries(metricsQueries, options)); + } + + // No valid targets, return the empty result to save a round trip. + if (_.isEmpty(dataQueryResponses)) { + return of({ + data: [], + state: LoadingState.Done, + }); + } + + return merge(...dataQueryResponses); + } + + handleLogQueries = ( + logQueries: CloudWatchLogsQuery[], + options: DataQueryRequest + ): Observable => { + const validLogQueries = logQueries.filter(item => item.logGroupNames?.length); + if (logQueries.length > validLogQueries.length) { + return of({ data: [], error: { message: 'Log group is required' } }); + } + + // No valid targets, return the empty result to save a round trip. + if (_.isEmpty(validLogQueries)) { + return of({ data: [], state: LoadingState.Done }); + } + + const queryParams = validLogQueries.map((target: CloudWatchLogsQuery) => ({ + queryString: target.expression, + refId: target.refId, + logGroupNames: target.logGroupNames, + region: this.replace(this.getActualRegion(target.region), options.scopedVars, true, 'region'), + })); + + return this.makeLogActionRequest('StartQuery', queryParams, options.scopedVars).pipe( + mergeMap(dataFrames => + this.logsQuery( + dataFrames.map(dataFrame => ({ + queryId: dataFrame.fields[0].values.get(0), + region: dataFrame.meta?.custom?.['Region'] ?? 'default', + refId: dataFrame.refId!, + statsGroups: (logQueries.find(target => target.refId === dataFrame.refId)! as CloudWatchLogsQuery) + .statsGroups, + })) + ) + ), + map(response => this.addDataLinksToLogsResponse(response, options)) + ); + }; + + handleMetricQueries = ( + metricQueries: CloudWatchMetricsQuery[], + options: DataQueryRequest + ): Observable => { + const validMetricsQueries = metricQueries .filter( item => - item.queryMode !== 'Logs' && - ((!!item.region && !!item.namespace && !!item.metricName && !_.isEmpty(item.statistics)) || - item.expression?.length > 0) + (!!item.region && !!item.namespace && !!item.metricName && !_.isEmpty(item.statistics)) || + item.expression?.length > 0 ) .map( (item: CloudWatchMetricsQuery): MetricQuery => { @@ -188,18 +211,18 @@ export class CloudWatchDatasource extends DataSourceApi @@ -280,9 +303,9 @@ export class CloudWatchDatasource extends DataSourceApi { + const logQueries: CloudWatchLogsQuery[] = []; + const metricsQueries: CloudWatchMetricsQuery[] = []; + + targets.forEach(query => { + const mode = query.queryMode ?? 'Metrics'; + if (mode === 'Logs') { + logQueries.push(query as CloudWatchLogsQuery); + } else { + metricsQueries.push(query as CloudWatchMetricsQuery); + } + }); + + return { + logQueries, + metricsQueries, + }; + }; } function withTeardown(observable: Observable, onUnsubscribe: () => void): Observable { diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts index 09ee6cfd977..b28ff2efa73 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts @@ -314,7 +314,7 @@ describe('CloudWatchDatasource', () => { }); it('should generate the correct query', async () => { - await ctx.ds.query(query); + await ctx.ds.query(query).toPromise(); expect(datasourceRequestMock.mock.calls[0][0].data.queries).toMatchObject( expect.arrayContaining([ expect.objectContaining({ @@ -365,7 +365,7 @@ describe('CloudWatchDatasource', () => { ], }; - await ctx.ds.query(query); + await ctx.ds.query(query).toPromise(); expect(datasourceRequestMock.mock.calls[0][0].data.queries[0].period).toEqual('600'); }); @@ -392,11 +392,14 @@ describe('CloudWatchDatasource', () => { }); it('should return series list', done => { - ctx.ds.query(query).then((result: any) => { - expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); - expect(result.data[0].fields[1].values.buffer[0]).toBe(response.results.A.series[0].points[0][0]); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); + expect(result.data[0].fields[1].values.buffer[0]).toBe(response.results.A.series[0].points[0][0]); + done(); + }); }); describe('a correct cloudwatch url should be built for each time series in the response', () => { @@ -408,14 +411,17 @@ describe('CloudWatchDatasource', () => { it('should be built correctly if theres one search expressions returned in meta for a given query row', done => { response.results['A'].meta.gmdMeta = [{ Expression: `REMOVE_EMPTY(SEARCH('some expression'))`, Period: '300' }]; - ctx.ds.query(query).then((result: any) => { - expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); - expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console'); - expect(decodeURIComponent(result.data[0].fields[1].config.links[0].url)).toContain( - `region=us-east-1#metricsV2:graph={"view":"timeSeries","stacked":false,"title":"A","start":"2016-12-31T15:00:00.000Z","end":"2016-12-31T16:00:00.000Z","region":"us-east-1","metrics":[{"expression":"REMOVE_EMPTY(SEARCH(\'some expression\'))"}]}` - ); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); + expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console'); + expect(decodeURIComponent(result.data[0].fields[1].config.links[0].url)).toContain( + `region=us-east-1#metricsV2:graph={"view":"timeSeries","stacked":false,"title":"A","start":"2016-12-31T15:00:00.000Z","end":"2016-12-31T16:00:00.000Z","region":"us-east-1","metrics":[{"expression":"REMOVE_EMPTY(SEARCH(\'some expression\'))"}]}` + ); + done(); + }); }); it('should be built correctly if theres two search expressions returned in meta for a given query row', done => { @@ -423,35 +429,44 @@ describe('CloudWatchDatasource', () => { { Expression: `REMOVE_EMPTY(SEARCH('first expression'))` }, { Expression: `REMOVE_EMPTY(SEARCH('second expression'))` }, ]; - ctx.ds.query(query).then((result: any) => { - expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); - expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console'); - expect(decodeURIComponent(result.data[0].fields[0].config.links[0].url)).toContain( - `region=us-east-1#metricsV2:graph={"view":"timeSeries","stacked":false,"title":"A","start":"2016-12-31T15:00:00.000Z","end":"2016-12-31T16:00:00.000Z","region":"us-east-1","metrics":[{"expression":"REMOVE_EMPTY(SEARCH(\'first expression\'))"},{"expression":"REMOVE_EMPTY(SEARCH(\'second expression\'))"}]}` - ); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); + expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console'); + expect(decodeURIComponent(result.data[0].fields[0].config.links[0].url)).toContain( + `region=us-east-1#metricsV2:graph={"view":"timeSeries","stacked":false,"title":"A","start":"2016-12-31T15:00:00.000Z","end":"2016-12-31T16:00:00.000Z","region":"us-east-1","metrics":[{"expression":"REMOVE_EMPTY(SEARCH(\'first expression\'))"},{"expression":"REMOVE_EMPTY(SEARCH(\'second expression\'))"}]}` + ); + done(); + }); }); it('should be built correctly if the query is a metric stat query', done => { response.results['A'].meta.gmdMeta = [{ Period: '300' }]; - ctx.ds.query(query).then((result: any) => { - expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); - expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console'); - expect(decodeURIComponent(result.data[0].fields[0].config.links[0].url)).toContain( - `region=us-east-1#metricsV2:graph={\"view\":\"timeSeries\",\"stacked\":false,\"title\":\"A\",\"start\":\"2016-12-31T15:00:00.000Z\",\"end\":\"2016-12-31T16:00:00.000Z\",\"region\":\"us-east-1\",\"metrics\":[[\"AWS/EC2\",\"CPUUtilization\",\"InstanceId\",\"i-12345678\",{\"stat\":\"Average\",\"period\":\"300\"}]]}` - ); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); + expect(result.data[0].fields[1].config.links[0].title).toBe('View in CloudWatch console'); + expect(decodeURIComponent(result.data[0].fields[0].config.links[0].url)).toContain( + `region=us-east-1#metricsV2:graph={\"view\":\"timeSeries\",\"stacked\":false,\"title\":\"A\",\"start\":\"2016-12-31T15:00:00.000Z\",\"end\":\"2016-12-31T16:00:00.000Z\",\"region\":\"us-east-1\",\"metrics\":[[\"AWS/EC2\",\"CPUUtilization\",\"InstanceId\",\"i-12345678\",{\"stat\":\"Average\",\"period\":\"300\"}]]}` + ); + done(); + }); }); it('should not be added at all if query is a math expression', done => { query.targets[0].expression = 'a * 2'; response.results['A'].meta.searchExpressions = []; - ctx.ds.query(query).then((result: any) => { - expect(result.data[0].fields[1].config.links).toBeUndefined(); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(result.data[0].fields[1].config.links).toBeUndefined(); + done(); + }); }); }); @@ -525,13 +540,16 @@ describe('CloudWatchDatasource', () => { it('should display one alert error message per region+datasource combination', done => { const memoizedDebounceSpy = jest.spyOn(ctx.ds, 'debouncedAlert'); - ctx.ds.query(query).catch(() => { - expect(memoizedDebounceSpy).toHaveBeenCalledWith('TestDatasource', 'us-east-1'); - expect(memoizedDebounceSpy).toHaveBeenCalledWith('TestDatasource', 'us-east-2'); - expect(memoizedDebounceSpy).toHaveBeenCalledWith('TestDatasource', 'eu-north-1'); - expect(memoizedDebounceSpy).toBeCalledTimes(3); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .catch(() => { + expect(memoizedDebounceSpy).toHaveBeenCalledWith('TestDatasource', 'us-east-1'); + expect(memoizedDebounceSpy).toHaveBeenCalledWith('TestDatasource', 'us-east-2'); + expect(memoizedDebounceSpy).toHaveBeenCalledWith('TestDatasource', 'eu-north-1'); + expect(memoizedDebounceSpy).toBeCalledTimes(3); + done(); + }); }); }); @@ -610,10 +628,13 @@ describe('CloudWatchDatasource', () => { ], }; - ctx.ds.query(query).then((result: any) => { - expect(requestParams.queries[0].region).toBe(instanceSettings.jsonData.defaultRegion); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(requestParams.queries[0].region).toBe(instanceSettings.jsonData.defaultRegion); + done(); + }); }); }); @@ -676,11 +697,14 @@ describe('CloudWatchDatasource', () => { }); it('should return series list', done => { - ctx.ds.query(query).then((result: any) => { - expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); - expect(result.data[0].fields[1].values.buffer[0]).toBe(response.results.A.series[0].points[0][0]); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then((result: any) => { + expect(getFrameDisplayName(result.data[0])).toBe(response.results.A.series[0].name); + expect(result.data[0].fields[1].values.buffer[0]).toBe(response.results.A.series[0].points[0][0]); + done(); + }); }); }); @@ -787,10 +811,13 @@ describe('CloudWatchDatasource', () => { ], }; - ctx.ds.query(query).then(() => { - expect(requestParams.queries[0].dimensions['dim2']).toStrictEqual(['var2-foo']); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then(() => { + expect(requestParams.queries[0].dimensions['dim2']).toStrictEqual(['var2-foo']); + done(); + }); }); it('should generate the correct query in the case of one multilple template variables', done => { @@ -819,12 +846,15 @@ describe('CloudWatchDatasource', () => { }, }; - ctx.ds.query(query).then(() => { - expect(requestParams.queries[0].dimensions['dim1']).toStrictEqual(['var1-foo']); - expect(requestParams.queries[0].dimensions['dim2']).toStrictEqual(['var2-foo']); - expect(requestParams.queries[0].dimensions['dim3']).toStrictEqual(['var3-foo', 'var3-baz']); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then(() => { + expect(requestParams.queries[0].dimensions['dim1']).toStrictEqual(['var1-foo']); + expect(requestParams.queries[0].dimensions['dim2']).toStrictEqual(['var2-foo']); + expect(requestParams.queries[0].dimensions['dim3']).toStrictEqual(['var3-foo', 'var3-baz']); + done(); + }); }); it('should generate the correct query in the case of multilple multi template variables', done => { @@ -849,12 +879,15 @@ describe('CloudWatchDatasource', () => { ], }; - ctx.ds.query(query).then(() => { - expect(requestParams.queries[0].dimensions['dim1']).toStrictEqual(['var1-foo']); - expect(requestParams.queries[0].dimensions['dim3']).toStrictEqual(['var3-foo', 'var3-baz']); - expect(requestParams.queries[0].dimensions['dim4']).toStrictEqual(['var4-foo', 'var4-baz']); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then(() => { + expect(requestParams.queries[0].dimensions['dim1']).toStrictEqual(['var1-foo']); + expect(requestParams.queries[0].dimensions['dim3']).toStrictEqual(['var3-foo', 'var3-baz']); + expect(requestParams.queries[0].dimensions['dim4']).toStrictEqual(['var4-foo', 'var4-baz']); + done(); + }); }); it('should generate the correct query for multilple template variables, lack scopedVars', done => { @@ -882,12 +915,15 @@ describe('CloudWatchDatasource', () => { }, }; - ctx.ds.query(query).then(() => { - expect(requestParams.queries[0].dimensions['dim1']).toStrictEqual(['var1-foo']); - expect(requestParams.queries[0].dimensions['dim2']).toStrictEqual(['var2-foo']); - expect(requestParams.queries[0].dimensions['dim3']).toStrictEqual(['var3-foo', 'var3-baz']); - done(); - }); + ctx.ds + .query(query) + .toPromise() + .then(() => { + expect(requestParams.queries[0].dimensions['dim1']).toStrictEqual(['var1-foo']); + expect(requestParams.queries[0].dimensions['dim2']).toStrictEqual(['var2-foo']); + expect(requestParams.queries[0].dimensions['dim3']).toStrictEqual(['var3-foo', 'var3-baz']); + done(); + }); }); }); diff --git a/public/app/plugins/datasource/cloudwatch/types.ts b/public/app/plugins/datasource/cloudwatch/types.ts index 8bbb9bf911d..dafe6187d00 100644 --- a/public/app/plugins/datasource/cloudwatch/types.ts +++ b/public/app/plugins/datasource/cloudwatch/types.ts @@ -3,8 +3,6 @@ import { DataQuery, SelectableValue, DataSourceJsonData } from '@grafana/data'; export interface CloudWatchMetricsQuery extends DataQuery { queryMode: 'Metrics'; - apiMode: 'Logs' | 'Metrics'; // TEMP: Remove when logs/metrics unification is done - id: string; region: string; namespace: string; @@ -37,12 +35,10 @@ export enum CloudWatchLogsQueryStatus { export interface CloudWatchLogsQuery extends DataQuery { queryMode: 'Logs'; - apiMode: 'Logs' | 'Metrics'; // TEMP: Remove when logs/metrics unification is done id: string; region: string; - namespace: string; - expression: string; - logGroupNames: string[]; + expression?: string; + logGroupNames?: string[]; statsGroups?: string[]; }