diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts index f040de1c318fd..e7338ced7def4 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts @@ -77,6 +77,20 @@ describe('Deprecations table', () => { ); }); + it('shows critical and warning deprecations count', () => { + const { find } = testBed; + const criticalDeprecations = esDeprecationsMockResponse.deprecations.filter( + (deprecation) => deprecation.isCritical + ); + const warningDeprecations = esDeprecationsMockResponse.deprecations.filter( + (deprecation) => deprecation.isCritical === false + ); + + expect(find('criticalDeprecationsCount').text()).toContain(criticalDeprecations.length); + + expect(find('warningDeprecationsCount').text()).toContain(warningDeprecations.length); + }); + describe('search bar', () => { it('filters results by "critical" status', async () => { const { find, actions } = testBed; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts index 6a97dd24286db..87875dc2ee2be 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts @@ -86,9 +86,10 @@ describe('Machine learning deprecation flyout', () => { // Reopen the flyout await actions.table.clickDeprecationRowAt('mlSnapshot', 0); - // Flyout actions should not be visible if deprecation was resolved - expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false); - expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false); + // Flyout actions should be disabled if deprecation was resolved + expect(find('mlSnapshotDetails.upgradeSnapshotButton').props().disabled).toBe(true); + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toContain('Upgrade complete'); + expect(find('mlSnapshotDetails.deleteSnapshotButton').props().disabled).toBe(true); }); it('handles upgrade failure', async () => { @@ -156,6 +157,11 @@ describe('Machine learning deprecation flyout', () => { // Reopen the flyout await actions.table.clickDeprecationRowAt('mlSnapshot', 0); + + // Flyout actions should be disabled if deprecation was resolved + expect(find('mlSnapshotDetails.deleteSnapshotButton').props().disabled).toBe(true); + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toContain('Deletion complete'); + expect(find('mlSnapshotDetails.upgradeSnapshotButton').props().disabled).toBe(true); }); it('handles delete failure', async () => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/app.tsx b/x-pack/plugins/upgrade_assistant/public/application/app.tsx index 864be6e5d996d..8a1ee9a91cabb 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -11,7 +11,7 @@ import { I18nStart, ScopedHistory } from 'src/core/public'; import { ApplicationStart } from 'kibana/public'; import { GlobalFlyout } from '../shared_imports'; -import { KibanaContextProvider } from '../shared_imports'; +import { KibanaContextProvider, APP_WRAPPER_CLASS } from '../shared_imports'; import { AppServicesContext } from '../types'; import { AppContextProvider, ContextValue, useAppContext } from './app_context'; import { ComingSoonPrompt } from './components/coming_soon_prompt'; @@ -62,7 +62,7 @@ export const RootComponent = ({ ...contextValue }: AppDependencies) => { return ( - + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx index ba72faf2f8c3f..5d61b076119e7 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx @@ -25,6 +25,7 @@ import { import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { MlSnapshotContext } from './context'; +import { SnapshotState } from './use_snapshot_state'; export interface FixSnapshotsFlyoutProps extends MlSnapshotContext { deprecation: EnrichedDeprecationInfo; @@ -38,12 +39,24 @@ const i18nTexts = { defaultMessage: 'Upgrade', } ), + upgradingButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.upgradingButtonLabel', + { + defaultMessage: 'Upgrading…', + } + ), retryUpgradeButtonLabel: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryUpgradeButtonLabel', { defaultMessage: 'Retry upgrade', } ), + upgradeResolvedButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteResolvupgradeResolvedButtonLabeledButtonLabel', + { + defaultMessage: 'Upgrade complete', + } + ), closeButtonLabel: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.closeButtonLabel', { @@ -56,6 +69,18 @@ const i18nTexts = { defaultMessage: 'Delete', } ), + deletingButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deletingButtonLabel', + { + defaultMessage: 'Deleting…', + } + ), + deleteResolvedButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteResolvedButtonLabel', + { + defaultMessage: 'Deletion complete', + } + ), retryDeleteButtonLabel: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryDeleteButtonLabel', { @@ -85,6 +110,44 @@ const i18nTexts = { ), }; +const getDeleteButtonLabel = (snapshotState: SnapshotState) => { + if (snapshotState.action === 'delete') { + if (snapshotState.error) { + return i18nTexts.retryDeleteButtonLabel; + } + + switch (snapshotState.status) { + case 'in_progress': + return i18nTexts.deletingButtonLabel; + case 'complete': + return i18nTexts.deleteResolvedButtonLabel; + case 'idle': + default: + return i18nTexts.deleteButtonLabel; + } + } + return i18nTexts.deleteButtonLabel; +}; + +const getUpgradeButtonLabel = (snapshotState: SnapshotState) => { + if (snapshotState.action === 'upgrade') { + if (snapshotState.error) { + return i18nTexts.retryUpgradeButtonLabel; + } + + switch (snapshotState.status) { + case 'in_progress': + return i18nTexts.upgradingButtonLabel; + case 'complete': + return i18nTexts.upgradeResolvedButtonLabel; + case 'idle': + default: + return i18nTexts.upgradeButtonLabel; + } + } + return i18nTexts.upgradeButtonLabel; +}; + export const FixSnapshotsFlyout = ({ deprecation, closeFlyout, @@ -92,9 +155,6 @@ export const FixSnapshotsFlyout = ({ upgradeSnapshot, deleteSnapshot, }: FixSnapshotsFlyoutProps) => { - // Flag used to hide certain parts of the UI if the deprecation has been resolved or is in progress - const isResolvable = ['idle', 'error'].includes(snapshotState.status); - const onUpgradeSnapshot = () => { upgradeSnapshot(); closeFlyout(); @@ -147,36 +207,40 @@ export const FixSnapshotsFlyout = ({ - {isResolvable && ( - - - - - {snapshotState.action === 'delete' && snapshotState.error - ? i18nTexts.retryDeleteButtonLabel - : i18nTexts.deleteButtonLabel} - - - - - {snapshotState.action === 'upgrade' && snapshotState.error - ? i18nTexts.retryUpgradeButtonLabel - : i18nTexts.upgradeButtonLabel} - - - - - )} + + + + + {getDeleteButtonLabel(snapshotState)} + + + + + {getUpgradeButtonLabel(snapshotState)} + + + + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx index a724922563e05..39f7c3d37ad52 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx @@ -68,7 +68,7 @@ export const useSnapshotState = ({ return; } - setSnapshotState(data); + setSnapshotState({ ...data, action: 'upgrade' }); // Only keep polling if it exists and is in progress. if (data?.status === 'in_progress') { @@ -97,7 +97,7 @@ export const useSnapshotState = ({ return; } - setSnapshotState(data); + setSnapshotState({ ...data, action: 'upgrade' }); updateSnapshotStatus(); }, [api, jobId, snapshotId, updateSnapshotStatus]); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx index 38367bd3cfaff..b714ae2ca2fd1 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations.tsx @@ -5,18 +5,44 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { withRouter, RouteComponentProps } from 'react-router-dom'; -import { EuiPageHeader, EuiSpacer, EuiPageContent } from '@elastic/eui'; +import { + EuiPageHeader, + EuiSpacer, + EuiPageContent, + EuiFlexGroup, + EuiFlexItem, + EuiHealth, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { EnrichedDeprecationInfo } from '../../../../common/types'; import { SectionLoading } from '../../../shared_imports'; import { useAppContext } from '../../app_context'; import { EsDeprecationsTable } from './es_deprecations_table'; import { EsDeprecationErrors } from './es_deprecation_errors'; import { NoDeprecationsPrompt } from '../shared'; +const getDeprecationCountByLevel = (deprecations: EnrichedDeprecationInfo[]) => { + const criticalDeprecations: EnrichedDeprecationInfo[] = []; + const warningDeprecations: EnrichedDeprecationInfo[] = []; + + deprecations.forEach((deprecation) => { + if (deprecation.isCritical) { + criticalDeprecations.push(deprecation); + return; + } + warningDeprecations.push(deprecation); + }); + + return { + criticalDeprecations: criticalDeprecations.length, + warningDeprecations: warningDeprecations.length, + }; +}; + const i18nTexts = { pageTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageTitle', { defaultMessage: 'Elasticsearch deprecation warnings', @@ -28,6 +54,20 @@ const i18nTexts = { isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { defaultMessage: 'Loading deprecations…', }), + getCriticalStatusLabel: (count: number) => + i18n.translate('xpack.upgradeAssistant.esDeprecations.criticalStatusLabel', { + defaultMessage: 'Critical: {count}', + values: { + count, + }, + }), + getWarningStatusLabel: (count: number) => + i18n.translate('xpack.upgradeAssistant.esDeprecations.warningStatusLabel', { + defaultMessage: 'Warning: {count}', + values: { + count, + }, + }), }; export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => { @@ -41,6 +81,13 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => { isInitialRequest, } = api.useLoadEsDeprecations(); + const deprecationsCountByLevel: { + warningDeprecations: number; + criticalDeprecations: number; + } = useMemo(() => getDeprecationCountByLevel(esDeprecations?.deprecations || []), [ + esDeprecations?.deprecations, + ]); + useEffect(() => { breadcrumbs.setBreadcrumbs('esDeprecations'); }, [breadcrumbs]); @@ -82,7 +129,20 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => { return (
- + + + + + {i18nTexts.getCriticalStatusLabel(deprecationsCountByLevel.criticalDeprecations)} + + + + + {i18nTexts.getWarningStatusLabel(deprecationsCountByLevel.warningDeprecations)} + + + + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx index dd187f19d5e96..aaf55f08e1bbc 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiBadge, EuiLink } from '@elastic/eui'; +import { EuiBadge, EuiLink, EuiText, EuiTextColor, EuiToolTip } from '@elastic/eui'; import { EnrichedDeprecationInfo } from '../../../../common/types'; import { DEPRECATION_TYPE_MAP } from '../constants'; import { DeprecationTableColumns } from '../types'; @@ -26,6 +26,18 @@ const i18nTexts = { defaultMessage: 'Critical', } ), + manualCellLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.manualCellLabel', + { + defaultMessage: 'Manual', + } + ), + manualCellTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.manualCellTooltipLabel', + { + defaultMessage: 'Resolve this deprecation manually.', + } + ), }; export const EsDeprecationsTableCells: React.FunctionComponent = ({ @@ -66,7 +78,13 @@ export const EsDeprecationsTableCells: React.FunctionComponent = ({ return <>{resolutionTableCell}; } - return <>{''}; + return ( + + + {i18nTexts.manualCellLabel} + + + ); } // Default behavior: render value or empty string if undefined diff --git a/x-pack/plugins/upgrade_assistant/public/shared_imports.ts b/x-pack/plugins/upgrade_assistant/public/shared_imports.ts index 64b52065f63e6..fefa6fd60f806 100644 --- a/x-pack/plugins/upgrade_assistant/public/shared_imports.ts +++ b/x-pack/plugins/upgrade_assistant/public/shared_imports.ts @@ -22,4 +22,6 @@ export { KibanaContextProvider } from '../../../../src/plugins/kibana_react/publ export { DataPublicPluginStart } from '../../../../src/plugins/data/public'; +export { APP_WRAPPER_CLASS } from '../../../../src/core/public'; + export const useKibana = () => _useKibana();