Commit 514f2bea by kay delaney Committed by GitHub

Chore: Remove several instances of non-strict null usage (#20563)

parent 665079dc
......@@ -18,8 +18,8 @@ export interface LocationUpdate {
replace?: boolean;
}
export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[];
export type UrlQueryMap = { [s: string]: UrlQueryValue };
export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[] | undefined;
export type UrlQueryMap = Record<string, UrlQueryValue>;
export interface LocationSrv {
update(options: LocationUpdate): void;
......
......@@ -83,7 +83,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
}));
interface Props {
isOpen: boolean;
isOpen?: boolean;
label: string;
loading?: boolean;
collapsible?: boolean;
......
......@@ -14,7 +14,7 @@ export interface GraphProps {
children?: JSX.Element | JSX.Element[];
series: GraphSeriesXY[];
timeRange: TimeRange; // NOTE: we should aim to make `time` a property of the axis, not force it for all graphs
timeZone: TimeZone; // NOTE: we should aim to make `time` a property of the axis, not force it for all graphs
timeZone?: TimeZone; // NOTE: we should aim to make `time` a property of the axis, not force it for all graphs
showLines?: boolean;
showPoints?: boolean;
showBars?: boolean;
......@@ -246,7 +246,7 @@ export class Graph extends PureComponent<GraphProps, GraphState> {
label: 'Datetime',
ticks: ticks,
timeformat: timeFormat(ticks, min, max),
timezone: timeZone ? timeZone : DefaultTimeZone,
timezone: timeZone ?? DefaultTimeZone,
},
yaxes,
grid: {
......
......@@ -16,7 +16,7 @@ export interface Props extends Themeable {
logRows?: LogRowModel[];
deduplicatedRows?: LogRowModel[];
dedupStrategy: LogsDedupStrategy;
highlighterExpressions: string[];
highlighterExpressions?: string[];
showTime: boolean;
timeZone: TimeZone;
rowLimit?: number;
......
......@@ -37,7 +37,7 @@ export interface Props {
export class RefreshPickerBase extends PureComponent<Props> {
static offOption = { label: 'Off', value: '' };
static liveOption = { label: 'Live', value: 'LIVE' };
static isLive = (refreshInterval: string): boolean => refreshInterval === RefreshPicker.liveOption.value;
static isLive = (refreshInterval?: string): boolean => refreshInterval === RefreshPicker.liveOption.value;
constructor(props: Props) {
super(props);
......
......@@ -42,7 +42,7 @@ export const LogLevelColor = {
};
const isoDateRegexp = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-6]\d[,\.]\d+([+-][0-2]\d:[0-5]\d|Z)/g;
function isDuplicateRow(row: LogRowModel, other: LogRowModel, strategy: LogsDedupStrategy): boolean {
function isDuplicateRow(row: LogRowModel, other: LogRowModel, strategy?: LogsDedupStrategy): boolean {
switch (strategy) {
case LogsDedupStrategy.exact:
// Exact still strips dates
......@@ -59,7 +59,7 @@ function isDuplicateRow(row: LogRowModel, other: LogRowModel, strategy: LogsDedu
}
}
export function dedupLogRows(rows: LogRowModel[], strategy: LogsDedupStrategy): LogRowModel[] {
export function dedupLogRows(rows: LogRowModel[], strategy?: LogsDedupStrategy): LogRowModel[] {
if (strategy === LogsDedupStrategy.none) {
return rows;
}
......@@ -68,7 +68,7 @@ export function dedupLogRows(rows: LogRowModel[], strategy: LogsDedupStrategy):
const rowCopy = { ...row };
const previous = result[result.length - 1];
if (index > 0 && isDuplicateRow(row, previous, strategy)) {
previous.duplicates++;
previous.duplicates!++;
} else {
rowCopy.duplicates = 0;
result.push(rowCopy);
......
......@@ -202,20 +202,20 @@ describe('hasNonEmptyQuery', () => {
describe('hasRefId', () => {
describe('when called with a null value', () => {
it('then it should return null', () => {
it('then it should return undefined', () => {
const input: any = null;
const result = getValueWithRefId(input);
expect(result).toBeNull();
expect(result).toBeUndefined();
});
});
describe('when called with a non object value', () => {
it('then it should return null', () => {
it('then it should return undefined', () => {
const input = 123;
const result = getValueWithRefId(input);
expect(result).toBeNull();
expect(result).toBeUndefined();
});
});
......@@ -249,11 +249,11 @@ describe('hasRefId', () => {
describe('getFirstQueryErrorWithoutRefId', () => {
describe('when called with a null value', () => {
it('then it should return null', () => {
it('then it should return undefined', () => {
const errors: DataQueryError[] = null;
const result = getFirstQueryErrorWithoutRefId(errors);
expect(result).toBeNull();
expect(result).toBeUndefined();
});
});
......
......@@ -418,13 +418,9 @@ export const getTimeRangeFromUrl = (range: RawTimeRange, timeZone: TimeZone): Ti
};
};
export const getValueWithRefId = (value: any): any | null => {
if (!value) {
return null;
}
if (typeof value !== 'object') {
return null;
export const getValueWithRefId = (value?: any): any => {
if (!value || typeof value !== 'object') {
return undefined;
}
if (value.refId) {
......@@ -440,12 +436,12 @@ export const getValueWithRefId = (value: any): any | null => {
}
}
return null;
return undefined;
};
export const getFirstQueryErrorWithoutRefId = (errors: DataQueryError[]) => {
export const getFirstQueryErrorWithoutRefId = (errors?: DataQueryError[]) => {
if (!errors) {
return null;
return undefined;
}
return errors.filter(error => (error && error.refId ? false : true))[0];
......@@ -503,7 +499,7 @@ export enum SortOrder {
Ascending = 'Ascending',
}
export const refreshIntervalToSortOrder = (refreshInterval: string) =>
export const refreshIntervalToSortOrder = (refreshInterval?: string) =>
RefreshPicker.isLive(refreshInterval) ? SortOrder.Ascending : SortOrder.Descending;
export const sortLogsResult = (logsResult: LogsModel, sortOrder: SortOrder): LogsModel => {
......
......@@ -36,6 +36,11 @@ export const AdHocFilter: React.FunctionComponent<Props> = props => {
const onChange = (changeType: ChangeType) => (item: SelectableValue<string>) => {
const { onKeyChanged, onValueChanged, onOperatorChanged } = props;
if (!item.value) {
return;
}
switch (changeType) {
case ChangeType.Key:
onKeyChanged(item.value);
......@@ -54,13 +59,13 @@ export const AdHocFilter: React.FunctionComponent<Props> = props => {
const { keys, initialKey, keysPlaceHolder, initialOperator, values, initialValue, valuesPlaceHolder } = props;
const operators = ['=', '!='];
const keysAsOptions = keys ? keys.map(stringToOption) : [];
const selectedKey = initialKey ? keysAsOptions.filter(option => option.value === initialKey) : null;
const selectedKey = initialKey ? keysAsOptions.filter(option => option.value === initialKey) : undefined;
const valuesAsOptions = values ? values.map(stringToOption) : [];
const selectedValue = initialValue ? valuesAsOptions.filter(option => option.value === initialValue) : null;
const selectedValue = initialValue ? valuesAsOptions.filter(option => option.value === initialValue) : undefined;
const operatorsAsOptions = operators.map(stringToOption);
const selectedOperator = initialOperator
? operatorsAsOptions.filter(option => option.value === initialOperator)
: null;
: undefined;
return (
<div className={cx([styles.keyValueContainer])}>
......
......@@ -174,11 +174,11 @@ describe('AdHocFilterField', () => {
const { instance } = setup();
const pairs: KeyValuePair[] = [];
const index = 0;
const key: string = undefined;
const key: undefined = undefined;
const keys: string[] = ['key 1', 'key 2'];
const value: string = undefined;
const values: string[] = undefined;
const operator: string = undefined;
const value: undefined = undefined;
const values: undefined = undefined;
const operator: undefined = undefined;
const result = instance.updatePairs(pairs, index, { key, keys, value, values, operator });
......
......@@ -131,7 +131,7 @@ export class AdHocFilterField<
return allPairs;
}
return allPairs.concat(pair);
}, []);
}, [] as KeyValuePair[]);
this.setState({ pairs });
};
......
......@@ -4,7 +4,7 @@ import { FadeIn } from 'app/core/components/Animations/FadeIn';
import { getFirstQueryErrorWithoutRefId, getValueWithRefId } from 'app/core/utils/explore';
interface Props {
queryErrors: DataQueryError[];
queryErrors?: DataQueryError[];
}
export const ErrorContainer: FunctionComponent<Props> = props => {
......
......@@ -203,9 +203,10 @@ export class Explore extends React.PureComponent<ExploreProps> {
onModifyQueries = (action: any, index?: number) => {
const { datasourceInstance } = this.props;
if (datasourceInstance && datasourceInstance.modifyQuery) {
const modifier = (queries: DataQuery, modification: any) => datasourceInstance.modifyQuery(queries, modification);
this.props.modifyQueries(this.props.exploreId, action, index, modifier);
if (datasourceInstance?.modifyQuery) {
const modifier = (queries: DataQuery, modification: any) =>
datasourceInstance.modifyQuery!(queries, modification);
this.props.modifyQueries(this.props.exploreId, action, modifier, index);
}
};
......@@ -277,7 +278,7 @@ export class Explore extends React.PureComponent<ExploreProps> {
{datasourceInstance && (
<div className="explore-container">
<QueryRows exploreEvents={this.exploreEvents} exploreId={exploreId} queryKeys={queryKeys} />
<ErrorContainer queryErrors={[queryResponse.error]} />
<ErrorContainer queryErrors={queryResponse.error ? [queryResponse.error] : undefined} />
<AutoSizer onResize={this.onResize} disableHeight>
{({ width }) => {
if (width === 0) {
......@@ -287,7 +288,7 @@ export class Explore extends React.PureComponent<ExploreProps> {
return (
<main className={`m-t-2 ${styles.logsMain}`} style={{ width }}>
<ErrorBoundaryAlert>
{showingStartPage && (
{showingStartPage && StartPage && (
<div className="grafana-info-box grafana-info-box--max-lg">
<StartPage
onClickExample={this.onClickExample}
......@@ -377,7 +378,7 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia
const initialQueries: DataQuery[] = ensureQueriesMemoized(queries);
const initialRange = urlRange ? getTimeRangeFromUrlMemoized(urlRange, timeZone).raw : DEFAULT_RANGE;
let newMode: ExploreMode;
let newMode: ExploreMode | undefined;
if (supportedModes.length) {
const urlModeIsValid = supportedModes.includes(urlMode);
......@@ -391,7 +392,7 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia
newMode = supportedModes[0];
}
} else {
newMode = [ExploreMode.Metrics, ExploreMode.Logs].includes(urlMode) ? urlMode : null;
newMode = [ExploreMode.Metrics, ExploreMode.Logs].includes(urlMode) ? urlMode : undefined;
}
const initialUI = ui || DEFAULT_UI_STATE;
......
......@@ -39,17 +39,17 @@ const getStyles = (theme: GrafanaTheme) => ({
});
interface Props extends Themeable {
series: GraphSeriesXY[];
series?: GraphSeriesXY[];
width: number;
absoluteRange: AbsoluteTimeRange;
loading: boolean;
loading?: boolean;
showPanel: boolean;
showBars: boolean;
showLines: boolean;
isStacked: boolean;
showingGraph: boolean;
showingTable: boolean;
timeZone: TimeZone;
showingGraph?: boolean;
showingTable?: boolean;
timeZone?: TimeZone;
onUpdateTimeRange: (absoluteRange: AbsoluteTimeRange) => void;
onToggleGraph?: (showingGraph: boolean) => void;
onHiddenSeriesChanged?: (hiddenSeries: string[]) => void;
......@@ -75,7 +75,7 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
onClickGraphButton = () => {
const { onToggleGraph, showingGraph } = this.props;
if (onToggleGraph) {
onToggleGraph(showingGraph);
onToggleGraph(showingGraph ?? false);
}
};
......
......@@ -73,7 +73,7 @@ export class ExploreTimeControls extends Component<Props> {
render() {
const { range, timeZone, splitted, syncedTimes, onChangeTimeSync, hideText } = this.props;
const timeSyncButton = splitted ? <TimeSyncButton onClick={onChangeTimeSync} isSynced={syncedTimes} /> : null;
const timeSyncButton = splitted ? <TimeSyncButton onClick={onChangeTimeSync} isSynced={syncedTimes} /> : undefined;
const timePickerCommonProps = {
value: range,
onChange: this.onChangeTimePicker,
......
......@@ -54,18 +54,18 @@ interface StateProps {
loading: boolean;
range: TimeRange;
timeZone: TimeZone;
selectedDatasource: DataSourceSelectItem;
selectedDatasource?: DataSourceSelectItem;
splitted: boolean;
syncedTimes: boolean;
refreshInterval: string;
refreshInterval?: string;
supportedModes: ExploreMode[];
selectedMode: ExploreMode;
hasLiveOption: boolean;
isLive: boolean;
isPaused: boolean;
originPanelId: number;
originPanelId?: number;
queries: DataQuery[];
datasourceLoading: boolean | null;
datasourceLoading?: boolean;
containerWidth: number;
}
......@@ -163,7 +163,7 @@ export class UnConnectedExploreToolbar extends PureComponent<Props> {
} = this.props;
const styles = getStyles();
const originDashboardIsEditable = Number.isInteger(originPanelId);
const originDashboardIsEditable = originPanelId && Number.isInteger(originPanelId);
const panelReturnClasses = classNames('btn', 'navbar-button', {
'btn--radius-right-0': originDashboardIsEditable,
'navbar-button navbar-button--border-right-0': originDashboardIsEditable,
......@@ -234,7 +234,7 @@ export class UnConnectedExploreToolbar extends PureComponent<Props> {
</div>
) : null}
{Number.isInteger(originPanelId) && !splitted && (
{originPanelId && Number.isInteger(originPanelId) && !splitted && (
<div className="explore-toolbar-content-item">
<Tooltip content={'Return to panel'} placement="bottom">
<button className={panelReturnClasses} onClick={() => this.returnToPanel()}>
......
......@@ -63,7 +63,7 @@ interface State {
}
class LiveLogs extends PureComponent<Props, State> {
private liveEndDiv: HTMLDivElement = null;
private liveEndDiv: HTMLDivElement | null = null;
private scrollContainerRef = React.createRef<HTMLDivElement>();
private lastScrollPos: number | null = null;
......@@ -77,7 +77,7 @@ class LiveLogs extends PureComponent<Props, State> {
componentDidUpdate(prevProps: Props) {
if (!prevProps.isPaused && this.props.isPaused) {
// So we paused the view and we changed the content size, but we want to keep the relative offset from the bottom.
if (this.lastScrollPos) {
if (this.lastScrollPos && this.scrollContainerRef.current) {
// There is last scroll pos from when user scrolled up a bit so go to that position.
const { clientHeight, scrollHeight } = this.scrollContainerRef.current;
const scrollTop = scrollHeight - (this.lastScrollPos + clientHeight);
......@@ -123,7 +123,7 @@ class LiveLogs extends PureComponent<Props, State> {
rowsToRender = () => {
const { isPaused } = this.props;
let rowsToRender: LogRowModel[] = this.state.logRowsToRender;
let { logRowsToRender: rowsToRender = [] } = this.state;
if (!isPaused) {
// A perf optimisation here. Show just 100 rows when streaming and full length when the streaming is paused.
rowsToRender = rowsToRender.slice(-100);
......
......@@ -37,7 +37,7 @@ interface Props {
dedupedRows?: LogRowModel[];
width: number;
highlighterExpressions: string[];
highlighterExpressions?: string[];
loading: boolean;
absoluteRange: AbsoluteTimeRange;
timeZone: TimeZone;
......
......@@ -30,7 +30,7 @@ import { LiveTailControls } from './useLiveTailControls';
import { getLinksFromLogsField } from '../panel/panellinks/linkSuppliers';
interface LogsContainerProps {
datasourceInstance: DataSourceApi | null;
datasourceInstance?: DataSourceApi;
exploreId: ExploreId;
loading: boolean;
......@@ -80,7 +80,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
getLogRowContext = async (row: LogRowModel, options?: any): Promise<any> => {
const { datasourceInstance } = this.props;
if (datasourceInstance) {
if (datasourceInstance?.getLogRowContext) {
return datasourceInstance.getLogRowContext(row, options);
}
......
......@@ -45,13 +45,13 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> {
target,
refresh: () => {
setTimeout(() => {
this.props.onQueryChange(target);
this.props.onExecuteQuery();
this.props.onQueryChange?.(target);
this.props.onExecuteQuery?.();
}, 1);
},
onQueryChange: () => {
setTimeout(() => {
this.props.onQueryChange(target);
this.props.onQueryChange?.(target);
}, 1);
},
events: exploreEvents,
......@@ -64,8 +64,8 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> {
this.angularScope = scopeProps.ctrl;
setTimeout(() => {
this.props.onQueryChange(target);
this.props.onExecuteQuery();
this.props.onQueryChange?.(target);
this.props.onExecuteQuery?.();
}, 1);
}
......
......@@ -134,12 +134,12 @@ export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
let QueryField;
if (mode === ExploreMode.Metrics && datasourceInstance.components.ExploreMetricsQueryField) {
if (mode === ExploreMode.Metrics && datasourceInstance.components?.ExploreMetricsQueryField) {
QueryField = datasourceInstance.components.ExploreMetricsQueryField;
} else if (mode === ExploreMode.Logs && datasourceInstance.components.ExploreLogsQueryField) {
} else if (mode === ExploreMode.Logs && datasourceInstance.components?.ExploreLogsQueryField) {
QueryField = datasourceInstance.components.ExploreLogsQueryField;
} else {
QueryField = datasourceInstance.components.ExploreQueryField;
QueryField = datasourceInstance.components?.ExploreQueryField;
}
return (
......
......@@ -2,7 +2,7 @@ import React from 'react';
export type Props = {
canToggleEditorModes: boolean;
isDisabled: boolean;
isDisabled?: boolean;
isNotStarted: boolean;
onClickToggleEditorMode: () => void;
onClickToggleDisabled: () => void;
......
......@@ -21,7 +21,7 @@ type Props = {
splitted: boolean;
loading: boolean;
onRun: () => void;
refreshInterval: string;
refreshInterval?: string;
onChangeRefreshInterval: (interval: string) => void;
showDropdown: boolean;
};
......
......@@ -28,7 +28,7 @@ export default class Table extends PureComponent<TableProps> {
if (link.className === 'link') {
const columnKey = column.Header().props.title;
const rowValue = rowInfo.row[columnKey];
this.props.onClickCell(columnKey, rowValue);
this.props.onClickCell?.(columnKey, rowValue);
}
}
},
......
......@@ -118,7 +118,7 @@ export interface LoadDatasourceReadyPayload {
export interface ModifyQueriesPayload {
exploreId: ExploreId;
modification: QueryFixAction;
index: number;
index?: number;
modifier: (query: DataQuery, modification: QueryFixAction) => DataQuery;
}
......
......@@ -162,7 +162,7 @@ export function changeQuery(
exploreId: ExploreId,
query: DataQuery,
index: number,
override: boolean
override = false
): ThunkResult<void> {
return (dispatch, getState) => {
// Null query means reset
......@@ -389,8 +389,8 @@ export function loadDatasource(exploreId: ExploreId, instance: DataSourceApi, or
export function modifyQueries(
exploreId: ExploreId,
modification: QueryFixAction,
index: number,
modifier: any
modifier: any,
index?: number
): ThunkResult<void> {
return dispatch => {
dispatch(modifyQueriesAction({ exploreId, modification, index, modifier }));
......
......@@ -59,7 +59,7 @@ const state: any = {
describe('Deduplication selector', () => {
it('returns the same rows if no deduplication', () => {
const dedups = deduplicatedRowsSelector(state as ExploreItemState);
expect(dedups.length).toBe(11);
expect(dedups?.length).toBe(11);
expect(dedups).toBe(state.logsResult.rows);
});
......@@ -68,7 +68,7 @@ describe('Deduplication selector', () => {
...state,
dedupStrategy: LogsDedupStrategy.numbers,
} as ExploreItemState);
expect(dedups.length).toBe(2);
expect(dedups?.length).toBe(2);
expect(dedups).not.toBe(state.logsResult.rows);
});
......@@ -77,7 +77,7 @@ describe('Deduplication selector', () => {
...state,
hiddenLogLevels: [LogLevel.debug],
} as ExploreItemState);
expect(dedups.length).toBe(2);
expect(dedups?.length).toBe(2);
expect(dedups).not.toBe(state.logsResult.rows);
dedups = deduplicatedRowsSelector({
......@@ -86,7 +86,7 @@ describe('Deduplication selector', () => {
hiddenLogLevels: [LogLevel.debug],
} as ExploreItemState);
expect(dedups.length).toBe(2);
expect(dedups?.length).toBe(2);
expect(dedups).not.toBe(state.logsResult.rows);
});
});
......@@ -14,7 +14,7 @@ export class ResultProcessor {
private timeZone: TimeZone
) {}
getGraphResult(): GraphSeriesXY[] {
getGraphResult(): GraphSeriesXY[] | null {
if (this.state.mode !== ExploreMode.Metrics) {
return null;
}
......@@ -34,7 +34,7 @@ export class ResultProcessor {
);
}
getTableResult(): TableModel {
getTableResult(): TableModel | null {
if (this.state.mode !== ExploreMode.Metrics) {
return null;
}
......@@ -78,7 +78,7 @@ export class ResultProcessor {
return mergeTablesIntoModel(new TableModel(), ...tables);
}
getLogsResult(): LogsModel {
getLogsResult(): LogsModel | null {
if (this.state.mode !== ExploreMode.Logs) {
return null;
}
......
......@@ -65,7 +65,7 @@ export interface ExploreItemState {
/**
* Datasource instance that has been selected. Datasource-specific logic can be run on this object.
*/
datasourceInstance: DataSourceApi | null;
datasourceInstance?: DataSourceApi;
/**
* Current data source name or null if default
*/
......@@ -73,7 +73,7 @@ export interface ExploreItemState {
/**
* True if the datasource is loading. `null` if the loading has not started yet.
*/
datasourceLoading: boolean | null;
datasourceLoading?: boolean;
/**
* True if there is no datasource to be selected.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment