diff --git a/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor.tsx index 0d721e7aeba..13b4199c3f5 100644 --- a/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor.tsx @@ -2,7 +2,7 @@ import React, { ChangeEvent } from 'react'; import { LegacyForms } from '@grafana/ui'; const { Switch } = LegacyForms; import { PanelData } from '@grafana/data'; -import { CloudWatchAnnotationQuery } from '../types'; +import { CloudWatchAnnotationQuery, CloudWatchQuery } from '../types'; import { CloudWatchDatasource } from '../datasource'; import { QueryField, PanelQueryEditor } from './'; @@ -20,7 +20,7 @@ export function AnnotationQueryEditor(props: React.PropsWithChildren) { <> onChange({ ...query, ...editorQuery })} + onChange={(editorQuery: CloudWatchQuery) => onChange({ ...query, ...editorQuery })} onRunQuery={() => {}} history={[]} > diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx index f59efe4102b..314f6552bd5 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx @@ -71,10 +71,16 @@ function useAuthenticationWarning(jsonData: CloudWatchJsonData) { function useDatasource(datasourceName: string) { const [datasource, setDatasource] = useState(); + useEffect(() => { getDatasourceSrv() .loadDatasource(datasourceName) - .then((datasource: CloudWatchDatasource) => setDatasource(datasource)); + .then((datasource) => { + // It's really difficult to type .loadDatasource() because it's inherently untyped as it involves two JSON.parse()'s + // So a "as" type assertion here is a necessary evil. + setDatasource(datasource as CloudWatchDatasource); + }); }, [datasourceName]); + return datasource; } diff --git a/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx index 3a1777b1787..1dee5d188bc 100644 --- a/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/LogsQueryEditor.tsx @@ -42,7 +42,9 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor datasource={datasource} query={query} onBlur={() => {}} - onChange={(val: CloudWatchLogsQuery) => onChange({ ...val, queryMode: 'Logs' })} + onChange={(val: CloudWatchQuery) => { + onChange({ ...val, queryMode: 'Logs' }); + }} onRunQuery={onRunQuery} history={[]} data={data} diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index 32f9e6fcedf..55e11302e6d 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -1,6 +1,6 @@ import React from 'react'; import angular from 'angular'; -import { find, isEmpty, isString, set } from 'lodash'; +import { find, findLast, isEmpty, isString, set } from 'lodash'; import { from, lastValueFrom, merge, Observable, of, throwError, zip } from 'rxjs'; import { catchError, concatMap, finalize, map, mergeMap, repeat, scan, share, takeWhile, tap } from 'rxjs/operators'; import { DataSourceWithBackend, getBackendSrv, toDataQueryResponse } from '@grafana/runtime'; @@ -446,9 +446,11 @@ export class CloudWatchDatasource return { data: [] }; } + const lastError = findLast(res.results, (v) => !!v.error); + return { data: dataframes, - error: Object.values(res.results).reduce((acc, curr) => (curr.error ? { message: curr.error } : acc), null), + error: lastError ? { message: lastError.error } : null, }; }), catchError((err) => { diff --git a/public/app/plugins/datasource/cloudwatch/migration.test.ts b/public/app/plugins/datasource/cloudwatch/migration.test.ts index 70418d27b57..53b7aacdec3 100644 --- a/public/app/plugins/datasource/cloudwatch/migration.test.ts +++ b/public/app/plugins/datasource/cloudwatch/migration.test.ts @@ -1,6 +1,6 @@ import { DataQuery } from '@grafana/data'; import { migrateMultipleStatsAnnotationQuery, migrateMultipleStatsMetricsQuery } from './migrations'; -import { CloudWatchAnnotationQuery, CloudWatchMetricsQuery } from './types'; +import { CloudWatchAnnotationQuery, CloudWatchMetricsAnnotationQuery, CloudWatchMetricsQuery } from './types'; describe('migration', () => { describe('migrateMultipleStatsMetricsQuery', () => { @@ -71,7 +71,7 @@ describe('migration', () => { }; const newAnnotations = migrateMultipleStatsAnnotationQuery(annotationToMigrate as CloudWatchAnnotationQuery); - const newCloudWatchAnnotations = newAnnotations as CloudWatchAnnotationQuery[]; + const newCloudWatchAnnotations = newAnnotations as CloudWatchMetricsAnnotationQuery[]; it('should create one new annotation for each stat', () => { expect(newAnnotations.length).toBe(1); @@ -110,7 +110,7 @@ describe('migration', () => { }); it('should use statistics prop and remove statistics prop', () => { - expect(annotationToMigrate.statistic).toEqual('p23.23'); + expect('statistic' in annotationToMigrate && annotationToMigrate.statistic).toEqual('p23.23'); expect(annotationToMigrate).not.toHaveProperty('statistics'); }); }); diff --git a/public/app/plugins/datasource/cloudwatch/migrations.ts b/public/app/plugins/datasource/cloudwatch/migrations.ts index b63b0331c04..7a62a5026a2 100644 --- a/public/app/plugins/datasource/cloudwatch/migrations.ts +++ b/public/app/plugins/datasource/cloudwatch/migrations.ts @@ -27,7 +27,8 @@ export function migrateMultipleStatsAnnotationQuery( annotationQuery: CloudWatchAnnotationQuery ): Array> { const newAnnotations: CloudWatchAnnotationQuery[] = []; - if (annotationQuery?.statistics && annotationQuery?.statistics.length) { + + if (annotationQuery && 'statistics' in annotationQuery && annotationQuery?.statistics?.length) { for (const stat of annotationQuery.statistics.splice(1)) { const { statistics, name, ...newAnnotation } = annotationQuery; newAnnotations.push({ ...newAnnotation, statistic: stat, name: `${name} - ${stat}` }); diff --git a/public/app/plugins/datasource/cloudwatch/types.ts b/public/app/plugins/datasource/cloudwatch/types.ts index cb233cc26b9..c533d1790e7 100644 --- a/public/app/plugins/datasource/cloudwatch/types.ts +++ b/public/app/plugins/datasource/cloudwatch/types.ts @@ -53,7 +53,7 @@ export type CloudWatchQuery = CloudWatchMetricsQuery | CloudWatchLogsQuery; export const isCloudWatchLogsQuery = (cloudwatchQuery: CloudWatchQuery): cloudwatchQuery is CloudWatchLogsQuery => (cloudwatchQuery as CloudWatchLogsQuery).queryMode === 'Logs'; -export interface CloudWatchAnnotationQuery extends CloudWatchMetricsQuery { +interface AnnotationProperties { enable: boolean; name: string; iconColor: string; @@ -62,6 +62,10 @@ export interface CloudWatchAnnotationQuery extends CloudWatchMetricsQuery { alarmNamePrefix: string; } +export type CloudWatchLogsAnnotationQuery = CloudWatchLogsQuery & AnnotationProperties; +export type CloudWatchMetricsAnnotationQuery = CloudWatchMetricsQuery & AnnotationProperties; +export type CloudWatchAnnotationQuery = CloudWatchLogsAnnotationQuery | CloudWatchMetricsAnnotationQuery; + export type SelectableStrings = Array>; export interface CloudWatchJsonData extends AwsAuthDataSourceJsonData { diff --git a/public/app/plugins/datasource/cloudwatch/utils/rxjs/increasingInterval.ts b/public/app/plugins/datasource/cloudwatch/utils/rxjs/increasingInterval.ts index 7e109d36b79..2bea8830729 100644 --- a/public/app/plugins/datasource/cloudwatch/utils/rxjs/increasingInterval.ts +++ b/public/app/plugins/datasource/cloudwatch/utils/rxjs/increasingInterval.ts @@ -9,14 +9,23 @@ export const increasingInterval = ( scheduler: SchedulerLike = asyncScheduler ): Observable => { return new Observable((subscriber) => { - subscriber.add( - scheduler.schedule(dispatch, startPeriod, { subscriber, counter: 0, period: startPeriod, step, endPeriod }) - ); + const state: IntervalState = { + subscriber, + counter: 0, + period: startPeriod, + step, + endPeriod, + }; + + subscriber.add(scheduler.schedule(dispatch, startPeriod, state)); return subscriber; }); }; -function dispatch(this: SchedulerAction, state: IntervalState) { +function dispatch(this: SchedulerAction, state?: IntervalState) { + if (!state) { + return; + } const { subscriber, counter, period, step, endPeriod } = state; subscriber.next(counter); const newPeriod = Math.min(period + step, endPeriod); diff --git a/scripts/ci-check-strict.sh b/scripts/ci-check-strict.sh index 2b057598e20..72e00c7f223 100755 --- a/scripts/ci-check-strict.sh +++ b/scripts/ci-check-strict.sh @@ -3,7 +3,7 @@ set -e echo -e "Collecting code stats (typescript errors & more)" -ERROR_COUNT_LIMIT=6 +ERROR_COUNT_LIMIT=1 ERROR_COUNT="$(yarn run tsc --project tsconfig.json --noEmit --strict true | grep -oP 'Found \K(\d+)')" if [ "$ERROR_COUNT" -gt $ERROR_COUNT_LIMIT ]; then