Unverified Commit d27326fb authored by Dorian Johnson's avatar Dorian Johnson Committed by GitHub

chore: fix remaining strictNullChecks errors; enforce in tsconfig (#758)

Signed-off-by: 's avatarMarcos Iglesias Valle <golodhros@gmail.com>
parent 05dc3e77
// BETTERER RESULTS V2.
exports[`strict null compilation`] = {
value: `{
"js/components/Footer/index.tsx:474946957": [
[79, 2, 15, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'(state: GlobalState) => { lastIndexed: number | null; }\' is not assignable to parameter of type \'MapStateToPropsParam<StateFromProps, {}, {}>\'.\\n Type \'(state: GlobalState) => { lastIndexed: number | null; }\' is not assignable to type \'MapStateToPropsFactory<StateFromProps, {}, {}>\'.\\n Type \'{ lastIndexed: number | null; }\' is not assignable to type \'MapStateToProps<StateFromProps, {}, {}>\'.\\n Type \'{ lastIndexed: number | null; }\' provides no match for the signature \'(state: {}, ownProps: {}): StateFromProps\'.", "1389821531"]
],
"js/components/common/SearchBar/index.tsx:3874012304": [
[255, 6, 11, "No overload matches this call.\\n The last overload gave the following error.\\n Type \'(() => SubmitSearchRequest) | null\' is not assignable to type \'ActionCreator<any>\'.\\n Type \'null\' is not assignable to type \'ActionCreator<any>\'.", "2296208050"],
[270, 4, 18, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'(dispatch: any, ownProps: any) => ActionCreator<unknown>\' is not assignable to parameter of type \'DispatchFromProps\'.\\n Type \'(dispatch: any, ownProps: any) => ActionCreator<unknown>\' is missing the following properties from type \'DispatchFromProps\': submitSearch, onInputChange, onSelectInlineResult", "2926224796"]
],
"js/config/index.spec.ts:3696338512": [
[17, 6, 61, "Object is possibly \'undefined\'.", "1496333578"],
[51, 6, 61, "Object is possibly \'undefined\'.", "1496333578"]
],
"js/ducks/announcements/index.ts:3464360346": [
[37, 2, 10, "Type \'null\' is not assignable to type \'number\'.", "3382497788"],
[49, 8, 10, "Type \'null\' is not assignable to type \'number\'.", "3382497788"]
],
"js/ducks/dashboard/reducer.ts:1902488284": [
[71, 2, 10, "Type \'null\' is not assignable to type \'number\'.", "3382497788"],
[83, 8, 10, "Type \'null\' is not assignable to type \'number\'.", "3382497788"]
],
"js/ducks/issue/reducer.ts:2547378323": [
[60, 6, 5, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "183290119"],
[61, 6, 12, "Type \'string | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "124336133"],
[75, 6, 5, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "183290119"],
[76, 6, 12, "Type \'string | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "124336133"],
[91, 2, 12, "Type \'null\' is not assignable to type \'string\'.", "124336133"]
],
"js/ducks/issue/sagas.ts:3265021214": [
[29, 38, 4, "Argument of type \'null\' is not assignable to parameter of type \'string | undefined\'.", "2087897566"],
[47, 33, 4, "Argument of type \'null\' is not assignable to parameter of type \'Issue\'.", "2087897566"]
],
"js/ducks/issue/tests/index.spec.ts:1055847482": [
[82, 38, 4, "Argument of type \'null\' is not assignable to parameter of type \'Issue[]\'.", "2087897566"],
[118, 40, 4, "Argument of type \'null\' is not assignable to parameter of type \'Issue\'.", "2087897566"],
[173, 56, 4, "Argument of type \'null\' is not assignable to parameter of type \'string | undefined\'.", "2087897566"],
[215, 51, 4, "Argument of type \'null\' is not assignable to parameter of type \'Issue\'.", "2087897566"],
[258, 39, 4, "Argument of type \'null\' is not assignable to parameter of type \'string | undefined\'.", "2087897566"],
[306, 34, 4, "Argument of type \'null\' is not assignable to parameter of type \'Issue\'.", "2087897566"]
],
"js/ducks/notification/tests/index.spec.ts:2474130513": [
[197, 43, 4, "Argument of type \'null\' is not assignable to parameter of type \'SubmitNotificationRequest\'.", "2087897566"]
],
"js/ducks/search/sagas.ts:1595931651": [
[68, 6, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'ResourceType\'.", "2620553983"],
[118, 49, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'ResourceType\'.", "2620553983"]
],
"js/ducks/search/tests/sagas.spec.ts:143749331": [
[155, 53, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'ResourceType\'.", "2620553983"],
[166, 50, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'ResourceType\'.", "2620553983"],
[287, 46, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'ResourceType\'.", "2620553983"]
],
"js/ducks/tableMetadata/api/v0.ts:1644381619": [
[137, 24, 7, "Argument of type \'Promise<AxiosResponse<any> | undefined>\' is not assignable to parameter of type \'never\'.", "1363914868"]
],
"js/ducks/tableMetadata/reducer.ts:2668005658": [
[65, 2, 10, "Type \'null\' is not assignable to type \'number\'.", "3382497788"]
],
"js/pages/ProfilePage/index.tsx:1225704099": [
[356, 2, 15, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'(state: GlobalState) => { user: PeopleUser; resourceRelations: { table: { bookmarks: Bookmark[]; own: Resource[]; read: Resource[]; }; dashboard: { bookmarks: Bookmark[] | undefined; own: Resource[] | undefined; read: never[]; }; }; }\' is not assignable to parameter of type \'MapStateToPropsParam<StateFromProps, {}, {}>\'.\\n Type \'(state: GlobalState) => { user: PeopleUser; resourceRelations: { table: { bookmarks: Bookmark[]; own: Resource[]; read: Resource[]; }; dashboard: { bookmarks: Bookmark[] | undefined; own: Resource[] | undefined; read: never[]; }; }; }\' is not assignable to type \'MapStateToPropsFactory<StateFromProps, {}, {}>\'.\\n Type \'{ user: PeopleUser; resourceRelations: { table: { bookmarks: Bookmark[]; own: Resource[]; read: Resource[]; }; dashboard: { bookmarks: Bookmark[] | undefined; own: Resource[] | undefined; read: never[]; }; }; }\' is not assignable to type \'MapStateToProps<StateFromProps, {}, {}>\'.\\n Type \'{ user: PeopleUser; resourceRelations: { table: { bookmarks: Bookmark[]; own: Resource[]; read: Resource[]; }; dashboard: { bookmarks: Bookmark[] | undefined; own: Resource[] | undefined; read: never[]; }; }; }\' provides no match for the signature \'(state: {}, ownProps: {}): StateFromProps\'.", "1389821531"]
],
"js/pages/SearchPage/SearchFilter/index.spec.tsx:1059167396": [
[233, 23, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'FilterConfig\'.", "2620553983"]
],
"js/pages/SearchPage/SearchFilter/index.tsx:2448037720": [
[96, 56, 4, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'{}\'.", "2087897566"]
],
"js/pages/SearchPage/index.tsx:3158270092": [
[176, 11, 12, "Property \'filterSections\' is missing in type \'{}\' but required in type \'Readonly<Pick<StateFromProps, \\"filterSections\\">>\'.", "250899467"]
],
"js/pages/TableDetailPage/TableDashboardResourceList/index.tsx:3276822301": [
[65, 2, 15, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'(state: GlobalState) => { dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' is not assignable to parameter of type \'MapStateToPropsParam<StateFromProps, OwnProps, {}>\'.\\n Type \'(state: GlobalState) => { dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' is not assignable to type \'MapStateToPropsFactory<StateFromProps, OwnProps, {}>\'.\\n Type \'{ dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' is not assignable to type \'MapStateToProps<StateFromProps, OwnProps, {}>\'.\\n Type \'{ dashboards: DashboardResource[]; isLoading: boolean; errorText: string | undefined; }\' provides no match for the signature \'(state: {}, ownProps: OwnProps): StateFromProps\'.", "1389821531"]
],
"js/pages/TableDetailPage/index.tsx:587812140": [
[235, 11, 26, "Type \'{ itemsPerPage: number; source: string; }\' is missing the following properties from type \'Readonly<Pick<TableDashboardResourceListProps, \\"source\\" | \\"isLoading\\" | \\"dashboards\\" | \\"itemsPerPage\\" | \\"errorText\\"> & OwnProps>\': isLoading, dashboards, errorText", "2224258167"]
]
}`
};
// BETTERER RESULTS V2.
\ No newline at end of file
import { typescript } from '@betterer/typescript';
export default {
'strict null compilation': typescript('./tsconfig.json', {
strictNullChecks: true,
}),
};
......@@ -14,7 +14,7 @@ import { formatDateTimeLong } from 'utils/dateUtils';
// Props
interface StateFromProps {
lastIndexed?: number;
lastIndexed: number | null;
}
interface DispatchFromProps {
......@@ -66,7 +66,7 @@ export class Footer extends React.Component<FooterProps> {
}
}
export const mapStateToProps = (state: GlobalState) => {
export const mapStateToProps = (state: GlobalState): StateFromProps => {
return {
lastIndexed: state.lastIndexed.lastIndexed,
};
......
......@@ -15,7 +15,7 @@ import AnnouncementsList from './AnnouncementsList';
export interface StateFromProps {
isLoading: boolean;
statusCode: number;
statusCode: number | null;
announcements: AnnouncementPost[];
}
......
......@@ -240,22 +240,23 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> {
}
}
export const mapStateToProps = (state: GlobalState) => {
export const mapStateToProps = (state: GlobalState): StateFromProps => {
return {
searchTerm: state.search.search_term,
};
};
export const mapDispatchToProps = (dispatch: any, ownProps) => {
export const mapDispatchToProps = (
dispatch: any,
ownProps
): DispatchFromProps => {
/* These values activate behavior only applicable on SearchPage */
const useFilters = ownProps.history.location.pathname === '/search';
const updateStateOnClear = ownProps.history.location.pathname === '/search';
return bindActionCreators(
const dispatchableActions: DispatchFromProps = bindActionCreators(
{
clearSearch: updateStateOnClear
? () => submitSearch({ useFilters, searchTerm: '' })
: null,
clearSearch: () => submitSearch({ useFilters, searchTerm: '' }),
submitSearch: (searchTerm: string) =>
submitSearch({ searchTerm, useFilters }),
onInputChange: getInlineResultsDebounce,
......@@ -263,6 +264,14 @@ export const mapDispatchToProps = (dispatch: any, ownProps) => {
},
dispatch
);
// Tricky: we want to clear this property, but the bindActionCreators convenience
// wrapper won't allow undefined values, so clear it after.
if (!updateStateOnClear) {
dispatchableActions.clearSearch = undefined;
}
return dispatchableActions;
};
export default withRouter(
......
......@@ -72,7 +72,7 @@ export function getDisplayNameByResource(resourceType: ResourceType): string {
*/
export function getFilterConfigByResource(
resourceType: ResourceType
): FilterConfig {
): FilterConfig | undefined {
return AppConfig.resourceConfig[resourceType].filterCategories;
}
......
......@@ -14,9 +14,9 @@ describe('getSourceDisplayName', () => {
it('returns given id for a configured source id', () => {
const testId = 'hive';
const expectedName =
AppConfig.resourceConfig[ResourceType.table].supportedSources[testId]
.displayName;
const expectedName = (<any>AppConfig).resourceConfig[ResourceType.table]
.supportedSources[testId].displayName;
expect(expectedName).toBeDefined();
expect(ConfigUtils.getSourceDisplayName(testId, ResourceType.table)).toBe(
expectedName
);
......@@ -48,9 +48,9 @@ describe('getSourceIconClass', () => {
it('returns given icon class for a configured database id', () => {
const testId = 'hive';
const expectedClass =
AppConfig.resourceConfig[ResourceType.table].supportedSources[testId]
.iconClass;
const expectedClass = (<any>AppConfig).resourceConfig[ResourceType.table]
.supportedSources[testId].iconClass;
expect(expectedClass).toBeDefined();
expect(ConfigUtils.getSourceIconClass(testId, ResourceType.table)).toBe(
expectedClass
);
......
......@@ -29,7 +29,7 @@ export function getAnnouncementsSuccess(
export interface AnnouncementsReducerState {
posts: AnnouncementPost[];
isLoading: boolean;
statusCode: number;
statusCode: number | null;
}
export const initialState: AnnouncementsReducerState = {
......
......@@ -39,7 +39,7 @@ export function getDashboardFailure(
export interface DashboardReducerState {
isLoading: boolean;
statusCode: number;
statusCode: number | null;
dashboard: DashboardMetadata;
}
......
......@@ -31,7 +31,7 @@ export function createIssueSuccess(issue: Issue): CreateIssueResponse {
};
}
export function createIssueFailure(issue: Issue): CreateIssueResponse {
export function createIssueFailure(issue?: Issue): CreateIssueResponse {
return {
type: CreateIssue.FAILURE,
payload: {
......@@ -82,14 +82,14 @@ export function getIssuesFailure(
/* REDUCER */
export interface IssueReducerState {
issues: Issue[];
allIssuesUrl: string;
total: number;
allIssuesUrl?: string;
total?: number;
isLoading: boolean;
}
export const initialIssuestate: IssueReducerState = {
issues: [],
allIssuesUrl: null,
allIssuesUrl: undefined,
total: 0,
isLoading: false,
};
......@@ -117,9 +117,13 @@ export default function reducer(
case CreateIssue.FAILURE:
return { ...state, isLoading: false };
case CreateIssue.SUCCESS:
const { issue } = (<CreateIssueResponse>action).payload;
if (issue === undefined) {
throw Error('payload.issue must be set for CreateIssue.SUCCESS');
}
return {
...state,
issues: [(<CreateIssueResponse>action).payload.issue, ...state.issues],
issues: [issue, ...state.issues],
isLoading: false,
};
default:
......
......@@ -27,7 +27,7 @@ export function* getIssuesWorker(action: GetIssuesRequest): SagaIterator {
getIssuesSuccess(response.issues, response.total, response.all_issues_url)
);
} catch (e) {
yield put(getIssuesFailure([], 0, null));
yield put(getIssuesFailure([], 0, undefined));
}
}
......@@ -45,7 +45,7 @@ export function* createIssueWorker(action: CreateIssueRequest): SagaIterator {
yield put(createIssueSuccess(response));
} catch (error) {
yield put(createIssueFailure(null));
yield put(createIssueFailure(undefined));
}
}
......
......@@ -80,7 +80,7 @@ describe('issue ducks', () => {
});
it('getIssuesFailure - returns the action to process failure', () => {
const action = getIssuesFailure(null);
const action = getIssuesFailure([]);
expect(action.type).toBe(GetIssues.FAILURE);
});
......@@ -116,10 +116,10 @@ describe('issue ducks', () => {
});
it('createIssueFailure - returns the action to process failure', () => {
const action = createIssueFailure(null);
const action = createIssueFailure();
const { payload } = action;
expect(action.type).toBe(CreateIssue.FAILURE);
expect(payload.issue).toBe(null);
expect(payload.issue).toBe(undefined);
});
it('createIssueSuccess - returns the action to process success', () => {
......@@ -154,7 +154,7 @@ describe('issue ducks', () => {
expect(reducer(testState, getIssues(tableKey))).toEqual({
issues: [],
isLoading: true,
allIssuesUrl: null,
allIssuesUrl: undefined,
total: 0,
});
});
......@@ -171,11 +171,11 @@ describe('issue ducks', () => {
});
it('should handle GetIssues.FAILURE', () => {
expect(reducer(testState, getIssuesFailure([], 0, null))).toEqual({
expect(reducer(testState, getIssuesFailure([], 0, undefined))).toEqual({
total,
issues: [],
isLoading: false,
allIssuesUrl: null,
allIssuesUrl: undefined,
});
});
......@@ -212,8 +212,16 @@ describe('issue ducks', () => {
});
});
it('should handle malformed CreateIssue.SUCCESS', () => {
const successBody = createIssueSuccess(issue);
successBody.payload.issue = undefined;
expect(() => {
reducer(testState, successBody);
}).toThrow();
});
it('should handle CreateIssue.FAILURE', () => {
expect(reducer(testState, createIssueFailure(null))).toEqual({
expect(reducer(testState, createIssueFailure())).toEqual({
total,
allIssuesUrl,
issues: [],
......@@ -235,8 +243,8 @@ describe('issue ducks', () => {
describe('getIssuesWorker', () => {
let action: GetIssuesRequest;
let allIssuesUrl: string;
let total: number;
let allIssuesUrl: string | undefined;
let total: number | undefined;
beforeAll(() => {
action = getIssues(tableKey);
issues = globalState.issue.issues;
......@@ -256,7 +264,7 @@ describe('issue ducks', () => {
it('handles request error', () => {
return expectSaga(getIssuesWorker, action)
.provide([[matchers.call.fn(API.getIssues), throwError(new Error())]])
.put(getIssuesFailure([], 0, null))
.put(getIssuesFailure([], 0, undefined))
.run();
});
});
......@@ -304,7 +312,7 @@ describe('issue ducks', () => {
.provide([
[matchers.call.fn(API.createIssue), throwError(new Error())],
])
.put(createIssueFailure(null))
.put(createIssueFailure())
.run();
});
});
......
......@@ -30,14 +30,14 @@ export interface GetIssuesResponse {
type: GetIssues.SUCCESS | GetIssues.FAILURE;
payload: {
issues: Issue[];
total: number;
allIssuesUrl: string;
total?: number;
allIssuesUrl?: string;
};
}
export interface CreateIssueResponse {
type: CreateIssue.SUCCESS | CreateIssue.FAILURE;
payload: {
issue: Issue;
issue?: Issue;
};
}
......@@ -195,7 +195,12 @@ describe('notifications ducks', () => {
});
it('handles request error', () => {
testSaga(submitNotificationWorker, null)
// Tricky: per the type definitions, `action.payload` must be non-null,
// and so must its constituents. This test is intended to exercise the
// parser's error handling logic, however there currently is none, so
// this test is somewhat useless, but still narrowly helpful to ensure
// that the function appropriately throws.
testSaga(submitNotificationWorker, <any>{ payload: null })
.next()
.put(submitNotificationFailure())
.next()
......
......@@ -66,7 +66,7 @@ export function* submitSearchWorker(action: SubmitSearchRequest): SagaIterator {
searchAll(
searchTerm ? SearchType.SUBMIT_TERM : SearchType.CLEAR_TERM,
searchTerm,
undefined,
ResourceType.table,
0,
useFilters
)
......@@ -116,7 +116,7 @@ export function* updateSearchStateWorker(
const { filters, resource, updateUrl, submitSearch } = action.payload;
const state = yield select(getSearchState);
if (filters && submitSearch) {
yield put(searchAll(SearchType.FILTER, '', undefined, 0, true));
yield put(searchAll(SearchType.FILTER, '', ResourceType.table, 0, true));
} else if (updateUrl) {
updateSearchUrl({
resource: resource || state.resource,
......
......@@ -153,7 +153,9 @@ describe('search sagas', () => {
submitSearch({ searchTerm: term, useFilters: true })
)
.next()
.put(searchAll(SearchType.SUBMIT_TERM, term, undefined, 0, true))
.put(
searchAll(SearchType.SUBMIT_TERM, term, ResourceType.table, 0, true)
)
.next()
.isDone();
});
......@@ -164,7 +166,7 @@ describe('search sagas', () => {
submitSearch({ searchTerm: '', useFilters: false })
)
.next()
.put(searchAll(SearchType.CLEAR_TERM, '', undefined, 0, false))
.put(searchAll(SearchType.CLEAR_TERM, '', ResourceType.table, 0, false))
.next()
.isDone();
});
......@@ -285,7 +287,7 @@ describe('search sagas', () => {
.next()
.select(SearchUtils.getSearchState)
.next(searchState)
.put(searchAll(SearchType.FILTER, '', undefined, 0, true))
.put(searchAll(SearchType.FILTER, '', ResourceType.table, 0, true))
.next()
.isDone();
});
......
......@@ -116,16 +116,14 @@ export function getTableOwners(tableKey: string) {
export function generateOwnerUpdateRequests(
updateArray: UpdateOwnerPayload[],
tableData: TableMetadata
) {
const updateRequests = [];
/* Create the request for updating each owner*/
updateArray.forEach((item) => {
): any {
/* Return the list of requests to be executed */
return updateArray.map((item) => {
const updatePayload = createOwnerUpdatePayload(item, tableData.key);
const notificationData = createOwnerNotificationData(item, tableData);
/* Chain requests to send notification on success to desired users */
const request = axios(updatePayload)
return axios(updatePayload)
.then(() => {
return axios.get(`/api/metadata/v0/user?user_id=${item.id}`);
})
......@@ -134,12 +132,7 @@ export function generateOwnerUpdateRequests(
return axios.post('/api/mail/v0/notification', notificationData);
}
});
updateRequests.push(request);
});
/* Return the list of requests to be executed */
return updateRequests;
}
export function getColumnDescription(
......
......@@ -268,7 +268,7 @@ export interface TableMetadataReducerState {
data: PreviewData;
status: number | null;
};
statusCode: number;
statusCode: number | null;
tableData: TableMetadata;
tableOwners: TableOwnerReducerState;
}
......
......@@ -24,7 +24,7 @@ export interface GetTableDataRequest {
export interface GetTableDataResponse {
type: GetTableData.SUCCESS | GetTableData.FAILURE;
payload: {
statusCode: number;
statusCode: number | null;
data: TableMetadata;
owners: OwnerDict;
tags: Tag[];
......
......@@ -53,7 +53,7 @@ interface DashboardPageState {
export interface StateFromProps {
isLoading: boolean;
statusCode: number;
statusCode: number | null;
dashboard: DashboardMetadata;
}
......
......@@ -328,7 +328,7 @@ export class ProfilePage extends React.Component<
}
}
export const mapStateToProps = (state: GlobalState) => {
export const mapStateToProps = (state: GlobalState): StateFromProps => {
return {
user: state.user.profile.user,
resourceRelations: {
......@@ -338,8 +338,9 @@ export const mapStateToProps = (state: GlobalState) => {
read: state.user.profile.read,
},
[ResourceType.dashboard]: {
bookmarks: state.bookmarks.bookmarksForUser[ResourceType.dashboard],
own: state.user.profile.own[ResourceType.dashboard],
bookmarks:
state.bookmarks.bookmarksForUser[ResourceType.dashboard] || [],
own: state.user.profile.own[ResourceType.dashboard] || [],
read: [],
},
},
......
......@@ -94,4 +94,4 @@ export const mapStateToProps = (state: GlobalState) => {
};
};
export default connect<StateFromProps>(mapStateToProps, null)(SearchFilter);
export default connect<StateFromProps>(mapStateToProps)(SearchFilter);
......@@ -19,7 +19,7 @@ interface OwnProps {
interface StateFromProps {
dashboards: DashboardResource[];
isLoading: boolean;
errorText: string;
errorText?: string;
}
export type TableDashboardResourceListProps = StateFromProps & OwnProps;
......@@ -62,7 +62,6 @@ export const mapStateToProps = (state: GlobalState) => {
};
};
export default connect<StateFromProps, {}, OwnProps>(
mapStateToProps,
null
)(TableDashboardResourceList);
export default connect<StateFromProps, {}, OwnProps>(mapStateToProps)(
TableDashboardResourceList
);
......@@ -16,8 +16,8 @@ import './styles.scss';
export interface StateFromProps {
issues: Issue[];
total: number;
allIssuesUrl: string;
total?: number;
allIssuesUrl?: string;
isLoading: boolean;
}
......
......@@ -77,7 +77,7 @@ export interface PropsFromState {
isLoading: boolean;
isLoadingDashboards: boolean;
numRelatedDashboards: number;
statusCode?: number;
statusCode: number | null;
tableData: TableMetadata;
}
export interface DispatchFromProps {
......
......@@ -6,6 +6,7 @@
"noImplicitAny": false,
"module": "esnext",
"target": "es2015",
"strictNullChecks": true,
"jsx": "react",
"typeRoots": ["node_modules/@types"],
"allowJs": true,
......
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