-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor UA Overview to support step-completion #111243
Changes from 13 commits
7f9becd
554bcdc
642e540
66b72a6
a979937
25d0491
27d9f08
768cd1a
22436ca
810c03f
0a14a6c
3340c42
0e2dc7f
9be3802
7ccb6ab
5b4f0d5
6e3bbea
b5b082b
f40b250
416aa3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { act } from 'react-dom/test-utils'; | ||
|
||
/** | ||
* These helpers are intended to be used in conjunction with jest.useFakeTimers(). | ||
*/ | ||
|
||
const flushPromiseJobQueue = async () => { | ||
// See https://stackoverflow.com/questions/52177631/jest-timer-and-promise-dont-work-well-settimeout-and-async-function | ||
await Promise.resolve(); | ||
}; | ||
|
||
export const advanceTime = async (ms: number) => { | ||
await act(async () => { | ||
jest.advanceTimersByTime(ms); | ||
await flushPromiseJobQueue(); | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -44,6 +44,37 @@ describe('Overview - Fix deprecation issues step', () => { | |||||
server.restore(); | ||||||
}); | ||||||
|
||||||
describe('Step status', () => { | ||||||
test(`It's complete when there are no critical deprecations`, async () => { | ||||||
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsEmpty); | ||||||
|
||||||
await act(async () => { | ||||||
const deprecationService = deprecationsServiceMock.createStartContract(); | ||||||
deprecationService.getAllDeprecations = jest.fn().mockRejectedValue([]); | ||||||
|
||||||
testBed = await setupOverviewPage({ | ||||||
services: { | ||||||
core: { | ||||||
deprecations: deprecationService, | ||||||
}, | ||||||
}, | ||||||
}); | ||||||
}); | ||||||
|
||||||
const { exists, component } = testBed; | ||||||
|
||||||
component.update(); | ||||||
|
||||||
expect(exists(`fixIssuesStep-complete`)).toBe(true); | ||||||
}); | ||||||
|
||||||
test('Its incomplete when there are critical deprecations', async () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
const { exists } = testBed; | ||||||
|
||||||
expect(exists(`fixIssuesStep-incomplete`)).toBe(true); | ||||||
}); | ||||||
}); | ||||||
|
||||||
describe('ES deprecations', () => { | ||||||
test('Shows deprecation warning and critical counts', () => { | ||||||
const { exists, find } = testBed; | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -33,14 +33,49 @@ describe('Overview - Fix deprecation logs step', () => { | |||||
server.restore(); | ||||||
}); | ||||||
|
||||||
describe('Step status', () => { | ||||||
sabarasaba marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
test(`It's complete when there are no deprecation logs since last checkpoint`, async () => { | ||||||
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(true)); | ||||||
|
||||||
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ | ||||||
count: 0, | ||||||
}); | ||||||
|
||||||
await act(async () => { | ||||||
testBed = await setupOverviewPage(); | ||||||
}); | ||||||
|
||||||
const { exists, component } = testBed; | ||||||
|
||||||
component.update(); | ||||||
|
||||||
expect(exists(`fixLogsStep-complete`)).toBe(true); | ||||||
}); | ||||||
|
||||||
test('Its incomplete when there are deprecation logs since last checkpoint', async () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(true)); | ||||||
|
||||||
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ | ||||||
count: 5, | ||||||
}); | ||||||
|
||||||
await act(async () => { | ||||||
testBed = await setupOverviewPage(); | ||||||
}); | ||||||
|
||||||
const { exists, component } = testBed; | ||||||
|
||||||
component.update(); | ||||||
|
||||||
expect(exists(`fixLogsStep-incomplete`)).toBe(true); | ||||||
}); | ||||||
}); | ||||||
|
||||||
describe('Step 1 - Toggle log writing and collecting', () => { | ||||||
test('toggles deprecation logging', async () => { | ||||||
const { find, actions } = testBed; | ||||||
|
||||||
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse({ | ||||||
isDeprecationLogIndexingEnabled: false, | ||||||
isDeprecationLoggingEnabled: false, | ||||||
}); | ||||||
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(false)); | ||||||
|
||||||
expect(find('deprecationLoggingToggle').props()['aria-checked']).toBe(true); | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
import React, { useEffect } from 'react'; | ||
import moment from 'moment-timezone'; | ||
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n/react'; | ||
import { i18n } from '@kbn/i18n'; | ||
|
@@ -20,22 +20,39 @@ import { | |
EuiCallOut, | ||
} from '@elastic/eui'; | ||
|
||
import { CloudBackupStatus } from '../../../../../common/types'; | ||
import { UseRequestResponse } from '../../../../shared_imports'; | ||
import { ResponseError } from '../../../lib/api'; | ||
|
||
export type CloudBackupStatusResponse = UseRequestResponse<CloudBackupStatus, ResponseError>; | ||
import { useAppContext } from '../../../app_context'; | ||
|
||
interface Props { | ||
cloudBackupStatusResponse: UseRequestResponse<CloudBackupStatus, ResponseError>; | ||
cloudSnapshotsUrl: string; | ||
setIsComplete: (isComplete: boolean) => void; | ||
} | ||
|
||
export const CloudBackup: React.FunctionComponent<Props> = ({ | ||
cloudBackupStatusResponse, | ||
cloudSnapshotsUrl, | ||
setIsComplete, | ||
}) => { | ||
const { isInitialRequest, isLoading, error, data, resendRequest } = cloudBackupStatusResponse; | ||
const { | ||
services: { api }, | ||
} = useAppContext(); | ||
|
||
const { | ||
isInitialRequest, | ||
isLoading, | ||
error, | ||
data, | ||
resendRequest, | ||
} = api.useLoadCloudBackupStatus(); | ||
|
||
// Tell overview whether the step is complete or not. | ||
useEffect(() => { | ||
// Loading shouldn't invalidate the previous state. | ||
if (!isLoading) { | ||
// An error should invalidate the previous state. | ||
setIsComplete((!error && data?.isBackedUp) ?? false); | ||
} | ||
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain why this is needed? |
||
}, [error, isLoading, data]); | ||
|
||
if (isInitialRequest && isLoading) { | ||
return <EuiLoadingContent data-test-subj="cloudBackupLoading" lines={3} />; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
* 2.0. | ||
*/ | ||
|
||
import React, { FunctionComponent } from 'react'; | ||
import React, { FunctionComponent, useEffect, useMemo } from 'react'; | ||
import { useHistory } from 'react-router-dom'; | ||
|
||
import { | ||
|
@@ -60,18 +60,34 @@ const i18nTexts = { | |
}), | ||
}; | ||
|
||
export const ESDeprecationStats: FunctionComponent = () => { | ||
interface Props { | ||
setIsFixed: (isFixed: boolean) => void; | ||
} | ||
|
||
export const ESDeprecationStats: FunctionComponent<Props> = ({ setIsFixed }) => { | ||
const history = useHistory(); | ||
const { | ||
services: { api }, | ||
} = useAppContext(); | ||
|
||
const { data: esDeprecations, isLoading, error } = api.useLoadEsDeprecations(); | ||
|
||
const warningDeprecations = | ||
esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical === false) || []; | ||
const criticalDeprecations = | ||
esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical) || []; | ||
const warningDeprecations = useMemo( | ||
() => | ||
esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical === false) || [], | ||
[esDeprecations] | ||
); | ||
const criticalDeprecations = useMemo( | ||
() => esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical) || [], | ||
[esDeprecations] | ||
); | ||
|
||
useEffect(() => { | ||
if (!isLoading && !error) { | ||
setIsFixed(criticalDeprecations.length === 0); | ||
} | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this still needed? |
||
}, [criticalDeprecations, isLoading, error]); | ||
|
||
const hasWarnings = warningDeprecations.length > 0; | ||
const hasCritical = criticalDeprecations.length > 0; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the flakiness in #111255 was due to not flushing this promise queue.