Chore: Fix more strict typescript errors (#35514)

This commit is contained in:
kay delaney
2021-06-14 15:13:48 +01:00
committed by GitHub
parent 6ee2f1fe3e
commit 0f81703c35
18 changed files with 128 additions and 161 deletions

View File

@@ -76,7 +76,7 @@ export class DataSourcePlugin<
return this; return this;
} }
setQueryEditorHelp(QueryEditorHelp: ComponentType<QueryEditorHelpProps>) { setQueryEditorHelp(QueryEditorHelp: ComponentType<QueryEditorHelpProps<TQuery>>) {
this.components.QueryEditorHelp = QueryEditorHelp; this.components.QueryEditorHelp = QueryEditorHelp;
return this; return this;
} }
@@ -84,7 +84,7 @@ export class DataSourcePlugin<
/** /**
* @deprecated prefer using `setQueryEditorHelp` * @deprecated prefer using `setQueryEditorHelp`
*/ */
setExploreStartPage(ExploreStartPage: ComponentType<QueryEditorHelpProps>) { setExploreStartPage(ExploreStartPage: ComponentType<QueryEditorHelpProps<TQuery>>) {
return this.setQueryEditorHelp(ExploreStartPage); return this.setQueryEditorHelp(ExploreStartPage);
} }
@@ -149,7 +149,7 @@ export interface DataSourcePluginComponents<
ExploreQueryField?: ComponentType<ExploreQueryFieldProps<DSType, TQuery, TOptions>>; ExploreQueryField?: ComponentType<ExploreQueryFieldProps<DSType, TQuery, TOptions>>;
ExploreMetricsQueryField?: ComponentType<ExploreQueryFieldProps<DSType, TQuery, TOptions>>; ExploreMetricsQueryField?: ComponentType<ExploreQueryFieldProps<DSType, TQuery, TOptions>>;
ExploreLogsQueryField?: ComponentType<ExploreQueryFieldProps<DSType, TQuery, TOptions>>; ExploreLogsQueryField?: ComponentType<ExploreQueryFieldProps<DSType, TQuery, TOptions>>;
QueryEditorHelp?: ComponentType<QueryEditorHelpProps>; QueryEditorHelp?: ComponentType<QueryEditorHelpProps<TQuery>>;
ConfigEditor?: ComponentType<DataSourcePluginOptionsEditorProps<TOptions, TSecureOptions>>; ConfigEditor?: ComponentType<DataSourcePluginOptionsEditorProps<TOptions, TSecureOptions>>;
MetadataInspector?: ComponentType<MetadataInspectorProps<DSType, TQuery, TOptions>>; MetadataInspector?: ComponentType<MetadataInspectorProps<DSType, TQuery, TOptions>>;
} }
@@ -210,7 +210,7 @@ abstract class DataSourceApi<
/** /**
* Imports queries from a different datasource * Imports queries from a different datasource
*/ */
async importQueries?(queries: DataQuery[], originDataSource: DataSourceApi): Promise<TQuery[]>; async importQueries?(queries: DataQuery[], originDataSource: DataSourceApi<DataQuery>): Promise<TQuery[]>;
/** /**
* Returns configuration for importing queries from other data sources * Returns configuration for importing queries from other data sources
@@ -387,9 +387,9 @@ export interface ExploreQueryFieldProps<
exploreId?: any; exploreId?: any;
} }
export interface QueryEditorHelpProps { export interface QueryEditorHelpProps<TQuery extends DataQuery = DataQuery> {
datasource: DataSourceApi; datasource: DataSourceApi<TQuery>;
onClickExample: (query: DataQuery) => void; onClickExample: (query: TQuery) => void;
exploreId?: any; exploreId?: any;
} }

View File

@@ -15,7 +15,7 @@ import { TimeZoneGroup } from './TimeZonePicker/TimeZoneGroup';
import { formatUtcOffset } from './TimeZonePicker/TimeZoneOffset'; import { formatUtcOffset } from './TimeZonePicker/TimeZoneOffset';
export interface Props { export interface Props {
onChange: (timeZone: TimeZone | undefined) => void; onChange: (timeZone?: TimeZone) => void;
value?: TimeZone; value?: TimeZone;
width?: number; width?: number;
autoFocus?: boolean; autoFocus?: boolean;

View File

@@ -98,7 +98,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
this.setState({ theme: value }); this.setState({ theme: value });
}; };
onTimeZoneChanged = (timezone: string) => { onTimeZoneChanged = (timezone?: string) => {
if (!timezone) { if (!timezone) {
return; return;
} }
@@ -109,7 +109,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
this.setState({ homeDashboardId: dashboardId }); this.setState({ homeDashboardId: dashboardId });
}; };
getFullDashName = (dashboard: DashboardSearchHit) => { getFullDashName = (dashboard: SelectableValue<DashboardSearchHit>) => {
if (typeof dashboard.folderTitle === 'undefined' || dashboard.folderTitle === '') { if (typeof dashboard.folderTitle === 'undefined' || dashboard.folderTitle === '') {
return dashboard.title; return dashboard.title;
} }
@@ -148,7 +148,9 @@ export class SharedPreferences extends PureComponent<Props, State> {
value={dashboards.find((dashboard) => dashboard.id === homeDashboardId)} value={dashboards.find((dashboard) => dashboard.id === homeDashboardId)}
getOptionValue={(i) => i.id} getOptionValue={(i) => i.id}
getOptionLabel={this.getFullDashName} getOptionLabel={this.getFullDashName}
onChange={(dashboard: DashboardSearchHit) => this.onHomeDashboardChanged(dashboard.id)} onChange={(dashboard: SelectableValue<DashboardSearchHit>) =>
this.onHomeDashboardChanged(dashboard.id)
}
options={dashboards} options={dashboards}
placeholder="Choose default dashboard" placeholder="Choose default dashboard"
/> />

View File

@@ -1,5 +1,5 @@
export class Deferred<T = any> { export class Deferred<T = any> {
resolve?: (reason?: T | PromiseLike<T>) => void; resolve?: (reason: T | PromiseLike<T>) => void;
reject?: (reason?: any) => void; reject?: (reason?: any) => void;
promise: Promise<T>; promise: Promise<T>;

View File

@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { getNavModel } from 'app/core/selectors/navModel'; import { getNavModel } from 'app/core/selectors/navModel';
import config from 'app/core/config'; import config from 'app/core/config';
@@ -29,39 +29,17 @@ import { UserOrgs } from './UserOrgs';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
interface Props extends GrafanaRouteComponentProps<{ id: string }> { interface OwnProps extends GrafanaRouteComponentProps<{ id: string }> {
navModel: NavModel; navModel: NavModel;
user: UserDTO; user?: UserDTO;
orgs: UserOrg[]; orgs: UserOrg[];
sessions: UserSession[]; sessions: UserSession[];
ldapSyncInfo: SyncInfo; ldapSyncInfo?: SyncInfo;
isLoading: boolean; isLoading: boolean;
error: UserAdminError; error?: UserAdminError;
loadAdminUserPage: typeof loadAdminUserPage;
revokeSession: typeof revokeSession;
revokeAllSessions: typeof revokeAllSessions;
updateUser: typeof updateUser;
setUserPassword: typeof setUserPassword;
disableUser: typeof disableUser;
enableUser: typeof enableUser;
deleteUser: typeof deleteUser;
updateUserPermissions: typeof updateUserPermissions;
addOrgUser: typeof addOrgUser;
updateOrgUserRole: typeof updateOrgUserRole;
deleteOrgUser: typeof deleteOrgUser;
syncLdapUser: typeof syncLdapUser;
} }
interface State { export class UserAdminPage extends PureComponent<Props> {
// isLoading: boolean;
}
export class UserAdminPage extends PureComponent<Props, State> {
state = {
// isLoading: true,
};
async componentDidMount() { async componentDidMount() {
const { match, loadAdminUserPage } = this.props; const { match, loadAdminUserPage } = this.props;
loadAdminUserPage(parseInt(match.params.id, 10)); loadAdminUserPage(parseInt(match.params.id, 10));
@@ -73,7 +51,7 @@ export class UserAdminPage extends PureComponent<Props, State> {
onPasswordChange = (password: string) => { onPasswordChange = (password: string) => {
const { user, setUserPassword } = this.props; const { user, setUserPassword } = this.props;
setUserPassword(user.id, password); user && setUserPassword(user.id, password);
}; };
onUserDelete = (userId: number) => { onUserDelete = (userId: number) => {
@@ -90,42 +68,41 @@ export class UserAdminPage extends PureComponent<Props, State> {
onGrafanaAdminChange = (isGrafanaAdmin: boolean) => { onGrafanaAdminChange = (isGrafanaAdmin: boolean) => {
const { user, updateUserPermissions } = this.props; const { user, updateUserPermissions } = this.props;
updateUserPermissions(user.id, isGrafanaAdmin); user && updateUserPermissions(user.id, isGrafanaAdmin);
}; };
onOrgRemove = (orgId: number) => { onOrgRemove = (orgId: number) => {
const { user, deleteOrgUser } = this.props; const { user, deleteOrgUser } = this.props;
deleteOrgUser(user.id, orgId); user && deleteOrgUser(user.id, orgId);
}; };
onOrgRoleChange = (orgId: number, newRole: string) => { onOrgRoleChange = (orgId: number, newRole: string) => {
const { user, updateOrgUserRole } = this.props; const { user, updateOrgUserRole } = this.props;
updateOrgUserRole(user.id, orgId, newRole); user && updateOrgUserRole(user.id, orgId, newRole);
}; };
onOrgAdd = (orgId: number, role: string) => { onOrgAdd = (orgId: number, role: string) => {
const { user, addOrgUser } = this.props; const { user, addOrgUser } = this.props;
addOrgUser(user, orgId, role); user && addOrgUser(user, orgId, role);
}; };
onSessionRevoke = (tokenId: number) => { onSessionRevoke = (tokenId: number) => {
const { user, revokeSession } = this.props; const { user, revokeSession } = this.props;
revokeSession(tokenId, user.id); user && revokeSession(tokenId, user.id);
}; };
onAllSessionsRevoke = () => { onAllSessionsRevoke = () => {
const { user, revokeAllSessions } = this.props; const { user, revokeAllSessions } = this.props;
revokeAllSessions(user.id); user && revokeAllSessions(user.id);
}; };
onUserSync = () => { onUserSync = () => {
const { user, syncLdapUser } = this.props; const { user, syncLdapUser } = this.props;
syncLdapUser(user.id); user && syncLdapUser(user.id);
}; };
render() { render() {
const { navModel, user, orgs, sessions, ldapSyncInfo, isLoading } = this.props; const { navModel, user, orgs, sessions, ldapSyncInfo, isLoading } = this.props;
// const { isLoading } = this.state;
const isLDAPUser = user && user.isExternal && user.authLabels && user.authLabels.includes('LDAP'); const isLDAPUser = user && user.isExternal && user.authLabels && user.authLabels.includes('LDAP');
const canReadSessions = contextSrv.hasPermission(AccessControlAction.UsersAuthTokenList); const canReadSessions = contextSrv.hasPermission(AccessControlAction.UsersAuthTokenList);
const canReadLDAPStatus = contextSrv.hasPermission(AccessControlAction.LDAPStatusRead); const canReadLDAPStatus = contextSrv.hasPermission(AccessControlAction.LDAPStatusRead);
@@ -198,4 +175,6 @@ const mapDispatchToProps = {
syncLdapUser, syncLdapUser,
}; };
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(UserAdminPage)); const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = OwnProps & ConnectedProps<typeof connector>;
export default hot(module)(connector(UserAdminPage));

View File

@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { Alert, Button, LegacyForms } from '@grafana/ui'; import { Alert, Button, LegacyForms } from '@grafana/ui';
const { FormField } = LegacyForms; const { FormField } = LegacyForms;
@@ -29,19 +29,13 @@ import {
import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
interface Props extends GrafanaRouteComponentProps<{}, { username: string }> { interface OwnProps extends GrafanaRouteComponentProps<{}, { username: string }> {
navModel: NavModel; navModel: NavModel;
ldapConnectionInfo: LdapConnectionInfo; ldapConnectionInfo: LdapConnectionInfo;
ldapUser: LdapUser; ldapUser?: LdapUser;
ldapSyncInfo: SyncInfo; ldapSyncInfo?: SyncInfo;
ldapError: LdapError; ldapError?: LdapError;
userError?: LdapError; userError?: LdapError;
loadLdapState: typeof loadLdapState;
loadLdapSyncStatus: typeof loadLdapSyncStatus;
loadUserMapping: typeof loadUserMapping;
clearUserError: typeof clearUserError;
clearUserMappingInfo: typeof clearUserMappingInfo;
} }
interface State { interface State {
@@ -163,4 +157,7 @@ const mapDispatchToProps = {
clearUserMappingInfo, clearUserMappingInfo,
}; };
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(LdapPage)); const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = OwnProps & ConnectedProps<typeof connector>;
export default hot(module)(connector(LdapPage));

View File

@@ -17,15 +17,9 @@ import { LdapState, LdapUser, UserAdminState, UserDTO, UserListAdminState } from
const makeInitialLdapState = (): LdapState => ({ const makeInitialLdapState = (): LdapState => ({
connectionInfo: [], connectionInfo: [],
syncInfo: null,
user: null,
ldapError: null,
connectionError: null,
userError: null,
}); });
const makeInitialUserAdminState = (): UserAdminState => ({ const makeInitialUserAdminState = (): UserAdminState => ({
user: null,
sessions: [], sessions: [],
orgs: [], orgs: [],
isLoading: true, isLoading: true,
@@ -95,7 +89,7 @@ describe('LDAP page reducer', () => {
error: (null as unknown) as string, error: (null as unknown) as string,
}, },
], ],
ldapError: null, ldapError: undefined,
}); });
}); });
}); });
@@ -167,7 +161,7 @@ describe('LDAP page reducer', () => {
.thenStateShouldEqual({ .thenStateShouldEqual({
...makeInitialLdapState(), ...makeInitialLdapState(),
user: getTestUserMapping(), user: getTestUserMapping(),
userError: null, userError: undefined,
}); });
}); });
}); });
@@ -189,7 +183,7 @@ describe('LDAP page reducer', () => {
) )
.thenStateShouldEqual({ .thenStateShouldEqual({
...makeInitialLdapState(), ...makeInitialLdapState(),
user: null, user: undefined,
userError: { userError: {
title: 'User not found', title: 'User not found',
body: 'Cannot find user', body: 'Cannot find user',
@@ -208,7 +202,7 @@ describe('LDAP page reducer', () => {
.whenActionIsDispatched(clearUserMappingInfoAction()) .whenActionIsDispatched(clearUserMappingInfoAction())
.thenStateShouldEqual({ .thenStateShouldEqual({
...makeInitialLdapState(), ...makeInitialLdapState(),
user: null, user: undefined,
}); });
}); });
}); });

View File

@@ -15,10 +15,10 @@ import {
const initialLdapState: LdapState = { const initialLdapState: LdapState = {
connectionInfo: [], connectionInfo: [],
syncInfo: null, syncInfo: undefined,
user: null, user: undefined,
connectionError: null, connectionError: undefined,
userError: null, userError: undefined,
}; };
const ldapSlice = createSlice({ const ldapSlice = createSlice({
@@ -27,7 +27,7 @@ const ldapSlice = createSlice({
reducers: { reducers: {
ldapConnectionInfoLoadedAction: (state, action: PayloadAction<LdapConnectionInfo>): LdapState => ({ ldapConnectionInfoLoadedAction: (state, action: PayloadAction<LdapConnectionInfo>): LdapState => ({
...state, ...state,
ldapError: null, ldapError: undefined,
connectionInfo: action.payload, connectionInfo: action.payload,
}), }),
ldapFailedAction: (state, action: PayloadAction<LdapError>): LdapState => ({ ldapFailedAction: (state, action: PayloadAction<LdapError>): LdapState => ({
@@ -41,20 +41,20 @@ const ldapSlice = createSlice({
userMappingInfoLoadedAction: (state, action: PayloadAction<LdapUser>): LdapState => ({ userMappingInfoLoadedAction: (state, action: PayloadAction<LdapUser>): LdapState => ({
...state, ...state,
user: action.payload, user: action.payload,
userError: null, userError: undefined,
}), }),
userMappingInfoFailedAction: (state, action: PayloadAction<LdapError>): LdapState => ({ userMappingInfoFailedAction: (state, action: PayloadAction<LdapError>): LdapState => ({
...state, ...state,
user: null, user: undefined,
userError: action.payload, userError: action.payload,
}), }),
clearUserMappingInfoAction: (state, action: PayloadAction<undefined>): LdapState => ({ clearUserMappingInfoAction: (state, action: PayloadAction<undefined>): LdapState => ({
...state, ...state,
user: null, user: undefined,
}), }),
clearUserErrorAction: (state, action: PayloadAction<undefined>): LdapState => ({ clearUserErrorAction: (state, action: PayloadAction<undefined>): LdapState => ({
...state, ...state,
userError: null, userError: undefined,
}), }),
}, },
}); });
@@ -74,11 +74,11 @@ export const ldapReducer = ldapSlice.reducer;
// UserAdminPage // UserAdminPage
const initialUserAdminState: UserAdminState = { const initialUserAdminState: UserAdminState = {
user: null, user: undefined,
sessions: [], sessions: [],
orgs: [], orgs: [],
isLoading: true, isLoading: true,
error: null, error: undefined,
}; };
export const userAdminSlice = createSlice({ export const userAdminSlice = createSlice({

View File

@@ -1,6 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { Form } from '@grafana/ui'; import { Form } from '@grafana/ui';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
@@ -13,25 +12,9 @@ import {
} from './utils/notificationChannels'; } from './utils/notificationChannels';
import { getNavModel } from 'app/core/selectors/navModel'; import { getNavModel } from 'app/core/selectors/navModel';
import { createNotificationChannel, loadNotificationTypes, testNotificationChannel } from './state/actions'; import { createNotificationChannel, loadNotificationTypes, testNotificationChannel } from './state/actions';
import { NotificationChannelType, NotificationChannelDTO, StoreState } from '../../types'; import { NotificationChannelDTO, StoreState } from '../../types';
import { resetSecureField } from './state/reducers'; import { resetSecureField } from './state/reducers';
interface OwnProps {}
interface ConnectedProps {
navModel: NavModel;
notificationChannelTypes: NotificationChannelType[];
}
interface DispatchProps {
createNotificationChannel: typeof createNotificationChannel;
loadNotificationTypes: typeof loadNotificationTypes;
testNotificationChannel: typeof testNotificationChannel;
resetSecureField: typeof resetSecureField;
}
type Props = OwnProps & ConnectedProps & DispatchProps;
class NewNotificationChannelPage extends PureComponent<Props> { class NewNotificationChannelPage extends PureComponent<Props> {
componentDidMount() { componentDidMount() {
this.props.loadNotificationTypes(); this.props.loadNotificationTypes();
@@ -79,18 +62,18 @@ class NewNotificationChannelPage extends PureComponent<Props> {
} }
} }
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state) => { const mapStateToProps = (state: StoreState) => ({
return { navModel: getNavModel(state.navIndex, 'channels'),
navModel: getNavModel(state.navIndex, 'channels'), notificationChannelTypes: state.notificationChannel.notificationChannelTypes,
notificationChannelTypes: state.notificationChannel.notificationChannelTypes, });
};
};
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { const mapDispatchToProps = {
createNotificationChannel, createNotificationChannel,
loadNotificationTypes, loadNotificationTypes,
testNotificationChannel, testNotificationChannel,
resetSecureField, resetSecureField,
}; };
export default connect(mapStateToProps, mapDispatchToProps)(NewNotificationChannelPage); const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = ConnectedProps<typeof connector>;
export default connector(NewNotificationChannelPage);

View File

@@ -1,4 +1,4 @@
import React, { FC, ReactNode } from 'react'; import React, { ReactNode } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, useStyles2, useTheme2 } from '@grafana/ui'; import { IconButton, useStyles2, useTheme2 } from '@grafana/ui';
@@ -27,11 +27,11 @@ export interface DynamicTableProps<T = unknown> {
isExpandable?: boolean; isExpandable?: boolean;
onCollapse?: (id: DynamicTableItemProps<T>) => void; onCollapse?: (id: DynamicTableItemProps<T>) => void;
onExpand?: (id: DynamicTableItemProps<T>) => void; onExpand?: (id: DynamicTableItemProps<T>) => void;
renderExpandedContent?: (item: DynamicTableItemProps, index: number) => ReactNode; renderExpandedContent?: (item: DynamicTableItemProps<T>, index: number) => ReactNode;
testIdGenerator?: (item: DynamicTableItemProps<T>) => string; testIdGenerator?: (item: DynamicTableItemProps<T>) => string;
} }
export const DynamicTable: FC<DynamicTableProps> = ({ export const DynamicTable = <T extends object>({
cols, cols,
items, items,
isExpandable = false, isExpandable = false,
@@ -39,7 +39,7 @@ export const DynamicTable: FC<DynamicTableProps> = ({
onExpand, onExpand,
renderExpandedContent, renderExpandedContent,
testIdGenerator, testIdGenerator,
}) => { }: DynamicTableProps<T>) => {
const styles = useStyles2(getStyles(cols, isExpandable)); const styles = useStyles2(getStyles(cols, isExpandable));
const theme = useTheme2(); const theme = useTheme2();
const isMobile = useMedia(`(${theme.breakpoints.down('sm')})`); const isMobile = useMedia(`(${theme.breakpoints.down('sm')})`);
@@ -84,7 +84,7 @@ export const DynamicTable: FC<DynamicTableProps> = ({
); );
}; };
const getStyles = (cols: DynamicTableColumnProps[], isExpandable: boolean) => { const getStyles = <T extends unknown>(cols: Array<DynamicTableColumnProps<T>>, isExpandable: boolean) => {
const sizes = cols.map((col) => { const sizes = cols.map((col) => {
if (!col.size) { if (!col.size) {
return 'auto'; return 'auto';

View File

@@ -29,38 +29,38 @@ import { DashboardModel } from '../../dashboard/state/DashboardModel';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { PanelModel } from 'app/features/dashboard/state'; import { PanelModel } from 'app/features/dashboard/state';
interface Props { interface Props<TQuery extends DataQuery> {
data: PanelData; data: PanelData;
query: DataQuery; query: TQuery;
queries: DataQuery[]; queries: TQuery[];
id: string; id: string;
index: number; index: number;
dataSource: DataSourceInstanceSettings; dataSource: DataSourceInstanceSettings;
onChangeDataSource?: (dsSettings: DataSourceInstanceSettings) => void; onChangeDataSource?: (dsSettings: DataSourceInstanceSettings) => void;
renderHeaderExtras?: () => ReactNode; renderHeaderExtras?: () => ReactNode;
onAddQuery: (query: DataQuery) => void; onAddQuery: (query: TQuery) => void;
onRemoveQuery: (query: DataQuery) => void; onRemoveQuery: (query: TQuery) => void;
onChange: (query: DataQuery) => void; onChange: (query: TQuery) => void;
onRunQuery: () => void; onRunQuery: () => void;
visualization?: ReactNode; visualization?: ReactNode;
hideDisableQuery?: boolean; hideDisableQuery?: boolean;
} }
interface State { interface State<TQuery extends DataQuery> {
loadedDataSourceIdentifier?: string | null; loadedDataSourceIdentifier?: string | null;
datasource: DataSourceApi | null; datasource: DataSourceApi<TQuery> | null;
hasTextEditMode: boolean; hasTextEditMode: boolean;
data?: PanelData; data?: PanelData;
isOpen?: boolean; isOpen?: boolean;
showingHelp: boolean; showingHelp: boolean;
} }
export class QueryEditorRow extends PureComponent<Props, State> { export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Props<TQuery>, State<TQuery>> {
element: HTMLElement | null = null; element: HTMLElement | null = null;
angularScope: AngularQueryComponentScope | null = null; angularScope: AngularQueryComponentScope<TQuery> | null = null;
angularQueryEditor: AngularComponent | null = null; angularQueryEditor: AngularComponent | null = null;
state: State = { state: State<TQuery> = {
datasource: null, datasource: null,
hasTextEditMode: false, hasTextEditMode: false,
data: undefined, data: undefined,
@@ -78,7 +78,7 @@ export class QueryEditorRow extends PureComponent<Props, State> {
} }
} }
getAngularQueryComponentScope(): AngularQueryComponentScope { getAngularQueryComponentScope(): AngularQueryComponentScope<TQuery> {
const { query, queries } = this.props; const { query, queries } = this.props;
const { datasource } = this.state; const { datasource } = this.state;
const panel = new PanelModel({ targets: queries }); const panel = new PanelModel({ targets: queries });
@@ -129,13 +129,13 @@ export class QueryEditorRow extends PureComponent<Props, State> {
} }
this.setState({ this.setState({
datasource, datasource: (datasource as unknown) as DataSourceApi<TQuery>,
loadedDataSourceIdentifier: dataSourceIdentifier, loadedDataSourceIdentifier: dataSourceIdentifier,
hasTextEditMode: has(datasource, 'components.QueryCtrl.prototype.toggleEditorMode'), hasTextEditMode: has(datasource, 'components.QueryCtrl.prototype.toggleEditorMode'),
}); });
} }
componentDidUpdate(prevProps: Props) { componentDidUpdate(prevProps: Props<TQuery>) {
const { datasource, loadedDataSourceIdentifier } = this.state; const { datasource, loadedDataSourceIdentifier } = this.state;
const { data, query } = this.props; const { data, query } = this.props;
@@ -252,7 +252,7 @@ export class QueryEditorRow extends PureComponent<Props, State> {
})); }));
}; };
onClickExample = (query: DataQuery) => { onClickExample = (query: TQuery) => {
this.props.onChange({ this.props.onChange({
...query, ...query,
refId: this.props.query.refId, refId: this.props.query.refId,
@@ -371,7 +371,11 @@ export class QueryEditorRow extends PureComponent<Props, State> {
} }
} }
function notifyAngularQueryEditorsOfData(scope: AngularQueryComponentScope, data: PanelData, editor: AngularComponent) { function notifyAngularQueryEditorsOfData<TQuery extends DataQuery>(
scope: AngularQueryComponentScope<TQuery>,
data: PanelData,
editor: AngularComponent
) {
if (data.state === LoadingState.Done) { if (data.state === LoadingState.Done) {
const legacy = data.series.map((v) => toLegacyResponseData(v)); const legacy = data.series.map((v) => toLegacyResponseData(v));
scope.events.emit(PanelEvents.dataReceived, legacy); scope.events.emit(PanelEvents.dataReceived, legacy);
@@ -384,14 +388,14 @@ function notifyAngularQueryEditorsOfData(scope: AngularQueryComponentScope, data
setTimeout(editor.digest); setTimeout(editor.digest);
} }
export interface AngularQueryComponentScope { export interface AngularQueryComponentScope<TQuery extends DataQuery> {
target: DataQuery; target: TQuery;
panel: PanelModel; panel: PanelModel;
dashboard: DashboardModel; dashboard: DashboardModel;
events: EventBusExtended; events: EventBusExtended;
refresh: () => void; refresh: () => void;
render: () => void; render: () => void;
datasource: DataSourceApi | null; datasource: DataSourceApi<TQuery> | null;
toggleEditorMode?: () => void; toggleEditorMode?: () => void;
getCollapsedText?: () => string; getCollapsedText?: () => string;
range: TimeRange; range: TimeRange;

View File

@@ -5,19 +5,19 @@ import { DataSourcePicker } from '@grafana/runtime';
import { Icon, Input, FieldValidationMessage, useStyles } from '@grafana/ui'; import { Icon, Input, FieldValidationMessage, useStyles } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
export interface Props { export interface Props<TQuery extends DataQuery = DataQuery> {
query: DataQuery; query: TQuery;
queries: DataQuery[]; queries: TQuery[];
disabled?: boolean; disabled?: boolean;
dataSource: DataSourceInstanceSettings; dataSource: DataSourceInstanceSettings;
renderExtras?: () => ReactNode; renderExtras?: () => ReactNode;
onChangeDataSource?: (settings: DataSourceInstanceSettings) => void; onChangeDataSource?: (settings: DataSourceInstanceSettings) => void;
onChange: (query: DataQuery) => void; onChange: (query: TQuery) => void;
onClick: (e: React.MouseEvent) => void; onClick: (e: React.MouseEvent) => void;
collapsedText: string | null; collapsedText: string | null;
} }
export const QueryEditorRowHeader: React.FC<Props> = (props) => { export const QueryEditorRowHeader = <TQuery extends DataQuery>(props: Props<TQuery>) => {
const { query, queries, onClick, onChange, collapsedText, renderExtras, disabled } = props; const { query, queries, onClick, onChange, collapsedText, renderExtras, disabled } = props;
const styles = useStyles(getStyles); const styles = useStyles(getStyles);
@@ -123,7 +123,10 @@ export const QueryEditorRowHeader: React.FC<Props> = (props) => {
); );
}; };
const renderDataSource = (props: Props, styles: ReturnType<typeof getStyles>): ReactNode => { const renderDataSource = <TQuery extends DataQuery>(
props: Props<TQuery>,
styles: ReturnType<typeof getStyles>
): ReactNode => {
const { dataSource, onChangeDataSource } = props; const { dataSource, onChangeDataSource } = props;
if (!onChangeDataSource) { if (!onChangeDataSource) {

View File

@@ -1,8 +1,12 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { QueryEditorHelpProps } from '@grafana/data'; import { QueryEditorHelpProps } from '@grafana/data';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { CloudMonitoringQuery } from '../types';
export default class CloudMonitoringCheatSheet extends PureComponent<QueryEditorHelpProps, { userExamples: string[] }> { export default class CloudMonitoringCheatSheet extends PureComponent<
QueryEditorHelpProps<CloudMonitoringQuery>,
{ userExamples: string[] }
> {
render() { render() {
return ( return (
<div> <div>

View File

@@ -5,7 +5,7 @@ import Prism from 'prismjs';
import tokenizer from '../syntax'; import tokenizer from '../syntax';
import { flattenTokens } from '@grafana/ui/src/slate-plugins/slate-prism'; import { flattenTokens } from '@grafana/ui/src/slate-plugins/slate-prism';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { CloudWatchLogsQuery } from '../types'; import { CloudWatchQuery } from '../types';
interface QueryExample { interface QueryExample {
category: string; category: string;
@@ -214,8 +214,11 @@ const exampleCategory = css`
margin-top: 5px; margin-top: 5px;
`; `;
export default class LogsCheatSheet extends PureComponent<QueryEditorHelpProps, { userExamples: string[] }> { export default class LogsCheatSheet extends PureComponent<
onClickExample(query: CloudWatchLogsQuery) { QueryEditorHelpProps<CloudWatchQuery>,
{ userExamples: string[] }
> {
onClickExample(query: CloudWatchQuery) {
this.props.onClickExample(query); this.props.onClickExample(query);
} }

View File

@@ -1,7 +1,8 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { shuffle } from 'lodash'; import { shuffle } from 'lodash';
import { QueryEditorHelpProps, DataQuery } from '@grafana/data'; import { QueryEditorHelpProps } from '@grafana/data';
import LokiLanguageProvider from '../language_provider'; import LokiLanguageProvider from '../language_provider';
import { LokiQuery } from '../types';
const DEFAULT_EXAMPLES = ['{job="default/prometheus"}']; const DEFAULT_EXAMPLES = ['{job="default/prometheus"}'];
const PREFERRED_LABELS = ['job', 'app', 'k8s_app']; const PREFERRED_LABELS = ['job', 'app', 'k8s_app'];
@@ -32,7 +33,7 @@ const LOGQL_EXAMPLES = [
}, },
]; ];
export default class LokiCheatSheet extends PureComponent<QueryEditorHelpProps, { userExamples: string[] }> { export default class LokiCheatSheet extends PureComponent<QueryEditorHelpProps<LokiQuery>, { userExamples: string[] }> {
userLabelTimer: NodeJS.Timeout; userLabelTimer: NodeJS.Timeout;
state = { state = {
userExamples: DEFAULT_EXAMPLES, userExamples: DEFAULT_EXAMPLES,
@@ -72,11 +73,7 @@ export default class LokiCheatSheet extends PureComponent<QueryEditorHelpProps,
const { onClickExample } = this.props; const { onClickExample } = this.props;
return ( return (
<div <div className="cheat-sheet-item__example" key={expr} onClick={(e) => onClickExample({ refId: 'A', expr })}>
className="cheat-sheet-item__example"
key={expr}
onClick={(e) => onClickExample({ refId: 'A', expr } as DataQuery)}
>
<code>{expr}</code> <code>{expr}</code>
</div> </div>
); );

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { QueryEditorHelpProps, DataQuery } from '@grafana/data'; import { QueryEditorHelpProps } from '@grafana/data';
import { PromQuery } from '../types';
const CHEAT_SHEET_ITEMS = [ const CHEAT_SHEET_ITEMS = [
{ {
@@ -25,7 +26,7 @@ const CHEAT_SHEET_ITEMS = [
}, },
]; ];
const PromCheatSheet = (props: QueryEditorHelpProps) => ( const PromCheatSheet = (props: QueryEditorHelpProps<PromQuery>) => (
<div> <div>
<h2>PromQL Cheat Sheet</h2> <h2>PromQL Cheat Sheet</h2>
{CHEAT_SHEET_ITEMS.map((item, index) => ( {CHEAT_SHEET_ITEMS.map((item, index) => (
@@ -34,7 +35,7 @@ const PromCheatSheet = (props: QueryEditorHelpProps) => (
{item.expression ? ( {item.expression ? (
<div <div
className="cheat-sheet-item__example" className="cheat-sheet-item__example"
onClick={(e) => props.onClickExample({ refId: 'A', expr: item.expression } as DataQuery)} onClick={(e) => props.onClickExample({ refId: 'A', expr: item.expression })}
> >
<code>{item.expression}</code> <code>{item.expression}</code>
</div> </div>

View File

@@ -68,9 +68,9 @@ export type LdapConnectionInfo = LdapServerInfo[];
export interface LdapState { export interface LdapState {
connectionInfo: LdapConnectionInfo; connectionInfo: LdapConnectionInfo;
user?: LdapUser | null; user?: LdapUser;
syncInfo?: SyncInfo | null; syncInfo?: SyncInfo;
connectionError?: LdapError | null; connectionError?: LdapError;
userError?: LdapError | null; userError?: LdapError;
ldapError?: LdapError | null; ldapError?: LdapError;
} }

View File

@@ -88,11 +88,11 @@ export interface UserOrg {
} }
export interface UserAdminState { export interface UserAdminState {
user: UserDTO | null; user?: UserDTO;
sessions: UserSession[]; sessions: UserSession[];
orgs: UserOrg[]; orgs: UserOrg[];
isLoading: boolean; isLoading: boolean;
error?: UserAdminError | null; error?: UserAdminError;
} }
export interface UserAdminError { export interface UserAdminError {