WIP Chore: reduce strict errors (#40462)

* Chore: reduce strict error in ngReact

* Chore: reduce strict errors for ShareModal

* Chore: reduce strict errors in VersioHistory

* Chore: reduce strict error in ExpressionDatasource

* Chore: reduce strict error in DashboardWatcher

* Chore: reduce strict error in PluginPage

* Chore: reduce strict errors for guard

* Chore: update threshold

* Chore: reduce strict errors in Graph

* Chore: reduce threshold

* Apply suggestions from code review

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>

* Chore: reduce strict errors in TimeSeries

* Chore: reduce threshold

* Chore: reduce strict errors in polyfill

* Chore: reduce threshold

* Chore: update after PR comments

* Update public/app/features/plugins/PluginPage.tsx

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>

* Update public/app/features/plugins/PluginPage.tsx

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>

* Chore: changes after PR comments

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
This commit is contained in:
Hugo Häggmark 2021-10-15 08:57:55 +02:00 committed by GitHub
parent 4fc86594c0
commit 09bb890092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 98 additions and 92 deletions

View File

@ -5,7 +5,15 @@ import {
identityOverrideProcessor,
} from '@grafana/data';
import React from 'react';
import { graphFieldOptions, HorizontalGroup, IconButton, Input, RadioButtonGroup, Tooltip } from '../..';
import {
GraphFieldConfig,
graphFieldOptions,
HorizontalGroup,
IconButton,
Input,
RadioButtonGroup,
Tooltip,
} from '../..';
import { StackingConfig, StackingMode } from '@grafana/schema';
export const StackingEditor: React.FC<FieldOverrideEditorProps<StackingConfig, any>> = ({
@ -49,7 +57,7 @@ export const StackingEditor: React.FC<FieldOverrideEditorProps<StackingConfig, a
};
export function addStackingConfig(
builder: FieldConfigEditorBuilder<{ stacking: StackingConfig }>,
builder: FieldConfigEditorBuilder<GraphFieldConfig>,
defaultConfig?: StackingConfig,
category = ['Graph styles']
) {

View File

@ -10,16 +10,16 @@
// - reactDirective (factory for creating specific directives that correspond to reactComponent directives)
import { kebabCase } from 'lodash';
import React from 'react';
import React, { ComponentType } from 'react';
import ReactDOM from 'react-dom';
import angular, { auto } from 'angular';
// get a react component from name (components can be an angular injectable e.g. value, factory or
// available on window
function getReactComponent(name: string, $injector: auto.IInjectorService) {
function getReactComponent(name: string | Function, $injector: auto.IInjectorService): ComponentType {
// if name is a function assume it is component and return it
if (angular.isFunction(name)) {
return name;
return (name as unknown) as ComponentType;
}
// a React component name must be specified
@ -46,7 +46,7 @@ function getReactComponent(name: string, $injector: auto.IInjectorService) {
throw Error('Cannot find react component ' + name);
}
return reactComponent;
return (reactComponent as unknown) as ComponentType;
}
// wraps a function with scope.$apply, if already applied just return

View File

@ -1,9 +1,9 @@
import React, { FormEvent, PureComponent } from 'react';
import { ClipboardButton, Field, Modal, RadioButtonGroup, Switch, TextArea } from '@grafana/ui';
import { AppEvents, SelectableValue } from '@grafana/data';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { appEvents } from 'app/core/core';
import { buildIframeHtml } from './utils';
import { ShareModalTabProps } from './types';
const themeOptions: Array<SelectableValue<string>> = [
{ label: 'Current', value: 'current' },
@ -11,10 +11,7 @@ const themeOptions: Array<SelectableValue<string>> = [
{ label: 'Light', value: 'light' },
];
interface Props {
dashboard: DashboardModel;
panel?: PanelModel;
}
interface Props extends ShareModalTabProps {}
interface State {
useCurrentTimeRange: boolean;

View File

@ -2,18 +2,14 @@ import React, { PureComponent } from 'react';
import { saveAs } from 'file-saver';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { Button, Field, Modal, Switch } from '@grafana/ui';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal';
import { appEvents } from 'app/core/core';
import { ShowModalReactEvent } from 'app/types/events';
import { ViewJsonModal } from './ViewJsonModal';
import { config } from '@grafana/runtime';
import { ShareModalTabProps } from './types';
interface Props {
dashboard: DashboardModel;
panel?: PanelModel;
onDismiss(): void;
}
interface Props extends ShareModalTabProps {}
interface State {
shareExternally: boolean;
@ -124,7 +120,7 @@ export class ShareExport extends PureComponent<Props, State> {
})
);
this.props.onDismiss();
this.props.onDismiss?.();
};
render() {

View File

@ -1,10 +1,8 @@
import React from 'react';
import { PanelModel } from 'app/features/dashboard/state';
import { AddLibraryPanelContents } from 'app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal';
import { ShareModalTabProps } from './types';
interface Props {
onDismiss?: () => void;
panel?: PanelModel;
interface Props extends ShareModalTabProps {
initialFolderId?: number;
}

View File

@ -2,10 +2,11 @@ import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import { setTemplateSrv } from '@grafana/runtime';
import config from 'app/core/config';
import { ShareLink, Props, State } from './ShareLink';
import { Props, ShareLink, State } from './ShareLink';
import { initTemplateSrv } from '../../../../../test/helpers/initTemplateSrv';
import { variableAdapters } from '../../../variables/adapters';
import { createQueryVariableAdapter } from '../../../variables/query/adapter';
import { PanelModel } from '../../state';
jest.mock('app/features/dashboard/services/TimeSrv', () => ({
getTimeSrv: () => ({
@ -108,7 +109,7 @@ describe('ShareModal', () => {
},
};
ctx.mount({
panel: { id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } },
panel: new PanelModel({ id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } }),
});
});
@ -121,7 +122,7 @@ describe('ShareModal', () => {
it('should generate render url', async () => {
mockLocationHref('http://dashboards.grafana.com/d/abcdefghi/my-dash');
ctx.mount({
panel: { id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } },
panel: new PanelModel({ id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } }),
});
await ctx.wrapper?.instance().buildUrl();
@ -134,7 +135,7 @@ describe('ShareModal', () => {
it('should generate render url for scripted dashboard', async () => {
mockLocationHref('http://dashboards.grafana.com/dashboard/script/my-dash.js');
ctx.mount({
panel: { id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } },
panel: new PanelModel({ id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } }),
});
await ctx.wrapper?.instance().buildUrl();
@ -166,7 +167,7 @@ describe('ShareModal', () => {
it('should remove editPanel from image url when is first param in querystring', async () => {
mockLocationHref('http://server/#!/test?editPanel=1');
ctx.mount({
panel: { id: 1, options: {}, fieldConfig: { defaults: {}, overrides: [] } },
panel: new PanelModel({ id: 1, options: {}, fieldConfig: { defaults: {}, overrides: [] } }),
});
await ctx.wrapper?.instance().buildUrl();

View File

@ -1,11 +1,11 @@
import React, { PureComponent } from 'react';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { Field, RadioButtonGroup, Switch, ClipboardButton, Icon, Input, FieldSet, Alert } from '@grafana/ui';
import { SelectableValue, PanelModel, AppEvents } from '@grafana/data';
import { DashboardModel } from 'app/features/dashboard/state';
import { Alert, ClipboardButton, Field, FieldSet, Icon, Input, RadioButtonGroup, Switch } from '@grafana/ui';
import { AppEvents, SelectableValue } from '@grafana/data';
import { buildImageUrl, buildShareUrl } from './utils';
import { appEvents } from 'app/core/core';
import config from 'app/core/config';
import { ShareModalTabProps } from './types';
const themeOptions: Array<SelectableValue<string>> = [
{ label: 'Current', value: 'current' },
@ -13,10 +13,7 @@ const themeOptions: Array<SelectableValue<string>> = [
{ label: 'Light', value: 'light' },
];
export interface Props {
dashboard: DashboardModel;
panel?: PanelModel;
}
export interface Props extends ShareModalTabProps {}
export interface State {
useCurrentTimeRange: boolean;

View File

@ -1,11 +1,12 @@
import React, { PureComponent } from 'react';
import { Button, ClipboardButton, Icon, Spinner, Select, Input, LinkButton, Field, Modal } from '@grafana/ui';
import { Button, ClipboardButton, Field, Icon, Input, LinkButton, Modal, Select, Spinner } from '@grafana/ui';
import { AppEvents, SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { appEvents } from 'app/core/core';
import { VariableRefresh } from '../../../variables/types';
import { ShareModalTabProps } from './types';
const snapshotApiUrl = '/api/snapshots';
@ -16,11 +17,7 @@ const expireOptions: Array<SelectableValue<number>> = [
{ label: '7 Days', value: 60 * 60 * 24 * 7 },
];
interface Props {
dashboard: DashboardModel;
panel?: PanelModel;
onDismiss(): void;
}
interface Props extends ShareModalTabProps {}
interface State {
isLoading: boolean;

View File

@ -1,6 +1,5 @@
import React from 'react';
import { PanelModel } from '@grafana/data';
import { DashboardModel, PanelModel as InternalPanelModel } from 'app/features/dashboard/state';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
export interface ShareModalTabProps {
dashboard: DashboardModel;
@ -8,13 +7,8 @@ export interface ShareModalTabProps {
onDismiss?(): void;
}
type ShareModalTabPropsWithInternalModel = ShareModalTabProps & { panel?: InternalPanelModel };
export type ShareModalTab =
| React.ComponentType<ShareModalTabProps>
| React.ComponentType<ShareModalTabPropsWithInternalModel>;
export interface ShareModalTabModel {
label: string;
value: string;
component: ShareModalTab;
component: React.ComponentType<ShareModalTabProps>;
}

View File

@ -1,4 +1,4 @@
import { getDiffText, getDiffOperationText, jsonDiff, Diff } from './utils';
import { Diff, getDiffOperationText, getDiffText, jsonDiff } from './utils';
describe('getDiffOperationText', () => {
const cases = [
@ -13,9 +13,13 @@ describe('getDiffOperationText', () => {
});
});
type DiffTextCase = [Partial<Diff>, string];
describe('getDiffText', () => {
const addEmptyArray = [{ op: 'add', value: [], path: ['annotations', 'list'], startLineNumber: 24 }, 'added list'];
const addArrayNumericProp = [
const addEmptyArray: DiffTextCase = [
{ op: 'add', value: [], path: ['annotations', 'list'], startLineNumber: 24 },
'added list',
];
const addArrayNumericProp: DiffTextCase = [
{
op: 'add',
value: ['tag'],
@ -23,7 +27,7 @@ describe('getDiffText', () => {
},
'added item 3',
];
const addArrayProp = [
const addArrayProp: DiffTextCase = [
{
op: 'add',
value: [{ name: 'dummy target 1' }, { name: 'dummy target 2' }],
@ -31,7 +35,7 @@ describe('getDiffText', () => {
},
'added 2 targets',
];
const addValueNumericProp = [
const addValueNumericProp: DiffTextCase = [
{
op: 'add',
value: 'foo',
@ -39,7 +43,7 @@ describe('getDiffText', () => {
},
'added item 3',
];
const addValueProp = [
const addValueProp: DiffTextCase = [
{
op: 'add',
value: 'foo',
@ -48,11 +52,11 @@ describe('getDiffText', () => {
'added targets',
];
const removeEmptyArray = [
const removeEmptyArray: DiffTextCase = [
{ op: 'remove', originalValue: [], path: ['annotations', 'list'], startLineNumber: 24 },
'deleted list',
];
const removeArrayNumericProp = [
const removeArrayNumericProp: DiffTextCase = [
{
op: 'remove',
originalValue: ['tag'],
@ -60,7 +64,7 @@ describe('getDiffText', () => {
},
'deleted item 3',
];
const removeArrayProp = [
const removeArrayProp: DiffTextCase = [
{
op: 'remove',
originalValue: [{ name: 'dummy target 1' }, { name: 'dummy target 2' }],
@ -68,7 +72,7 @@ describe('getDiffText', () => {
},
'deleted 2 targets',
];
const removeValueNumericProp = [
const removeValueNumericProp: DiffTextCase = [
{
op: 'remove',
originalValue: 'foo',
@ -76,7 +80,7 @@ describe('getDiffText', () => {
},
'deleted item 3',
];
const removeValueProp = [
const removeValueProp: DiffTextCase = [
{
op: 'remove',
originalValue: 'foo',
@ -84,7 +88,7 @@ describe('getDiffText', () => {
},
'deleted targets',
];
const replaceValueNumericProp = [
const replaceValueNumericProp: DiffTextCase = [
{
op: 'replace',
originalValue: 'foo',
@ -93,7 +97,7 @@ describe('getDiffText', () => {
},
'changed item 3',
];
const replaceValueProp = [
const replaceValueProp: DiffTextCase = [
{
op: 'replace',
originalValue: 'foo',
@ -120,8 +124,8 @@ describe('getDiffText', () => {
test.each(cases)(
'returns a semantic message based on the type of diff, the values and the location of the change',
(diff: Diff, expected: string) => {
expect(getDiffText(diff)).toBe(expected);
(diff: Partial<Diff>, expected: string) => {
expect(getDiffText((diff as unknown) as Diff)).toBe(expected);
}
);
});

View File

@ -1,7 +1,6 @@
import React, { PureComponent } from 'react';
import { SelectableValue, QueryEditorProps } from '@grafana/data';
import { DataSourceApi, QueryEditorProps, SelectableValue } from '@grafana/data';
import { InlineField, Select } from '@grafana/ui';
import { ExpressionDatasourceApi } from './ExpressionDatasource';
import { Resample } from './components/Resample';
import { Reduce } from './components/Reduce';
import { Math } from './components/Math';
@ -9,7 +8,7 @@ import { ClassicConditions } from './components/ClassicConditions';
import { getDefaults } from './utils/expressionTypes';
import { ExpressionQuery, ExpressionQueryType, gelTypes } from './types';
type Props = QueryEditorProps<ExpressionDatasourceApi, ExpressionQuery>;
type Props = QueryEditorProps<DataSourceApi<ExpressionQuery>, ExpressionQuery>;
const labelWidth = 14;
export class ExpressionQueryEditor extends PureComponent<Props> {

View File

@ -63,7 +63,7 @@ class DashboardWatcher {
};
this.leave();
if (uid) {
this.subscription = live.getStream(this.channel).subscribe(this.observer);
this.subscription = live.getStream<DashboardEvent>(this.channel).subscribe(this.observer);
}
this.uid = uid;
}

View File

@ -8,6 +8,7 @@ import {
GrafanaTheme2,
NavModel,
NavModelItem,
PanelPluginMeta,
PluginDependencies,
PluginInclude,
PluginIncludeType,
@ -17,10 +18,9 @@ import {
PluginSignatureType,
PluginType,
UrlQueryMap,
PanelPluginMeta,
} from '@grafana/data';
import { AppNotificationSeverity } from 'app/types';
import { Alert, LinkButton, PluginSignatureBadge, Tooltip, Badge, useStyles2, Icon } from '@grafana/ui';
import { Alert, Badge, Icon, LinkButton, PluginSignatureBadge, Tooltip, useStyles2 } from '@grafana/ui';
import Page from 'app/core/components/Page/Page';
import { getPluginSettings } from './PluginSettingsCache';
@ -490,22 +490,29 @@ export function getLoadingNav(): NavModel {
};
}
export function loadPlugin(pluginId: string): Promise<GrafanaPlugin> {
return getPluginSettings(pluginId).then((info) => {
if (info.type === PluginType.app) {
return importAppPlugin(info);
}
if (info.type === PluginType.datasource) {
return importDataSourcePlugin(info);
}
if (info.type === PluginType.panel) {
return importPanelPluginFromMeta(info as PanelPluginMeta);
}
if (info.type === PluginType.renderer) {
return Promise.resolve({ meta: info } as GrafanaPlugin);
}
return Promise.reject('Unknown Plugin type: ' + info.type);
});
export async function loadPlugin(pluginId: string): Promise<GrafanaPlugin> {
const info = await getPluginSettings(pluginId);
let result: GrafanaPlugin | undefined;
if (info.type === PluginType.app) {
result = await importAppPlugin(info);
}
if (info.type === PluginType.datasource) {
result = await importDataSourcePlugin(info);
}
if (info.type === PluginType.panel) {
const panelPlugin = await importPanelPluginFromMeta(info as PanelPluginMeta);
result = (panelPlugin as unknown) as GrafanaPlugin;
}
if (info.type === PluginType.renderer) {
result = { meta: info } as GrafanaPlugin;
}
if (!result) {
throw new Error('Unknown Plugin type: ' + info.type);
}
return result;
}
type PluginSignatureDetailsBadgeProps = {

View File

@ -8,7 +8,6 @@ import {
DataSourceApi,
DataSourceJsonData,
MetricFindValue,
QueryEditorProps,
StandardVariableQuery,
StandardVariableSupport,
VariableModel,
@ -86,7 +85,7 @@ interface DataSourceWithCustomVariableSupport<
> extends DataSourceApi<TQuery, TOptions> {
variables: {
getType(): VariableSupportType;
editor: ComponentType<QueryEditorProps<any, TQuery, TOptions, VariableQuery>>;
editor: VariableQueryEditorType;
query(request: DataQueryRequest<TQuery>): Observable<DataQueryResponse>;
};
}
@ -184,7 +183,7 @@ export function isQueryEditor<
>(
component: VariableQueryEditorType,
datasource: DataSourceApi<TQuery, TOptions>
): component is ComponentType<QueryEditorProps<DataSourceApi<TQuery, TOptions>, TQuery, TOptions, any>> {
): component is VariableQueryEditorType {
if (!component) {
return false;
}

View File

@ -9,7 +9,7 @@ import 'vendor/flot/jquery.flot.dashes';
import './jquery.flot.events';
import $ from 'jquery';
import { min as _min, max as _max, clone, find, isUndefined, map, toNumber, sortBy as _sortBy, flatten } from 'lodash';
import { clone, find, flatten, isUndefined, map, max as _max, min as _min, sortBy as _sortBy, toNumber } from 'lodash';
import { tickStep } from 'app/core/utils/ticks';
import { coreModule, updateLegendValues } from 'app/core/core';
import GraphTooltip from './graph_tooltip';
@ -37,6 +37,7 @@ import {
getTimeField,
getValueFormat,
hasLinks,
LegacyEventHandler,
LegacyGraphHoverClearEvent,
LegacyGraphHoverEvent,
LinkModelSupplier,
@ -67,7 +68,13 @@ class GraphElement {
timeRegionManager: TimeRegionManager;
declare legendElem: HTMLElement;
constructor(private scope: any, private elem: JQuery, private timeSrv: TimeSrv) {
constructor(
private scope: any,
private elem: JQuery & {
bind(eventType: string, handler: (eventObject: JQueryEventObject, ...args: any[]) => any): JQuery; // need to extend with Plot
},
private timeSrv: TimeSrv
) {
this.ctrl = scope.ctrl;
this.contextMenu = scope.ctrl.contextMenuCtrl;
this.dashboard = this.ctrl.dashboard;
@ -167,7 +174,7 @@ class GraphElement {
ReactDOM.unmountComponentAtNode(this.legendElem);
}
onGraphHoverClear(event: any, info: any) {
onGraphHoverClear(handler: LegacyEventHandler<any>) {
if (this.plot) {
this.tooltip.clear(this.plot);
}

View File

@ -8,9 +8,11 @@ window.matchMedia = (mediaQueryString) => {
let mql = oMatchMedia(mediaQueryString);
if (!mql.addEventListener) {
// @ts-ignore
mql.addEventListener = (type: string, listener: MqlListener) => {
mql.addListener(listener);
};
// @ts-ignore
mql.removeEventListener = (type: string, listener: MqlListener) => {
mql.removeListener(listener);
};

View File

@ -3,7 +3,7 @@ set -e
echo -e "Collecting code stats (typescript errors & more)"
ERROR_COUNT_LIMIT=39
ERROR_COUNT_LIMIT=24
ERROR_COUNT="$(./node_modules/.bin/tsc --project tsconfig.json --noEmit --strict true | grep -oP 'Found \K(\d+)')"
if [ "$ERROR_COUNT" -gt $ERROR_COUNT_LIMIT ]; then