From fd44c01675e54973370969dfb9e78f173aff7910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 8 Jul 2020 11:05:20 +0200 Subject: [PATCH] Chore: Fix typescript strict null fixes now at 298 (#26125) * Chore: Fix typescript strict null errors * Added new limit * Fixed ts issue * fixed tests * trying to fix type inference * Fixing more ts errors * Revert tsconfig option * Fix * Fixed code * More fixes * fix tests * Updated snapshot * Chore: More ts strict null fixes * More fixes in some really messed up azure config components * More fixes, current count: 441 * 419 * More fixes * Fixed invalid initial state in explore * Fixing tests * Fixed tests * Explore fix * More fixes * Progress * Sub 300 * Fixed incorrect type * removed unused import --- packages/grafana-data/src/types/datasource.ts | 4 +- .../src/services/templateSrv.ts | 2 +- .../CustomHeadersSettings.test.tsx | 1 + .../DataSourceHttpSettings.story.tsx | 1 + .../src/components/QueryField/QueryField.tsx | 2 +- public/app/core/components/Page/Page.tsx | 2 +- .../app/core/components/Page/PageContents.tsx | 2 +- public/app/core/table_model.ts | 2 +- .../features/dashboard/state/runRequest.ts | 8 +++- .../datasources/__mocks__/dataSourcesMocks.ts | 1 + public/app/features/datasources/mocks.ts | 1 + .../DataSourceSettingsPage.test.tsx.snap | 2 + .../app/features/datasources/state/actions.ts | 4 +- .../features/datasources/state/navModel.ts | 9 ++-- public/app/features/explore/state/reducers.ts | 2 - public/app/features/folders/state/navModel.ts | 4 +- .../components/SnapshotListTable.tsx | 4 +- public/app/features/org/UserInviteForm.tsx | 2 +- .../app/features/panel/metrics_panel_ctrl.ts | 2 +- .../panel/panellinks/linkSuppliers.ts | 33 ++++++++------- .../app/features/panel/panellinks/link_srv.ts | 23 +++++----- public/app/features/panel/query_ctrl.ts | 2 +- public/app/features/plugins/AppRootPage.tsx | 4 +- public/app/features/plugins/PluginPage.tsx | 42 ++++++++++--------- .../features/plugins/PluginSignatureBadge.tsx | 8 +++- public/app/features/plugins/datasource_srv.ts | 2 +- .../app/features/plugins/plugin_component.ts | 6 ++- .../plugins/wrappers/AppConfigWrapper.tsx | 4 +- public/app/features/profile/SignupForm.tsx | 4 +- .../search/components/DashboardListPage.tsx | 3 +- public/app/features/search/loaders.ts | 6 +-- public/app/features/teams/TeamGroupSync.tsx | 2 +- public/app/features/teams/TeamList.tsx | 4 +- public/app/features/teams/TeamMemberRow.tsx | 11 +++-- public/app/features/teams/TeamMembers.tsx | 8 ++-- public/app/features/teams/TeamPages.tsx | 8 ++-- public/app/features/teams/state/navModel.ts | 6 +-- .../app/features/templating/template_srv.ts | 4 +- .../pickers/OptionsPicker/reducer.ts | 4 +- .../CloudMonitoringMetricFindQuery.ts | 21 ++++++++-- .../datasource/cloud-monitoring/api.ts | 2 +- .../components/Aggregations.test.tsx | 6 +-- .../components/Aggregations.tsx | 10 ++--- .../cloud-monitoring/components/AliasBy.tsx | 4 +- .../cloud-monitoring/components/Metrics.tsx | 13 +++--- .../components/QueryEditor.tsx | 4 +- .../components/VariableQueryEditor.tsx | 2 +- .../datasource/cloud-monitoring/datasource.ts | 8 ++-- .../datasource/cloud-monitoring/functions.ts | 2 +- .../cloudwatch/components/CloudWatchLink.tsx | 8 +++- .../cloudwatch/components/Dimensions.tsx | 8 ++-- .../cloudwatch/components/LogsQueryField.tsx | 2 +- .../components/MetricsQueryFieldsEditor.tsx | 4 +- .../cloudwatch/components/Stats.tsx | 6 +-- .../datasource/cloudwatch/datasource.ts | 1 - .../cloudwatch/language_provider.ts | 14 +++---- .../dashboard/DashboardQueryEditor.tsx | 10 ++--- .../datasource/dashboard/runSharedRequest.ts | 4 +- .../elasticsearch/configuration/DataLink.tsx | 2 +- .../configuration/ElasticDetails.tsx | 10 +++-- .../datasource/elasticsearch/datasource.ts | 17 ++++---- .../elasticsearch/elastic_response.ts | 5 ++- .../datasource/elasticsearch/index_pattern.ts | 2 +- .../datasource/elasticsearch/metric_agg.ts | 2 +- .../plugins/datasource/elasticsearch/types.ts | 2 +- .../app_insights_datasource.test.ts | 4 +- .../app_insights/app_insights_datasource.ts | 12 ++++-- .../azure_log_analytics_datasource.ts | 28 ++++++------- .../azure_monitor/azure_monitor_datasource.ts | 23 +++++----- .../components/AnalyticsConfig.tsx | 12 +++--- .../components/AzureCredentialsForm.tsx | 10 ++--- .../components/ConfigEditor.tsx | 31 +++++++------- .../components/InsightsConfig.tsx | 2 +- .../components/MonitorConfig.tsx | 2 +- .../datasource.ts | 6 +-- .../editor/KustoQueryField.tsx | 7 ++-- .../editor/query_field.tsx | 12 ++---- .../datasource/graphite/FunctionEditor.tsx | 6 +-- .../graphite/FunctionEditorControls.tsx | 2 +- .../plugins/datasource/graphite/datasource.ts | 21 +++++----- .../app/plugins/datasource/graphite/gfunc.ts | 2 +- .../graphite/specs/datasource.test.ts | 4 +- .../components/InfluxLogsQueryField.tsx | 24 +++++------ .../plugins/datasource/influxdb/datasource.ts | 23 +++++----- .../datasource/influxdb/influx_query_model.ts | 8 ++-- .../datasource/influxdb/influx_series.ts | 2 +- .../datasource/influxdb/query_builder.ts | 8 ++-- .../plugins/datasource/influxdb/query_ctrl.ts | 6 +-- .../plugins/datasource/jaeger/QueryField.tsx | 2 +- .../plugins/datasource/jaeger/datasource.ts | 2 +- .../components/AnnotationsQueryEditor.tsx | 1 - .../components/LokiExploreQueryEditor.tsx | 2 +- .../loki/components/LokiQueryEditor.tsx | 4 +- .../loki/components/LokiQueryFieldForm.tsx | 2 +- .../loki/components/useLokiLabels.ts | 4 +- .../loki/components/useLokiSyntaxAndLabels.ts | 2 +- .../loki/configuration/DerivedFields.test.tsx | 3 ++ public/app/plugins/datasource/loki/mocks.ts | 2 +- .../loki/result_transformer.test.ts | 12 +++--- public/app/plugins/datasource/loki/types.ts | 2 +- .../postgres/specs/postgres_query.test.ts | 2 +- .../datasource/prometheus/datasource.test.ts | 12 +++--- scripts/ci-frontend-metrics.sh | 2 +- 103 files changed, 386 insertions(+), 331 deletions(-) diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index 230cee309fe..02c5affd6fc 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -329,7 +329,7 @@ export interface ExploreQueryFieldProps< } export interface ExploreStartPageProps { - datasource?: DataSourceApi; + datasource: DataSourceApi; exploreMode: ExploreMode; onClickExample: (query: DataQuery) => void; exploreId?: any; @@ -490,7 +490,7 @@ export interface DataSourceSettings; + secureJsonFields: KeyValue; readOnly: boolean; withCredentials: boolean; version?: number; diff --git a/packages/grafana-runtime/src/services/templateSrv.ts b/packages/grafana-runtime/src/services/templateSrv.ts index 36cc70df3a7..6cf5d33060a 100644 --- a/packages/grafana-runtime/src/services/templateSrv.ts +++ b/packages/grafana-runtime/src/services/templateSrv.ts @@ -16,7 +16,7 @@ export interface TemplateSrv { /** * Replace the values within the target string. See also {@link InterpolateFunction} */ - replace(target: string, scopedVars?: ScopedVars, format?: string | Function): string; + replace(target?: string, scopedVars?: ScopedVars, format?: string | Function): string; } let singletonInstance: TemplateSrv; diff --git a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx index f12ef86df39..121645c3f40 100644 --- a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx +++ b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx @@ -28,6 +28,7 @@ const setup = (propOverrides?: object) => { secureJsonData: { password: true, }, + secureJsonFields: {}, readOnly: true, }, onChange: jest.fn(), diff --git a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx index 2af5d141daf..ddd5dc18517 100644 --- a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx +++ b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx @@ -28,6 +28,7 @@ const settingsMock: DataSourceSettings = { secureJsonData: { password: true, }, + secureJsonFields: {}, readOnly: true, }; diff --git a/packages/grafana-ui/src/components/QueryField/QueryField.tsx b/packages/grafana-ui/src/components/QueryField/QueryField.tsx index 86b546312db..b27a2b4f105 100644 --- a/packages/grafana-ui/src/components/QueryField/QueryField.tsx +++ b/packages/grafana-ui/src/components/QueryField/QueryField.tsx @@ -26,7 +26,7 @@ export interface QueryFieldProps { // We have both value and local state. This is usually an antipattern but we need to keep local state // for perf reasons and also have outside value in for example in Explore redux that is mutable from logs // creating a two way binding. - query: string | null; + query?: string | null; onRunQuery?: () => void; onBlur?: () => void; onChange?: (value: string) => void; diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx index fa45c6330db..363aec5a3b6 100644 --- a/public/app/core/components/Page/Page.tsx +++ b/public/app/core/components/Page/Page.tsx @@ -12,7 +12,7 @@ import { isEqual } from 'lodash'; import { Branding } from '../Branding/Branding'; interface Props { - children: JSX.Element[] | JSX.Element; + children: React.ReactNode; navModel: NavModel; } diff --git a/public/app/core/components/Page/PageContents.tsx b/public/app/core/components/Page/PageContents.tsx index 7f6c4d57253..a4dbdb2af6b 100644 --- a/public/app/core/components/Page/PageContents.tsx +++ b/public/app/core/components/Page/PageContents.tsx @@ -6,7 +6,7 @@ import PageLoader from '../PageLoader/PageLoader'; interface Props { isLoading?: boolean; - children: JSX.Element[] | JSX.Element | null; + children: React.ReactNode; } class PageContents extends Component { diff --git a/public/app/core/table_model.ts b/public/app/core/table_model.ts index e361f6316f4..5e54f15c5f4 100644 --- a/public/app/core/table_model.ts +++ b/public/app/core/table_model.ts @@ -17,7 +17,7 @@ export default class TableModel implements TableData { rows: any[]; type: string; columnMap: any; - refId: string; + refId?: string; meta?: QueryResultMeta; constructor(table?: any) { diff --git a/public/app/features/dashboard/state/runRequest.ts b/public/app/features/dashboard/state/runRequest.ts index 47b16a0bc97..262cbdbcc83 100644 --- a/public/app/features/dashboard/state/runRequest.ts +++ b/public/app/features/dashboard/state/runRequest.ts @@ -182,7 +182,7 @@ export function getProcessedDataFrames(results?: DataQueryResponseData[]): DataF return dataFrames; } -export function preProcessPanelData(data: PanelData, lastResult: PanelData): PanelData { +export function preProcessPanelData(data: PanelData, lastResult?: PanelData): PanelData { const { series } = data; // for loading states with no data, use last result @@ -191,7 +191,11 @@ export function preProcessPanelData(data: PanelData, lastResult: PanelData): Pan lastResult = data; } - return { ...lastResult, state: LoadingState.Loading }; + return { + ...lastResult, + state: LoadingState.Loading, + request: data.request, + }; } // Make sure the data frames are properly formatted diff --git a/public/app/features/datasources/__mocks__/dataSourcesMocks.ts b/public/app/features/datasources/__mocks__/dataSourcesMocks.ts index 9abd7eb48d0..0c01224af99 100644 --- a/public/app/features/datasources/__mocks__/dataSourcesMocks.ts +++ b/public/app/features/datasources/__mocks__/dataSourcesMocks.ts @@ -44,5 +44,6 @@ export const getMockDataSource = (): DataSourceSettings => { typeLogoUrl: 'public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png', url: '', user: '', + secureJsonFields: {}, }; }; diff --git a/public/app/features/datasources/mocks.ts b/public/app/features/datasources/mocks.ts index c9d21aa5907..d2cc7be296a 100644 --- a/public/app/features/datasources/mocks.ts +++ b/public/app/features/datasources/mocks.ts @@ -19,5 +19,6 @@ export function createDatasourceSettings(jsonData: T): DataSourceSettings jsonData, readOnly: false, withCredentials: false, + secureJsonFields: {}, }; } diff --git a/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap b/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap index 2575c724ae4..7d94ba444b1 100644 --- a/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap +++ b/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap @@ -51,6 +51,7 @@ exports[`Render should render alpha info text 1`] = ` "orgId": 1, "password": "", "readOnly": false, + "secureJsonFields": Object {}, "type": "cloudwatch", "typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", "url": "", @@ -242,6 +243,7 @@ exports[`Render should render is ready only message 1`] = ` "orgId": 1, "password": "", "readOnly": true, + "secureJsonFields": Object {}, "type": "cloudwatch", "typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", "url": "", diff --git a/public/app/features/datasources/state/actions.ts b/public/app/features/datasources/state/actions.ts index 4554d4bd7a1..285768814c9 100644 --- a/public/app/features/datasources/state/actions.ts +++ b/public/app/features/datasources/state/actions.ts @@ -62,7 +62,7 @@ export const initDataSourceSettings = ( } const dataSource = dependencies.getDataSource(getState().dataSources, pageId); - const dataSourceMeta = dependencies.getDataSourceMeta(getState().dataSources, dataSource.type); + const dataSourceMeta = dependencies.getDataSourceMeta(getState().dataSources, dataSource!.type); const importedPlugin = await dependencies.importDataSourcePlugin(dataSourceMeta); dispatch(initDataSourceSettingsSucceeded(importedPlugin)); @@ -118,7 +118,7 @@ export function loadDataSources(): ThunkResult { export function loadDataSource(id: number): ThunkResult { return async dispatch => { - const dataSource = await getBackendSrv().get(`/api/datasources/${id}`); + const dataSource = (await getBackendSrv().get(`/api/datasources/${id}`)) as DataSourceSettings; const pluginInfo = (await getPluginSettings(dataSource.type)) as DataSourcePluginMeta; const plugin = await importDataSourcePlugin(pluginInfo); diff --git a/public/app/features/datasources/state/navModel.ts b/public/app/features/datasources/state/navModel.ts index bfbedb45e5d..1790502e2c1 100644 --- a/public/app/features/datasources/state/navModel.ts +++ b/public/app/features/datasources/state/navModel.ts @@ -88,6 +88,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { typeLogoUrl: 'public/img/icn-datasource.svg', url: '', user: '', + secureJsonFields: {}, }, { meta: { @@ -113,14 +114,14 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { module: '', baseUrl: '', }, - } as GenericDataSourcePlugin + } as any ); let node: NavModelItem; // find active page - for (const child of main.children) { - if (child.id.indexOf(pageName) > 0) { + for (const child of main.children!) { + if (child.id!.indexOf(pageName) > 0) { child.active = true; node = child; break; @@ -129,7 +130,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { return { main: main, - node: node, + node: node!, }; } diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index 315c5a8eaa0..693c6c9323e 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -3,7 +3,6 @@ import { AnyAction } from 'redux'; import { PayloadAction } from '@reduxjs/toolkit'; import { DataQuery, - DataQueryRequest, DataSourceApi, DefaultTimeRange, LoadingState, @@ -129,7 +128,6 @@ export const makeExploreItemState = (): ExploreItemState => ({ export const createEmptyQueryResponse = (): PanelData => ({ state: LoadingState.NotStarted, - request: {} as DataQueryRequest, series: [], error: null, timeRange: DefaultTimeRange, diff --git a/public/app/features/folders/state/navModel.ts b/public/app/features/folders/state/navModel.ts index 29517e5e7d0..82de51b64c7 100644 --- a/public/app/features/folders/state/navModel.ts +++ b/public/app/features/folders/state/navModel.ts @@ -47,10 +47,10 @@ export function getLoadingNav(tabIndex: number): NavModel { version: 0, }); - main.children[tabIndex].active = true; + main.children![tabIndex].active = true; return { main: main, - node: main.children[tabIndex], + node: main.children![tabIndex], }; } diff --git a/public/app/features/manage-dashboards/components/SnapshotListTable.tsx b/public/app/features/manage-dashboards/components/SnapshotListTable.tsx index a0189dca322..2aa5d13f622 100644 --- a/public/app/features/manage-dashboards/components/SnapshotListTable.tsx +++ b/public/app/features/manage-dashboards/components/SnapshotListTable.tsx @@ -10,7 +10,7 @@ interface Props { export const SnapshotListTable: FC = ({ url }) => { const [snapshots, setSnapshots] = useState([]); - const [removeSnapshot, setRemoveSnapshot] = useState(); + const [removeSnapshot, setRemoveSnapshot] = useState(); const getSnapshots = useCallback(async () => { await getBackendSrv() @@ -91,7 +91,7 @@ export const SnapshotListTable: FC = ({ url }) => { confirmText="Delete" onDismiss={() => setRemoveSnapshot(undefined)} onConfirm={() => { - doRemoveSnapshot(removeSnapshot); + doRemoveSnapshot(removeSnapshot!); setRemoveSnapshot(undefined); }} /> diff --git a/public/app/features/org/UserInviteForm.tsx b/public/app/features/org/UserInviteForm.tsx index 3b1096d95d7..dd6efe75b5b 100644 --- a/public/app/features/org/UserInviteForm.tsx +++ b/public/app/features/org/UserInviteForm.tsx @@ -60,7 +60,7 @@ export const UserInviteForm: FC = ({ updateLocation }) => { <> diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index e543357af21..5d13eab49c0 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -33,7 +33,7 @@ class MetricsPanelCtrl extends PanelCtrl { timeInfo?: string; skipDataOnInit: boolean; dataList: LegacyResponseData[]; - querySubscription?: Unsubscribable; + querySubscription?: Unsubscribable | null; useDataFrames = false; constructor($scope: any, $injector: any) { diff --git a/public/app/features/panel/panellinks/linkSuppliers.ts b/public/app/features/panel/panellinks/linkSuppliers.ts index 7da9fe379e8..5453b11a7e6 100644 --- a/public/app/features/panel/panellinks/linkSuppliers.ts +++ b/public/app/features/panel/panellinks/linkSuppliers.ts @@ -38,7 +38,7 @@ interface DataViewVars { fields?: Record; } -interface DataLinkScopedVars extends ScopedVars { +interface DataLinkScopedVars { __series?: ScopedVar; __field?: ScopedVar; __value?: ScopedVar; @@ -53,6 +53,7 @@ export const getFieldLinksSupplier = (value: FieldDisplay): LinkModelSupplier { const scopedVars: DataLinkScopedVars = { @@ -71,8 +72,8 @@ export const getFieldLinksSupplier = (value: FieldDisplay): LinkModelSupplier= 0) { + const { timeField } = getTimeField(dataFrame); + scopedVars['__value'] = { + value: { + raw: field.values.get(value.rowIndex), + numeric: value.display.numeric, + text: formattedValueToString(value.display), + time: timeField ? timeField.values.get(value.rowIndex) : undefined, + }, + text: 'Value', + }; + } // Expose other values on the row if (value.view) { @@ -124,13 +125,13 @@ export const getFieldLinksSupplier = (value: FieldDisplay): LinkModelSupplier { - return getLinkSrv().getDataLinkUIModel(link, scopedVars, value); + return getLinkSrv().getDataLinkUIModel(link, scopedVars as ScopedVars, value); }); }, }; }; -export const getPanelLinksSupplier = (value: PanelModel): LinkModelSupplier => { +export const getPanelLinksSupplier = (value: PanelModel): LinkModelSupplier | undefined => { const links = value.links; if (!links || links.length === 0) { diff --git a/public/app/features/panel/panellinks/link_srv.ts b/public/app/features/panel/panellinks/link_srv.ts index 2d6a2d66eca..7e9d0881d2e 100644 --- a/public/app/features/panel/panellinks/link_srv.ts +++ b/public/app/features/panel/panellinks/link_srv.ts @@ -20,6 +20,7 @@ import { textUtil, DataLink, PanelPlugin, + DataLinkClickEvent, } from '@grafana/data'; const timeRangeVars = [ @@ -126,8 +127,8 @@ const getFieldVars = (dataFrames: DataFrame[]) => { }; const getDataFrameVars = (dataFrames: DataFrame[]) => { - let numeric: Field = undefined; - let title: Field = undefined; + let numeric: Field | undefined = undefined; + let title: Field | undefined = undefined; const suggestions: VariableSuggestion[] = []; const keys: KeyValue = {}; @@ -245,7 +246,7 @@ export const getPanelOptionsVariableSuggestions = (plugin: PanelPlugin, data?: D }; export interface LinkService { - getDataLinkUIModel: (link: DataLink, scopedVars: ScopedVars, origin: T) => LinkModel; + getDataLinkUIModel: (link: DataLink, scopedVars: ScopedVars | undefined, origin: T) => LinkModel; getAnchorInfo: (link: any) => any; getLinkUrl: (link: any) => string; } @@ -295,15 +296,17 @@ export class LinkSrv implements LinkService { }); } - let onClick: (e: any) => void = undefined; + let onClick: ((event: DataLinkClickEvent) => void) | undefined = undefined; if (link.onClick) { - onClick = (e: any) => { - link.onClick({ - origin, - scopedVars, - e, - }); + onClick = (e: DataLinkClickEvent) => { + if (link.onClick) { + link.onClick({ + origin, + scopedVars, + e, + }); + } }; } diff --git a/public/app/features/panel/query_ctrl.ts b/public/app/features/panel/query_ctrl.ts index 86dac19d9d2..aa3b3016135 100644 --- a/public/app/features/panel/query_ctrl.ts +++ b/public/app/features/panel/query_ctrl.ts @@ -7,7 +7,7 @@ export class QueryCtrl { panelCtrl: any; panel: any; hasRawMode: boolean; - error: string; + error?: string | null; isLastQuery: boolean; constructor(public $scope: any, public $injector: auto.IInjectorService) { diff --git a/public/app/features/plugins/AppRootPage.tsx b/public/app/features/plugins/AppRootPage.tsx index 9858827313e..c5e5e327bb5 100644 --- a/public/app/features/plugins/AppRootPage.tsx +++ b/public/app/features/plugins/AppRootPage.tsx @@ -22,7 +22,7 @@ interface Props { interface State { loading: boolean; - plugin?: AppPlugin; + plugin?: AppPlugin | null; nav: NavModel; } @@ -83,7 +83,7 @@ class AppRootPage extends Component { return ( - {!loading && plugin && ( + {plugin && plugin.root && ( )} diff --git a/public/app/features/plugins/PluginPage.tsx b/public/app/features/plugins/PluginPage.tsx index 018b826052c..6fec9edf38a 100644 --- a/public/app/features/plugins/PluginPage.tsx +++ b/public/app/features/plugins/PluginPage.tsx @@ -123,12 +123,14 @@ class PluginPage extends PureComponent { componentDidUpdate(prevProps: Props) { const prevPage = prevProps.query.page as string; const page = this.props.query.page as string; + if (prevPage !== page) { const { nav, defaultPage } = this.state; const node = { ...nav.node, - children: setActivePage(page, nav.node.children, defaultPage), + children: setActivePage(page, nav.node.children!, defaultPage), }; + this.setState({ nav: { node: node, @@ -146,7 +148,7 @@ class PluginPage extends PureComponent { return ; } - const active = nav.main.children.find(tab => tab.active); + const active = nav.main.children!.find(tab => tab.active); if (active) { // Find the current config tab if (plugin.configPages) { @@ -175,7 +177,7 @@ class PluginPage extends PureComponent { showUpdateInfo = () => { appEvents.emit(CoreEvents.showModal, { src: 'public/app/features/plugins/partials/update_instructions.html', - model: this.state.plugin.meta, + model: this.state.plugin!.meta, }); }; @@ -190,7 +192,7 @@ class PluginPage extends PureComponent { {meta.info.version} {meta.hasUpdate && (
- + Update Available! @@ -203,7 +205,7 @@ class PluginPage extends PureComponent { renderSidebarIncludeBody(item: PluginInclude) { if (item.type === PluginIncludeType.page) { - const pluginId = this.state.plugin.meta.id; + const pluginId = this.state.plugin!.meta.id; const page = item.name.toLowerCase().replace(' ', '-'); return ( @@ -220,7 +222,7 @@ class PluginPage extends PureComponent { ); } - renderSidebarIncludes(includes: PluginInclude[]) { + renderSidebarIncludes(includes?: PluginInclude[]) { if (!includes || !includes.length) { return null; } @@ -241,7 +243,7 @@ class PluginPage extends PureComponent { ); } - renderSidebarDependencies(dependencies: PluginDependencies) { + renderSidebarDependencies(dependencies?: PluginDependencies) { if (!dependencies) { return null; } @@ -295,10 +297,11 @@ class PluginPage extends PureComponent { const { loading, nav, plugin } = this.state; const { $contextSrv } = this.props; const isAdmin = $contextSrv.hasRole('Admin'); + return ( - {!loading && ( + {plugin && (
{plugin.loadError && ( @@ -316,14 +319,12 @@ class PluginPage extends PureComponent { {this.renderBody()}
)} @@ -341,7 +342,7 @@ function getPluginTabsNav( isAdmin: boolean ): { defaultPage: string; nav: NavModel } { const { meta } = plugin; - let defaultPage: string; + let defaultPage: string | undefined; const pages: NavModelItem[] = []; if (true) { @@ -377,6 +378,7 @@ function getPluginTabsNav( url: `${appSubUrl}${path}?page=${page.id}`, id: page.id, }); + if (!defaultPage) { defaultPage = page.id; } @@ -405,11 +407,11 @@ function getPluginTabsNav( subTitle: meta.info.author.name, breadcrumbs: [{ title: 'Plugins', url: 'plugins' }], url: `${appSubUrl}${path}`, - children: setActivePage(query.page as string, pages, defaultPage), + children: setActivePage(query.page as string, pages, defaultPage!), }; return { - defaultPage, + defaultPage: defaultPage!, nav: { node: node, main: node, @@ -427,9 +429,11 @@ function setActivePage(pageId: string, pages: NavModelItem[], defaultPageId: str } return { ...p, active }; }); + if (!found) { changed[0].active = true; } + return changed; } diff --git a/public/app/features/plugins/PluginSignatureBadge.tsx b/public/app/features/plugins/PluginSignatureBadge.tsx index 308462d7dbe..78b21350360 100644 --- a/public/app/features/plugins/PluginSignatureBadge.tsx +++ b/public/app/features/plugins/PluginSignatureBadge.tsx @@ -3,7 +3,7 @@ import { Badge, BadgeProps } from '@grafana/ui'; import { PluginSignatureStatus } from '@grafana/data'; interface Props { - status: PluginSignatureStatus; + status?: PluginSignatureStatus; } export const PluginSignatureBadge: React.FC = ({ status }) => { @@ -11,7 +11,11 @@ export const PluginSignatureBadge: React.FC = ({ status }) => { return ; }; -function getSignatureDisplayModel(signature: PluginSignatureStatus): BadgeProps { +function getSignatureDisplayModel(signature?: PluginSignatureStatus): BadgeProps { + if (!signature) { + signature = PluginSignatureStatus.invalid; + } + switch (signature) { case PluginSignatureStatus.internal: return { text: 'Core', icon: 'cube', color: 'blue', tooltip: 'Core plugin that is bundled with Grafana' }; diff --git a/public/app/features/plugins/datasource_srv.ts b/public/app/features/plugins/datasource_srv.ts index 243a772d848..51880df99b6 100644 --- a/public/app/features/plugins/datasource_srv.ts +++ b/public/app/features/plugins/datasource_srv.ts @@ -126,7 +126,7 @@ export class DatasourceSrv implements DataSourceService { Object.entries(config.datasources).forEach(([key, value]) => { if (value.meta?.metrics) { - let metricSource = { value: key, name: key, meta: value.meta, sort: key }; + let metricSource: DataSourceSelectItem = { value: key, name: key, meta: value.meta, sort: key }; //Make sure grafana and mixed are sorted at the bottom if (value.meta.id === 'grafana') { diff --git a/public/app/features/plugins/plugin_component.ts b/public/app/features/plugins/plugin_component.ts index 55564a6f9b5..b65f05c81ca 100644 --- a/public/app/features/plugins/plugin_component.ts +++ b/public/app/features/plugins/plugin_component.ts @@ -122,7 +122,7 @@ function pluginDirectiveLoader( 'panel-ctrl': 'ctrl', datasource: 'ctrl.datasource', }, - Component: ds.components.QueryCtrl, + Component: ds.components!.QueryCtrl, }); } // Annotations @@ -189,6 +189,10 @@ function pluginDirectiveLoader( case 'app-page': { const appModel = scope.ctrl.appModel; return importAppPlugin(appModel).then(appPlugin => { + if (!appPlugin.angularPages) { + throw new Error('Plugin has no page components'); + } + return { baseUrl: appModel.baseUrl, name: 'app-page-' + appModel.id + '-' + scope.ctrl.page.slug, diff --git a/public/app/features/plugins/wrappers/AppConfigWrapper.tsx b/public/app/features/plugins/wrappers/AppConfigWrapper.tsx index 44b38735a99..0387ac94c2f 100644 --- a/public/app/features/plugins/wrappers/AppConfigWrapper.tsx +++ b/public/app/features/plugins/wrappers/AppConfigWrapper.tsx @@ -14,12 +14,12 @@ interface Props { } interface State { - angularCtrl: AngularComponent; + angularCtrl: AngularComponent | null; refresh: number; } export class AppConfigCtrlWrapper extends PureComponent { - element: HTMLElement; // for angular ctrl + element: HTMLElement | null = null; // Needed for angular scope preUpdateHook = () => Promise.resolve(); diff --git a/public/app/features/profile/SignupForm.tsx b/public/app/features/profile/SignupForm.tsx index 0c4e340b411..5f83d9622ff 100644 --- a/public/app/features/profile/SignupForm.tsx +++ b/public/app/features/profile/SignupForm.tsx @@ -77,7 +77,7 @@ export const SignupForm: FC = props => { - + = props => { })} /> - + = memo(({ navModel, uid, url }) => { if (!uid || !url.startsWith('/dashboards')) { return Promise.resolve({ pageNavModel: navModel }); } + return loadFolderPage(uid!, 'manage-folder-dashboards').then(({ folder, model }) => { const path = locationUtil.stripBaseFromUrl(folder.url); @@ -33,7 +34,7 @@ export const DashboardListPage: FC = memo(({ navModel, uid, url }) => { }, [uid]); return ( - + diff --git a/public/app/features/search/loaders.ts b/public/app/features/search/loaders.ts index 9ad6e1870c9..e1f21f00310 100644 --- a/public/app/features/search/loaders.ts +++ b/public/app/features/search/loaders.ts @@ -41,14 +41,14 @@ export const loadFolderPage = (uid: string, activeChildId: string) => { const folderUrl = folder.url; navModel.main.text = folderTitle; - const dashTab = navModel.main.children.find((child: any) => child.id === 'manage-folder-dashboards'); + const dashTab = navModel.main.children!.find((child: any) => child.id === 'manage-folder-dashboards'); dashTab!.url = folderUrl; if (folder.canAdmin) { - const permTab = navModel.main.children.find((child: any) => child.id === 'manage-folder-permissions'); + const permTab = navModel.main.children!.find((child: any) => child.id === 'manage-folder-permissions'); permTab!.url = folderUrl + '/permissions'; - const settingsTab = navModel.main.children.find((child: any) => child.id === 'manage-folder-settings'); + const settingsTab = navModel.main.children!.find((child: any) => child.id === 'manage-folder-settings'); settingsTab!.url = folderUrl + '/settings'; } else { navModel.main.children = [dashTab!]; diff --git a/public/app/features/teams/TeamGroupSync.tsx b/public/app/features/teams/TeamGroupSync.tsx index e64fec6206b..c1d0e659ea5 100644 --- a/public/app/features/teams/TeamGroupSync.tsx +++ b/public/app/features/teams/TeamGroupSync.tsx @@ -19,7 +19,7 @@ export interface Props { interface State { isAdding: boolean; - newGroupId?: string; + newGroupId: string; } const headerTooltip = `Sync LDAP or OAuth groups with your Grafana teams.`; diff --git a/public/app/features/teams/TeamList.tsx b/public/app/features/teams/TeamList.tsx index 5650fa737a7..cbb4c57f4b4 100644 --- a/public/app/features/teams/TeamList.tsx +++ b/public/app/features/teams/TeamList.tsx @@ -23,8 +23,8 @@ export interface Props { loadTeams: typeof loadTeams; deleteTeam: typeof deleteTeam; setSearchQuery: typeof setSearchQuery; - editorsCanAdmin?: boolean; - signedInUser?: User; + editorsCanAdmin: boolean; + signedInUser: User; } export class TeamList extends PureComponent { diff --git a/public/app/features/teams/TeamMemberRow.tsx b/public/app/features/teams/TeamMemberRow.tsx index 243dda9b833..9e6b5abec57 100644 --- a/public/app/features/teams/TeamMemberRow.tsx +++ b/public/app/features/teams/TeamMemberRow.tsx @@ -14,8 +14,8 @@ export interface Props { syncEnabled: boolean; editorsCanAdmin: boolean; signedInUserIsTeamAdmin: boolean; - removeTeamMember?: typeof removeTeamMember; - updateTeamMember?: typeof updateTeamMember; + removeTeamMember: typeof removeTeamMember; + updateTeamMember: typeof updateTeamMember; } export class TeamMemberRow extends PureComponent { @@ -31,14 +31,17 @@ export class TeamMemberRow extends PureComponent { onPermissionChange = (item: SelectableValue, member: TeamMember) => { const permission = item.value; - const updatedTeamMember = { ...member, permission }; + const updatedTeamMember: TeamMember = { + ...member, + permission: permission as number, + }; this.props.updateTeamMember(updatedTeamMember); }; renderPermissions(member: TeamMember) { const { editorsCanAdmin, signedInUserIsTeamAdmin } = this.props; - const value = teamsPermissionLevels.find(dp => dp.value === member.permission); + const value = teamsPermissionLevels.find(dp => dp.value === member.permission)!; return ( diff --git a/public/app/features/teams/TeamMembers.tsx b/public/app/features/teams/TeamMembers.tsx index 45348c71cf7..e8fadf1bd62 100644 --- a/public/app/features/teams/TeamMembers.tsx +++ b/public/app/features/teams/TeamMembers.tsx @@ -20,13 +20,13 @@ export interface Props { addTeamMember: typeof addTeamMember; setSearchMemberQuery: typeof setSearchMemberQuery; syncEnabled: boolean; - editorsCanAdmin?: boolean; - signedInUser?: SignedInUser; + editorsCanAdmin: boolean; + signedInUser: SignedInUser; } export interface State { isAdding: boolean; - newTeamMember?: User; + newTeamMember?: User | null; } export class TeamMembers extends PureComponent { @@ -48,7 +48,7 @@ export class TeamMembers extends PureComponent { }; onAddUserToTeam = async () => { - this.props.addTeamMember(this.state.newTeamMember.id); + this.props.addTeamMember(this.state.newTeamMember!.id); this.setState({ newTeamMember: null }); }; diff --git a/public/app/features/teams/TeamPages.tsx b/public/app/features/teams/TeamPages.tsx index 6d7774ecf6c..05ed53d4327 100644 --- a/public/app/features/teams/TeamPages.tsx +++ b/public/app/features/teams/TeamPages.tsx @@ -23,9 +23,9 @@ export interface Props { teamId: number; pageName: string; navModel: NavModel; - members?: TeamMember[]; - editorsCanAdmin?: boolean; - signedInUser?: User; + members: TeamMember[]; + editorsCanAdmin: boolean; + signedInUser: User; } interface State { @@ -92,7 +92,7 @@ export class TeamPages extends PureComponent { return navModel; }; - renderPage(isSignedInUserTeamAdmin: boolean) { + renderPage(isSignedInUserTeamAdmin: boolean): React.ReactNode { const { isSyncEnabled } = this.state; const { members } = this.props; const currentPage = this.getCurrentPage(); diff --git a/public/app/features/teams/state/navModel.ts b/public/app/features/teams/state/navModel.ts index 25c1e3b53bf..12faf41a733 100644 --- a/public/app/features/teams/state/navModel.ts +++ b/public/app/features/teams/state/navModel.ts @@ -54,8 +54,8 @@ export function getTeamLoadingNav(pageName: string): NavModel { let node: NavModelItem; // find active page - for (const child of main.children) { - if (child.id.indexOf(pageName) > 0) { + for (const child of main.children!) { + if (child.id!.indexOf(pageName) > 0) { child.active = true; node = child; break; @@ -64,6 +64,6 @@ export function getTeamLoadingNav(pageName: string): NavModel { return { main: main, - node: node, + node: node!, }; } diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index 75fcfd44d46..7cc8d75cf13 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -318,9 +318,9 @@ export class TemplateSrv implements BaseTemplateSrv { return scopedVar.value; } - replace(target: string, scopedVars?: ScopedVars, format?: string | Function): string { + replace(target?: string, scopedVars?: ScopedVars, format?: string | Function): string { if (!target) { - return target; + return target ?? ''; } this.regex.lastIndex = 0; diff --git a/public/app/features/variables/pickers/OptionsPicker/reducer.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.ts index 71c93a5c78d..ecd6dbe18ea 100644 --- a/public/app/features/variables/pickers/OptionsPicker/reducer.ts +++ b/public/app/features/variables/pickers/OptionsPicker/reducer.ts @@ -16,7 +16,7 @@ export interface OptionsPickerState { id: string; selectedValues: VariableOption[]; selectedTags: VariableTag[]; - queryValue: string | null; + queryValue: string; highlightIndex: number; tags: VariableTag[]; options: VariableOption[]; @@ -26,7 +26,7 @@ export interface OptionsPickerState { export const initialState: OptionsPickerState = { id: '', highlightIndex: -1, - queryValue: null, + queryValue: '', selectedTags: [], selectedValues: [], tags: [], diff --git a/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts b/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts index 9863fa9d4dc..c4945184772 100644 --- a/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts +++ b/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts @@ -120,21 +120,34 @@ export default class CloudMonitoringMetricFindQuery { return []; } const metricDescriptors = await this.datasource.getMetricTypes(projectName); - const { valueType, metricKind } = metricDescriptors.find( + const descriptor = metricDescriptors.find( (m: any) => m.type === this.datasource.templateSrv.replace(selectedMetricType) ); - return getAlignmentOptionsByMetric(valueType, metricKind).map(this.toFindQueryResult); + + if (!descriptor) { + return []; + } + + return getAlignmentOptionsByMetric(descriptor.valueType, descriptor.metricKind).map(this.toFindQueryResult); } async handleAggregationQuery({ selectedMetricType, projectName }: VariableQueryData) { if (!selectedMetricType) { return []; } + const metricDescriptors = await this.datasource.getMetricTypes(projectName); - const { valueType, metricKind } = metricDescriptors.find( + const descriptor = metricDescriptors.find( (m: any) => m.type === this.datasource.templateSrv.replace(selectedMetricType) ); - return getAggregationOptionsByMetric(valueType as ValueTypes, metricKind as MetricKind).map(this.toFindQueryResult); + + if (!descriptor) { + return []; + } + + return getAggregationOptionsByMetric(descriptor.valueType as ValueTypes, descriptor.metricKind as MetricKind).map( + this.toFindQueryResult + ); } async handleSLOServicesQuery({ projectName }: VariableQueryData) { diff --git a/public/app/plugins/datasource/cloud-monitoring/api.ts b/public/app/plugins/datasource/cloud-monitoring/api.ts index 02a7045896a..d9dece79b4f 100644 --- a/public/app/plugins/datasource/cloud-monitoring/api.ts +++ b/public/app/plugins/datasource/cloud-monitoring/api.ts @@ -38,7 +38,7 @@ export default class Api { method: 'GET', }); - const responsePropName = path.match(/([^\/]*)\/*$/)[1]; + const responsePropName = path.match(/([^\/]*)\/*$/)![1]; let res = []; if (response && response.data && response.data[responsePropName]) { res = response.data[responsePropName].map(responseMap); diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.test.tsx index 06bdd5a29cc..f2f0233a602 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.test.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.test.tsx @@ -13,7 +13,7 @@ const props: Props = { metricDescriptor: { valueType: '', metricKind: '', - }, + } as any, crossSeriesReducer: '', groupBys: [], children: renderProps =>
, @@ -33,7 +33,7 @@ describe('Aggregations', () => { metricDescriptor: { valueType: ValueTypes.DOUBLE, metricKind: MetricKind.GAUGE, - }, + } as any, }; it('should not have the reduce values', () => { @@ -54,7 +54,7 @@ describe('Aggregations', () => { metricDescriptor: { valueType: ValueTypes.MONEY, metricKind: MetricKind.CUMULATIVE, - }, + } as any, }; it('should have the reduce values', () => { diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.tsx index 326fcd0f20e..4c9540cd572 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/Aggregations.tsx @@ -5,16 +5,14 @@ import { SelectableValue } from '@grafana/data'; import { Segment, Icon } from '@grafana/ui'; import { getAggregationOptionsByMetric } from '../functions'; import { ValueTypes, MetricKind } from '../constants'; +import { MetricDescriptor } from '../types'; export interface Props { onChange: (metricDescriptor: string) => void; - metricDescriptor: { - valueType: string; - metricKind: string; - }; + metricDescriptor?: MetricDescriptor; crossSeriesReducer: string; groupBys: string[]; - children?: (renderProps: any) => JSX.Element; + children: (displayAdvancedOptions: boolean) => React.ReactNode; templateVariableOptions: Array>; } @@ -28,7 +26,7 @@ export const Aggregations: FC = props => {
props.onChange(value)} + onChange={({ value }) => props.onChange(value!)} value={selected} options={[ { diff --git a/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx b/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx index 9e7caf0d614..21fc3bb5899 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx @@ -4,11 +4,11 @@ import { QueryInlineField } from '.'; export interface Props { onChange: (alias: any) => void; - value: string; + value?: string; } export const AliasBy: FunctionComponent = ({ value = '', onChange }) => { - const [alias, setAlias] = useState(value); + const [alias, setAlias] = useState(value ?? ''); const propagateOnChange = debounce(onChange, 1000); diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Metrics.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Metrics.tsx index f474a147f52..8aab3c2df62 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/Metrics.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/Metrics.tsx @@ -14,7 +14,7 @@ export interface Props { datasource: CloudMonitoringDatasource; projectName: string; metricType: string; - children?: (renderProps: any) => JSX.Element; + children: (metricDescriptor?: MetricDescriptor) => JSX.Element; } interface State { @@ -23,8 +23,8 @@ interface State { services: any[]; service: string; metric: string; - metricDescriptor: MetricDescriptor; - projectName: string; + metricDescriptor?: MetricDescriptor; + projectName: string | null; } export function Metrics(props: Props) { @@ -34,7 +34,6 @@ export function Metrics(props: Props) { services: [], service: '', metric: '', - metricDescriptor: null, projectName: null, }); @@ -57,7 +56,7 @@ export function Metrics(props: Props) { }, [projectName]); const getSelectedMetricDescriptor = (metricDescriptors: MetricDescriptor[], metricType: string) => { - return metricDescriptors.find(md => md.type === props.templateSrv.replace(metricType)); + return metricDescriptors.find(md => md.type === props.templateSrv.replace(metricType))!; }; const getMetricsList = (metricDescriptors: MetricDescriptor[]) => { @@ -97,9 +96,9 @@ export function Metrics(props: Props) { }; const onMetricTypeChange = ({ value }: SelectableValue, extra: any = {}) => { - const metricDescriptor = getSelectedMetricDescriptor(state.metricDescriptors, value); + const metricDescriptor = getSelectedMetricDescriptor(state.metricDescriptors, value!); setState({ ...state, metricDescriptor, ...extra }); - props.onChange({ ...metricDescriptor, type: value }); + props.onChange({ ...metricDescriptor, type: value! }); }; const getServicesList = (metricDescriptors: MetricDescriptor[]) => { diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx index 3d39eb00a51..c0d785f3fa8 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx @@ -63,8 +63,8 @@ export class QueryEditor extends PureComponent { render() { const { datasource, query, onRunQuery, onChange } = this.props; - const metricQuery = { ...defaultQuery, projectName: datasource.getDefaultProject(), ...query.metricQuery }; - const sloQuery = { ...defaultSLOQuery, projectName: datasource.getDefaultProject(), ...query.sloQuery }; + const metricQuery = { ...defaultQuery, ...query.metricQuery, projectName: datasource.getDefaultProject() }; + const sloQuery = { ...defaultSLOQuery, ...query.sloQuery, projectName: datasource.getDefaultProject() }; const queryType = query.queryType || QueryType.METRICS; const meta = this.props.data?.series.length ? this.props.data?.series[0].meta : {}; const usedAlignmentPeriod = meta?.alignmentPeriod as string; diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx index eee80a4578f..ae9252cfb55 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx @@ -87,7 +87,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent { const { metricDescriptors, labels, metricTypes, services, ...queryModel } = this.state; - const query = this.queryTypes.find(q => q.value === this.state.selectedQueryType); + const query = this.queryTypes.find(q => q.value === this.state.selectedQueryType)!; this.props.onChange(queryModel, `Google Cloud Monitoring - ${query.name}`); }; diff --git a/public/app/plugins/datasource/cloud-monitoring/datasource.ts b/public/app/plugins/datasource/cloud-monitoring/datasource.ts index 64acbb61bff..eb3bc48d876 100644 --- a/public/app/plugins/datasource/cloud-monitoring/datasource.ts +++ b/public/app/plugins/datasource/cloud-monitoring/datasource.ts @@ -263,8 +263,8 @@ export default class CloudMonitoringDatasource extends DataSourceApi>> { return this.api.get(`${this.templateSrv.replace(projectName)}/services`, { responseMap: ({ name }: { name: string }) => ({ - value: name.match(/([^\/]*)\/*$/)[1], - label: name.match(/([^\/]*)\/*$/)[1], + value: name.match(/([^\/]*)\/*$/)![1], + label: name.match(/([^\/]*)\/*$/)![1], }), }); } @@ -276,7 +276,7 @@ export default class CloudMonitoringDatasource extends DataSourceApi ({ - value: name.match(/([^\/]*)\/*$/)[1], + value: name.match(/([^\/]*)\/*$/)![1], label: displayName, goal, }), @@ -323,7 +323,7 @@ export default class CloudMonitoringDatasource extends DataSourceApi { }; export const filtersToStringArray = (filters: Filter[]) => { - const strArr = _.flatten(filters.map(({ key, operator, value, condition }) => [key, operator, value, condition])); + const strArr = _.flatten(filters.map(({ key, operator, value, condition }) => [key, operator, value, condition!])); return strArr.filter((_, i) => i !== strArr.length - 1); }; diff --git a/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx b/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx index ae954c17260..72b8c0c5dbe 100644 --- a/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/CloudWatchLink.tsx @@ -8,7 +8,7 @@ import { CloudWatchDatasource } from '../datasource'; interface Props { query: CloudWatchLogsQuery; - panelData: PanelData; + panelData?: PanelData; datasource: CloudWatchDatasource; } @@ -18,8 +18,12 @@ interface State { export default class CloudWatchLink extends Component { state: State = { href: '' }; + async componentDidUpdate(prevProps: Props) { - if (prevProps.panelData !== this.props.panelData && this.props.panelData.request) { + const { panelData: panelDataNew } = this.props; + const { panelData: panelDataOld } = prevProps; + + if (panelDataOld !== panelDataNew && panelDataNew?.request) { const href = this.getExternalLink(); this.setState({ href }); } diff --git a/public/app/plugins/datasource/cloudwatch/components/Dimensions.tsx b/public/app/plugins/datasource/cloudwatch/components/Dimensions.tsx index f2f05891567..cfba4d3f2de 100644 --- a/public/app/plugins/datasource/cloudwatch/components/Dimensions.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/Dimensions.tsx @@ -31,7 +31,7 @@ export const Dimensions: FunctionComponent = ({ dimensions, loadValues, l }, [data]); const excludeUsedKeys = (options: SelectableStrings) => { - return options.filter(({ value }) => !Object.keys(data).includes(value)); + return options.filter(({ value }) => !Object.keys(data).includes(value!)); }; return ( @@ -47,7 +47,7 @@ export const Dimensions: FunctionComponent = ({ dimensions, loadValues, l if (newKey === removeText) { setData({ ...newDimensions }); } else { - setData({ ...newDimensions, [newKey]: '' }); + setData({ ...newDimensions, [newKey!]: '' }); } }} /> @@ -57,7 +57,7 @@ export const Dimensions: FunctionComponent = ({ dimensions, loadValues, l value={value} placeholder="select dimension value" loadOptions={() => loadValues(key)} - onChange={({ value: newValue }) => setData({ ...data, [key]: newValue })} + onChange={({ value: newValue }) => setData({ ...data, [key]: newValue! })} /> {Object.values(data).length > 1 && index + 1 !== Object.values(data).length && ( @@ -73,7 +73,7 @@ export const Dimensions: FunctionComponent = ({ dimensions, loadValues, l } loadOptions={() => loadKeys().then(excludeUsedKeys)} - onChange={({ value: newKey }) => setData({ ...data, [newKey]: '' })} + onChange={({ value: newKey }) => setData({ ...data, [newKey!]: '' })} /> )} diff --git a/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx index e28b21a1a15..7a484390d45 100644 --- a/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/LogsQueryField.tsx @@ -40,7 +40,7 @@ export interface CloudWatchLogsQueryFieldProps extends ExploreQueryFieldProps void; ExtraFieldElement?: ReactNode; syntaxLoaded: boolean; - syntax: Grammar; + syntax: Grammar | null; exploreId: ExploreId; allowCustomValue?: boolean; } diff --git a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx index c01d25c61ea..7896ae7082c 100644 --- a/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/MetricsQueryFieldsEditor.tsx @@ -94,7 +94,7 @@ export function MetricsQueryFieldsEditor({ placeholder="Select region" options={regions} allowCustomValue - onChange={({ value: region }) => onQueryChange({ ...query, region })} + onChange={({ value: region }) => onQueryChange({ ...query, region: region! })} /> @@ -106,7 +106,7 @@ export function MetricsQueryFieldsEditor({ placeholder="Select namespace" allowCustomValue options={namespaces} - onChange={({ value: namespace }) => onQueryChange({ ...query, namespace })} + onChange={({ value: namespace }) => onQueryChange({ ...query, namespace: namespace! })} /> diff --git a/public/app/plugins/datasource/cloudwatch/components/Stats.tsx b/public/app/plugins/datasource/cloudwatch/components/Stats.tsx index d3267380e8c..748b19f77b6 100644 --- a/public/app/plugins/datasource/cloudwatch/components/Stats.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/Stats.tsx @@ -26,7 +26,7 @@ export const Stats: FunctionComponent = ({ stats, values, onChange, varia onChange( value === removeText ? values.filter((_, i) => i !== index) - : values.map((v, i) => (i === index ? value : v)) + : values.map((v, i) => (i === index ? value! : v)) ) } /> @@ -38,8 +38,8 @@ export const Stats: FunctionComponent = ({ stats, values, onChange, varia } allowCustomValue - onChange={({ value }) => onChange([...values, value])} - options={[...stats.filter(({ value }) => !values.includes(value)), variableOptionGroup]} + onChange={({ value }) => onChange([...values, value!])} + options={[...stats.filter(({ value }) => !values.includes(value!)), variableOptionGroup]} /> ); diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index eed9553b2f6..1a437a37c4a 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -177,7 +177,6 @@ export class CloudWatchDatasource extends DataSourceApi => { const queryCommand = commandToken.content.toLowerCase(); const prevToken = prevNonWhitespaceToken(curToken); @@ -190,11 +190,11 @@ export class CloudWatchLanguageProvider extends LanguageProvider { if (queryCommand === 'parse') { if (currentTokenIsFirstArg) { - return await this.getFieldCompletionItems(context.logGroupNames ?? []); + return await this.getFieldCompletionItems(context?.logGroupNames ?? []); } } - const currentTokenIsAfterCommandAndEmpty = isTokenType(commandToken.next, 'whitespace') && !commandToken.next.next; + const currentTokenIsAfterCommandAndEmpty = isTokenType(commandToken.next, 'whitespace') && !commandToken.next?.next; const currentTokenIsAfterCommand = currentTokenIsAfterCommandAndEmpty || nextNonWhitespaceToken(commandToken) === curToken; @@ -207,7 +207,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider { } if (['display', 'fields'].includes(queryCommand)) { - const typeaheadOutput = await this.getFieldCompletionItems(context.logGroupNames ?? []); + const typeaheadOutput = await this.getFieldCompletionItems(context?.logGroupNames ?? []); typeaheadOutput.suggestions.push(...this.getFieldAndFilterFunctionCompletionItems().suggestions); return typeaheadOutput; @@ -224,7 +224,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider { } if (queryCommand === 'filter' && currentTokenIsFirstArg) { - const sugg = await this.getFieldCompletionItems(context.logGroupNames ?? []); + const sugg = await this.getFieldCompletionItems(context?.logGroupNames ?? []); const boolFuncs = this.getBoolFuncCompletionItems(); sugg.suggestions.push(...boolFuncs.suggestions); return sugg; @@ -235,10 +235,10 @@ export class CloudWatchLanguageProvider extends LanguageProvider { private async handleSortCommand( isFirstArgument: boolean, curToken: Token, - context: TypeaheadContext + context?: TypeaheadContext ): Promise { if (isFirstArgument) { - return await this.getFieldCompletionItems(context.logGroupNames ?? []); + return await this.getFieldCompletionItems(context?.logGroupNames ?? []); } else if (isTokenType(prevNonWhitespaceToken(curToken), 'field-name')) { // suggest sort options return { diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx index 5ed265b61a0..52e1df63d12 100644 --- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx +++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx @@ -52,7 +52,7 @@ export class DashboardQueryEditor extends PureComponent { } async componentDidMount() { - this.componentDidUpdate(null); + this.componentDidUpdate(this.props); } async componentDidUpdate(prevProps: Props) { @@ -60,9 +60,9 @@ export class DashboardQueryEditor extends PureComponent { if (!prevProps || prevProps.panelData !== panelData) { const query = this.props.panel.targets[0] as DashboardQuery; - const defaultDS = await getDatasourceSrv().get(null); + const defaultDS = await getDatasourceSrv().get(); const dashboard = getDashboardSrv().getCurrent(); - const panel = dashboard.getPanelById(query.panelId); + const panel = dashboard.getPanelById(query.panelId ?? -124134); if (!panel) { this.setState({ defaultDatasource: defaultDS.name }); @@ -143,7 +143,7 @@ export class DashboardQueryEditor extends PureComponent { const dashboard = getDashboardSrv().getCurrent(); const query = this.getQuery(); - let selected: SelectableValue; + let selected: SelectableValue | undefined; const panels: Array> = []; for (const panel of dashboard.panels) { @@ -188,7 +188,7 @@ export class DashboardQueryEditor extends PureComponent { isSearchable={true} options={panels} value={selected} - onChange={item => this.onPanelChanged(item.value)} + onChange={item => this.onPanelChanged(item.value!)} />
{query.panelId && this.renderQueryData(editURL)}
diff --git a/public/app/plugins/datasource/dashboard/runSharedRequest.ts b/public/app/plugins/datasource/dashboard/runSharedRequest.ts index 1d64dfdcd84..5cd8609335e 100644 --- a/public/app/plugins/datasource/dashboard/runSharedRequest.ts +++ b/public/app/plugins/datasource/dashboard/runSharedRequest.ts @@ -23,7 +23,7 @@ export function runSharedRequest(options: QueryRunnerOptions): Observable { ); }; -function useInternalLink(datasourceUid: string): [boolean, Dispatch>] { +function useInternalLink(datasourceUid?: string): [boolean, Dispatch>] { const [showInternalLink, setShowInternalLink] = useState(!!datasourceUid); const previousUid = usePrevious(datasourceUid); diff --git a/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx b/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx index 2f0bff273aa..2c26f3007db 100644 --- a/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx +++ b/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx @@ -86,13 +86,13 @@ export const ElasticDetails = (props: Props) => { onChange={option => { const maxConcurrentShardRequests = getMaxConcurrenShardRequestOrDefault( value.jsonData.maxConcurrentShardRequests, - option.value + option.value! ); onChange({ ...value, jsonData: { ...value.jsonData, - esVersion: option.value, + esVersion: option.value!, maxConcurrentShardRequests, }, }); @@ -179,10 +179,12 @@ const intervalHandler = (value: Props['value'], onChange: Props['onChange']) => if (!database || database.length === 0 || database.startsWith('[logstash-]')) { let newDatabase = ''; + if (newInterval !== undefined) { const pattern = indexPatternTypes.find(pattern => pattern.value === newInterval); + if (pattern) { - newDatabase = pattern.example; + newDatabase = pattern.example ?? ''; } } @@ -205,7 +207,7 @@ const intervalHandler = (value: Props['value'], onChange: Props['onChange']) => } }; -function getMaxConcurrenShardRequestOrDefault(maxConcurrentShardRequests: number, version: number): number { +function getMaxConcurrenShardRequestOrDefault(maxConcurrentShardRequests: number | undefined, version: number): number { if (maxConcurrentShardRequests === 5 && version < 70) { return 256; } diff --git a/public/app/plugins/datasource/elasticsearch/datasource.ts b/public/app/plugins/datasource/elasticsearch/datasource.ts index 89976082bb2..fec5cd700e9 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.ts +++ b/public/app/plugins/datasource/elasticsearch/datasource.ts @@ -20,15 +20,15 @@ import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { DataLinkConfig, ElasticsearchOptions, ElasticsearchQuery } from './types'; export class ElasticDatasource extends DataSourceApi { - basicAuth: string; - withCredentials: boolean; + basicAuth?: string; + withCredentials?: boolean; url: string; name: string; index: string; timeField: string; esVersion: number; interval: string; - maxConcurrentShardRequests: number; + maxConcurrentShardRequests?: number; queryBuilder: ElasticQueryBuilder; indexPattern: IndexPattern; logMessageField?: string; @@ -44,9 +44,9 @@ export class ElasticDatasource extends DataSourceApi= 56 && this.esVersion < 70) { queryHeader['max_concurrent_shard_requests'] = this.maxConcurrentShardRequests; } + return angular.toJson(queryHeader); } @@ -402,6 +404,7 @@ export class ElasticDatasource extends DataSourceApi { const er = new ElasticResponse(sentTargets, res); + if (sentTargets.some(target => target.isLogsQuery)) { const response = er.getLogs(this.logMessageField, this.logLevelField); for (const dataFrame of response.data) { diff --git a/public/app/plugins/datasource/elasticsearch/elastic_response.ts b/public/app/plugins/datasource/elasticsearch/elastic_response.ts index a104114ea56..f4e45800c14 100644 --- a/public/app/plugins/datasource/elasticsearch/elastic_response.ts +++ b/public/app/plugins/datasource/elasticsearch/elastic_response.ts @@ -12,7 +12,8 @@ export class ElasticResponse { } processMetrics(esAgg: any, target: any, seriesList: any, props: any) { - let metric, y, i, newSeries, bucket, value; + let metric, y, i, bucket, value; + let newSeries: any; for (y = 0; y < target.metrics.length; y++) { metric = target.metrics[y]; @@ -486,7 +487,7 @@ const flattenHits = (hits: Doc[]): { docs: Array>; propNames let propNames: string[] = []; for (const hit of hits) { - const flattened = hit._source ? flatten(hit._source, null) : {}; + const flattened = hit._source ? flatten(hit._source) : {}; const doc = { _id: hit._id, _type: hit._type, diff --git a/public/app/plugins/datasource/elasticsearch/index_pattern.ts b/public/app/plugins/datasource/elasticsearch/index_pattern.ts index 9b8393c220d..8732c53d540 100644 --- a/public/app/plugins/datasource/elasticsearch/index_pattern.ts +++ b/public/app/plugins/datasource/elasticsearch/index_pattern.ts @@ -9,7 +9,7 @@ const intervalMap: any = { }; export class IndexPattern { - constructor(private pattern: any, private interval: string | null) {} + constructor(private pattern: any, private interval?: string) {} getIndexForToday() { if (this.interval) { diff --git a/public/app/plugins/datasource/elasticsearch/metric_agg.ts b/public/app/plugins/datasource/elasticsearch/metric_agg.ts index ea79c1c7057..0b51b6c0912 100644 --- a/public/app/plugins/datasource/elasticsearch/metric_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/metric_agg.ts @@ -89,7 +89,7 @@ export class ElasticMetricAggCtrl { } return memo; }, - [] + [] as string[] ); $scope.settingsLinkText = 'Stats: ' + stats.join(', '); diff --git a/public/app/plugins/datasource/elasticsearch/types.ts b/public/app/plugins/datasource/elasticsearch/types.ts index b89f47fdb34..ec07da2c737 100644 --- a/public/app/plugins/datasource/elasticsearch/types.ts +++ b/public/app/plugins/datasource/elasticsearch/types.ts @@ -3,7 +3,7 @@ import { DataQuery, DataSourceJsonData } from '@grafana/data'; export interface ElasticsearchOptions extends DataSourceJsonData { timeField: string; esVersion: number; - interval: string; + interval?: string; timeInterval: string; maxConcurrentShardRequests?: number; logMessageField?: string; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts index d8d1eaf6c13..c176638a77e 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts @@ -423,7 +423,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of metric names', () => { - return ctx.ds.metricFindQuery('appInsightsMetricNames()').then((results: any) => { + return ctx.ds.metricFindQueryInternal('appInsightsMetricNames()').then((results: any) => { expect(results.length).toBe(2); expect(results[0].text).toBe('exceptions/server'); expect(results[0].value).toBe('exceptions/server'); @@ -461,7 +461,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of group bys', () => { - return ctx.ds.metricFindQuery('appInsightsGroupBys(requests/count)').then((results: any) => { + return ctx.ds.metricFindQueryInternal('appInsightsGroupBys(requests/count)').then((results: any) => { expect(results[0].text).toContain('client/os'); expect(results[0].value).toContain('client/os'); expect(results[1].text).toContain('client/city'); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts index 54cdebb6a50..80c18bf0a03 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts @@ -1,4 +1,4 @@ -import { ScopedVars } from '@grafana/data'; +import { ScopedVars, MetricFindValue } from '@grafana/data'; import { DataQueryRequest, DataSourceInstanceSettings } from '@grafana/data'; import { getBackendSrv, getTemplateSrv, DataSourceWithBackend } from '@grafana/runtime'; import _, { isString } from 'lodash'; @@ -122,7 +122,13 @@ export default class AppInsightsDatasource extends DataSourceWithBackend | null { const appInsightsMetricNameQuery = query.match(/^AppInsightsMetricNames\(\)/i); if (appInsightsMetricNameQuery) { return this.getMetricNames(); @@ -134,7 +140,7 @@ export default class AppInsightsDatasource extends DataSourceWithBackend 0) { - const url = await this.buildDeepLink(df.meta); + const url = await this.buildDeepLink(df.meta.custom); if (url?.length) { for (const field of df.fields) { field.config.links = [ @@ -158,10 +152,10 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< return res; } - private async buildDeepLink(meta: QueryResultMeta) { - const base64Enc = encodeURIComponent(meta.custom.encodedQuery); - const workspaceId = meta.custom.workspace; - const subscription = meta.custom.subscription; + private async buildDeepLink(customMeta: Record) { + const base64Enc = encodeURIComponent(customMeta.encodedQuery); + const workspaceId = customMeta.workspace; + const subscription = customMeta.subscription; const details = await this.getWorkspaceDetails(workspaceId); if (!details.workspace || !details.resourceGroup) { @@ -200,7 +194,13 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< }; } - metricFindQuery(query: string): Promise { + /** + * This is named differently than DataSourceApi.metricFindQuery + * because it's not exposed to Grafana like the main AzureMonitorDataSource. + * And some of the azure internal data sources return null in this function, which the + * external interface does not support + */ + metricFindQueryInternal(query: string): Promise { const workspacesQuery = query.match(/^workspaces\(\)/i); if (workspacesQuery) { return this.getWorkspaces(this.subscriptionId); @@ -233,7 +233,7 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< throw { message: err.error.data.error.message }; } }); - }) as Promise; // ?? + }) as Promise; } private buildQuery(query: string, options: any, workspace: any) { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts index f28f07e5535..e7bd4980b67 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts @@ -10,7 +10,7 @@ import { AzureMonitorResourceGroupsResponse, AzureQueryType, } from '../types'; -import { DataSourceInstanceSettings, ScopedVars } from '@grafana/data'; +import { DataSourceInstanceSettings, ScopedVars, MetricFindValue } from '@grafana/data'; import { getBackendSrv, DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime'; const defaultDropdownValue = 'select'; @@ -32,8 +32,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend f.dimension && f.dimension !== 'None') .map(f => { - const filter = templateSrv.replace(f.filter, scopedVars); + const filter = templateSrv.replace(f.filter ?? '', scopedVars); return { dimension: templateSrv.replace(f.dimension, scopedVars), operator: f.operator || 'eq', @@ -107,7 +102,13 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend | null { const subscriptionsQuery = query.match(/^Subscriptions\(\)/i); if (subscriptionsQuery) { return this.getSubscriptions(); @@ -196,7 +197,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend 0; } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.tsx index 0cbc9a26e65..1728c0e8b4f 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.tsx @@ -53,7 +53,7 @@ export class AnalyticsConfig extends PureComponent { onAzureLogAnalyticsSameAsChange = () => { const { options, onUpdateDatasourceOptions, makeSameAs } = this.props; - if (!options.jsonData.azureLogAnalyticsSameAs && options.secureJsonData.clientSecret) { + if (!options.jsonData.azureLogAnalyticsSameAs && options.secureJsonData!.clientSecret) { makeSameAs(); } else if (!options.jsonData.azureLogAnalyticsSameAs) { // if currently off, clear monitor secret @@ -94,7 +94,7 @@ export class AnalyticsConfig extends PureComponent { jsonData.tenantId && jsonData.clientId && jsonData.subscriptionId && - (secureJsonData.clientSecret || secureJsonFields.clientSecret) + (secureJsonData!.clientSecret || secureJsonFields.clientSecret) ); } @@ -104,7 +104,7 @@ export class AnalyticsConfig extends PureComponent { jsonData.logAnalyticsClientId && jsonData.logAnalyticsClientId.length && jsonData.logAnalyticsSubscriptionId && - (secureJsonFields.logAnalyticsClientSecret || secureJsonData.logAnalyticsClientSecret) + (secureJsonFields.logAnalyticsClientSecret || secureJsonData!.logAnalyticsClientSecret) ); }; @@ -132,14 +132,14 @@ export class AnalyticsConfig extends PureComponent { jsonData.azureLogAnalyticsSameAs && secureJsonFields && !secureJsonFields.clientSecret && - !secureJsonData.clientSecret; + !secureJsonData!.clientSecret; return ( <>

Azure Log Analytics API Details

@@ -156,7 +156,7 @@ export class AnalyticsConfig extends PureComponent { selectedSubscription={jsonData.logAnalyticsSubscriptionId} tenantId={jsonData.logAnalyticsTenantId} clientId={jsonData.logAnalyticsClientId} - clientSecret={secureJsonData.logAnalyticsClientSecret} + clientSecret={secureJsonData!.logAnalyticsClientSecret} clientSecretConfigured={secureJsonFields.logAnalyticsClientSecret} onSubscriptionSelectChange={this.onLogAnalyticsSubscriptionSelect} onTenantIdChange={this.onLogAnalyticsTenantIdChange} diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx index f3060c39a37..fb70864dac5 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx @@ -7,10 +7,10 @@ export interface Props { selectedAzureCloud?: string; selectedSubscription?: string; azureCloudOptions?: SelectableValue[]; - tenantId: string; - clientId: string; - clientSecret: string; - clientSecretConfigured: boolean; + tenantId?: string; + clientId?: string; + clientSecret?: string; + clientSecretConfigured?: boolean; subscriptionOptions?: SelectableValue[]; onAzureCloudChange?: (value: SelectableValue) => void; onSubscriptionSelectChange?: (value: SelectableValue) => void; @@ -124,7 +124,7 @@ export class AzureCredentialsForm extends PureComponent { Default Subscription
diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MonitorConfig.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MonitorConfig.tsx index cc7d7670335..177a9b70846 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MonitorConfig.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MonitorConfig.tsx @@ -63,7 +63,7 @@ export class MonitorConfig extends PureComponent { selectedSubscription={options.jsonData.subscriptionId} tenantId={options.jsonData.tenantId} clientId={options.jsonData.clientId} - clientSecret={options.secureJsonData.clientSecret} + clientSecret={options.secureJsonData?.clientSecret} clientSecretConfigured={options.secureJsonFields.clientSecret} onAzureCloudChange={this.onAzureCloudSelect} onSubscriptionSelectChange={this.onSubscriptionSelect} diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts index e20c2c7cfba..1bcccf14c80 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts @@ -118,17 +118,17 @@ export default class Datasource extends DataSourceApi { const selection = window.getSelection(); - if (selection.anchorNode) { + + if (selection && selection.anchorNode) { const wrapperNode = selection.anchorNode.parentElement; if (wrapperNode === null) { return; @@ -408,7 +409,7 @@ export default class KustoQueryField extends QueryField { if (match && match.length > 1 && match[0] && match[1]) { return match[1]; } else { - return null; + return undefined; } } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/query_field.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/query_field.tsx index 7e27238f809..2099efd3de4 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/query_field.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/query_field.tsx @@ -103,13 +103,6 @@ class QueryField extends React.Component { }); }; - request = (url?: string) => { - if (this.props.request) { - return this.props.request(url); - } - return fetch(url); - }; - onChangeQuery = () => { // Send text change to parent const { onQueryChange } = this.props; @@ -256,13 +249,14 @@ class QueryField extends React.Component { const { suggestions } = this.state; const menu = this.menuEl; const selection = window.getSelection(); - const node = selection.anchorNode; // No menu, nothing to do - if (!menu) { + if (!menu || !selection) { return; } + const node = selection.anchorNode; + // No suggestions or blur, remove menu const hasSuggesstions = suggestions && suggestions.length > 0; if (!hasSuggesstions) { diff --git a/public/app/plugins/datasource/graphite/FunctionEditor.tsx b/public/app/plugins/datasource/graphite/FunctionEditor.tsx index c850b6efacf..b4450a58fa8 100644 --- a/public/app/plugins/datasource/graphite/FunctionEditor.tsx +++ b/public/app/plugins/datasource/graphite/FunctionEditor.tsx @@ -13,8 +13,8 @@ const FunctionDescription = React.lazy(async () => { // @ts-ignore const { default: rst2html } = await import(/* webpackChunkName: "rst2html" */ 'rst2html'); return { - default: (props: { description: string }) => ( -
+ default: (props: { description?: string }) => ( +
), }; }); @@ -77,7 +77,7 @@ class FunctionEditor extends React.PureComponent { return ( <> - {this.triggerRef && ( + {this.triggerRef.current && ( void; } -const FunctionHelpButton = (props: { description: string; name: string; onDescriptionShow: () => void }) => { +const FunctionHelpButton = (props: { description?: string; name: string; onDescriptionShow: () => void }) => { if (props.description) { return ; } diff --git a/public/app/plugins/datasource/graphite/datasource.ts b/public/app/plugins/datasource/graphite/datasource.ts index 7a6af8474c3..99f1dbb1391 100644 --- a/public/app/plugins/datasource/graphite/datasource.ts +++ b/public/app/plugins/datasource/graphite/datasource.ts @@ -8,6 +8,7 @@ import { QueryResultMetaStat, ScopedVars, toDataFrame, + TimeRange, } from '@grafana/data'; import { isVersionGtOrEq, SemVersion } from 'app/core/utils/version'; import gfunc from './gfunc'; @@ -29,7 +30,7 @@ export class GraphiteDatasource extends DataSourceApi = null; + funcDefsPromise: Promise | null = null; _seriesRefLetters: string; /** @ngInject */ @@ -64,8 +65,8 @@ export class GraphiteDatasource extends DataSourceApi): Promise { const graphOptions = { - from: this.translateTime(options.rangeRaw.from, false, options.timezone), - until: this.translateTime(options.rangeRaw.to, true, options.timezone), + from: this.translateTime(options.range.raw.from, false, options.timezone), + until: this.translateTime(options.range.raw.to, true, options.timezone), targets: options.targets, format: (options as any).format, cacheTimeout: options.cacheTimeout || this.cacheTimeout, @@ -199,7 +200,7 @@ export class GraphiteDatasource extends DataSourceApi { + return this.events({ range: options.range, tags: tags }).then((results: any) => { const list = []; for (let i = 0; i < results.data.length; i++) { const e = results.data[i]; @@ -269,7 +270,7 @@ export class GraphiteDatasource extends DataSourceApi { const query = { panelId: 3, dashboardId: 5, - rangeRaw: { from: 'now-1h', to: 'now' }, + range: { raw: { from: 'now-1h', to: 'now' } }, targets: [{ target: 'prod1.count' }, { target: 'prod2.count' }], maxDataPoints: 500, }; @@ -179,8 +179,8 @@ describe('graphiteDatasource', () => { range: { from: dateTime(1432288354), to: dateTime(1432288401), + raw: { from: 'now-24h', to: 'now' }, }, - rangeRaw: { from: 'now-24h', to: 'now' }, }; describe('and tags are returned as string', () => { diff --git a/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx b/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx index 786ea09fd0e..550dea0016b 100644 --- a/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx +++ b/public/app/plugins/datasource/influxdb/components/InfluxLogsQueryField.tsx @@ -13,15 +13,15 @@ export interface Props extends ExploreQueryFieldProps { templateSrv: TemplateSrv = new TemplateSrv(); state: State = { measurements: [], - measurement: (null as unknown) as string, - field: (null as unknown) as string, - error: (null as unknown) as string, + measurement: null, + field: null, + error: null, }; async componentDidMount() { @@ -115,10 +115,10 @@ export class InfluxLogsQueryField extends React.PureComponent { ...query, resultFormat: 'table', groupBy: [], - select: [[{ type: 'field', params: [field] }]], + select: [[{ type: 'field', params: [field ?? ''] }]], tags: pairs, limit: '1000', - measurement, + measurement: measurement ?? '', }, this.templateSrv ); @@ -143,7 +143,7 @@ export class InfluxLogsQueryField extends React.PureComponent { {cascadeText} diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index 6d183769005..1d0c3a38756 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -34,8 +34,9 @@ export default class InfluxDatasource extends DataSourceWithBackend) { super(instanceSettings); + this.type = 'influxdb'; - this.urls = _.map(instanceSettings.url.split(','), url => { + this.urls = (instanceSettings.url ?? '').split(',').map(url => { return url.trim(); }); @@ -67,7 +68,7 @@ export default class InfluxDatasource extends DataSourceWithBackend { return { ...query, - query: getTemplateSrv().replace(query.query, scopedVars), // The raw query text + query: getTemplateSrv().replace(query.query ?? '', scopedVars), // The raw query text }; } @@ -79,7 +80,7 @@ export default class InfluxDatasource extends DataSourceWithBackend { if (current !== '') { acc += ';' + current; @@ -109,7 +109,8 @@ export default class InfluxDatasource extends DataSourceWithBackend 0) { - timeFilter += ' AND ' + queryModel.renderAdhocFilters(adhocFilters); + const tmpQuery = new InfluxQueryModel({ refId: 'A' }, templateSrv, scopedVars); + timeFilter += ' AND ' + tmpQuery.renderAdhocFilters(adhocFilters); } // replace grafana variables @@ -175,7 +176,7 @@ export default class InfluxDatasource extends DataSourceWithBackend { if (!data || !data.results || !data.results[0]) { @@ -233,7 +234,7 @@ export default class InfluxDatasource extends DataSourceWithBackend { const expandedTag = { ...tag, - value: templateSrv.replace(tag.value, null, 'regex'), + value: templateSrv.replace(tag.value, undefined, 'regex'), }; return expandedTag; }); @@ -246,7 +247,7 @@ export default class InfluxDatasource extends DataSourceWithBackend { return this.responseParser.parse(query, resp); @@ -292,7 +293,7 @@ export default class InfluxDatasource extends DataSourceWithBackend 0) { query += ' WHERE ' + whereConditions.join(' '); } } + if (type === 'MEASUREMENTS') { query += ' LIMIT 100'; //Solve issue #2524 by limiting the number of measurements returned //LIMIT must be after WITH MEASUREMENT and WHERE clauses //This also could be used for TAG KEYS and TAG VALUES, if desired } + return query; } } diff --git a/public/app/plugins/datasource/influxdb/query_ctrl.ts b/public/app/plugins/datasource/influxdb/query_ctrl.ts index edfabdb9d09..9cffb74b5a5 100644 --- a/public/app/plugins/datasource/influxdb/query_ctrl.ts +++ b/public/app/plugins/datasource/influxdb/query_ctrl.ts @@ -104,7 +104,7 @@ export class InfluxQueryCtrl extends QueryCtrl { memo.push(menu); return memo; }, - [] + [] as any ); } @@ -384,7 +384,7 @@ export class InfluxQueryCtrl extends QueryCtrl { rebuildTargetTagConditions() { const tags: any[] = []; let tagIndex = 0; - let tagOperator = ''; + let tagOperator: string | null = ''; _.each(this.tagSegments, (segment2, index) => { if (segment2.type === 'key') { @@ -411,7 +411,7 @@ export class InfluxQueryCtrl extends QueryCtrl { this.panelCtrl.refresh(); } - getTagValueOperator(tagValue: string, tagOperator: string): string { + getTagValueOperator(tagValue: string, tagOperator: string): string | null { if (tagOperator !== '=~' && tagOperator !== '!~' && /^\/.*\/$/.test(tagValue)) { return '=~'; } else if ((tagOperator === '=~' || tagOperator === '!~') && /^(?!\/.*\/$)/.test(tagValue)) { diff --git a/public/app/plugins/datasource/jaeger/QueryField.tsx b/public/app/plugins/datasource/jaeger/QueryField.tsx index 47824c4456d..dd8fefa6fa6 100644 --- a/public/app/plugins/datasource/jaeger/QueryField.tsx +++ b/public/app/plugins/datasource/jaeger/QueryField.tsx @@ -124,7 +124,7 @@ export class JaegerQueryField extends React.PureComponent { this.setState(state => { // Place new traces into the correct service/operation sub-tree const serviceOptions = state.serviceOptions.map(serviceOption => { - if (serviceOption.value === service) { + if (serviceOption.value === service && serviceOption.children) { const operationOptions = serviceOption.children.map(operationOption => { if (operationOption.value === operationValue) { return { diff --git a/public/app/plugins/datasource/jaeger/datasource.ts b/public/app/plugins/datasource/jaeger/datasource.ts index 701a2a8e8ef..75adb45a932 100644 --- a/public/app/plugins/datasource/jaeger/datasource.ts +++ b/public/app/plugins/datasource/jaeger/datasource.ts @@ -102,7 +102,7 @@ export class JaegerDatasource extends DataSourceApi { function getTime(date: string | DateTime, roundUp: boolean) { if (typeof date === 'string') { - date = dateMath.parse(date, roundUp); + date = dateMath.parse(date, roundUp)!; } return date.valueOf() * 1000; } diff --git a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx index dba7c85c792..73c9162f129 100644 --- a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx @@ -40,7 +40,6 @@ export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEdito onChange={(query: LokiQuery) => onChange(query.expr)} onRunQuery={() => {}} history={[]} - data={null} onLoadOptions={setActiveOption} onLabelsRefresh={refreshLabels} absoluteRange={absolute} diff --git a/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx index 8ddda562862..7dafc37b38d 100644 --- a/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/LokiExploreQueryEditor.tsx @@ -15,7 +15,7 @@ export function LokiExploreQueryEditor(props: Props) { const { query, data, datasource, exploreMode, history, onChange, onRunQuery } = props; let absolute: AbsoluteTimeRange; - if (data && !_.isEmpty(data.request)) { + if (data && data.request) { const { range } = data.request; absolute = { diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx index 7782269f853..d46425b520b 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx @@ -27,11 +27,11 @@ export class LokiQueryEditor extends PureComponent { // Query target properties that are fully controlled inputs this.state = { // Fully controlled text inputs - legendFormat: query.legendFormat, + legendFormat: query.legendFormat ?? '', }; } - calcAbsoluteRange = (data: PanelData): AbsoluteTimeRange => { + calcAbsoluteRange = (data: PanelData | undefined): AbsoluteTimeRange => { if (data && data.request) { const { range } = data.request; return { diff --git a/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx b/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx index f0e9518bff8..dfcfd1d00ca 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryFieldForm.tsx @@ -63,7 +63,7 @@ function willApplySuggestion(suggestion: string, { typeaheadContext, typeaheadTe export interface LokiQueryFieldFormProps extends ExploreQueryFieldProps { history: LokiHistoryItem[]; - syntax: Grammar; + syntax: Grammar | null; logLabelOptions: CascaderOption[]; syntaxLoaded: boolean; absoluteRange: AbsoluteTimeRange; diff --git a/public/app/plugins/datasource/loki/components/useLokiLabels.ts b/public/app/plugins/datasource/loki/components/useLokiLabels.ts index 74ff17a373d..f5f91203c29 100644 --- a/public/app/plugins/datasource/loki/components/useLokiLabels.ts +++ b/public/app/plugins/datasource/loki/components/useLokiLabels.ts @@ -21,7 +21,7 @@ export const useLokiLabels = ( const mounted = useRefMounted(); // State - const [logLabelOptions, setLogLabelOptions] = useState([]); + const [logLabelOptions, setLogLabelOptions] = useState([]); const [shouldTryRefreshLabels, setRefreshLabels] = useState(false); /** * Holds information about currently selected option from rc-cascader to perform effect @@ -56,7 +56,7 @@ export const useLokiLabels = ( if (languageProviderInitialised) { const targetOption = activeOption[activeOption.length - 1]; if (targetOption) { - const nextOptions = logLabelOptions.map(option => { + const nextOptions = logLabelOptions.map((option: any) => { if (option.value === targetOption.value) { return { ...option, diff --git a/public/app/plugins/datasource/loki/components/useLokiSyntaxAndLabels.ts b/public/app/plugins/datasource/loki/components/useLokiSyntaxAndLabels.ts index b0faca472d6..19b66e22705 100644 --- a/public/app/plugins/datasource/loki/components/useLokiSyntaxAndLabels.ts +++ b/public/app/plugins/datasource/loki/components/useLokiSyntaxAndLabels.ts @@ -39,7 +39,7 @@ const useInitLanguageProvider = (languageProvider: LokiLanguageProvider, absolut */ const useLokiSyntax = (languageProvider: LokiLanguageProvider, languageProviderInitialized: boolean) => { // State - const [syntax, setSyntax] = useState(null); + const [syntax, setSyntax] = useState(null); // Effects useEffect(() => { diff --git a/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx b/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx index 02c4e418f4a..5bc0c9818e0 100644 --- a/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx +++ b/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx @@ -18,6 +18,7 @@ describe('DerivedFields', () => { it('renders correctly when no fields', async () => { let wrapper: any; + //@ts-ignore await act(async () => { wrapper = await mount( {}} />); }); @@ -42,6 +43,7 @@ describe('DerivedFields', () => { it('adds new field', async () => { const onChangeMock = jest.fn(); let wrapper: any; + //@ts-ignore await act(async () => { wrapper = await mount(); }); @@ -53,6 +55,7 @@ describe('DerivedFields', () => { it('removes field', async () => { const onChangeMock = jest.fn(); let wrapper: any; + //@ts-ignore await act(async () => { wrapper = await mount(); }); diff --git a/public/app/plugins/datasource/loki/mocks.ts b/public/app/plugins/datasource/loki/mocks.ts index 8b75dfee9b1..e91830e89b2 100644 --- a/public/app/plugins/datasource/loki/mocks.ts +++ b/public/app/plugins/datasource/loki/mocks.ts @@ -31,7 +31,7 @@ export function makeMockLokiDatasource(labelsAndValues: Labels, series?: SeriesF const seriesMatch = url.match(lokiSeriesEndpointRegex); if (labelsMatch) { return labelsAndValues[labelsMatch[1]] || []; - } else if (seriesMatch) { + } else if (seriesMatch && series && params) { return series[params.match] || []; } else { throw new Error(`Unexpected url error, ${url}`); diff --git a/public/app/plugins/datasource/loki/result_transformer.test.ts b/public/app/plugins/datasource/loki/result_transformer.test.ts index 45a529321fa..a72083228ba 100644 --- a/public/app/plugins/datasource/loki/result_transformer.test.ts +++ b/public/app/plugins/datasource/loki/result_transformer.test.ts @@ -142,20 +142,20 @@ describe('enhanceDataFrame', () => { }); expect(df.fields.length).toBe(3); const fc = new FieldCache(df); - expect(fc.getFieldByName('trace1').values.toArray()).toEqual([null, '1234', null]); - expect(fc.getFieldByName('trace1').config.links[0]).toEqual({ + expect(fc.getFieldByName('trace1')!.values.toArray()).toEqual([null, '1234', null]); + expect(fc.getFieldByName('trace1')!.config.links![0]).toEqual({ url: 'http://localhost/${__value.raw}', title: '', }); - expect(fc.getFieldByName('trace2').values.toArray()).toEqual([null, null, 'foo']); - expect(fc.getFieldByName('trace2').config.links.length).toBe(2); - expect(fc.getFieldByName('trace2').config.links[0]).toEqual({ + expect(fc.getFieldByName('trace2')!.values.toArray()).toEqual([null, null, 'foo']); + expect(fc.getFieldByName('trace2')!.config.links!.length).toBe(2); + expect(fc.getFieldByName('trace2')!.config.links![0]).toEqual({ title: '', internal: { datasourceUid: 'uid', query: { query: 'test' } }, url: '', }); - expect(fc.getFieldByName('trace2').config.links[1]).toEqual({ + expect(fc.getFieldByName('trace2')!.config.links![1]).toEqual({ title: '', internal: { datasourceUid: 'uid2', query: { query: 'test' } }, url: '', diff --git a/public/app/plugins/datasource/loki/types.ts b/public/app/plugins/datasource/loki/types.ts index ccf611b6ca8..6fb6587e54d 100644 --- a/public/app/plugins/datasource/loki/types.ts +++ b/public/app/plugins/datasource/loki/types.ts @@ -91,7 +91,7 @@ export interface LokiTailResponse { dropped_entries?: Array<{ labels: Record; timestamp: string; - }>; + }> | null; } export type LokiResult = LokiVectorResult | LokiMatrixResult | LokiStreamResult; diff --git a/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts b/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts index 2ad6718c7ab..d5b520e798a 100644 --- a/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts +++ b/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts @@ -4,7 +4,7 @@ import { TemplateSrv } from 'app/features/templating/template_srv'; describe('PostgresQuery', () => { // @ts-ignore const templateSrv: TemplateSrv = { - replace: jest.fn(text => text), + replace: jest.fn(text => text) as any, }; describe('When initializing', () => { diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts index e490818ed4f..ee08172cd1b 100644 --- a/public/app/plugins/datasource/prometheus/datasource.test.ts +++ b/public/app/plugins/datasource/prometheus/datasource.test.ts @@ -1295,7 +1295,7 @@ describe('PrometheusDatasource', () => { encodeURIComponent('rate(test[$__interval])') + '&start=60&end=420&step=10'; - templateSrv.replace = jest.fn(str => str); + templateSrv.replace = jest.fn(str => str) as any; datasourceRequestMock.mockImplementation(() => Promise.resolve(response)); ds.query(query as any); const res = datasourceRequestMock.mock.calls[0][0]; @@ -1336,7 +1336,7 @@ describe('PrometheusDatasource', () => { encodeURIComponent('rate(test[$__interval])') + '&start=60&end=420&step=10'; datasourceRequestMock.mockImplementation(() => Promise.resolve(response)); - templateSrv.replace = jest.fn(str => str); + templateSrv.replace = jest.fn(str => str) as any; ds.query(query as any); const res = datasourceRequestMock.mock.calls[0][0]; expect(res.method).toBe('GET'); @@ -1377,7 +1377,7 @@ describe('PrometheusDatasource', () => { encodeURIComponent('rate(test[$__interval])') + '&start=0&end=400&step=100'; datasourceRequestMock.mockImplementation(() => Promise.resolve(response)); - templateSrv.replace = jest.fn(str => str); + templateSrv.replace = jest.fn(str => str) as any; ds.query(query as any); const res = datasourceRequestMock.mock.calls[0][0]; expect(res.method).toBe('GET'); @@ -1423,7 +1423,7 @@ describe('PrometheusDatasource', () => { encodeURIComponent('rate(test[$__interval])') + '&start=50&end=400&step=50'; - templateSrv.replace = jest.fn(str => str); + templateSrv.replace = jest.fn(str => str) as any; datasourceRequestMock.mockImplementation(() => Promise.resolve(response)); ds.query(query as any); const res = datasourceRequestMock.mock.calls[0][0]; @@ -1522,7 +1522,7 @@ describe('PrometheusDatasource', () => { '&step=' + step; datasourceRequestMock.mockImplementation(() => Promise.resolve(response)); - templateSrv.replace = jest.fn(str => str); + templateSrv.replace = jest.fn(str => str) as any; ds.query(query as any); const res = datasourceRequestMock.mock.calls[0][0]; expect(res.method).toBe('GET'); @@ -1572,7 +1572,7 @@ describe('PrometheusDatasource', () => { query.targets[0].expr )}&start=0&end=3600&step=60`; - templateSrv.replace = jest.fn(str => str); + templateSrv.replace = jest.fn(str => str) as any; datasourceRequestMock.mockImplementation(() => Promise.resolve(response)); ds.query(query as any); const res = datasourceRequestMock.mock.calls[0][0]; diff --git a/scripts/ci-frontend-metrics.sh b/scripts/ci-frontend-metrics.sh index 571587aef31..f7bfd5e376e 100755 --- a/scripts/ci-frontend-metrics.sh +++ b/scripts/ci-frontend-metrics.sh @@ -2,7 +2,7 @@ echo -e "Collecting code stats (typescript errors & more)" -ERROR_COUNT_LIMIT=600 +ERROR_COUNT_LIMIT=398 DIRECTIVES_LIMIT=172 CONTROLLERS_LIMIT=139