From 0d3ce8126e28dc63eb5552437da0ddcc29ff46a1 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 27 Jul 2021 15:32:13 -0400 Subject: [PATCH 01/18] wip: remove tabs from ES deprecations page --- .../public/doc_links/doc_links_service.ts | 1 + .../plugins/upgrade_assistant/common/types.ts | 19 +- .../public/application/app.tsx | 2 +- .../application/components/constants.tsx | 23 ++ .../deprecation_tab_content.tsx | 228 ---------------- .../deprecations/deprecation_group_item.tsx | 75 ----- .../deprecations/index_table.test.tsx | 99 ------- .../deprecations/index_table.tsx | 200 -------------- .../deprecations/list.test.tsx | 129 --------- .../es_deprecations/deprecations/list.tsx | 120 -------- .../es_deprecations/es_deprecations.tsx | 257 +++++++----------- .../es_deprecations/es_deprecations_table.tsx | 170 ++++++++++++ .../components/overview/es_stats.tsx | 24 +- .../public/application/components/types.ts | 2 - .../server/lib/es_migration_apis.test.ts | 5 +- .../server/lib/es_migration_apis.ts | 125 +++++++-- .../server/routes/cluster_checkup.ts | 9 +- 17 files changed, 410 insertions(+), 1078 deletions(-) delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 7152c7eb3cb1b..532b0266c17ea 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -198,6 +198,7 @@ export class DocLinksService { transportSettings: `${ELASTICSEARCH_DOCS}modules-network.html#common-network-settings`, typesRemoval: `${ELASTICSEARCH_DOCS}removal-of-types.html`, deprecationLogging: `${ELASTICSEARCH_DOCS}logging.html#deprecation-logging`, + deprecationInfo: `${ELASTICSEARCH_DOCS}migration-api-deprecation.html`, }, siem: { guide: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index 88fa103bace89..7496ef4cae51c 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -5,6 +5,10 @@ * 2.0. */ +import { + MigrationDeprecationInfoDeprecation, + MigrationDeprecationInfoResponse, +} from '@elastic/elasticsearch/api/types'; import { SavedObject, SavedObjectAttributes } from 'src/core/public'; export enum ReindexStep { @@ -183,13 +187,6 @@ export interface DeprecationInfo { export interface IndexSettingsDeprecationInfo { [indexName: string]: DeprecationInfo[]; } -export interface DeprecationAPIResponse { - cluster_settings: DeprecationInfo[]; - ml_settings: DeprecationInfo[]; - node_settings: DeprecationInfo[]; - index_settings: IndexSettingsDeprecationInfo; -} - export interface ReindexAction { type: 'reindex'; /** @@ -212,15 +209,17 @@ export interface IndexSettingAction { type: 'indexSetting'; deprecatedSettings: string[]; } -export interface EnrichedDeprecationInfo extends DeprecationInfo { +export interface EnrichedDeprecationInfo + extends Omit { + type: keyof MigrationDeprecationInfoResponse; + isCritical: boolean; index?: string; correctiveAction?: ReindexAction | MlAction | IndexSettingAction; } export interface UpgradeAssistantStatus { readyForUpgrade: boolean; - cluster: EnrichedDeprecationInfo[]; - indices: EnrichedDeprecationInfo[]; + deprecations: EnrichedDeprecationInfo[]; } export interface ResolveIndexResponseFromES { diff --git a/x-pack/plugins/upgrade_assistant/public/application/app.tsx b/x-pack/plugins/upgrade_assistant/public/application/app.tsx index 8086d3322c0e9..e342bceade0ec 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -30,7 +30,7 @@ const App: React.FunctionComponent = () => { return ( - + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx index 7b4bee75bc757..c7f974fab6a89 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx @@ -7,6 +7,8 @@ import { IconColor } from '@elastic/eui'; import { invert } from 'lodash'; +import { i18n } from '@kbn/i18n'; + import { DeprecationInfo } from '../../../common/types'; export const LEVEL_MAP: { [level: string]: number } = { @@ -26,3 +28,24 @@ export const COLOR_MAP: { [level: string]: IconColor } = { }; export const DEPRECATIONS_PER_PAGE = 25; + +export const DEPRECATION_TYPE_MAP = { + cluster_settings: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.clusterDeprecationTypeLabel', + { + defaultMessage: 'Cluster', + } + ), + index_settings: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexDeprecationTypeLabel', + { + defaultMessage: 'Index', + } + ), + node_settings: i18n.translate('xpack.upgradeAssistant.esDeprecations.nodeDeprecationTypeLabel', { + defaultMessage: 'Node', + }), + ml_settings: i18n.translate('xpack.upgradeAssistant.esDeprecations.mlDeprecationTypeLabel', { + defaultMessage: 'Machine Learning', + }), +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx deleted file mode 100644 index 8be407371f038..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_tab_content.tsx +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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 { find, groupBy } from 'lodash'; -import React, { FunctionComponent, useState, useEffect } from 'react'; -import { i18n } from '@kbn/i18n'; - -import { EuiSpacer, EuiHorizontalRule } from '@elastic/eui'; - -import { EnrichedDeprecationInfo } from '../../../../common/types'; -import { SectionLoading } from '../../../shared_imports'; -import { GroupByOption, LevelFilterOption, UpgradeAssistantTabProps } from '../types'; -import { - NoDeprecationsPrompt, - SearchBar, - DeprecationPagination, - DeprecationListBar, -} from '../shared'; -import { DEPRECATIONS_PER_PAGE } from '../constants'; -import { EsDeprecationErrors } from './es_deprecation_errors'; -import { EsDeprecationAccordion } from './deprecations'; - -const i18nTexts = { - isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { - defaultMessage: 'Loading deprecations…', - }), -}; - -export interface CheckupTabProps extends UpgradeAssistantTabProps { - checkupLabel: string; -} - -export const createDependenciesFilter = (level: LevelFilterOption, search: string = '') => { - const conditions: Array<(dep: EnrichedDeprecationInfo) => boolean> = []; - - if (level !== 'all') { - conditions.push((dep: EnrichedDeprecationInfo) => dep.level === level); - } - - if (search.length > 0) { - conditions.push((dep) => { - try { - // 'i' is used for case-insensitive matching - const searchReg = new RegExp(search, 'i'); - return searchReg.test(dep.message); - } catch (e) { - // ignore any regexp errors. - return true; - } - }); - } - - // Return true if every condition function returns true (boolean AND) - return (dep: EnrichedDeprecationInfo) => conditions.map((c) => c(dep)).every((t) => t); -}; - -const filterDeprecations = ( - deprecations: EnrichedDeprecationInfo[] = [], - currentFilter: LevelFilterOption, - search: string -) => deprecations.filter(createDependenciesFilter(currentFilter, search)); - -const groupDeprecations = ( - deprecations: EnrichedDeprecationInfo[], - currentFilter: LevelFilterOption, - search: string, - currentGroupBy: GroupByOption -) => groupBy(filterDeprecations(deprecations, currentFilter, search), currentGroupBy); - -const getPageCount = ( - deprecations: EnrichedDeprecationInfo[], - currentFilter: LevelFilterOption, - search: string, - currentGroupBy: GroupByOption -) => - Math.ceil( - Object.keys(groupDeprecations(deprecations, currentFilter, search, currentGroupBy)).length / - DEPRECATIONS_PER_PAGE - ); - -/** - * Displays a list of deprecations that are filterable and groupable. Can be used for cluster, - * nodes, or indices deprecations. - */ -export const DeprecationTabContent: FunctionComponent = ({ - checkupLabel, - deprecations, - error, - isLoading, - refreshCheckupData, - navigateToOverviewPage, -}) => { - const [currentFilter, setCurrentFilter] = useState('all'); - const [search, setSearch] = useState(''); - const [currentGroupBy, setCurrentGroupBy] = useState(GroupByOption.message); - const [expandState, setExpandState] = useState({ - forceExpand: false, - expandNumber: 0, - }); - const [currentPage, setCurrentPage] = useState(0); - - const getAvailableGroupByOptions = () => { - if (!deprecations) { - return []; - } - - return Object.keys(GroupByOption).filter((opt) => find(deprecations, opt)) as GroupByOption[]; - }; - - const setExpandAll = (expandAll: boolean) => { - setExpandState({ forceExpand: expandAll, expandNumber: expandState.expandNumber + 1 }); - }; - - useEffect(() => { - if (deprecations) { - const pageCount = getPageCount(deprecations, currentFilter, search, currentGroupBy); - - if (currentPage >= pageCount) { - setCurrentPage(0); - } - } - }, [currentPage, deprecations, currentFilter, search, currentGroupBy]); - - if (deprecations && deprecations.length === 0) { - return ( -
- -
- ); - } - - let content: React.ReactNode; - - if (isLoading) { - content = {i18nTexts.isLoading}; - } else if (deprecations?.length) { - const levelGroups = groupBy(deprecations, 'level'); - const levelToDeprecationCountMap = Object.keys(levelGroups).reduce((counts, level) => { - counts[level] = levelGroups[level].length; - return counts; - }, {} as Record); - - const filteredDeprecations = filterDeprecations(deprecations, currentFilter, search); - - const groups = groupDeprecations(deprecations, currentFilter, search, currentGroupBy); - - content = ( -
- - - - - - - <> - {Object.keys(groups) - .sort() - // Apply pagination - .slice(currentPage * DEPRECATIONS_PER_PAGE, (currentPage + 1) * DEPRECATIONS_PER_PAGE) - .map((groupName, index) => [ -
- - -
, - ])} - - {/* Only show pagination if we have more than DEPRECATIONS_PER_PAGE. */} - {Object.keys(groups).length > DEPRECATIONS_PER_PAGE && ( - <> - - - - - )} - -
- ); - } else if (error) { - content = ; - } - - return ( -
- - - {content} -
- ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx deleted file mode 100644 index 66e2a5d25998b..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/deprecation_group_item.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 React, { FunctionComponent } from 'react'; -import { EuiAccordion, EuiBadge } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import { EnrichedDeprecationInfo } from '../../../../../common/types'; -import { DeprecationHealth } from '../../shared'; -import { GroupByOption } from '../../types'; -import { EsDeprecationList } from './list'; -import { LEVEL_MAP } from '../../constants'; - -export interface Props { - id: string; - deprecations: EnrichedDeprecationInfo[]; - title: string; - currentGroupBy: GroupByOption; - forceExpand: boolean; - dataTestSubj: string; -} - -/** - * A single accordion item for a grouped deprecation item. - */ -export const EsDeprecationAccordion: FunctionComponent = ({ - id, - deprecations, - title, - currentGroupBy, - forceExpand, - dataTestSubj, -}) => { - const hasIndices = Boolean( - currentGroupBy === GroupByOption.message && - (deprecations as EnrichedDeprecationInfo[]).filter((d) => d.index).length - ); - const numIndices = hasIndices ? deprecations.length : null; - - return ( - - {hasIndices && ( - <> - - {numIndices}{' '} - - -   - - )} - LEVEL_MAP[d.level])} - /> - - } - > - - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx deleted file mode 100644 index f4ac573d86b11..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 React from 'react'; -import { shallow } from 'enzyme'; - -import { IndexDeprecationTableProps, IndexDeprecationTable } from './index_table'; - -describe('IndexDeprecationTable', () => { - const defaultProps = { - indices: [ - { index: 'index1', details: 'Index 1 deets', correctiveAction: { type: 'reindex' } }, - { index: 'index2', details: 'Index 2 deets', correctiveAction: { type: 'reindex' } }, - { index: 'index3', details: 'Index 3 deets', correctiveAction: { type: 'reindex' } }, - ], - } as IndexDeprecationTableProps; - - // Relying pretty heavily on EUI to implement the table functionality correctly. - // This test simply verifies that the props passed to EuiBaseTable are the ones - // expected. - test('render', () => { - expect(shallow()).toMatchInlineSnapshot(` - - `); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx deleted file mode 100644 index 6b0f94ea24bc7..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_table.tsx +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 { sortBy } from 'lodash'; -import React from 'react'; - -import { EuiBasicTable } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { - EnrichedDeprecationInfo, - IndexSettingAction, - ReindexAction, -} from '../../../../../common/types'; -import { AppContext } from '../../../app_context'; -import { ReindexButton } from './reindex'; -import { FixIndexSettingsButton } from './index_settings'; - -const PAGE_SIZES = [10, 25, 50, 100, 250, 500, 1000]; - -export interface IndexDeprecationDetails { - index: string; - correctiveAction?: EnrichedDeprecationInfo['correctiveAction']; - details?: string; -} - -export interface IndexDeprecationTableProps { - indices: IndexDeprecationDetails[]; -} - -interface IndexDeprecationTableState { - sortField: string; - sortDirection: 'asc' | 'desc'; - pageIndex: number; - pageSize: number; -} - -export class IndexDeprecationTable extends React.Component< - IndexDeprecationTableProps, - IndexDeprecationTableState -> { - constructor(props: IndexDeprecationTableProps) { - super(props); - - this.state = { - sortField: 'index', - sortDirection: 'asc', - pageIndex: 0, - pageSize: 10, - }; - } - - public render() { - const { pageIndex, pageSize, sortField, sortDirection } = this.state; - - const columns = [ - { - field: 'index', - name: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.deprecations.indexTable.indexColumnLabel', - { - defaultMessage: 'Index', - } - ), - sortable: true, - }, - { - field: 'details', - name: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.deprecations.indexTable.detailsColumnLabel', - { - defaultMessage: 'Details', - } - ), - }, - ]; - - const actionsColumn = this.generateActionsColumn(); - - if (actionsColumn) { - columns.push(actionsColumn as any); - } - - const sorting = { - sort: { field: sortField as keyof IndexDeprecationDetails, direction: sortDirection }, - }; - const pagination = { - pageIndex, - pageSize, - ...this.pageSizeOptions(), - }; - - return ( - { - return { - 'data-test-subj': `indexTableRow-${indexDetails.index}`, - }; - }} - /> - ); - } - - private getRows() { - const { sortField, sortDirection, pageIndex, pageSize } = this.state; - const { indices } = this.props; - - let sorted = sortBy(indices, sortField); - if (sortDirection === 'desc') { - sorted = sorted.reverse(); - } - - const start = pageIndex * pageSize; - return sorted.slice(start, start + pageSize); - } - - private onTableChange = (tableProps: any) => { - this.setState({ - sortField: tableProps.sort.field, - sortDirection: tableProps.sort.direction, - pageIndex: tableProps.page.index, - pageSize: tableProps.page.size, - }); - }; - - private pageSizeOptions() { - const { indices } = this.props; - const totalItemCount = indices.length; - - // If we only have that smallest page size, don't show any page size options. - if (totalItemCount <= PAGE_SIZES[0]) { - return { totalItemCount, pageSizeOptions: [], hidePerPageOptions: true }; - } - - // Keep a size option if the # of items is larger than the previous option. - // This avoids having a long list of useless page sizes. - const pageSizeOptions = PAGE_SIZES.filter((perPage, idx) => { - return idx === 0 || totalItemCount > PAGE_SIZES[idx - 1]; - }); - - return { totalItemCount, pageSizeOptions, hidePerPageOptions: false }; - } - - private generateActionsColumn() { - // NOTE: this naive implementation assumes all indices in the table - // should show the reindex button or fix indices button. This should work for known use cases. - const { indices } = this.props; - const showReindexButton = Boolean(indices.find((i) => i.correctiveAction?.type === 'reindex')); - const showFixSettingsButton = Boolean( - indices.find((i) => i.correctiveAction?.type === 'indexSetting') - ); - - if (showReindexButton === false && showFixSettingsButton === false) { - return null; - } - - return { - actions: [ - { - render(indexDep: IndexDeprecationDetails) { - if (showReindexButton) { - return ( - - {({ http, docLinks }) => { - return ( - - ); - }} - - ); - } - - return ( - - ); - }, - }, - ], - }; - } -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx deleted file mode 100644 index 2bfa8119e41bc..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.test.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 { shallow } from 'enzyme'; -import React from 'react'; - -import { EnrichedDeprecationInfo } from '../../../../../common/types'; -import { GroupByOption } from '../../types'; -import { EsDeprecationList } from './list'; - -describe('EsDeprecationList', () => { - describe('group by message', () => { - const defaultProps = { - deprecations: [ - { message: 'Issue 1', url: '', level: 'warning' }, - { message: 'Issue 1', url: '', level: 'warning' }, - ] as EnrichedDeprecationInfo[], - currentGroupBy: GroupByOption.message, - }; - - test('shows simple messages when index field is not present', () => { - expect(shallow()).toMatchInlineSnapshot(` -
- - -
- `); - }); - - test('shows index deprecation when index field is present', () => { - // Add index fields to deprecation items - const props = { - ...defaultProps, - deprecations: defaultProps.deprecations.map((d, index) => ({ - ...d, - index: index.toString(), - })), - }; - const wrapper = shallow(); - expect(wrapper).toMatchInlineSnapshot(` - - `); - }); - }); - - describe('group by index', () => { - const defaultProps = { - deprecations: [ - { message: 'Issue 1', index: 'index1', url: '', level: 'warning' }, - { message: 'Issue 2', index: 'index1', url: '', level: 'warning' }, - ] as EnrichedDeprecationInfo[], - currentGroupBy: GroupByOption.index, - }; - - test('shows detailed messages', () => { - expect(shallow()).toMatchInlineSnapshot(` -
- - -
- `); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx deleted file mode 100644 index 7b543a7e94b33..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/list.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 React, { FunctionComponent } from 'react'; - -import { DeprecationInfo, EnrichedDeprecationInfo } from '../../../../../common/types'; -import { GroupByOption } from '../../types'; - -import { COLOR_MAP, LEVEL_MAP } from '../../constants'; -import { DeprecationCell } from './cell'; -import { IndexDeprecationDetails, IndexDeprecationTable } from './index_table'; - -const sortByLevelDesc = (a: DeprecationInfo, b: DeprecationInfo) => { - return -1 * (LEVEL_MAP[a.level] - LEVEL_MAP[b.level]); -}; - -/** - * Used to show a single deprecation message with any detailed information. - */ -const MessageDeprecation: FunctionComponent<{ - deprecation: EnrichedDeprecationInfo; -}> = ({ deprecation }) => { - const items = []; - - if (deprecation.details) { - items.push({ body: deprecation.details }); - } - - return ( - - ); -}; - -/** - * Used to show a single (simple) deprecation message with any detailed information. - */ -const SimpleMessageDeprecation: FunctionComponent<{ deprecation: EnrichedDeprecationInfo }> = ({ - deprecation, -}) => { - const items = []; - - if (deprecation.details) { - items.push({ body: deprecation.details }); - } - - return ( - - ); -}; - -interface IndexDeprecationProps { - deprecation: EnrichedDeprecationInfo; - indices: IndexDeprecationDetails[]; -} - -/** - * Shows a single deprecation and table of affected indices with details for each index. - */ -const IndexDeprecation: FunctionComponent = ({ deprecation, indices }) => { - return ( - - - - ); -}; - -/** - * A list of deprecations that is either shown as individual deprecation cells or as a - * deprecation summary for a list of indices. - */ -export const EsDeprecationList: FunctionComponent<{ - deprecations: EnrichedDeprecationInfo[]; - currentGroupBy: GroupByOption; -}> = ({ deprecations, currentGroupBy }) => { - // If we're grouping by message and the first deprecation has an index field, show an index - // group deprecation. Otherwise, show each message. - if (currentGroupBy === GroupByOption.message && deprecations[0].index !== undefined) { - // We assume that every deprecation message is the same issue (since they have the same - // message) and that each deprecation will have an index associated with it. - - const indices = deprecations.map((dep) => ({ - index: dep.index!, - details: dep.details, - correctiveAction: dep.correctiveAction, - })); - return ; - } else if (currentGroupBy === GroupByOption.index) { - return ( -
- {deprecations.sort(sortByLevelDesc).map((dep, index) => ( - - ))} -
- ); - } else { - return ( -
- {deprecations.sort(sortByLevelDesc).map((dep, index) => ( - - ))} -
- ); - } -}; 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 4fc4d691c4038..53681061f32e6 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,36 +5,38 @@ * 2.0. */ -import React, { useMemo, useEffect, useState } from 'react'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; +import React, { useEffect } from 'react'; import { EuiButton, EuiButtonEmpty, EuiPageHeader, - EuiTabbedContent, - EuiTabbedContentTab, EuiToolTip, - EuiNotificationBadge, EuiSpacer, + EuiPageContent, + EuiFlexItem, + EuiFlexGroup, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { SectionLoading } from '../../../shared_imports'; import { useAppContext } from '../../app_context'; -import { UpgradeAssistantTabProps, EsTabs, TelemetryState } from '../types'; -import { DeprecationTabContent } from './deprecation_tab_content'; +import { EsDeprecationsTable } from './es_deprecations_table'; const i18nTexts = { pageTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageTitle', { - defaultMessage: 'Elasticsearch', + defaultMessage: 'Elasticsearch deprecation issues', }), pageDescription: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageDescription', { defaultMessage: - 'Review the deprecated cluster and index settings. You must resolve any critical issues before upgrading.', + 'Review your deprecation issues. Reindex indices or follow step-by-step instructions for any issues in need of manual configuration.', }), docLinkText: i18n.translate('xpack.upgradeAssistant.esDeprecations.docLinkText', { defaultMessage: 'Documentation', }), + isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { + defaultMessage: 'Loading deprecations…', + }), backupDataButton: { label: i18n.translate('xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel', { defaultMessage: 'Back up your data', @@ -43,166 +45,101 @@ const i18nTexts = { defaultMessage: 'Take a snapshot before you make any changes.', }), }, - clusterTab: { - tabName: i18n.translate('xpack.upgradeAssistant.esDeprecations.clusterTabLabel', { - defaultMessage: 'Cluster', - }), - deprecationType: i18n.translate('xpack.upgradeAssistant.esDeprecations.clusterLabel', { - defaultMessage: 'cluster', - }), - }, - indicesTab: { - tabName: i18n.translate('xpack.upgradeAssistant.esDeprecations.indicesTabLabel', { - defaultMessage: 'Indices', - }), - deprecationType: i18n.translate('xpack.upgradeAssistant.esDeprecations.indexLabel', { - defaultMessage: 'index', + deprecationIssuesButton: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.deprecationIssuesButtonLabel', { + defaultMessage: 'Learn more about deprecation issues', }), }, }; -interface MatchParams { - tabName: EsTabs; -} - -export const EsDeprecationsContent = withRouter( - ({ - match: { - params: { tabName }, - }, - history, - }: RouteComponentProps) => { - const [telemetryState, setTelemetryState] = useState(TelemetryState.Complete); - - const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); - - const { data: checkupData, isLoading, error, resendRequest } = api.useLoadUpgradeStatus(); - - const onTabClick = (selectedTab: EuiTabbedContentTab) => { - history.push(`/es_deprecations/${selectedTab.id}`); - }; - - const tabs = useMemo(() => { - const commonTabProps: UpgradeAssistantTabProps = { - error, - isLoading, - refreshCheckupData: resendRequest, - navigateToOverviewPage: () => history.push('/overview'), - }; - - return [ - { - id: 'cluster', - 'data-test-subj': 'upgradeAssistantClusterTab', - name: ( - - {i18nTexts.clusterTab.tabName} - {checkupData && checkupData.cluster.length > 0 && ( - <> - {' '} - {checkupData.cluster.length} - - )} - - ), - content: ( - - ), - }, - { - id: 'indices', - 'data-test-subj': 'upgradeAssistantIndicesTab', - name: ( - - {i18nTexts.indicesTab.tabName} - {checkupData && checkupData.indices.length > 0 && ( - <> - {' '} - {checkupData.indices.length} - - )} - - ), - content: ( - - ), - }, - ]; - }, [checkupData, error, history, isLoading, resendRequest]); - - useEffect(() => { - breadcrumbs.setBreadcrumbs('esDeprecations'); - }, [breadcrumbs]); - - useEffect(() => { - if (isLoading === false) { - setTelemetryState(TelemetryState.Running); - - async function sendTelemetryData() { - await api.sendTelemetryData({ - [tabName]: true, - }); - setTelemetryState(TelemetryState.Complete); - } - - sendTelemetryData(); - } - }, [api, tabName, isLoading]); +export const EsDeprecationsContent = () => { + // const [telemetryState, setTelemetryState] = useState(TelemetryState.Complete); + + const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); + const { data: esDeprecations, isLoading, error, resendRequest } = api.useLoadUpgradeStatus(); + + useEffect(() => { + breadcrumbs.setBreadcrumbs('esDeprecations'); + }, [breadcrumbs]); + + // TODO: refactor telemetry as we no longer need to keep track of tabs + // useEffect(() => { + // if (isLoading === false) { + // setTelemetryState(TelemetryState.Running); + + // async function sendTelemetryData() { + // await api.sendTelemetryData({ + // [tabName]: true, + // }); + // setTelemetryState(TelemetryState.Complete); + // } + + // sendTelemetryData(); + // } + // }, [api, tabName, isLoading]); + + if (error) { + // TODO handle error + return null; + } + + if (isLoading) { return ( - <> - - {i18nTexts.docLinkText} - , - ]} - > - + + {i18nTexts.isLoading} + + ); + } + + return ( +
+ + {i18nTexts.docLinkText} + , + ]} + > + + + + + {i18nTexts.backupDataButton.label} + + + + - {i18nTexts.backupDataButton.label} + {i18nTexts.deprecationIssuesButton.label} - - - - - - tab.id === tabName)} - /> - - ); - } -); + + + + + + + +
+ ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx new file mode 100644 index 0000000000000..eede057507ac1 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -0,0 +1,170 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiInMemoryTable, + EuiBasicTableColumn, + EuiButton, + EuiBadge, + EuiLink, + SearchFilterConfig, +} from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../common/types'; +import { DEPRECATION_TYPE_MAP } from '../constants'; + +const i18nTexts = { + typeColumnTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeColumnTitle', { + defaultMessage: 'Type', + }), + sourceColumnTitle: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.sourceColumnTitle', + { + defaultMessage: 'Source', + } + ), + issueColumnTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle', { + defaultMessage: 'Issue', + }), + statusColumnTitle: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', + { + defaultMessage: 'Status', + } + ), + criticalBadgeLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.criticalBadgeLabel', + { + defaultMessage: 'critical', + } + ), + refreshButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.refreshButtonLabel', + { + defaultMessage: 'Refresh', + } + ), + noDeprecationsMessage: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.noDeprecationsMessage', + { + defaultMessage: 'No Elasticsearch deprecations found', + } + ), + typeFilterLabel: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeFilterLabel', { + defaultMessage: 'Type', + }), + criticalFilterLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.table.criticalFilterLabel', + { + defaultMessage: 'Critical', + } + ), +}; + +interface Props { + deprecations?: EnrichedDeprecationInfo[]; + reload: () => void; +} + +export const EsDeprecationsTable: React.FunctionComponent = ({ deprecations, reload }) => { + const columns: Array> = [ + { + field: 'type', + name: i18nTexts.typeColumnTitle, + truncateText: true, + sortable: true, + render: (type: 'cluster_settings' | 'index_settings' | 'node_settings' | 'ml_settings') => + DEPRECATION_TYPE_MAP[type], + }, + { + field: 'index', + name: i18nTexts.sourceColumnTitle, + truncateText: true, + sortable: true, + }, + { + field: 'message', + name: i18nTexts.issueColumnTitle, + truncateText: true, + sortable: true, + // TODO handle onClick + render: (message: string) => {message}, + }, + { + field: 'isCritical', + name: i18nTexts.statusColumnTitle, + truncateText: true, + sortable: true, + render: (isCritical: boolean) => { + if (isCritical) { + return {i18nTexts.criticalBadgeLabel}; + } + return null; + }, + }, + ]; + + const pagination = { + initialPageSize: 20, + pageSizeOptions: [10, 20, 50], + }; + + const searchConfig = { + box: { + incremental: true, + }, + filters: [ + { + type: 'is', + field: 'isCritical', + name: i18nTexts.criticalFilterLabel, + }, + { + type: 'field_value_selection', + field: 'type', + name: i18nTexts.typeFilterLabel, + multiSelect: false, + options: (Object.keys(DEPRECATION_TYPE_MAP) as Array< + keyof typeof DEPRECATION_TYPE_MAP + >).map((type) => ({ + value: type, + name: DEPRECATION_TYPE_MAP[type], + })), + }, + ] as SearchFilterConfig[], + toolsRight: [ + + {i18nTexts.refreshButtonLabel} + , + ], + }; + + return ( + ({ + 'data-test-subj': 'row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="esDeprecationsTable" + message={i18nTexts.noDeprecationsMessage} + tableLayout="auto" + /> + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/es_stats.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/es_stats.tsx index 3152639d3f10d..59e857c0f1393 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/es_stats.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/es_stats.tsx @@ -57,13 +57,11 @@ const i18nTexts = { criticalDeprecations, }, }), - getTotalDeprecationsTooltip: (clusterCount: number, indexCount: number) => + getTotalDeprecationsTooltip: (totalDeprecations: number) => i18n.translate('xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip', { - defaultMessage: - 'This cluster is using {clusterCount} deprecated cluster settings and {indexCount} deprecated index settings', + defaultMessage: 'This cluster has {totalDeprecations} critical deprecations', values: { - clusterCount, - indexCount, + totalDeprecations, }, }), }; @@ -77,9 +75,9 @@ export const ESDeprecationStats: FunctionComponent = ({ history }) => { const { data: esDeprecations, isLoading, error } = api.useLoadUpgradeStatus(); - const allDeprecations = esDeprecations?.cluster?.concat(esDeprecations?.indices) ?? []; + const allDeprecations = esDeprecations?.deprecations ?? []; const criticalDeprecations = allDeprecations.filter( - (deprecation) => deprecation.level === 'critical' + (deprecation) => deprecation.isCritical === true ); return ( @@ -92,7 +90,7 @@ export const ESDeprecationStats: FunctionComponent = ({ history }) => { {i18nTexts.viewDeprecationsLink} @@ -111,10 +109,7 @@ export const ESDeprecationStats: FunctionComponent = ({ history }) => { <> {i18nTexts.totalDeprecationsTitle}{' '} = ({ history }) => {

{isLoading ? i18nTexts.loadingText - : i18nTexts.getTotalDeprecationsTooltip( - esDeprecations?.cluster.length ?? 0, - esDeprecations?.indices.length ?? 0 - )} + : i18nTexts.getTotalDeprecationsTooltip(allDeprecations.length)}

)} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts index 8e2bf20b845a3..bda77c65fcf1b 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -44,5 +44,3 @@ export enum TelemetryState { Running, Complete, } - -export type EsTabs = 'cluster' | 'indices'; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts index 6477ce738c084..6f5e0245c3859 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts @@ -8,7 +8,7 @@ import _ from 'lodash'; import { RequestEvent } from '@elastic/elasticsearch/lib/Transport'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { DeprecationAPIResponse } from '../../common/types'; +import { MigrationDeprecationInfoResponse } from '@elastic/elasticsearch/api/types'; import { getUpgradeAssistantStatus } from './es_migration_apis'; import fakeDeprecations from './__fixtures__/fake_deprecations.json'; @@ -32,12 +32,11 @@ describe('getUpgradeAssistantStatus', () => { }; // @ts-expect-error mock data is too loosely typed - const deprecationsResponse: DeprecationAPIResponse = _.cloneDeep(fakeDeprecations); + const deprecationsResponse: MigrationDeprecationInfoResponse = _.cloneDeep(fakeDeprecations); const esClient = elasticsearchServiceMock.createScopedClusterClient(); esClient.asCurrentUser.migration.deprecations.mockResolvedValue( - // @ts-expect-error not full interface asApiResponse(deprecationsResponse) ); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index 85cde9069d60f..dc50482822909 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -5,47 +5,127 @@ * 2.0. */ +import { + MigrationDeprecationInfoDeprecation, + MigrationDeprecationInfoResponse, +} from '@elastic/elasticsearch/api/types'; import { IScopedClusterClient } from 'src/core/server'; import { indexSettingDeprecations } from '../../common/constants'; -import { - DeprecationAPIResponse, - EnrichedDeprecationInfo, - UpgradeAssistantStatus, -} from '../../common/types'; +import { EnrichedDeprecationInfo, UpgradeAssistantStatus } from '../../common/types'; import { esIndicesStateCheck } from './es_indices_state_check'; export async function getUpgradeAssistantStatus( dataClient: IScopedClusterClient ): Promise { - const { body: deprecations } = await dataClient.asCurrentUser.migration.deprecations(); + // const { body: deprecations } = await dataClient.asCurrentUser.migration.deprecations(); + + // TODO temp mock data + const deprecations: MigrationDeprecationInfoResponse = { + cluster_settings: [ + { + level: 'warning', + message: "A Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + ], + node_settings: [ + { + level: 'critical', + message: "B Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + ], + index_settings: { + logs: [ + { + level: 'warning', + message: "C Index name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_index_name', + details: "This index is named [logs:apache], which contains the illegal character ':'.", + }, + ], + }, + ml_settings: [ + { + level: 'critical', + message: "D Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + ], + }; - const cluster = getClusterDeprecations(deprecations); - const indices = await getCombinedIndexInfos(deprecations, dataClient); + const getCombinedDeprecations = async () => { + const indices = await getCombinedIndexInfos(deprecations, dataClient); + + return Object.keys(deprecations).reduce((combinedDeprecations, deprecationType) => { + if (deprecationType === 'index_settings') { + combinedDeprecations = [...combinedDeprecations, ...indices]; + } else { + const deprecationsByType = deprecations[ + deprecationType as keyof MigrationDeprecationInfoResponse + ] as MigrationDeprecationInfoDeprecation[]; + + const enrichedDeprecationInfo = deprecationsByType.map( + ({ details, level, message, url }) => { + return { + details, + message, + url, + type: deprecationType as keyof MigrationDeprecationInfoResponse, + isCritical: level === 'critical', + correctiveAction: getCorrectiveAction(message), + }; + } + ); + + combinedDeprecations = [...combinedDeprecations, ...enrichedDeprecationInfo]; + } - const criticalWarnings = cluster.concat(indices).filter((d) => d.level === 'critical'); + return combinedDeprecations; + }, [] as EnrichedDeprecationInfo[]); + }; + + const combinedDeprecations = await getCombinedDeprecations(); + const criticalWarnings = combinedDeprecations.filter(({ isCritical }) => isCritical === true); + const sortByCritical = (a: EnrichedDeprecationInfo, b: EnrichedDeprecationInfo) => { + return a.isCritical === b.isCritical ? 0 : a.isCritical ? -1 : 1; + }; return { readyForUpgrade: criticalWarnings.length === 0, - cluster, - indices, + deprecations: combinedDeprecations.sort(sortByCritical), }; } // Reformats the index deprecations to an array of deprecation warnings extended with an index field. const getCombinedIndexInfos = async ( - deprecations: DeprecationAPIResponse, + deprecations: MigrationDeprecationInfoResponse, dataClient: IScopedClusterClient ) => { const indices = Object.keys(deprecations.index_settings).reduce( (indexDeprecations, indexName) => { return indexDeprecations.concat( deprecations.index_settings[indexName].map( - (d) => + ({ details, message, url, level }) => ({ - ...d, + details, + message, + url, index: indexName, - correctiveAction: getCorrectiveAction(d.message), + type: 'index_settings', + isCritical: level === 'critical', + correctiveAction: getCorrectiveAction(message), } as EnrichedDeprecationInfo) ) ); @@ -70,20 +150,7 @@ const getCombinedIndexInfos = async ( return indices as EnrichedDeprecationInfo[]; }; -const getClusterDeprecations = (deprecations: DeprecationAPIResponse) => { - const combinedDeprecations = deprecations.cluster_settings - .concat(deprecations.ml_settings) - .concat(deprecations.node_settings); - - return combinedDeprecations.map((deprecation) => { - return { - ...deprecation, - correctiveAction: getCorrectiveAction(deprecation.message), - }; - }) as EnrichedDeprecationInfo[]; -}; - -const getCorrectiveAction = (message: string) => { +const getCorrectiveAction = (message: string): EnrichedDeprecationInfo['correctiveAction'] => { const indexSettingDeprecation = Object.values(indexSettingDeprecations).find( ({ deprecationMessage }) => deprecationMessage === message ); diff --git a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts index 31026be55fa30..eb091b89c66cf 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts @@ -11,6 +11,7 @@ import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; import { RouteDependencies } from '../types'; import { reindexActionsFactory } from '../lib/reindexing/reindex_actions'; import { reindexServiceFactory } from '../lib/reindexing'; +import { handleEsError } from '../shared_imports'; export function registerClusterCheckupRoutes({ router, licensing, log }: RouteDependencies) { router.get( @@ -40,7 +41,7 @@ export function registerClusterCheckupRoutes({ router, licensing, log }: RouteDe log, licensing ); - const indexNames = status.indices + const indexNames = status.deprecations .filter(({ index }) => typeof index !== 'undefined') .map(({ index }) => index as string); @@ -50,11 +51,7 @@ export function registerClusterCheckupRoutes({ router, licensing, log }: RouteDe body: status, }); } catch (e) { - if (e.statusCode === 403) { - return response.forbidden(e.message); - } - - throw e; + return handleEsError({ error: e, response }); } } ) From 9215c6846cee2b33633c26f1742d61b2b98d8a44 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 28 Jul 2021 12:54:51 -0400 Subject: [PATCH 02/18] fix telemetry --- .../schema/xpack_plugins.json | 16 +++-------- .../plugins/upgrade_assistant/common/types.ts | 11 +++----- .../es_deprecations/es_deprecations.tsx | 28 ++++++++----------- .../public/application/components/types.ts | 5 ---- .../lib/telemetry/es_ui_open_apis.test.ts | 10 ++----- .../server/lib/telemetry/es_ui_open_apis.ts | 14 +++------- .../lib/telemetry/usage_collector.test.ts | 6 ++-- .../server/lib/telemetry/usage_collector.ts | 18 +++--------- .../server/routes/telemetry.test.ts | 12 ++++---- .../server/routes/telemetry.ts | 8 ++---- .../telemetry_saved_object_type.ts | 6 +--- 11 files changed, 41 insertions(+), 93 deletions(-) diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 270117eed8499..3c9dce63f2cb9 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -2283,8 +2283,7 @@ "error_fix_action": { "type": "long", "_meta": { - "description": - "Number of times the user used the fix action of an error displayed in the workspace." + "description": "Number of times the user used the fix action of an error displayed in the workspace." } }, "open_formula_popover": { @@ -2531,8 +2530,7 @@ "error_fix_action": { "type": "long", "_meta": { - "description": - "Number of times the user used the fix action of an error displayed in the workspace." + "description": "Number of times the user used the fix action of an error displayed in the workspace." } }, "open_formula_popover": { @@ -5923,16 +5921,10 @@ }, "ui_open": { "properties": { - "cluster": { + "elasticsearch": { "type": "long", "_meta": { - "description": "Number of times a user viewed the list of Elasticsearch cluster deprecations." - } - }, - "indices": { - "type": "long", - "_meta": { - "description": "Number of times a user viewed the list of Elasticsearch index deprecations." + "description": "Number of times a user viewed the list of Elasticsearch deprecations." } }, "overview": { diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index 7496ef4cae51c..ce2f25d629fd2 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -120,13 +120,12 @@ export enum IndexGroup { // Telemetry types export const UPGRADE_ASSISTANT_TYPE = 'upgrade-assistant-telemetry'; export const UPGRADE_ASSISTANT_DOC_ID = 'upgrade-assistant-telemetry'; -export type UIOpenOption = 'overview' | 'cluster' | 'indices' | 'kibana'; +export type UIOpenOption = 'overview' | 'elasticsearch' | 'kibana'; export type UIReindexOption = 'close' | 'open' | 'start' | 'stop'; export interface UIOpen { overview: boolean; - cluster: boolean; - indices: boolean; + elasticsearch: boolean; kibana: boolean; } @@ -140,8 +139,7 @@ export interface UIReindex { export interface UpgradeAssistantTelemetrySavedObject { ui_open: { overview: number; - cluster: number; - indices: number; + elasticsearch: number; kibana: number; }; ui_reindex: { @@ -155,8 +153,7 @@ export interface UpgradeAssistantTelemetrySavedObject { export interface UpgradeAssistantTelemetry { ui_open: { overview: number; - cluster: number; - indices: number; + elasticsearch: number; kibana: number; }; ui_reindex: { 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 53681061f32e6..ab654b00194a1 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 @@ -53,8 +53,6 @@ const i18nTexts = { }; export const EsDeprecationsContent = () => { - // const [telemetryState, setTelemetryState] = useState(TelemetryState.Complete); - const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); const { data: esDeprecations, isLoading, error, resendRequest } = api.useLoadUpgradeStatus(); @@ -63,21 +61,17 @@ export const EsDeprecationsContent = () => { breadcrumbs.setBreadcrumbs('esDeprecations'); }, [breadcrumbs]); - // TODO: refactor telemetry as we no longer need to keep track of tabs - // useEffect(() => { - // if (isLoading === false) { - // setTelemetryState(TelemetryState.Running); - - // async function sendTelemetryData() { - // await api.sendTelemetryData({ - // [tabName]: true, - // }); - // setTelemetryState(TelemetryState.Complete); - // } - - // sendTelemetryData(); - // } - // }, [api, tabName, isLoading]); + useEffect(() => { + if (isLoading === false) { + async function sendTelemetryData() { + await api.sendTelemetryData({ + elasticsearch: true, + }); + } + + sendTelemetryData(); + } + }, [api, isLoading]); if (error) { // TODO handle error diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts index bda77c65fcf1b..e930e41573bcf 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -39,8 +39,3 @@ export enum GroupByOption { index = 'index', node = 'node', } - -export enum TelemetryState { - Running, - Complete, -} diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts index a911c5810dd0a..3db855fabffb9 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts @@ -22,8 +22,7 @@ describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => { await upsertUIOpenOption({ overview: true, - cluster: true, - indices: true, + elasticsearch: true, kibana: true, savedObjects: { createInternalRepository: () => internalRepo } as any, }); @@ -37,12 +36,7 @@ describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => { expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, - ['ui_open.cluster'] - ); - expect(internalRepo.incrementCounter).toHaveBeenCalledWith( - UPGRADE_ASSISTANT_TYPE, - UPGRADE_ASSISTANT_DOC_ID, - ['ui_open.indices'] + ['ui_open.elasticsearch'] ); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts index ab876828a343c..3d463fe4b03ed 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts @@ -33,8 +33,7 @@ type UpsertUIOpenOptionDependencies = UIOpen & { savedObjects: SavedObjectsServi export async function upsertUIOpenOption({ overview, - cluster, - indices, + elasticsearch, savedObjects, kibana, }: UpsertUIOpenOptionDependencies): Promise { @@ -42,12 +41,8 @@ export async function upsertUIOpenOption({ await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'overview' }); } - if (cluster) { - await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'cluster' }); - } - - if (indices) { - await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'indices' }); + if (elasticsearch) { + await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'elasticsearch' }); } if (kibana) { @@ -56,8 +51,7 @@ export async function upsertUIOpenOption({ return { overview, - cluster, - indices, + elasticsearch, kibana, }; } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts index 30195f6652fb2..6dffa0afffcd4 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts @@ -49,8 +49,7 @@ describe('Upgrade Assistant Usage Collector', () => { return { attributes: { 'ui_open.overview': 10, - 'ui_open.cluster': 20, - 'ui_open.indices': 30, + 'ui_open.elasticsearch': 20, 'ui_open.kibana': 15, 'ui_reindex.close': 1, 'ui_reindex.open': 4, @@ -89,8 +88,7 @@ describe('Upgrade Assistant Usage Collector', () => { expect(upgradeAssistantStats).toEqual({ ui_open: { overview: 10, - cluster: 20, - indices: 30, + elasticsearch: 20, kibana: 15, }, ui_reindex: { diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts index 564cd69c042b8..fb3e69a9588f6 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts @@ -71,8 +71,7 @@ export async function fetchUpgradeAssistantMetrics( const defaultTelemetrySavedObject = { ui_open: { overview: 0, - cluster: 0, - indices: 0, + elasticsearch: 0, kibana: 0, }, ui_reindex: { @@ -90,8 +89,7 @@ export async function fetchUpgradeAssistantMetrics( return { ui_open: { overview: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.overview', 0), - cluster: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.cluster', 0), - indices: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.indices', 0), + elasticsearch: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.elasticsearch', 0), kibana: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.kibana', 0), }, ui_reindex: { @@ -140,18 +138,10 @@ export function registerUpgradeAssistantUsageCollector({ }, }, ui_open: { - cluster: { + elasticsearch: { type: 'long', _meta: { - description: - 'Number of times a user viewed the list of Elasticsearch cluster deprecations.', - }, - }, - indices: { - type: 'long', - _meta: { - description: - 'Number of times a user viewed the list of Elasticsearch index deprecations.', + description: 'Number of times a user viewed the list of Elasticsearch deprecations.', }, }, overview: { diff --git a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts index 05ad542ec9c00..578cceb702751 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts @@ -44,8 +44,8 @@ describe('Upgrade Assistant Telemetry API', () => { it('returns correct payload with single option', async () => { const returnPayload = { overview: true, - cluster: false, - indices: false, + elasticsearch: false, + kibana: false, }; (upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload); @@ -65,8 +65,8 @@ describe('Upgrade Assistant Telemetry API', () => { it('returns correct payload with multiple option', async () => { const returnPayload = { overview: true, - cluster: true, - indices: true, + elasticsearch: true, + kibana: true, }; (upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload); @@ -79,8 +79,8 @@ describe('Upgrade Assistant Telemetry API', () => { createRequestMock({ body: { overview: true, - cluster: true, - indices: true, + elasticsearch: true, + kibana: true, }, }), kibanaResponseFactory diff --git a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts index 4e9b4b9a472a9..d083b38c7c240 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts @@ -18,19 +18,17 @@ export function registerTelemetryRoutes({ router, getSavedObjectsService }: Rout validate: { body: schema.object({ overview: schema.boolean({ defaultValue: false }), - cluster: schema.boolean({ defaultValue: false }), - indices: schema.boolean({ defaultValue: false }), + elasticsearch: schema.boolean({ defaultValue: false }), kibana: schema.boolean({ defaultValue: false }), }), }, }, async (ctx, request, response) => { - const { cluster, indices, overview, kibana } = request.body; + const { elasticsearch, overview, kibana } = request.body; return response.ok({ body: await upsertUIOpenOption({ savedObjects: getSavedObjectsService(), - cluster, - indices, + elasticsearch, overview, kibana, }), diff --git a/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts b/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts index f76c07da678da..42d5d339dd050 100644 --- a/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts +++ b/x-pack/plugins/upgrade_assistant/server/saved_object_types/telemetry_saved_object_type.ts @@ -21,11 +21,7 @@ export const telemetrySavedObjectType: SavedObjectsType = { type: 'long', null_value: 0, }, - cluster: { - type: 'long', - null_value: 0, - }, - indices: { + elasticsearch: { type: 'long', null_value: 0, }, From 32ac42e5134fce0e5e8bcb5a67e06126abd82571 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 28 Jul 2021 19:52:20 -0400 Subject: [PATCH 03/18] wip: implement flyout functionality --- .../translations/translations/ja-JP.json | 70 ++-- .../translations/translations/zh-CN.json | 85 ++--- .../public/application/app.tsx | 10 +- .../components/es_deprecations/_index.scss | 2 +- .../_index.scss | 1 - .../deprecation_types/default/flyout.tsx | 96 ++++++ .../default/index.ts} | 2 +- .../deprecation_types/default/table_row.tsx | 74 +++++ .../index.tsx | 5 +- .../index_settings/flyout.tsx | 146 ++++++++ .../index_settings}/index.ts | 2 +- .../index_settings/status_table_cell.tsx | 80 +++++ .../index_settings/table_row.tsx | 100 ++++++ .../ml_snapshots/context.tsx | 65 ++++ .../deprecation_types/ml_snapshots/flyout.tsx | 166 ++++++++++ .../ml_snapshots}/index.ts | 2 +- .../ml_snapshots/status_table_cell.tsx | 122 +++++++ .../ml_snapshots/table_row.tsx | 95 ++++++ .../ml_snapshots/use_snapshot_state.tsx | 6 +- .../reindex/_index.scss | 1 - .../deprecation_types/reindex/context.tsx | 61 ++++ .../checklist_step.test.tsx.snap | 0 .../__snapshots__/warning_step.test.tsx.snap | 0 .../reindex/flyout/_index.scss | 0 .../reindex/flyout/_step_progress.scss | 0 .../reindex/flyout/checklist_step.test.tsx | 2 +- .../reindex/flyout/checklist_step.tsx | 2 +- .../reindex/flyout/container.tsx | 142 ++++++++ .../reindex/flyout/index.tsx | 8 + .../reindex/flyout/progress.test.tsx | 2 +- .../reindex/flyout/progress.tsx | 2 +- .../reindex/flyout/step_progress.tsx | 0 .../reindex/flyout/warning_step.test.tsx | 0 .../reindex/flyout/warning_step_checkbox.tsx | 0 .../reindex/flyout/warnings_step.tsx | 0 .../reindex}/index.tsx | 2 +- .../reindex/status_table_cell.tsx | 143 ++++++++ .../deprecation_types/reindex/table_row.tsx | 95 ++++++ .../reindex/use_reindex_state.tsx | 181 ++++++++++ .../es_deprecations/deprecations/_cell.scss | 4 - .../es_deprecations/deprecations/cell.tsx | 146 -------- .../deprecations/index_settings/button.tsx | 54 --- .../remove_settings_provider.tsx | 131 -------- .../deprecations/ml_snapshots/button.tsx | 125 ------- .../ml_snapshots/fix_snapshots_flyout.tsx | 181 ---------- .../deprecations/reindex/_button.scss | 5 - .../deprecations/reindex/button.tsx | 244 -------------- .../deprecations/reindex/flyout/container.tsx | 172 ---------- .../reindex/polling_service.test.ts | 87 ----- .../deprecations/reindex/polling_service.ts | 169 ---------- .../es_deprecations/es_deprecations.tsx | 8 +- .../es_deprecations/es_deprecations_table.tsx | 313 +++++++++++------- .../es_deprecations_table_cells.tsx | 64 ++++ .../kibana_deprecations.tsx | 2 +- .../components/overview/overview.tsx | 2 +- .../public/application/components/types.ts | 23 +- .../public/application/lib/api.ts | 33 +- .../application/lib/es_deprecation_errors.ts | 3 +- .../public/shared_imports.ts | 1 + .../server/lib/es_migration_apis.ts | 13 +- 60 files changed, 1967 insertions(+), 1583 deletions(-) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/_index.scss (60%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/reindex/index.tsx => deprecation_types/default/index.ts} (84%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/index.tsx (55%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/ml_snapshots => deprecation_types/index_settings}/index.ts (82%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/index_settings => deprecation_types/ml_snapshots}/index.ts (83%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/ml_snapshots/use_snapshot_state.tsx (96%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/_index.scss (57%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/__snapshots__/warning_step.test.tsx.snap (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/_index.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/_step_progress.scss (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/checklist_step.test.tsx (97%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/checklist_step.tsx (98%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/progress.test.tsx (99%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/progress.tsx (99%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/step_progress.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/warning_step.test.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/warning_step_checkbox.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations => deprecation_types}/reindex/flyout/warnings_step.tsx (100%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/{deprecations/reindex/flyout => deprecation_types/reindex}/index.tsx (84%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ffdd031cfef06..c6dd8ce2529fd 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6530,7 +6530,6 @@ "xpack.canvas.error.esService.fieldsFetchErrorMessage": "「{index}」の Elasticsearch フィールドを取得できませんでした", "xpack.canvas.error.esService.indicesFetchErrorMessage": "Elasticsearch インデックスを取得できませんでした", "xpack.canvas.error.RenderWithFn.renderErrorMessage": "「{functionName}」のレンダリングが失敗しました", - "expressionRepeatImage.error.repeatImage.missingMaxArgument": "{emptyImageArgument} を指定する場合は、{maxArgument} を設定する必要があります", "xpack.canvas.error.useCloneWorkpad.cloneFailureErrorMessage": "ワークパッドのクローンを作成できませんでした", "xpack.canvas.error.useCreateWorkpad.uploadFailureErrorMessage": "ワークパッドをアップロードできませんでした", "xpack.canvas.error.useDeleteWorkpads.deleteFailureErrorMessage": "すべてのワークパッドを削除できませんでした", @@ -6703,10 +6702,6 @@ "xpack.canvas.functions.if.args.elseHelpText": "条件が {BOOLEAN_FALSE} の場合の戻り値です。指定されておらず、条件が満たされていない場合は、元の {CONTEXT} が戻されます。", "xpack.canvas.functions.if.args.thenHelpText": "条件が {BOOLEAN_TRUE} の場合の戻り値です。指定されておらず、条件が満たされている場合は、元の {CONTEXT} が戻されます。", "xpack.canvas.functions.ifHelpText": "条件付きロジックを実行します。", - "expressionImage.functions.image.args.dataurlHelpText": "画像の {https} {URL} または {BASE64} データ {URL} です。", - "expressionImage.functions.image.args.modeHelpText": "{contain} はサイズに合わせて拡大・縮小して画像全体を表示し、{cover} はコンテナーを画像で埋め、必要に応じて両端や下をクロップします。{stretch} は画像の高さと幅をコンテナーの 100% になるよう変更します。", - "expressionImage.functions.image.invalidImageModeErrorMessage": "「mode」は「{contain}」、「{cover}」、または「{stretch}」でなければなりません", - "expressionImage.functions.imageHelpText": "画像を表示します。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", "xpack.canvas.functions.joinRows.args.columnHelpText": "値を抽出する列またはフィールド。", "xpack.canvas.functions.joinRows.args.distinctHelpText": "一意の値のみを抽出しますか?", "xpack.canvas.functions.joinRows.args.quoteHelpText": "各抽出された値を囲む引用符文字。", @@ -6724,11 +6719,6 @@ "xpack.canvas.functions.markdown.args.fontHelpText": "コンテンツの {CSS} フォントプロパティです。たとえば、{fontFamily} または {fontWeight} です。", "xpack.canvas.functions.markdown.args.openLinkHelpText": "新しいタブでリンクを開くためのtrue/false値。デフォルト値は「false」です。「true」に設定するとすべてのリンクが新しいタブで開くようになります。", "xpack.canvas.functions.markdownHelpText": "{MARKDOWN} テキストをレンダリングするエレメントを追加します。ヒント:単一の数字、メトリック、テキストの段落には {markdownFn} 関数を使います。", - "expressionMetric.functions.metric.args.labelFontHelpText": "ラベルの {CSS} フォントプロパティです。例:{FONT_FAMILY} または {FONT_WEIGHT}。", - "expressionMetric.functions.metric.args.labelHelpText": "メトリックを説明するテキストです。", - "expressionMetric.functions.metric.args.metricFontHelpText": "メトリックの {CSS} フォントプロパティです。例:{FONT_FAMILY} または {FONT_WEIGHT}。", - "expressionMetric.functions.metric.args.metricFormatHelpText": "{NUMERALJS} 形式の文字列。例:{example1} または {example2}。", - "expressionMetric.functions.metricHelpText": "ラベルの上に数字を表示します。", "xpack.canvas.functions.neq.args.valueHelpText": "{CONTEXT} と比較される値です。", "xpack.canvas.functions.neqHelpText": "{CONTEXT} が引数と等しくないかを戻します。", "xpack.canvas.functions.pie.args.fontHelpText": "ラベルの {CSS} フォントプロパティです。例:{FONT_FAMILY} または {FONT_WEIGHT}。", @@ -6776,11 +6766,6 @@ "xpack.canvas.functions.render.args.containerStyleHelpText": "背景、境界、透明度を含む、コンテナーのスタイルです。", "xpack.canvas.functions.render.args.cssHelpText": "このエレメントの対象となるカスタム {CSS} のブロックです。", "xpack.canvas.functions.renderHelpText": "{CONTEXT}を特定のエレメントとしてレンダリングし、背景と境界のスタイルなどのエレメントレベルのオプションを設定します。", - "expressionRepeatImage.functions.repeatImage.args.emptyImageHelpText": "この画像のエレメントについて、{CONTEXT}および{maxArg}パラメーターの差異を解消します。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", - "expressionRepeatImage.functions.repeatImage.args.imageHelpText": "繰り返す画像です。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", - "expressionRepeatImage.functions.repeatImage.args.maxHelpText": "画像が繰り返される最高回数です。", - "expressionRepeatImage.functions.repeatImage.args.sizeHelpText": "画像の高さまたは幅のピクセル単位での最高値です。画像が縦長の場合、この関数は高さを制限します。", - "expressionRepeatImage.functions.repeatImageHelpText": "繰り返し画像エレメントを構成します。", "xpack.canvas.functions.replace.args.flagsHelpText": "フラグを指定します。{url}を参照してください。", "xpack.canvas.functions.replace.args.patternHelpText": "{JS} 正規表現のテキストまたはパターンです。例:{example}。ここではキャプチャグループを使用できます。", "xpack.canvas.functions.replace.args.replacementHelpText": "文字列の一致する部分の代わりです。キャプチャグループはノードによってアクセス可能です。例:{example}。", @@ -6959,22 +6944,14 @@ "xpack.canvas.renderer.dropdownFilter.matchAllOptionLabel": "すべて", "xpack.canvas.renderer.embeddable.displayName": "埋め込み可能", "xpack.canvas.renderer.embeddable.helpDescription": "Kibana の他の部分から埋め込み可能な保存済みオブジェクトをレンダリングします", - "expressionImage.renderer.image.displayName": "画像", - "expressionImage.renderer.image.helpDescription": "画像をレンダリングします", "xpack.canvas.renderer.markdown.displayName": "マークダウン", "xpack.canvas.renderer.markdown.helpDescription": "{MARKDOWN} インプットを使用して {HTML} を表示", - "expressionMetric.renderer.metric.displayName": "メトリック", - "expressionMetric.renderer.metric.helpDescription": "ラベルの上に数字をレンダリングします", "xpack.canvas.renderer.pie.displayName": "円グラフ", "xpack.canvas.renderer.pie.helpDescription": "データから円グラフをレンダリングします", "xpack.canvas.renderer.plot.displayName": "座標プロット", "xpack.canvas.renderer.plot.helpDescription": "データから XY プロットをレンダリングします", "xpack.canvas.renderer.progress.displayName": "進捗インジケーター", "xpack.canvas.renderer.progress.helpDescription": "エレメントのパーセンテージを示す進捗インジケーターをレンダリングします", - "expressionRepeatImage.renderer.repeatImage.displayName": "画像の繰り返し", - "expressionRepeatImage.renderer.repeatImage.helpDescription": "画像を指定回数繰り返し表示します", - "expressionShape.renderer.shape.displayName": "形状", - "expressionShape.renderer.shape.helpDescription": "基本的な図形をレンダリングします", "xpack.canvas.renderer.table.displayName": "データテーブル", "xpack.canvas.renderer.table.helpDescription": "表形式データを {HTML} としてレンダリングします", "xpack.canvas.renderer.text.displayName": "プレインテキスト", @@ -7458,6 +7435,29 @@ "xpack.canvas.workpadTemplates.table.descriptionColumnTitle": "説明", "xpack.canvas.workpadTemplates.table.nameColumnTitle": "テンプレート名", "xpack.canvas.workpadTemplates.table.tagsColumnTitle": "タグ", + "expressionRepeatImage.error.repeatImage.missingMaxArgument": "{emptyImageArgument} を指定する場合は、{maxArgument} を設定する必要があります", + "expressionRepeatImage.functions.repeatImage.args.emptyImageHelpText": "この画像のエレメントについて、{CONTEXT}および{maxArg}パラメーターの差異を解消します。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", + "expressionRepeatImage.functions.repeatImage.args.imageHelpText": "繰り返す画像です。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", + "expressionRepeatImage.functions.repeatImage.args.maxHelpText": "画像が繰り返される最高回数です。", + "expressionRepeatImage.functions.repeatImage.args.sizeHelpText": "画像の高さまたは幅のピクセル単位での最高値です。画像が縦長の場合、この関数は高さを制限します。", + "expressionRepeatImage.functions.repeatImageHelpText": "繰り返し画像エレメントを構成します。", + "expressionRepeatImage.renderer.repeatImage.displayName": "画像の繰り返し", + "expressionRepeatImage.renderer.repeatImage.helpDescription": "画像を指定回数繰り返し表示します", + "expressionImage.functions.image.args.dataurlHelpText": "画像の {https} {URL} または {BASE64} データ {URL} です。", + "expressionImage.functions.image.args.modeHelpText": "{contain} はサイズに合わせて拡大・縮小して画像全体を表示し、{cover} はコンテナーを画像で埋め、必要に応じて両端や下をクロップします。{stretch} は画像の高さと幅をコンテナーの 100% になるよう変更します。", + "expressionImage.functions.image.invalidImageModeErrorMessage": "「mode」は「{contain}」、「{cover}」、または「{stretch}」でなければなりません", + "expressionImage.functions.imageHelpText": "画像を表示します。画像アセットは{BASE64}データ{URL}として提供するか、部分式で渡します。", + "expressionImage.renderer.image.displayName": "画像", + "expressionImage.renderer.image.helpDescription": "画像をレンダリングします", + "expressionMetric.functions.metric.args.labelFontHelpText": "ラベルの {CSS} フォントプロパティです。例:{FONT_FAMILY} または {FONT_WEIGHT}。", + "expressionMetric.functions.metric.args.labelHelpText": "メトリックを説明するテキストです。", + "expressionMetric.functions.metric.args.metricFontHelpText": "メトリックの {CSS} フォントプロパティです。例:{FONT_FAMILY} または {FONT_WEIGHT}。", + "expressionMetric.functions.metric.args.metricFormatHelpText": "{NUMERALJS} 形式の文字列。例:{example1} または {example2}。", + "expressionMetric.functions.metricHelpText": "ラベルの上に数字を表示します。", + "expressionMetric.renderer.metric.displayName": "メトリック", + "expressionMetric.renderer.metric.helpDescription": "ラベルの上に数字をレンダリングします", + "expressionShape.renderer.shape.displayName": "形状", + "expressionShape.renderer.shape.helpDescription": "基本的な図形をレンダリングします", "expressionError.errorComponent.description": "表現が失敗し次のメッセージが返されました:", "expressionError.errorComponent.title": "おっと!表現が失敗しました", "expressionError.renderer.debug.displayName": "デバッグ", @@ -25035,24 +25035,13 @@ "xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibanaの廃止予定", "xpack.upgradeAssistant.breadcrumb.overviewLabel": "アップグレードアシスタント", "xpack.upgradeAssistant.checkupTab.changeFiltersShowMoreLabel": "より多く表示させるにはフィルターを変更します。", - "xpack.upgradeAssistant.checkupTab.confirmationModal.removeButtonLabel": "削除", "xpack.upgradeAssistant.checkupTab.controls.filterBar.criticalButtonLabel": "重大", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIndexLabel": "インデックス別", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIssueLabel": "問題別", "xpack.upgradeAssistant.checkupTab.deprecations.criticalActionTooltip": "アップグレード前にこの問題を解決してください。", "xpack.upgradeAssistant.checkupTab.deprecations.criticalLabel": "重大", - "xpack.upgradeAssistant.checkupTab.deprecations.documentationButtonLabel": "ドキュメント", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.detailsColumnLabel": "詳細", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.indexColumnLabel": "インデックス", "xpack.upgradeAssistant.checkupTab.deprecations.warningActionTooltip": "アップグレード前にこの問題を解決することをお勧めしますが、必須ではありません。", "xpack.upgradeAssistant.checkupTab.deprecations.warningLabel": "警告", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.cancelButtonLabel": "キャンセル", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.description": "次の廃止予定のインデックス設定が検出されました。これらは削除される予定です。", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.errorNotificationText": "インデックス設定の削除エラー", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.successNotificationText": "インデックス設定が削除されました", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.title": "廃止予定の設定を'{indexName}'から削除しますか?", - "xpack.upgradeAssistant.checkupTab.indexSettings.doneButtonLabel": "完了", - "xpack.upgradeAssistant.checkupTab.indexSettings.fixButtonLabel": "修正", "xpack.upgradeAssistant.checkupTab.noDeprecationsLabel": "説明がありません", "xpack.upgradeAssistant.checkupTab.numDeprecationsShownLabel": "{total} 件中 {numShown} 件を表示中", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.cancelButtonLabel": "キャンセル", @@ -25080,7 +25069,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.resumeWatcherStepTitle": "Watcher を再開中", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.stopWatcherStepTitle": "Watcher を停止中", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklistTitle": "プロセスを再インデックス中", - "xpack.upgradeAssistant.checkupTab.reindexing.flyout.flyoutHeader": "{indexName} を再インデックス", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails": "このインデックスは現在閉じています。アップグレードアシスタントが開き、再インデックスを実行してからインデックスを閉じます。 {reindexingMayTakeLongerEmph}。詳細については {docs} をご覧ください。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis": "再インデックスには通常よりも時間がかかることがあります", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutTitle": "インデックスが閉じました", @@ -25092,13 +25080,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutDetail": "続行する前に、インデックスをバックアップしてください。再インデックスを続行するには、各変更を承諾してください。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutTitle": "このインデックスには元に戻すことのできない破壊的な変更が含まれています", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.documentationLinkLabel": "ドキュメント", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.cancelledLabel": "キャンセル済み", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.doneLabel": "完了", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.failedLabel": "失敗", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.indexClosedToolTipDetails": "「{indexName}」は再インデックスが必要ですが現在閉じています。アップグレードアシスタントが開き、再インデックスを実行してからインデックスを閉じます。再インデックスには通常よりも時間がかかることがあります。", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.loadingLabel": "読み込み中…", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.pausedLabel": "一時停止中", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.reindexLabel": "再インデックス", "xpack.upgradeAssistant.deprecationGroupItem.docLinkText": "ドキュメンテーションを表示", "xpack.upgradeAssistant.deprecationGroupItem.fixButtonLabel": "修正する手順を表示", "xpack.upgradeAssistant.deprecationGroupItem.resolveButtonLabel": "クイック解決", @@ -25119,11 +25100,7 @@ "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "構成は最新です。KibanaおよびすべてのElasticsearchノードは同じバージョンを実行しています。", "xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel": "データをバックアップ", "xpack.upgradeAssistant.esDeprecations.backupDataTooltipText": "変更を行う前にスナップショットを作成します。", - "xpack.upgradeAssistant.esDeprecations.clusterLabel": "クラスター", - "xpack.upgradeAssistant.esDeprecations.clusterTabLabel": "クラスター", "xpack.upgradeAssistant.esDeprecations.docLinkText": "ドキュメント", - "xpack.upgradeAssistant.esDeprecations.indexLabel": "インデックス", - "xpack.upgradeAssistant.esDeprecations.indicesTabLabel": "インデックス", "xpack.upgradeAssistant.esDeprecations.loadingText": "廃止予定を読み込んでいます...", "xpack.upgradeAssistant.esDeprecations.pageDescription": "廃止予定のクラスターとインデックス設定をレビューします。アップグレード前に重要な問題を解決する必要があります。", "xpack.upgradeAssistant.esDeprecations.pageTitle": "Elasticsearch", @@ -25132,7 +25109,6 @@ "xpack.upgradeAssistant.esDeprecationStats.loadingText": "Elasticsearchの廃止統計情報を読み込んでいます...", "xpack.upgradeAssistant.esDeprecationStats.statsTitle": "Elasticsearch", "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTitle": "廃止予定", - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip": "このクラスターは{clusterCount}個の廃止予定のクラスター設定と{indexCount}個の廃止予定のインデックス設定を使用しています。", "xpack.upgradeAssistant.esDeprecationStats.viewDeprecationsLinkText": "廃止予定を表示", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorDescription": "エラーについては、Kibanaサーバーログを確認してください。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorTitle": "Kibana廃止予定を取得できませんでした", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b241e1455864d..24424cc8b5f72 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6570,7 +6570,6 @@ "xpack.canvas.error.esService.fieldsFetchErrorMessage": "无法为“{index}”提取 Elasticsearch 字段", "xpack.canvas.error.esService.indicesFetchErrorMessage": "无法提取 Elasticsearch 索引", "xpack.canvas.error.RenderWithFn.renderErrorMessage": "呈现“{functionName}”失败。", - "expressionRepeatImage.error.repeatImage.missingMaxArgument": "如果提供 {emptyImageArgument},则必须设置 {maxArgument}", "xpack.canvas.error.useCloneWorkpad.cloneFailureErrorMessage": "无法克隆 Workpad", "xpack.canvas.error.useCreateWorkpad.uploadFailureErrorMessage": "无法上传 Workpad", "xpack.canvas.error.useDeleteWorkpads.deleteFailureErrorMessage": "无法删除所有 Workpad", @@ -6744,10 +6743,6 @@ "xpack.canvas.functions.if.args.elseHelpText": "条件为 {BOOLEAN_FALSE} 时的返回值。未指定且条件未满足时,将返回原始 {CONTEXT}。", "xpack.canvas.functions.if.args.thenHelpText": "条件为 {BOOLEAN_TRUE} 时的返回值。未指定且条件满足时,将返回原始 {CONTEXT}。", "xpack.canvas.functions.ifHelpText": "执行条件逻辑。", - "expressionImage.functions.image.args.dataurlHelpText": "图像的 {https} {URL} 或 {BASE64} 数据 {URL}。", - "expressionImage.functions.image.args.modeHelpText": "{contain} 将显示整个图像,图像缩放至适合大小。{cover} 将使用该图像填充容器,根据需要在两边或底部裁剪图像。{stretch} 将图像的高和宽调整为容器的 100%。", - "expressionImage.functions.image.invalidImageModeErrorMessage": "“mode”必须为“{contain}”、“{cover}”或“{stretch}”", - "expressionImage.functions.imageHelpText": "显示图像。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", "xpack.canvas.functions.joinRows.args.columnHelpText": "从其中提取值的列或字段。", "xpack.canvas.functions.joinRows.args.distinctHelpText": "仅提取唯一值?", "xpack.canvas.functions.joinRows.args.quoteHelpText": "要将每个提取的值引起来的引号字符。", @@ -6765,11 +6760,6 @@ "xpack.canvas.functions.markdown.args.fontHelpText": "内容的 {CSS} 字体属性。例如 {fontFamily} 或 {fontWeight}。", "xpack.canvas.functions.markdown.args.openLinkHelpText": "用于在新标签页中打开链接的 true 或 false 值。默认值为 `false`。设置为 `true` 时将在新标签页中打开所有链接。", "xpack.canvas.functions.markdownHelpText": "添加呈现 {MARKDOWN} 文本的元素。提示:将 {markdownFn} 函数用于单个数字、指标和文本段落。", - "expressionMetric.functions.metric.args.labelFontHelpText": "标签的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", - "expressionMetric.functions.metric.args.labelHelpText": "描述指标的文本。", - "expressionMetric.functions.metric.args.metricFontHelpText": "指标的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", - "expressionMetric.functions.metric.args.metricFormatHelpText": "{NUMERALJS} 格式字符串。例如 {example1} 或 {example2}。", - "expressionMetric.functions.metricHelpText": "在标签上显示数字。", "xpack.canvas.functions.neq.args.valueHelpText": "与 {CONTEXT} 比较的值。", "xpack.canvas.functions.neqHelpText": "返回 {CONTEXT} 是否不等于参数。", "xpack.canvas.functions.pie.args.fontHelpText": "标签的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", @@ -6817,11 +6807,6 @@ "xpack.canvas.functions.render.args.containerStyleHelpText": "容器的样式,包括背景、边框和透明度。", "xpack.canvas.functions.render.args.cssHelpText": "要限定于元素的任何定制 {CSS} 块。", "xpack.canvas.functions.renderHelpText": "将 {CONTEXT} 呈现为特定元素,并设置元素级别选项,例如背景和边框样式。", - "expressionRepeatImage.functions.repeatImage.args.emptyImageHelpText": "使用此图像填充元素的 {CONTEXT} 和 {maxArg} 参数之间的差距。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", - "expressionRepeatImage.functions.repeatImage.args.imageHelpText": "要重复的图像。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", - "expressionRepeatImage.functions.repeatImage.args.maxHelpText": "图像可以重复的最大次数。", - "expressionRepeatImage.functions.repeatImage.args.sizeHelpText": "图像的最大高度或宽度,以像素为单位。图像的高大于宽时,此函数将限制高度。", - "expressionRepeatImage.functions.repeatImageHelpText": "配置重复图像元素。", "xpack.canvas.functions.replace.args.flagsHelpText": "指定标志。请参见 {url}。", "xpack.canvas.functions.replace.args.patternHelpText": "{JS} 正则表达式的文本或模式。例如,{example}。您可以在此处使用捕获组。", "xpack.canvas.functions.replace.args.replacementHelpText": "字符串匹配部分的替代。捕获组可以通过其索引进行访问。例如,{example}。", @@ -7000,24 +6985,14 @@ "xpack.canvas.renderer.dropdownFilter.matchAllOptionLabel": "任意", "xpack.canvas.renderer.embeddable.displayName": "可嵌入", "xpack.canvas.renderer.embeddable.helpDescription": "从 Kibana 的其他部分呈现可嵌入的已保存对象", - "expressionImage.renderer.image.displayName": "图像", - "expressionImage.renderer.image.helpDescription": "呈现图像", "xpack.canvas.renderer.markdown.displayName": "Markdown", "xpack.canvas.renderer.markdown.helpDescription": "使用 {MARKDOWN} 输入呈现 {HTML}", - "expressionMetric.renderer.metric.displayName": "指标", - "expressionMetric.renderer.metric.helpDescription": "在标签上呈现数字", "xpack.canvas.renderer.pie.displayName": "饼图", "xpack.canvas.renderer.pie.helpDescription": "根据您的数据呈现饼图", "xpack.canvas.renderer.plot.displayName": "坐标图", "xpack.canvas.renderer.plot.helpDescription": "根据您的数据呈现 XY 坐标图", "xpack.canvas.renderer.progress.displayName": "进度指示", "xpack.canvas.renderer.progress.helpDescription": "呈现显示元素百分比的进度指示", - "expressionRepeatImage.renderer.repeatImage.displayName": "图像重复", - "expressionRepeatImage.renderer.repeatImage.helpDescription": "重复图像给定次数", - "expressionRevealImage.renderer.revealImage.displayName": "图像显示", - "expressionRevealImage.renderer.revealImage.helpDescription": "显示一定百分比的图像,以制作定制的仪表样式图表", - "expressionShape.renderer.shape.displayName": "形状", - "expressionShape.renderer.shape.helpDescription": "呈现基本形状", "xpack.canvas.renderer.table.displayName": "数据表", "xpack.canvas.renderer.table.helpDescription": "将表格数据呈现为 {HTML}", "xpack.canvas.renderer.text.displayName": "纯文本", @@ -7509,17 +7484,42 @@ "xpack.canvas.workpadTemplates.table.descriptionColumnTitle": "描述", "xpack.canvas.workpadTemplates.table.nameColumnTitle": "模板名称", "xpack.canvas.workpadTemplates.table.tagsColumnTitle": "标签", + "expressionRepeatImage.error.repeatImage.missingMaxArgument": "如果提供 {emptyImageArgument},则必须设置 {maxArgument}", + "expressionRepeatImage.functions.repeatImage.args.emptyImageHelpText": "使用此图像填充元素的 {CONTEXT} 和 {maxArg} 参数之间的差距。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", + "expressionRepeatImage.functions.repeatImage.args.imageHelpText": "要重复的图像。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", + "expressionRepeatImage.functions.repeatImage.args.maxHelpText": "图像可以重复的最大次数。", + "expressionRepeatImage.functions.repeatImage.args.sizeHelpText": "图像的最大高度或宽度,以像素为单位。图像的高大于宽时,此函数将限制高度。", + "expressionRepeatImage.functions.repeatImageHelpText": "配置重复图像元素。", + "expressionRepeatImage.renderer.repeatImage.displayName": "图像重复", + "expressionRepeatImage.renderer.repeatImage.helpDescription": "重复图像给定次数", + "expressionImage.functions.image.args.dataurlHelpText": "图像的 {https} {URL} 或 {BASE64} 数据 {URL}。", + "expressionImage.functions.image.args.modeHelpText": "{contain} 将显示整个图像,图像缩放至适合大小。{cover} 将使用该图像填充容器,根据需要在两边或底部裁剪图像。{stretch} 将图像的高和宽调整为容器的 100%。", + "expressionImage.functions.image.invalidImageModeErrorMessage": "“mode”必须为“{contain}”、“{cover}”或“{stretch}”", + "expressionImage.functions.imageHelpText": "显示图像。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", + "expressionImage.renderer.image.displayName": "图像", + "expressionImage.renderer.image.helpDescription": "呈现图像", + "expressionMetric.functions.metric.args.labelFontHelpText": "标签的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", + "expressionMetric.functions.metric.args.labelHelpText": "描述指标的文本。", + "expressionMetric.functions.metric.args.metricFontHelpText": "指标的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", + "expressionMetric.functions.metric.args.metricFormatHelpText": "{NUMERALJS} 格式字符串。例如 {example1} 或 {example2}。", + "expressionMetric.functions.metricHelpText": "在标签上显示数字。", + "expressionMetric.renderer.metric.displayName": "指标", + "expressionMetric.renderer.metric.helpDescription": "在标签上呈现数字", + "expressionRevealImage.renderer.revealImage.displayName": "图像显示", + "expressionRevealImage.renderer.revealImage.helpDescription": "显示一定百分比的图像,以制作定制的仪表样式图表", + "expressionRevealImage.functions.revealImage.args.emptyImageHelpText": "要显示的可选背景图像。以 `{BASE64}` 数据 {URL} 的形式提供图像资产或传入子表达式。", + "expressionRevealImage.functions.revealImage.args.imageHelpText": "要显示的图像。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", + "expressionRevealImage.functions.revealImage.args.originHelpText": "要开始图像填充的位置。例如 {list} 或 {end}。", + "expressionRevealImage.functions.revealImage.invalidPercentErrorMessage": "无效值:“{percent}”。百分比必须介于 0 和 1 之间", + "expressionRevealImage.functions.revealImageHelpText": "配置图像显示元素。", + "expressionShape.renderer.shape.displayName": "形状", + "expressionShape.renderer.shape.helpDescription": "呈现基本形状", "expressionError.errorComponent.description": "表达式失败,并显示消息:", "expressionError.errorComponent.title": "哎哟!表达式失败", "expressionError.renderer.debug.displayName": "故障排查", "expressionError.renderer.debug.helpDescription": "将故障排查输出呈现为带格式的 {JSON}", "expressionError.renderer.error.displayName": "错误信息", "expressionError.renderer.error.helpDescription": "以用户友好的方式呈现错误数据", - "expressionRevealImage.functions.revealImage.args.emptyImageHelpText": "要显示的可选背景图像。以 `{BASE64}` 数据 {URL} 的形式提供图像资产或传入子表达式。", - "expressionRevealImage.functions.revealImage.args.imageHelpText": "要显示的图像。以 {BASE64} 数据 {URL} 的形式提供图像资产或传入子表达式。", - "expressionRevealImage.functions.revealImage.args.originHelpText": "要开始图像填充的位置。例如 {list} 或 {end}。", - "expressionRevealImage.functions.revealImage.invalidPercentErrorMessage": "无效值:“{percent}”。百分比必须介于 0 和 1 之间", - "expressionRevealImage.functions.revealImageHelpText": "配置图像显示元素。", "xpack.cases.connectors.cases.externalIncidentAdded": " (由 {user} 于 {date}添加) ", "xpack.cases.connectors.cases.externalIncidentCreated": " (由 {user} 于 {date}创建) ", "xpack.cases.connectors.cases.externalIncidentDefault": " (由 {user} 于 {date}创建) ", @@ -25425,25 +25425,13 @@ "xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibana 弃用", "xpack.upgradeAssistant.breadcrumb.overviewLabel": "升级助手", "xpack.upgradeAssistant.checkupTab.changeFiltersShowMoreLabel": "更改筛选以显示更多内容。", - "xpack.upgradeAssistant.checkupTab.confirmationModal.removeButtonLabel": "移除", "xpack.upgradeAssistant.checkupTab.controls.filterBar.criticalButtonLabel": "紧急", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIndexLabel": "按索引", "xpack.upgradeAssistant.checkupTab.controls.groupByBar.byIssueLabel": "按问题", "xpack.upgradeAssistant.checkupTab.deprecations.criticalActionTooltip": "请解决此问题后再升级。", "xpack.upgradeAssistant.checkupTab.deprecations.criticalLabel": "紧急", - "xpack.upgradeAssistant.checkupTab.deprecations.documentationButtonLabel": "文档", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.detailsColumnLabel": "详情", - "xpack.upgradeAssistant.checkupTab.deprecations.indexTable.indexColumnLabel": "索引", "xpack.upgradeAssistant.checkupTab.deprecations.warningActionTooltip": "建议在升级之前先解决此问题,但这不是必需的。", "xpack.upgradeAssistant.checkupTab.deprecations.warningLabel": "警告", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.cancelButtonLabel": "取消", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.description": "检测到并将移除以下弃用的索引设置:", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.errorNotificationText": "移除索引设置时出错", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.successNotificationText": "索引设置已移除", - "xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.title": "从“{indexName}”移除已弃用的设置?", - "xpack.upgradeAssistant.checkupTab.indexSettings.doneButtonLabel": "完成", - "xpack.upgradeAssistant.checkupTab.indexSettings.fixButtonLabel": "修复", - "xpack.upgradeAssistant.checkupTab.indicesBadgeLabel": "{numIndices, plural, other { 个索引}}", "xpack.upgradeAssistant.checkupTab.noDeprecationsLabel": "无弃用内容", "xpack.upgradeAssistant.checkupTab.numDeprecationsShownLabel": "显示 {numShown} 个,共 {total} 个", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.cancelButtonLabel": "取消", @@ -25471,7 +25459,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.resumeWatcherStepTitle": "正在恢复 Watcher", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklist.stopWatcherStepTitle": "正在停止 Watcher", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexingChecklistTitle": "重新索引过程", - "xpack.upgradeAssistant.checkupTab.reindexing.flyout.flyoutHeader": "重新索引 {indexName}", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails": "此索引当前已关闭。升级助手将打开索引,重新索引,然后关闭索引。{reindexingMayTakeLongerEmph}。请参阅文档{docs}以了解更多信息。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis": "重新索引可能比通常花费更多的时间", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutTitle": "索引已关闭", @@ -25483,13 +25470,6 @@ "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutDetail": "继续前备份索引。要继续重新索引,请接受每个更改。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.destructiveCallout.calloutTitle": "此索引需要无法恢复的破坏性更改", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.warningsStep.documentationLinkLabel": "文档", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.cancelledLabel": "已取消", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.doneLabel": "完成", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.failedLabel": "失败", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.indexClosedToolTipDetails": "“{indexName}”需要重新索引,但当前已关闭。升级助手将打开索引,重新索引,然后关闭索引。重新索引可能比通常花费更多的时间。", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.loadingLabel": "正在加载……", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.pausedLabel": "已暂停", - "xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.reindexLabel": "重新索引", "xpack.upgradeAssistant.deprecationGroupItem.docLinkText": "查看文档", "xpack.upgradeAssistant.deprecationGroupItem.fixButtonLabel": "显示修复步骤", "xpack.upgradeAssistant.deprecationGroupItem.resolveButtonLabel": "快速解决", @@ -25510,11 +25490,7 @@ "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "您的配置是最新的。Kibana 和索引 Elasticsearch 节点正在运行相同的版本。", "xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel": "备份您的数据", "xpack.upgradeAssistant.esDeprecations.backupDataTooltipText": "在进行任何更改之前拍取快照。", - "xpack.upgradeAssistant.esDeprecations.clusterLabel": "集群", - "xpack.upgradeAssistant.esDeprecations.clusterTabLabel": "集群", "xpack.upgradeAssistant.esDeprecations.docLinkText": "文档", - "xpack.upgradeAssistant.esDeprecations.indexLabel": "索引", - "xpack.upgradeAssistant.esDeprecations.indicesTabLabel": "索引", "xpack.upgradeAssistant.esDeprecations.loadingText": "正在加载弃用……", "xpack.upgradeAssistant.esDeprecations.pageDescription": "查看已弃用的群集和索引设置。在升级之前必须解决任何紧急问题。", "xpack.upgradeAssistant.esDeprecations.pageTitle": "Elasticsearch", @@ -25523,7 +25499,6 @@ "xpack.upgradeAssistant.esDeprecationStats.loadingText": "正在加载 Elasticsearch 弃用统计……", "xpack.upgradeAssistant.esDeprecationStats.statsTitle": "Elasticsearch", "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTitle": "弃用", - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip": "此集群正在使用 {clusterCount} 个已弃用集群设置和 {indexCount} 个已弃用的索引设置", "xpack.upgradeAssistant.esDeprecationStats.viewDeprecationsLinkText": "查看弃用", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorDescription": "请在 Kibana 服务器日志中查看错误。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorTitle": "无法检索 Kibana 弃用", diff --git a/x-pack/plugins/upgrade_assistant/public/application/app.tsx b/x-pack/plugins/upgrade_assistant/public/application/app.tsx index e342bceade0ec..40d4bd51d487a 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -8,12 +8,14 @@ import React from 'react'; import { Router, Switch, Route, Redirect } from 'react-router-dom'; import { I18nStart, ScopedHistory } from 'src/core/public'; +import { GlobalFlyout } from '../shared_imports'; import { AppContextProvider, ContextValue, useAppContext } from './app_context'; import { ComingSoonPrompt } from './components/coming_soon_prompt'; import { EsDeprecationsContent } from './components/es_deprecations'; import { KibanaDeprecationsContent } from './components/kibana_deprecations'; import { DeprecationsOverview } from './components/overview'; +const { GlobalFlyoutProvider } = GlobalFlyout; export interface AppDependencies extends ContextValue { i18n: I18nStart; history: ScopedHistory; @@ -48,9 +50,11 @@ export const AppWithRouter = ({ history }: { history: ScopedHistory }) => { export const RootComponent = ({ i18n, history, ...contextValue }: AppDependencies) => { return ( - - - + + + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss index d64400a8abdcf..4865e977f5261 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/_index.scss @@ -1 +1 @@ -@import 'deprecations/index'; +@import 'deprecation_types/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss similarity index 60% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss index 1f4f0352e7939..c3e842941a250 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/_index.scss @@ -1,2 +1 @@ -@import 'cell'; @import 'reindex/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx new file mode 100644 index 0000000000000..053975d255978 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx @@ -0,0 +1,96 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiButtonEmpty, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiText, + EuiTextColor, + EuiLink, +} from '@elastic/eui'; + +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; + +export interface DefaultDeprecationFlyoutProps { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; +} + +const i18nTexts = { + getFlyoutDescription: (indexName: string) => + i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.secondaryDescription', + { + defaultMessage: 'Index: {indexName}', + values: { + indexName, + }, + } + ), + learnMoreLinkLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.learnMoreLinkLabel', + { + defaultMessage: 'Learn more about this deprecation', + } + ), + closeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.cancelButtonLabel', + { + defaultMessage: 'Close', + } + ), +}; + +export const DefaultDeprecationFlyout = ({ + deprecation, + closeFlyout, +}: DefaultDeprecationFlyoutProps) => { + const { message, url, details, index } = deprecation; + + return ( + <> + + +

{message}

+
+ {index && ( + +

+ {i18nTexts.getFlyoutDescription(index)} +

+
+ )} +
+ + +

{details}

+

+ + {i18nTexts.learnMoreLinkLabel} + +

+
+
+ + + + + {i18nTexts.closeButtonLabel} + + + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/index.ts similarity index 84% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/index.ts index 6fbb38b04bbd6..ea537b642d8e4 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ReindexButton } from './button'; +export { DefaultTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx new file mode 100644 index 0000000000000..5d1f07a3901bc --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx @@ -0,0 +1,74 @@ +/* + * 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 React, { useState, useEffect } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { DeprecationTableColumns } from '../../../types'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { DefaultDeprecationFlyout, DefaultDeprecationFlyoutProps } from './flyout'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface Props { + rowFieldNames: DeprecationTableColumns[]; + deprecation: EnrichedDeprecationInfo; +} + +export const DefaultTableRow: React.FunctionComponent = ({ rowFieldNames, deprecation }) => { + const [showFlyout, setShowFlyout] = useState(false); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'deprecationDetails', + Component: DefaultDeprecationFlyout, + props: { + deprecation, + closeFlyout: () => setShowFlyout(false), + }, + flyoutProps: { + onClose: () => setShowFlyout(false), + 'data-test-subj': 'defaultDeprecationDetails', + 'aria-labelledby': 'defaultDeprecationDetailsFlyoutTitle', + }, + }); + } + }, [addContentToGlobalFlyout, deprecation, showFlyout]); + + useEffect(() => { + if (showFlyout === false) { + removeContentFromGlobalFlyout('deprecationDetails'); + } + }, [showFlyout, removeContentFromGlobalFlyout]); + + return ( + <> + {rowFieldNames.map((field) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + /> + + ); + })} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index.tsx similarity index 55% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index.tsx index a4152e52a35b7..eb0221a722a30 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index.tsx @@ -5,4 +5,7 @@ * 2.0. */ -export { EsDeprecationAccordion } from './deprecation_group_item'; +export { MlSnapshotsTableRow } from './ml_snapshots'; +export { IndexSettingsTableRow } from './index_settings'; +export { DefaultTableRow } from './default'; +export { ReindexTableRow } from './reindex'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx new file mode 100644 index 0000000000000..6dd11f49e61cd --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx @@ -0,0 +1,146 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiButton, + EuiButtonEmpty, + EuiCode, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiText, + EuiTextColor, + EuiLink, + EuiSpacer, +} from '@elastic/eui'; +import { EnrichedDeprecationInfo, IndexSettingAction } from '../../../../../../common/types'; + +export interface RemoveIndexSettingsFlyoutProps { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; + removeIndexSettings: (index: string, settings: string[]) => Promise; +} + +const i18nTexts = { + getFlyoutDescription: (indexName: string) => + i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.secondaryDescription', + { + defaultMessage: 'Index: {indexName}', + values: { + indexName, + }, + } + ), + learnMoreLinkLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.learnMoreLinkLabel', + { + defaultMessage: 'Learn more about this deprecation', + } + ), + removeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.removeButtonLabel', + { + defaultMessage: 'Remove deprecated settings', + } + ), + closeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.cancelButtonLabel', + { + defaultMessage: 'Close', + } + ), + confirmationText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.description', + { + defaultMessage: 'Remove the following deprecated index settings?', + } + ), +}; + +export const RemoveIndexSettingsFlyout = ({ + deprecation, + closeFlyout, + removeIndexSettings, +}: RemoveIndexSettingsFlyoutProps) => { + const { index, message, details, url, correctiveAction } = deprecation; + + // TODO handle error banner/retry if error + return ( + <> + + +

{message}

+
+ +

+ {i18nTexts.getFlyoutDescription(index!)} +

+
+
+ + +

{details}

+

+ + {i18nTexts.learnMoreLinkLabel} + +

+
+ + + + +

{i18nTexts.confirmationText}

+
+ + + + +
    + {(correctiveAction as IndexSettingAction).deprecatedSettings.map( + (setting, settingIndex) => ( +
  • + {setting} +
  • + ) + )} +
+
+
+ + + + + {i18nTexts.closeButtonLabel} + + + + + removeIndexSettings( + index!, + (correctiveAction as IndexSettingAction).deprecatedSettings + ) + } + > + {i18nTexts.removeButtonLabel} + + + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/index.ts similarity index 82% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/index.ts index d537c94cf67ae..282b8308f403f 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { FixMlSnapshotsButton } from './button'; +export { IndexSettingsTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx new file mode 100644 index 0000000000000..93fb8bdbb34ee --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx @@ -0,0 +1,80 @@ +/* + * 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 React from 'react'; + +import { EuiFlexItem, EuiText, EuiFlexGroup, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { Status } from './table_row'; + +const i18nTexts = { + deleteInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.deletingButtonLabel', + { + defaultMessage: 'Settings removal in progress…', + } + ), + deleteCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.deleteCompleteText', + { + defaultMessage: 'Settings removal complete', + } + ), + deleteFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.deleteFailedText', + { + defaultMessage: 'Settings removal failed', + } + ), +}; + +interface Props { + status: Status; +} + +export const IndexSettingsStatusCell: React.FunctionComponent = ({ status }) => { + if (status === 'in_progress') { + return ( + + + + + + {i18nTexts.deleteInProgressText} + + + ); + } + + if (status === 'complete') { + return ( + + + + + + {i18nTexts.deleteCompleteText} + + + ); + } + + if (status === 'error') { + return ( + + + + + + {i18nTexts.deleteFailedText} + + + ); + } + + return <>{''}; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx new file mode 100644 index 0000000000000..ef0760493d66a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx @@ -0,0 +1,100 @@ +/* + * 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 React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { useAppContext } from '../../../../app_context'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { DeprecationTableColumns } from '../../../types'; +import { IndexSettingsStatusCell } from './status_table_cell'; +import { RemoveIndexSettingsFlyout, RemoveIndexSettingsFlyoutProps } from './flyout'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface Props { + deprecation: EnrichedDeprecationInfo; + rowFieldNames: DeprecationTableColumns[]; +} + +export type Status = 'in_progress' | 'complete' | 'idle' | 'error'; + +export const IndexSettingsTableRow: React.FunctionComponent = ({ + rowFieldNames, + deprecation, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + const [status, setStatus] = useState('idle'); + + const { api } = useAppContext(); + + const closeFlyout = useCallback(() => setShowFlyout(false), []); + + const removeIndexSettings = useCallback( + async (index: string, settings: string[]) => { + setStatus('in_progress'); + + const { error } = await api.updateIndexSettings(index, settings); + + setStatus(error ? 'error' : 'complete'); + closeFlyout(); + }, + [api, closeFlyout] + ); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'indexSettingsFlyout', + Component: RemoveIndexSettingsFlyout, + props: { + closeFlyout, + deprecation, + removeIndexSettings, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'indexSettingsDetails', + 'aria-labelledby': 'indexSettingsDetailsFlyoutTitle', + }, + }); + } + }, [addContentToGlobalFlyout, deprecation, removeIndexSettings, showFlyout, closeFlyout]); + + useEffect(() => { + if (showFlyout === false) { + removeContentFromGlobalFlyout('indexSettingsFlyout'); + } + }, [showFlyout, removeContentFromGlobalFlyout]); + + return ( + <> + {rowFieldNames.map((field: DeprecationTableColumns) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + statusTableCell={} + /> + + ); + })} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx new file mode 100644 index 0000000000000..972d640d18c5a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/context.tsx @@ -0,0 +1,65 @@ +/* + * 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 React, { useEffect, createContext, useContext } from 'react'; +import { ApiService } from '../../../../lib/api'; + +import { useSnapshotState, SnapshotState } from './use_snapshot_state'; + +export interface MlSnapshotContext { + snapshotState: SnapshotState; + upgradeSnapshot: () => Promise; + deleteSnapshot: () => Promise; +} + +const MlSnapshotsContext = createContext(undefined); + +export const useMlSnapshotContext = () => { + const context = useContext(MlSnapshotsContext); + if (context === undefined) { + throw new Error('useMlSnapshotContext must be used within a '); + } + return context; +}; + +interface Props { + api: ApiService; + children: React.ReactNode; + snapshotId: string; + jobId: string; +} + +export const MlSnapshotsStatusProvider: React.FunctionComponent = ({ + api, + snapshotId, + jobId, + children, +}) => { + const { updateSnapshotStatus, snapshotState, upgradeSnapshot, deleteSnapshot } = useSnapshotState( + { + jobId, + snapshotId, + api, + } + ); + + useEffect(() => { + updateSnapshotStatus(); + }, [updateSnapshotStatus]); + + return ( + + {children} + + ); +}; 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 new file mode 100644 index 0000000000000..81ff09f168e97 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/flyout.tsx @@ -0,0 +1,166 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiTitle, + EuiText, + EuiCallOut, + EuiSpacer, +} from '@elastic/eui'; + +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { MlSnapshotContext } from './context'; + +export interface FixSnapshotsFlyoutProps extends MlSnapshotContext { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; +} + +const i18nTexts = { + upgradeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.upgradeButtonLabel', + { + defaultMessage: 'Upgrade', + } + ), + retryUpgradeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryUpgradeButtonLabel', + { + defaultMessage: 'Retry upgrade', + } + ), + closeButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.cancelButtonLabel', + { + defaultMessage: 'Close', + } + ), + deleteButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteButtonLabel', + { + defaultMessage: 'Delete', + } + ), + retryDeleteButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryDeleteButtonLabel', + { + defaultMessage: 'Retry delete', + } + ), + flyoutTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.title', { + defaultMessage: 'Upgrade or delete model snapshot', + }), + deleteSnapshotErrorTitle: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteSnapshotErrorTitle', + { + defaultMessage: 'Error deleting snapshot', + } + ), + upgradeSnapshotErrorTitle: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.upgradeSnapshotErrorTitle', + { + defaultMessage: 'Error upgrading snapshot', + } + ), +}; + +export const FixSnapshotsFlyout = ({ + deprecation, + closeFlyout, + snapshotState, + upgradeSnapshot, + deleteSnapshot, +}: FixSnapshotsFlyoutProps) => { + const onUpgradeSnapshot = () => { + upgradeSnapshot(); + closeFlyout(); + }; + + const onDeleteSnapshot = () => { + deleteSnapshot(); + closeFlyout(); + }; + + return ( + <> + + +

{i18nTexts.flyoutTitle}

+
+
+ + {snapshotState.error && ( + <> + + {snapshotState.error.message} + + + + )} + +

{deprecation.details}

+
+
+ + + + + {i18nTexts.closeButtonLabel} + + + + + + + {snapshotState.action === 'delete' && snapshotState.error + ? i18nTexts.retryDeleteButtonLabel + : i18nTexts.deleteButtonLabel} + + + + + {snapshotState.action === 'upgrade' && snapshotState.error + ? i18nTexts.retryUpgradeButtonLabel + : i18nTexts.upgradeButtonLabel} + + + + + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/index.ts similarity index 83% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/index.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/index.ts index e8a83790ee2a6..d523184454533 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { FixIndexSettingsButton } from './button'; +export { MlSnapshotsTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx new file mode 100644 index 0000000000000..8013588206efc --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx @@ -0,0 +1,122 @@ +/* + * 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 React from 'react'; + +import { + EuiBadge, + EuiFlexItem, + EuiText, + EuiFlexGroup, + EuiIcon, + EuiLoadingSpinner, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { useMlSnapshotContext } from './context'; + +const i18nTexts = { + upgradeInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradeInProgressText', + { + defaultMessage: 'Upgrade in progress…', + } + ), + deleteInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deletingButtonLabel', + { + defaultMessage: 'Deletion in progress…', + } + ), + upgradeCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradeCompleteText', + { + defaultMessage: 'Upgrade complete', + } + ), + deleteCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteCompleteText', + { + defaultMessage: 'Deletion complete', + } + ), + upgradeFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradeFailedText', + { + defaultMessage: 'Upgrade failed', + } + ), + deleteFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteFailedText', + { + defaultMessage: 'Deletion failed', + } + ), + criticalBadgeLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.criticalBadgeLabel', + { + defaultMessage: 'Critical', + } + ), +}; + +export const MlSnapshotsStatusCell: React.FunctionComponent = () => { + const { snapshotState } = useMlSnapshotContext(); + + if (snapshotState.status === 'in_progress') { + return ( + + + + + + + {snapshotState.action === 'delete' + ? i18nTexts.deleteInProgressText + : i18nTexts.upgradeInProgressText} + + + + ); + } + + if (snapshotState.status === 'complete') { + return ( + + + + + + + {snapshotState.action === 'delete' + ? i18nTexts.deleteCompleteText + : i18nTexts.upgradeCompleteText} + + + + ); + } + + if (snapshotState.status === 'error') { + return ( + + + + + + + {snapshotState.action === 'delete' + ? i18nTexts.deleteFailedText + : i18nTexts.upgradeFailedText} + + + + ); + } + + return {i18nTexts.criticalBadgeLabel}; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx new file mode 100644 index 0000000000000..d16a58f7cf2c8 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx @@ -0,0 +1,95 @@ +/* + * 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 React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { EnrichedDeprecationInfo, MlAction } from '../../../../../../common/types'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { useAppContext } from '../../../../app_context'; +import { DeprecationTableColumns } from '../../../types'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { MlSnapshotsStatusCell } from './status_table_cell'; +import { FixSnapshotsFlyout, FixSnapshotsFlyoutProps } from './flyout'; +import { MlSnapshotsStatusProvider, useMlSnapshotContext } from './context'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface TableRowProps { + deprecation: EnrichedDeprecationInfo; + rowFieldNames: DeprecationTableColumns[]; +} + +export const MlSnapshotsTableRowCells: React.FunctionComponent = ({ + rowFieldNames, + deprecation, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + const snapshotState = useMlSnapshotContext(); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(() => setShowFlyout(false), []); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'mlFlyout', + Component: FixSnapshotsFlyout, + props: { + deprecation, + closeFlyout, + ...snapshotState, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'mlSnapshotDetails', + 'aria-labelledby': 'mlSnapshotDetailsFlyoutTitle', + }, + }); + } + }, [snapshotState, addContentToGlobalFlyout, showFlyout, deprecation, closeFlyout]); + + useEffect(() => { + if (showFlyout === false) { + removeContentFromGlobalFlyout('mlFlyout'); + } + }, [showFlyout, removeContentFromGlobalFlyout]); + + return ( + <> + {rowFieldNames.map((field: DeprecationTableColumns) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + statusTableCell={} + /> + + ); + })} + + ); +}; + +export const MlSnapshotsTableRow: React.FunctionComponent = (props) => { + const { api } = useAppContext(); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/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 similarity index 96% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/use_snapshot_state.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/use_snapshot_state.tsx index 2dd4638c772b3..7c5d770a04235 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/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 @@ -11,13 +11,17 @@ import { ApiService, ResponseError } from '../../../../lib/api'; const POLL_INTERVAL_MS = 1000; -export interface SnapshotStatus { +interface SnapshotStatus { snapshotId: string; jobId: string; status: 'complete' | 'in_progress' | 'error' | 'idle'; action?: 'upgrade' | 'delete'; } +export interface SnapshotState extends SnapshotStatus { + error: ResponseError | undefined; +} + export const useSnapshotState = ({ jobId, snapshotId, diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss similarity index 57% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss index 014edc96b0565..4cd55614ab4e6 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_index.scss +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/_index.scss @@ -1,2 +1 @@ -@import 'button'; @import 'flyout/index'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx new file mode 100644 index 0000000000000..2d34253d2c426 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/context.tsx @@ -0,0 +1,61 @@ +/* + * 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 React, { useEffect, createContext, useContext } from 'react'; + +import { ApiService } from '../../../../lib/api'; +import { useReindexStatus, ReindexState } from './use_reindex_state'; + +export interface ReindexStateContext { + reindexState: ReindexState; + startReindex: () => Promise; + cancelReindex: () => Promise; +} + +const ReindexContext = createContext(undefined); + +export const useReindexContext = () => { + const context = useContext(ReindexContext); + if (context === undefined) { + throw new Error('useReindexContext must be used within a '); + } + return context; +}; + +interface Props { + api: ApiService; + children: React.ReactNode; + indexName: string; +} + +export const ReindexStatusProvider: React.FunctionComponent = ({ + api, + indexName, + children, +}) => { + const { reindexState, startReindex, cancelReindex, updateStatus } = useReindexStatus({ + indexName, + api, + }); + + useEffect(() => { + updateStatus(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + {children} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/warning_step.test.tsx.snap similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/__snapshots__/warning_step.test.tsx.snap diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_index.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_step_progress.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_step_progress.scss similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/_step_progress.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/_step_progress.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.test.tsx similarity index 97% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.test.tsx index f8d72addc2d18..a3a0f15188fca 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { ReindexStatus } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { ChecklistFlyoutStep } from './checklist_step'; describe('ChecklistFlyout', () => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx similarity index 98% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx index e852171a696b4..e30c42a0f95f5 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/checklist_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx @@ -22,7 +22,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { ReindexStatus } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { ReindexProgress } from './progress'; const buttonLabel = (status?: ReindexStatus) => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx new file mode 100644 index 0000000000000..a01d48aff7e1a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx @@ -0,0 +1,142 @@ +/* + * 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 React, { useState } from 'react'; +import { DocLinksStart } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCallOut, EuiFlyoutHeader, EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui'; + +import { + EnrichedDeprecationInfo, + ReindexAction, + ReindexStatus, +} from '../../../../../../../common/types'; +import { useAppContext } from '../../../../../app_context'; + +import type { ReindexStateContext } from '../context'; +import { ChecklistFlyoutStep } from './checklist_step'; +import { WarningsFlyoutStep } from './warnings_step'; + +enum ReindexFlyoutStep { + reindexWarnings, + checklist, +} + +export interface ReindexFlyoutProps extends ReindexStateContext { + deprecation: EnrichedDeprecationInfo; + closeFlyout: () => void; +} + +const getOpenAndCloseIndexDocLink = (docLinks: DocLinksStart) => ( + + {i18n.translate( + 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.openAndCloseDocumentation', + { defaultMessage: 'documentation' } + )} + +); + +const getIndexClosedCallout = (docLinks: DocLinksStart) => ( + <> + +

+ + {i18n.translate( + 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis', + { defaultMessage: 'Reindexing may take longer than usual' } + )} + + ), + }} + /> +

+
+ + +); + +export const ReindexFlyout: React.FunctionComponent = ({ + reindexState, + startReindex, + cancelReindex, + closeFlyout, + deprecation, +}) => { + const { status, reindexWarnings } = reindexState; + const { index, correctiveAction } = deprecation; + const { docLinks } = useAppContext(); + // If there are any warnings and we haven't started reindexing, show the warnings step first. + const [currentFlyoutStep, setCurrentFlyoutStep] = useState( + reindexWarnings && reindexWarnings.length > 0 && status === undefined + ? ReindexFlyoutStep.reindexWarnings + : ReindexFlyoutStep.checklist + ); + + let flyoutContents: React.ReactNode; + + const globalCallout = + (correctiveAction as ReindexAction).blockerForReindexing === 'index-closed' && + reindexState.status !== ReindexStatus.completed + ? getIndexClosedCallout(docLinks) + : undefined; + switch (currentFlyoutStep) { + case ReindexFlyoutStep.reindexWarnings: + flyoutContents = ( + globalCallout} + closeFlyout={closeFlyout} + warnings={reindexState.reindexWarnings!} + advanceNextStep={() => setCurrentFlyoutStep(ReindexFlyoutStep.checklist)} + /> + ); + break; + case ReindexFlyoutStep.checklist: + flyoutContents = ( + globalCallout} + closeFlyout={closeFlyout} + reindexState={reindexState} + startReindex={startReindex} + cancelReindex={cancelReindex} + /> + ); + break; + default: + throw new Error(`Invalid flyout step: ${currentFlyoutStep}`); + } + + return ( + <> + + +

+ +

+
+
+ {flyoutContents} + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx new file mode 100644 index 0000000000000..6b9eee80acb57 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/index.tsx @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { ReindexFlyout, ReindexFlyoutProps } from './container'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.test.tsx similarity index 99% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.test.tsx index 24a00af7a9fee..b49d816302213 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.test.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.test.tsx @@ -9,7 +9,7 @@ import { shallow } from 'enzyme'; import React from 'react'; import { IndexGroup, ReindexStatus, ReindexStep } from '../../../../../../../common/types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { ReindexProgress } from './progress'; describe('ReindexProgress', () => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.tsx similarity index 99% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.tsx index 088266f3a4840..65a790fe96691 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/progress.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/progress.tsx @@ -19,7 +19,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { IndexGroup, ReindexStatus, ReindexStep } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; -import { ReindexState } from '../polling_service'; +import type { ReindexState } from '../use_reindex_state'; import { StepProgress, StepProgressStep } from './step_progress'; const ErrorCallout: React.FunctionComponent<{ errorMessage: string | null }> = ({ diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/step_progress.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/step_progress.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/step_progress.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step.test.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step.test.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step_checkbox.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step_checkbox.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warning_step_checkbox.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warning_step_checkbox.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warnings_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warnings_step.tsx similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/warnings_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/warnings_step.tsx diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/index.tsx similarity index 84% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/index.tsx index facc830234667..bbb1493f15bcc 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/index.tsx @@ -5,4 +5,4 @@ * 2.0. */ -export { ReindexFlyout } from './container'; +export { ReindexTableRow } from './table_row'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx new file mode 100644 index 0000000000000..b6919bdc1575c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx @@ -0,0 +1,143 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiIcon, + EuiLoadingSpinner, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiBadge, +} from '@elastic/eui'; +import { ReindexStatus } from '../../../../../../common/types'; +import { LoadingState } from '../../../types'; +import { useReindexContext } from './context'; + +const i18nTexts = { + reindexLoadingStatusText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexLoadingStatusText', + { + defaultMessage: 'Loading status…', + } + ), + reindexInProgressText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexInProgressText', + { + defaultMessage: 'Reindexing in progress…', + } + ), + reindexCompleteText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexCompleteText', + { + defaultMessage: 'Reindex complete', + } + ), + reindexFailedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexFailedText', + { + defaultMessage: 'Reindex failed', + } + ), + reindexCanceledText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexCanceledText', + { + defaultMessage: 'Reindex canceled', + } + ), + reindexPausedText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.reindex.reindexPausedText', + { + defaultMessage: 'Reindex paused', + } + ), + criticalBadgeLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.criticalBadgeLabel', + { + defaultMessage: 'Critical', + } + ), +}; + +export const ReindexStatusCell: React.FunctionComponent = () => { + const { reindexState } = useReindexContext(); + + if (reindexState.loadingState === LoadingState.Loading) { + return ( + + + + + + {i18nTexts.reindexLoadingStatusText} + + + ); + } + + switch (reindexState.status) { + case ReindexStatus.inProgress: + return ( + + + + + + {i18nTexts.reindexInProgressText} + + + ); + case ReindexStatus.completed: + return ( + + + + + + {i18nTexts.reindexCompleteText} + + + ); + case ReindexStatus.failed: + return ( + + + + + + {i18nTexts.reindexCompleteText} + + + ); + case ReindexStatus.paused: + return ( + + + + + + {i18nTexts.reindexPausedText} + + + ); + case ReindexStatus.cancelled: + return ( + + + + + + {i18nTexts.reindexCanceledText} + + + ); + } + + return {i18nTexts.criticalBadgeLabel}; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx new file mode 100644 index 0000000000000..4803d2e4a0ec7 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx @@ -0,0 +1,95 @@ +/* + * 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 React, { useState, useEffect, useCallback } from 'react'; +import { EuiTableRowCell } from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; +import { GlobalFlyout } from '../../../../../shared_imports'; +import { useAppContext } from '../../../../app_context'; +import { DeprecationTableColumns } from '../../../types'; +import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; +import { ReindexStatusCell } from './status_table_cell'; +import { ReindexFlyout, ReindexFlyoutProps } from './flyout'; +import { ReindexStatusProvider, useReindexContext } from './context'; + +const { useGlobalFlyout } = GlobalFlyout; + +interface TableRowProps { + deprecation: EnrichedDeprecationInfo; + rowFieldNames: DeprecationTableColumns[]; +} + +export const ReindexTableRowCells: React.FunctionComponent = ({ + rowFieldNames, + deprecation, +}) => { + const [showFlyout, setShowFlyout] = useState(false); + const reindexState = useReindexContext(); + + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(() => setShowFlyout(false), []); + + useEffect(() => { + if (showFlyout) { + addContentToGlobalFlyout({ + id: 'reindexFlyout', + Component: ReindexFlyout, + props: { + deprecation, + closeFlyout, + ...reindexState, + }, + flyoutProps: { + onClose: closeFlyout, + 'data-test-subj': 'reindexDetails', + 'aria-labelledby': 'reindexDetailsFlyoutTitle', + }, + }); + } + }, [addContentToGlobalFlyout, deprecation, showFlyout, reindexState, closeFlyout]); + + useEffect(() => { + if (showFlyout === false) { + removeContentFromGlobalFlyout('reindexFlyout'); + } + }, [showFlyout, removeContentFromGlobalFlyout]); + + return ( + <> + {rowFieldNames.map((field: DeprecationTableColumns) => { + return ( + + setShowFlyout(true)} + deprecation={deprecation} + statusTableCell={} + /> + + ); + })} + + ); +}; + +export const ReindexTableRow: React.FunctionComponent = (props) => { + const { api } = useAppContext(); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx new file mode 100644 index 0000000000000..eff3eefe8d776 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx @@ -0,0 +1,181 @@ +/* + * 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 { useRef, useCallback, useState, useEffect } from 'react'; + +import { + IndexGroup, + ReindexOperation, + ReindexStatus, + ReindexStep, + ReindexWarning, +} from '../../../../../../common/types'; +import { LoadingState } from '../../../types'; +import { ApiService } from '../../../../lib/api'; + +const POLL_INTERVAL = 1000; + +export interface ReindexState { + loadingState: LoadingState; + cancelLoadingState?: LoadingState; + lastCompletedStep?: ReindexStep; + status?: ReindexStatus; + reindexTaskPercComplete: number | null; + errorMessage: string | null; + reindexWarnings?: ReindexWarning[]; + hasRequiredPrivileges?: boolean; + indexGroup?: IndexGroup; +} + +interface StatusResponse { + warnings?: ReindexWarning[]; + reindexOp?: ReindexOperation; + hasRequiredPrivileges?: boolean; + indexGroup?: IndexGroup; +} + +const getReindexState = ( + reindexState: ReindexState, + { reindexOp, warnings, hasRequiredPrivileges, indexGroup }: StatusResponse +) => { + const newReindexState = { + ...reindexState, + loadingState: LoadingState.Success, + }; + + if (warnings) { + newReindexState.reindexWarnings = warnings; + } + + if (hasRequiredPrivileges !== undefined) { + newReindexState.hasRequiredPrivileges = hasRequiredPrivileges; + } + + if (indexGroup) { + newReindexState.indexGroup = indexGroup; + } + + if (reindexOp) { + // Prevent the UI flickering back to inProgress after cancelling + newReindexState.lastCompletedStep = reindexOp.lastCompletedStep; + newReindexState.status = reindexOp.status; + newReindexState.reindexTaskPercComplete = reindexOp.reindexTaskPercComplete; + newReindexState.errorMessage = reindexOp.errorMessage; + + if (reindexOp.status === ReindexStatus.cancelled) { + newReindexState.cancelLoadingState = LoadingState.Success; + } + } + + return newReindexState; +}; + +export const useReindexStatus = ({ indexName, api }: { indexName: string; api: ApiService }) => { + const [reindexState, setReindexState] = useState({ + loadingState: LoadingState.Loading, + errorMessage: null, + reindexTaskPercComplete: null, + }); + + const pollIntervalIdRef = useRef | null>(null); + const isMounted = useRef(false); + + const clearPollInterval = useCallback(() => { + if (pollIntervalIdRef.current) { + clearTimeout(pollIntervalIdRef.current); + pollIntervalIdRef.current = null; + } + }, []); + + const updateStatus = useCallback(async () => { + clearPollInterval(); + + const { data, error } = await api.getReindexStatus(indexName); + + if (error) { + setReindexState({ + ...reindexState, + status: ReindexStatus.failed, + }); + return; + } + + setReindexState(getReindexState(reindexState, data)); + + // Only keep polling if it exists and is in progress. + if (data.reindexOp && data.reindexOp.status === ReindexStatus.inProgress) { + pollIntervalIdRef.current = setTimeout(updateStatus, POLL_INTERVAL); + } + }, [clearPollInterval, api, indexName, reindexState]); + + const startReindex = useCallback(async () => { + const currentReindexState = { + ...reindexState, + }; + + setReindexState({ + ...currentReindexState, + // Only reset last completed step if we aren't currently paused + lastCompletedStep: + currentReindexState.status === ReindexStatus.paused + ? currentReindexState.lastCompletedStep + : undefined, + status: ReindexStatus.inProgress, + reindexTaskPercComplete: null, + errorMessage: null, + cancelLoadingState: undefined, + }); + + const { data, error } = await api.startReindexTask(indexName); + + if (error) { + setReindexState({ + ...reindexState, + status: ReindexStatus.failed, + }); + return; + } + + setReindexState(getReindexState(reindexState, data)); + updateStatus(); + }, [api, indexName, reindexState, updateStatus]); + + const cancelReindex = useCallback(async () => { + const { error } = await api.cancelReindexTask(indexName); + + setReindexState({ + ...reindexState, + cancelLoadingState: LoadingState.Loading, + }); + + if (error) { + setReindexState({ + ...reindexState, + cancelLoadingState: LoadingState.Error, + }); + return; + } + }, [api, indexName, reindexState]); + + useEffect(() => { + isMounted.current = true; + + return () => { + isMounted.current = false; + + // Clean up on unmount. + clearPollInterval(); + }; + }, [clearPollInterval]); + + return { + reindexState, + startReindex, + cancelReindex, + updateStatus, + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss deleted file mode 100644 index e53fd9b254cf0..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/_cell.scss +++ /dev/null @@ -1,4 +0,0 @@ -.upgDeprecationCell { - overflow: hidden; - padding: $euiSize 0 0 $euiSizeL; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx deleted file mode 100644 index 4324379f456ea..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/cell.tsx +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 React, { ReactNode, FunctionComponent } from 'react'; - -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EnrichedDeprecationInfo, - MlAction, - ReindexAction, - IndexSettingAction, -} from '../../../../../common/types'; -import { AppContext } from '../../../app_context'; -import { ReindexButton } from './reindex'; -import { FixIndexSettingsButton } from './index_settings'; -import { FixMlSnapshotsButton } from './ml_snapshots'; - -interface DeprecationCellProps { - items?: Array<{ title?: string; body: string }>; - docUrl?: string; - headline?: string; - healthColor?: string; - children?: ReactNode; - correctiveAction?: EnrichedDeprecationInfo['correctiveAction']; - indexName?: string; -} - -interface CellActionProps { - correctiveAction: EnrichedDeprecationInfo['correctiveAction']; - indexName?: string; - items: Array<{ title?: string; body: string }>; -} - -const CellAction: FunctionComponent = ({ correctiveAction, indexName, items }) => { - const { type: correctiveActionType } = correctiveAction!; - switch (correctiveActionType) { - case 'mlSnapshot': - const { jobId, snapshotId } = correctiveAction as MlAction; - return ( - - ); - - case 'reindex': - const { blockerForReindexing } = correctiveAction as ReindexAction; - - return ( - - {({ http, docLinks }) => ( - - )} - - ); - - case 'indexSetting': - const { deprecatedSettings } = correctiveAction as IndexSettingAction; - - return ; - - default: - throw new Error(`No UI defined for corrective action: ${correctiveActionType}`); - } -}; - -/** - * Used to display a deprecation with links to docs, a health indicator, and other descriptive information. - */ -export const DeprecationCell: FunctionComponent = ({ - headline, - healthColor, - correctiveAction, - indexName, - docUrl, - items = [], - children, -}) => ( -
- - {healthColor && ( - - - - )} - - - {headline && ( - -

{headline}

-
- )} - - {items.map((item, index) => ( - - {item.title &&
{item.title}
} -

{item.body}

-
- ))} - - {docUrl && ( - <> - - - - - - - )} -
- - {correctiveAction && ( - - - - )} -
- - - - {children} -
-); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx deleted file mode 100644 index e63e26f3ecc61..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/button.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 React from 'react'; - -import { EuiButton } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { RemoveIndexSettingsProvider } from './remove_settings_provider'; - -const i18nTexts = { - fixButtonLabel: i18n.translate('xpack.upgradeAssistant.checkupTab.indexSettings.fixButtonLabel', { - defaultMessage: 'Fix', - }), - doneButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.doneButtonLabel', - { - defaultMessage: 'Done', - } - ), -}; - -interface Props { - settings: string[]; - index: string; -} - -/** - * Renders a button if the given index contains deprecated index settings - */ -export const FixIndexSettingsButton: React.FunctionComponent = ({ settings, index }) => { - return ( - - {(removeIndexSettingsPrompt, successfulRequests) => { - const isSuccessfulRequest = successfulRequests[index] === true; - return ( - removeIndexSettingsPrompt(index, settings)} - isDisabled={isSuccessfulRequest} - iconType={isSuccessfulRequest ? 'check' : undefined} - > - {isSuccessfulRequest ? i18nTexts.doneButtonLabel : i18nTexts.fixButtonLabel} - - ); - }} - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx deleted file mode 100644 index 1fd0c79dbbef3..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/index_settings/remove_settings_provider.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 React, { useState, useRef } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiCode, EuiConfirmModal } from '@elastic/eui'; -import { useAppContext } from '../../../../app_context'; - -interface Props { - children: ( - removeSettingsPrompt: (index: string, settings: string[]) => void, - successfulRequests: { [key: string]: boolean } - ) => React.ReactNode; -} - -const i18nTexts = { - removeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.confirmationModal.removeButtonLabel', - { - defaultMessage: 'Remove', - } - ), - cancelButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.cancelButtonLabel', - { - defaultMessage: 'Cancel', - } - ), - modalDescription: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.description', - { - defaultMessage: 'The following deprecated index settings were detected and will be removed:', - } - ), - successNotificationText: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.successNotificationText', - { - defaultMessage: 'Index settings removed', - } - ), - errorNotificationText: i18n.translate( - 'xpack.upgradeAssistant.checkupTab.indexSettings.confirmationModal.errorNotificationText', - { - defaultMessage: 'Error removing index settings', - } - ), -}; - -export const RemoveIndexSettingsProvider = ({ children }: Props) => { - const [isModalOpen, setIsModalOpen] = useState(false); - const [successfulRequests, setSuccessfulRequests] = useState<{ [key: string]: boolean }>({}); - const [isLoading, setIsLoading] = useState(false); - - const deprecatedSettings = useRef([]); - const indexName = useRef(undefined); - - const { api, notifications } = useAppContext(); - - const removeIndexSettings = async () => { - setIsLoading(true); - - const { error } = await api.updateIndexSettings(indexName.current!, deprecatedSettings.current); - - setIsLoading(false); - closeModal(); - - if (error) { - notifications.toasts.addDanger(i18nTexts.errorNotificationText); - } else { - setSuccessfulRequests({ - [indexName.current!]: true, - }); - notifications.toasts.addSuccess(i18nTexts.successNotificationText); - } - }; - - const closeModal = () => { - setIsModalOpen(false); - }; - - const removeSettingsPrompt = (index: string, settings: string[]) => { - setIsModalOpen(true); - setSuccessfulRequests({ - [index]: false, - }); - indexName.current = index; - deprecatedSettings.current = settings; - }; - - return ( - <> - {children(removeSettingsPrompt, successfulRequests)} - - {isModalOpen && ( - - <> -

{i18nTexts.modalDescription}

-
    - {deprecatedSettings.current.map((setting, index) => ( -
  • - {setting} -
  • - ))} -
- -
- )} - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx deleted file mode 100644 index 13b7dacc3b598..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/button.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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 React, { useEffect, useState } from 'react'; - -import { ButtonSize, EuiButton } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { FixSnapshotsFlyout } from './fix_snapshots_flyout'; -import { useAppContext } from '../../../../app_context'; -import { useSnapshotState } from './use_snapshot_state'; - -const i18nTexts = { - fixButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.fixButtonLabel', - { - defaultMessage: 'Fix', - } - ), - upgradingButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.upgradingButtonLabel', - { - defaultMessage: 'Upgrading…', - } - ), - deletingButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.deletingButtonLabel', - { - defaultMessage: 'Deleting…', - } - ), - doneButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.doneButtonLabel', - { - defaultMessage: 'Done', - } - ), - failedButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.failedButtonLabel', - { - defaultMessage: 'Failed', - } - ), -}; - -interface Props { - snapshotId: string; - jobId: string; - description: string; -} - -export const FixMlSnapshotsButton: React.FunctionComponent = ({ - snapshotId, - jobId, - description, -}) => { - const { api } = useAppContext(); - const { snapshotState, upgradeSnapshot, deleteSnapshot, updateSnapshotStatus } = useSnapshotState( - { - jobId, - snapshotId, - api, - } - ); - - const [showFlyout, setShowFlyout] = useState(false); - - useEffect(() => { - updateSnapshotStatus(); - }, [updateSnapshotStatus]); - - const commonButtonProps = { - size: 's' as ButtonSize, - onClick: () => setShowFlyout(true), - 'data-test-subj': 'fixMlSnapshotsButton', - }; - - let button = {i18nTexts.fixButtonLabel}; - - switch (snapshotState.status) { - case 'in_progress': - button = ( - - {snapshotState.action === 'delete' - ? i18nTexts.deletingButtonLabel - : i18nTexts.upgradingButtonLabel} - - ); - break; - case 'complete': - button = ( - - {i18nTexts.doneButtonLabel} - - ); - break; - case 'error': - button = ( - - {i18nTexts.failedButtonLabel} - - ); - break; - } - - return ( - <> - {button} - - {showFlyout && ( - setShowFlyout(false)} - /> - )} - - ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx deleted file mode 100644 index 7dafab011a69a..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/ml_snapshots/fix_snapshots_flyout.tsx +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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 React from 'react'; -import { i18n } from '@kbn/i18n'; - -import { - EuiButton, - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiPortal, - EuiTitle, - EuiText, - EuiCallOut, - EuiSpacer, -} from '@elastic/eui'; -import { SnapshotStatus } from './use_snapshot_state'; -import { ResponseError } from '../../../../lib/api'; - -interface SnapshotState extends SnapshotStatus { - error?: ResponseError; -} -interface Props { - upgradeSnapshot: () => Promise; - deleteSnapshot: () => Promise; - description: string; - closeFlyout: () => void; - snapshotState: SnapshotState; -} - -const i18nTexts = { - upgradeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.upgradeButtonLabel', - { - defaultMessage: 'Upgrade', - } - ), - retryUpgradeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryUpgradeButtonLabel', - { - defaultMessage: 'Retry upgrade', - } - ), - closeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.cancelButtonLabel', - { - defaultMessage: 'Close', - } - ), - deleteButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteButtonLabel', - { - defaultMessage: 'Delete', - } - ), - retryDeleteButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryDeleteButtonLabel', - { - defaultMessage: 'Retry delete', - } - ), - flyoutTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.title', { - defaultMessage: 'Upgrade or delete model snapshot', - }), - deleteSnapshotErrorTitle: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteSnapshotErrorTitle', - { - defaultMessage: 'Error deleting snapshot', - } - ), - upgradeSnapshotErrorTitle: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.upgradeSnapshotErrorTitle', - { - defaultMessage: 'Error upgrading snapshot', - } - ), -}; - -export const FixSnapshotsFlyout = ({ - upgradeSnapshot, - deleteSnapshot, - description, - closeFlyout, - snapshotState, -}: Props) => { - const onUpgradeSnapshot = () => { - upgradeSnapshot(); - closeFlyout(); - }; - - const onDeleteSnapshot = () => { - deleteSnapshot(); - closeFlyout(); - }; - - return ( - - - - -

{i18nTexts.flyoutTitle}

-
-
- - {snapshotState.error && ( - <> - - {snapshotState.error.message} - - - - )} - -

{description}

-
-
- - - - - {i18nTexts.closeButtonLabel} - - - - - - - {snapshotState.action === 'delete' && snapshotState.error - ? i18nTexts.retryDeleteButtonLabel - : i18nTexts.deleteButtonLabel} - - - - - {snapshotState.action === 'upgrade' && snapshotState.error - ? i18nTexts.retryUpgradeButtonLabel - : i18nTexts.upgradeButtonLabel} - - - - - - -
-
- ); -}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss deleted file mode 100644 index f12149f9e88cb..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/_button.scss +++ /dev/null @@ -1,5 +0,0 @@ -.upgReindexButton__spinner { - position: relative; - top: $euiSizeXS / 2; - margin-right: $euiSizeXS; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx deleted file mode 100644 index 646f253931664..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/button.tsx +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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 { set } from '@elastic/safer-lodash-set'; -import React, { Fragment, ReactNode } from 'react'; -import { i18n } from '@kbn/i18n'; -import { Subscription } from 'rxjs'; - -import { EuiButton, EuiLoadingSpinner, EuiText, EuiToolTip } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { DocLinksStart, HttpSetup } from 'src/core/public'; -import { API_BASE_PATH } from '../../../../../../common/constants'; -import { ReindexAction, ReindexStatus, UIReindexOption } from '../../../../../../common/types'; -import { LoadingState } from '../../../types'; -import { ReindexFlyout } from './flyout'; -import { ReindexPollingService, ReindexState } from './polling_service'; - -interface ReindexButtonProps { - indexName: string; - http: HttpSetup; - docLinks: DocLinksStart; - reindexBlocker?: ReindexAction['blockerForReindexing']; -} - -interface ReindexButtonState { - flyoutVisible: boolean; - reindexState: ReindexState; -} - -/** - * Displays a button that will display a flyout when clicked with the reindexing status for - * the given `indexName`. - */ -export class ReindexButton extends React.Component { - private service: ReindexPollingService; - private subscription?: Subscription; - - constructor(props: ReindexButtonProps) { - super(props); - - this.service = this.newService(); - this.state = { - flyoutVisible: false, - reindexState: this.service.status$.value, - }; - } - - public async componentDidMount() { - this.subscribeToUpdates(); - } - - public async componentWillUnmount() { - this.unsubscribeToUpdates(); - } - - public componentDidUpdate(prevProps: ReindexButtonProps) { - if (prevProps.indexName !== this.props.indexName) { - this.unsubscribeToUpdates(); - this.service = this.newService(); - this.subscribeToUpdates(); - } - } - - public render() { - const { indexName, reindexBlocker, docLinks } = this.props; - const { flyoutVisible, reindexState } = this.state; - - const buttonProps: any = { size: 's', onClick: this.showFlyout }; - let buttonContent: ReactNode = ( - - ); - - if (reindexState.loadingState === LoadingState.Loading) { - buttonProps.disabled = true; - buttonContent = ( - - ); - } else { - switch (reindexState.status) { - case ReindexStatus.inProgress: - buttonContent = ( - - Reindexing… - - ); - break; - case ReindexStatus.completed: - buttonProps.color = 'secondary'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'check'; - buttonContent = ( - - ); - break; - case ReindexStatus.failed: - buttonProps.color = 'danger'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'cross'; - buttonContent = ( - - ); - break; - case ReindexStatus.paused: - buttonProps.color = 'warning'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'pause'; - buttonContent = ( - - ); - case ReindexStatus.cancelled: - buttonProps.color = 'danger'; - buttonProps.iconSide = 'left'; - buttonProps.iconType = 'cross'; - buttonContent = ( - - ); - break; - } - } - - const showIndexedClosedWarning = - reindexBlocker === 'index-closed' && reindexState.status !== ReindexStatus.completed; - - if (showIndexedClosedWarning) { - buttonProps.color = 'warning'; - buttonProps.iconType = 'alert'; - } - - const button = {buttonContent}; - - return ( - - {showIndexedClosedWarning ? ( - - {i18n.translate( - 'xpack.upgradeAssistant.checkupTab.reindexing.reindexButton.indexClosedToolTipDetails', - { - defaultMessage: - '"{indexName}" needs to be reindexed, but it is currently closed. The Upgrade Assistant will open, reindex and then close the index. Reindexing may take longer than usual.', - values: { indexName }, - } - )} - - } - > - {button} - - ) : ( - button - )} - - {flyoutVisible && ( - - )} - - ); - } - - private newService() { - const { indexName, http } = this.props; - return new ReindexPollingService(indexName, http); - } - - private subscribeToUpdates() { - this.service.updateStatus(); - this.subscription = this.service!.status$.subscribe((reindexState) => - this.setState({ reindexState }) - ); - } - - private unsubscribeToUpdates() { - if (this.subscription) { - this.subscription.unsubscribe(); - delete this.subscription; - } - - if (this.service) { - this.service.stopPolling(); - } - } - - private startReindex = async () => { - if (!this.state.reindexState.status) { - // if status didn't exist we are starting a reindex action - this.sendUIReindexTelemetryInfo('start'); - } - - await this.service.startReindex(); - }; - - private cancelReindex = async () => { - this.sendUIReindexTelemetryInfo('stop'); - await this.service.cancelReindex(); - }; - - private showFlyout = () => { - this.sendUIReindexTelemetryInfo('open'); - this.setState({ flyoutVisible: true }); - }; - - private closeFlyout = () => { - this.sendUIReindexTelemetryInfo('close'); - this.setState({ flyoutVisible: false }); - }; - - private async sendUIReindexTelemetryInfo(uiReindexAction: UIReindexOption) { - await this.props.http.put(`${API_BASE_PATH}/stats/ui_reindex`, { - body: JSON.stringify(set({}, uiReindexAction, true)), - }); - } -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx deleted file mode 100644 index 97031dd08ee2a..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/flyout/container.tsx +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 React from 'react'; -import { DocLinksStart } from 'kibana/public'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiCallOut, - EuiFlyout, - EuiFlyoutHeader, - EuiLink, - EuiPortal, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; - -import { ReindexAction, ReindexStatus } from '../../../../../../../common/types'; - -import { ReindexState } from '../polling_service'; -import { ChecklistFlyoutStep } from './checklist_step'; -import { WarningsFlyoutStep } from './warnings_step'; - -enum ReindexFlyoutStep { - reindexWarnings, - checklist, -} - -interface ReindexFlyoutProps { - indexName: string; - closeFlyout: () => void; - reindexState: ReindexState; - startReindex: () => void; - cancelReindex: () => void; - docLinks: DocLinksStart; - reindexBlocker?: ReindexAction['blockerForReindexing']; -} - -interface ReindexFlyoutState { - currentFlyoutStep: ReindexFlyoutStep; -} - -const getOpenAndCloseIndexDocLink = (docLinks: DocLinksStart) => ( - - {i18n.translate( - 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.openAndCloseDocumentation', - { defaultMessage: 'documentation' } - )} - -); - -const getIndexClosedCallout = (docLinks: DocLinksStart) => ( - <> - -

- - {i18n.translate( - 'xpack.upgradeAssistant.checkupTab.reindexing.flyout.indexClosedCallout.calloutDetails.reindexingTakesLongerEmphasis', - { defaultMessage: 'Reindexing may take longer than usual' } - )} - - ), - }} - /> -

-
- - -); - -/** - * Wrapper for the contents of the flyout that manages which step of the flyout to show. - */ -export class ReindexFlyout extends React.Component { - constructor(props: ReindexFlyoutProps) { - super(props); - const { status, reindexWarnings } = props.reindexState; - - this.state = { - // If there are any warnings and we haven't started reindexing, show the warnings step first. - currentFlyoutStep: - reindexWarnings && reindexWarnings.length > 0 && status === undefined - ? ReindexFlyoutStep.reindexWarnings - : ReindexFlyoutStep.checklist, - }; - } - - public render() { - const { - closeFlyout, - indexName, - reindexState, - startReindex, - cancelReindex, - reindexBlocker, - docLinks, - } = this.props; - const { currentFlyoutStep } = this.state; - - let flyoutContents: React.ReactNode; - - const globalCallout = - reindexBlocker === 'index-closed' && reindexState.status !== ReindexStatus.completed - ? getIndexClosedCallout(docLinks) - : undefined; - switch (currentFlyoutStep) { - case ReindexFlyoutStep.reindexWarnings: - flyoutContents = ( - globalCallout} - closeFlyout={closeFlyout} - warnings={reindexState.reindexWarnings!} - advanceNextStep={this.advanceNextStep} - /> - ); - break; - case ReindexFlyoutStep.checklist: - flyoutContents = ( - globalCallout} - closeFlyout={closeFlyout} - reindexState={reindexState} - startReindex={startReindex} - cancelReindex={cancelReindex} - /> - ); - break; - default: - throw new Error(`Invalid flyout step: ${currentFlyoutStep}`); - } - - return ( - - - - -

- -

-
-
- {flyoutContents} -
-
- ); - } - - public advanceNextStep = () => { - this.setState({ currentFlyoutStep: ReindexFlyoutStep.checklist }); - }; -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts deleted file mode 100644 index 13818e864783e..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 { ReindexStatus, ReindexStep } from '../../../../../../common/types'; -import { ReindexPollingService } from './polling_service'; -import { httpServiceMock } from 'src/core/public/mocks'; - -const mockClient = httpServiceMock.createSetupContract(); - -describe('ReindexPollingService', () => { - beforeEach(() => { - mockClient.post.mockReset(); - mockClient.get.mockReset(); - }); - - it('does not poll when reindexOp is null', async () => { - mockClient.get.mockResolvedValueOnce({ - warnings: [], - reindexOp: null, - }); - - const service = new ReindexPollingService('myIndex', mockClient); - service.updateStatus(); - await new Promise((resolve) => setTimeout(resolve, 1200)); // wait for poll interval - - expect(mockClient.get).toHaveBeenCalledTimes(1); - service.stopPolling(); - }); - - it('does not poll when first check is a 200 and status is failed', async () => { - mockClient.get.mockResolvedValue({ - warnings: [], - reindexOp: { - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.failed, - errorMessage: `Oh no!`, - }, - }); - - const service = new ReindexPollingService('myIndex', mockClient); - service.updateStatus(); - await new Promise((resolve) => setTimeout(resolve, 1200)); // wait for poll interval - - expect(mockClient.get).toHaveBeenCalledTimes(1); - expect(service.status$.value.errorMessage).toEqual(`Oh no!`); - service.stopPolling(); - }); - - it('begins to poll when first check is a 200 and status is inProgress', async () => { - mockClient.get.mockResolvedValue({ - warnings: [], - reindexOp: { - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.inProgress, - }, - }); - - const service = new ReindexPollingService('myIndex', mockClient); - service.updateStatus(); - await new Promise((resolve) => setTimeout(resolve, 1200)); // wait for poll interval - - expect(mockClient.get).toHaveBeenCalledTimes(2); - service.stopPolling(); - }); - - describe('startReindex', () => { - it('posts to endpoint', async () => { - const service = new ReindexPollingService('myIndex', mockClient); - await service.startReindex(); - - expect(mockClient.post).toHaveBeenCalledWith('/api/upgrade_assistant/reindex/myIndex'); - }); - }); - - describe('cancelReindex', () => { - it('posts to cancel endpoint', async () => { - const service = new ReindexPollingService('myIndex', mockClient); - await service.cancelReindex(); - - expect(mockClient.post).toHaveBeenCalledWith('/api/upgrade_assistant/reindex/myIndex/cancel'); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts deleted file mode 100644 index 239bd56bd2fa5..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecations/reindex/polling_service.ts +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 { BehaviorSubject } from 'rxjs'; - -import { HttpSetup } from 'src/core/public'; -import { API_BASE_PATH } from '../../../../../../common/constants'; -import { - IndexGroup, - ReindexOperation, - ReindexStatus, - ReindexStep, - ReindexWarning, -} from '../../../../../../common/types'; -import { LoadingState } from '../../../types'; - -const POLL_INTERVAL = 1000; - -export interface ReindexState { - loadingState: LoadingState; - cancelLoadingState?: LoadingState; - lastCompletedStep?: ReindexStep; - status?: ReindexStatus; - reindexTaskPercComplete: number | null; - errorMessage: string | null; - reindexWarnings?: ReindexWarning[]; - hasRequiredPrivileges?: boolean; - indexGroup?: IndexGroup; -} - -interface StatusResponse { - warnings?: ReindexWarning[]; - reindexOp?: ReindexOperation; - hasRequiredPrivileges?: boolean; - indexGroup?: IndexGroup; -} - -/** - * Service used by the frontend to start reindexing and get updates on the state of a reindex - * operation. Exposes an Observable that can be used to subscribe to state updates. - */ -export class ReindexPollingService { - public status$: BehaviorSubject; - private pollTimeout?: NodeJS.Timeout; - - constructor(private indexName: string, private http: HttpSetup) { - this.status$ = new BehaviorSubject({ - loadingState: LoadingState.Loading, - errorMessage: null, - reindexTaskPercComplete: null, - }); - } - - public updateStatus = async () => { - // Prevent two loops from being started. - this.stopPolling(); - - try { - const data = await this.http.get( - `${API_BASE_PATH}/reindex/${this.indexName}` - ); - this.updateWithResponse(data); - - // Only keep polling if it exists and is in progress. - if (data.reindexOp && data.reindexOp.status === ReindexStatus.inProgress) { - this.pollTimeout = setTimeout(this.updateStatus, POLL_INTERVAL); - } - } catch (e) { - this.status$.next({ - ...this.status$.value, - status: ReindexStatus.failed, - }); - } - }; - - public stopPolling = () => { - if (this.pollTimeout) { - clearTimeout(this.pollTimeout); - } - }; - - public startReindex = async () => { - try { - // Optimistically assume it will start, reset other state. - const currentValue = this.status$.value; - this.status$.next({ - ...currentValue, - // Only reset last completed step if we aren't currently paused - lastCompletedStep: - currentValue.status === ReindexStatus.paused ? currentValue.lastCompletedStep : undefined, - status: ReindexStatus.inProgress, - reindexTaskPercComplete: null, - errorMessage: null, - cancelLoadingState: undefined, - }); - - const data = await this.http.post( - `${API_BASE_PATH}/reindex/${this.indexName}` - ); - - this.updateWithResponse({ reindexOp: data }); - this.updateStatus(); - } catch (e) { - this.status$.next({ ...this.status$.value, status: ReindexStatus.failed }); - } - }; - - public cancelReindex = async () => { - try { - this.status$.next({ - ...this.status$.value, - cancelLoadingState: LoadingState.Loading, - }); - - await this.http.post(`${API_BASE_PATH}/reindex/${this.indexName}/cancel`); - } catch (e) { - this.status$.next({ - ...this.status$.value, - cancelLoadingState: LoadingState.Error, - }); - } - }; - - private updateWithResponse = ({ - reindexOp, - warnings, - hasRequiredPrivileges, - indexGroup, - }: StatusResponse) => { - const currentValue = this.status$.value; - // Next value should always include the entire state, not just what changes. - // We make a shallow copy as a starting new state. - const nextValue = { - ...currentValue, - // If we're getting any updates, set to success. - loadingState: LoadingState.Success, - }; - - if (warnings) { - nextValue.reindexWarnings = warnings; - } - - if (hasRequiredPrivileges !== undefined) { - nextValue.hasRequiredPrivileges = hasRequiredPrivileges; - } - - if (indexGroup) { - nextValue.indexGroup = indexGroup; - } - - if (reindexOp) { - // Prevent the UI flickering back to inProgres after cancelling. - nextValue.lastCompletedStep = reindexOp.lastCompletedStep; - nextValue.status = reindexOp.status; - nextValue.reindexTaskPercComplete = reindexOp.reindexTaskPercComplete; - nextValue.errorMessage = reindexOp.errorMessage; - - if (reindexOp.status === ReindexStatus.cancelled) { - nextValue.cancelLoadingState = LoadingState.Success; - } - } - - this.status$.next(nextValue); - }; -} 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 ab654b00194a1..8abbda3896eca 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 @@ -22,6 +22,7 @@ import { i18n } from '@kbn/i18n'; import { SectionLoading } from '../../../shared_imports'; import { useAppContext } from '../../app_context'; import { EsDeprecationsTable } from './es_deprecations_table'; +import { EsDeprecationErrors } from './es_deprecation_errors'; const i18nTexts = { pageTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageTitle', { @@ -64,7 +65,7 @@ export const EsDeprecationsContent = () => { useEffect(() => { if (isLoading === false) { async function sendTelemetryData() { - await api.sendTelemetryData({ + await api.sendPageTelemetryData({ elasticsearch: true, }); } @@ -74,8 +75,7 @@ export const EsDeprecationsContent = () => { }, [api, isLoading]); if (error) { - // TODO handle error - return null; + return ; } if (isLoading) { @@ -120,7 +120,7 @@ export const EsDeprecationsContent = () => {
void; } export const EsDeprecationsTable: React.FunctionComponent = ({ deprecations, reload }) => { - const columns: Array> = [ - { - field: 'type', - name: i18nTexts.typeColumnTitle, - truncateText: true, - sortable: true, - render: (type: 'cluster_settings' | 'index_settings' | 'node_settings' | 'ml_settings') => - DEPRECATION_TYPE_MAP[type], - }, - { - field: 'index', - name: i18nTexts.sourceColumnTitle, - truncateText: true, - sortable: true, - }, - { - field: 'message', - name: i18nTexts.issueColumnTitle, - truncateText: true, - sortable: true, - // TODO handle onClick - render: (message: string) => {message}, - }, - { - field: 'isCritical', - name: i18nTexts.statusColumnTitle, - truncateText: true, - sortable: true, - render: (isCritical: boolean) => { - if (isCritical) { - return {i18nTexts.criticalBadgeLabel}; - } - return null; - }, - }, - ]; - - const pagination = { - initialPageSize: 20, - pageSizeOptions: [10, 20, 50], - }; + // const pagination = { + // initialPageSize: 20, + // pageSizeOptions: [10, 20, 50], + // }; + + // const sorting = { + // sort: { + // field: 'isCritical', + // direction: 'desc', + // }, + // enableAllColumns: true, + // } as const; + + // const searchConfig = { + // box: { + // incremental: true, + // placeholder: i18nTexts.searchPlaceholderLabel, + // }, + // filters: [ + // { + // type: 'is', + // field: 'isCritical', + // name: i18nTexts.criticalFilterLabel, + // }, + // { + // type: 'field_value_selection', + // field: 'type', + // name: i18nTexts.typeFilterLabel, + // multiSelect: false, + // options: (Object.keys(DEPRECATION_TYPE_MAP) as Array< + // keyof typeof DEPRECATION_TYPE_MAP + // >).map((type) => ({ + // value: type, + // name: DEPRECATION_TYPE_MAP[type], + // })), + // }, + // ] as SearchFilterConfig[], + // toolsRight: [ + // + // {i18nTexts.refreshButtonLabel} + // , + // ], + // }; - const searchConfig = { - box: { - incremental: true, - }, - filters: [ - { - type: 'is', - field: 'isCritical', - name: i18nTexts.criticalFilterLabel, - }, - { - type: 'field_value_selection', - field: 'type', - name: i18nTexts.typeFilterLabel, - multiSelect: false, - options: (Object.keys(DEPRECATION_TYPE_MAP) as Array< - keyof typeof DEPRECATION_TYPE_MAP - >).map((type) => ({ - value: type, - name: DEPRECATION_TYPE_MAP[type], - })), - }, - ] as SearchFilterConfig[], - toolsRight: [ - - {i18nTexts.refreshButtonLabel} - , - ], + // return ( + // ({ + // 'data-test-subj': 'row', + // })} + // cellProps={() => ({ + // 'data-test-subj': 'cell', + // })} + // data-test-subj="esDeprecationsTable" + // message={i18nTexts.noDeprecationsMessage} + // tableLayout="auto" + // /> + // ); + + const renderTableRowCells = (deprecation: EnrichedDeprecationInfo, index: number) => { + const { correctiveAction } = deprecation; + + if (correctiveAction?.type === 'mlSnapshot') { + return ; + } + + if (correctiveAction?.type === 'indexSetting') { + return ; + } + + if (correctiveAction?.type === 'reindex') { + return ; + } + + return ; }; + // TODO implement commented-out table functionality return ( - ({ - 'data-test-subj': 'row', - })} - cellProps={() => ({ - 'data-test-subj': 'cell', - })} - data-test-subj="esDeprecationsTable" - message={i18nTexts.noDeprecationsMessage} - tableLayout="auto" - /> +
+ + + + + + + {i18nTexts.refreshButtonLabel} + + + + + + + {/* + + + + + + */} + + + + {headerLabels.map((label) => { + return ( + this.onSort(fieldName)} + // isSorted={isSorted} + // isSortAscending={isSortAscending} + > + {label} + + ); + })} + + + + {(deprecations || []).map((deprecation, index) => { + return ( + + {renderTableRowCells(deprecation, index)} + + ); + })} + + + {/* {this.renderFooterCells()} */} + + + + + {/* */} +
); }; 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 new file mode 100644 index 0000000000000..b4f6bba228198 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table_cells.tsx @@ -0,0 +1,64 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiBadge, EuiLink } from '@elastic/eui'; +import { EnrichedDeprecationInfo } from '../../../../common/types'; +import { DEPRECATION_TYPE_MAP } from '../constants'; +import { DeprecationTableColumns } from '../types'; + +interface Props { + statusTableCell?: React.ReactNode; + fieldName: DeprecationTableColumns; + deprecation: EnrichedDeprecationInfo; + openFlyout: () => void; +} + +const i18nTexts = { + criticalBadgeLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.criticalBadgeLabel', + { + defaultMessage: 'Critical', + } + ), +}; + +export const EsDeprecationsTableCells: React.FunctionComponent = ({ + statusTableCell, + fieldName, + deprecation, + openFlyout, +}) => { + // "Type" column + if (fieldName === 'type') { + return <>{DEPRECATION_TYPE_MAP[deprecation.type as EnrichedDeprecationInfo['type']]}; + } + + // "Status column" + if (fieldName === 'correctiveAction') { + if (statusTableCell) { + return <>{statusTableCell}; + } else if (deprecation.isCritical === true) { + return {i18nTexts.criticalBadgeLabel}; + } + + return <>{''}; + } + + // "Issue" column + if (fieldName === 'message') { + return ( + + {deprecation.message} + + ); + } + + // Default behavior: render value or empty string if undefined + return <>{deprecation[fieldName] ?? ''}; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx index 31b5c80d5b377..56d6e23d9d4f3 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/kibana_deprecations/kibana_deprecations.tsx @@ -112,7 +112,7 @@ export const KibanaDeprecationsContent = withRouter(({ history }: RouteComponent useEffect(() => { async function sendTelemetryData() { - await api.sendTelemetryData({ + await api.sendPageTelemetryData({ kibana: true, }); } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx index b77d4a337295c..a3bc231e17234 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx @@ -76,7 +76,7 @@ export const DeprecationsOverview: FunctionComponent = ({ history }) => { useEffect(() => { async function sendTelemetryData() { - await api.sendTelemetryData({ + await api.sendPageTelemetryData({ overview: true, }); } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts index e930e41573bcf..34e7dad6260d4 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -5,27 +5,6 @@ * 2.0. */ -import React from 'react'; - -import { EnrichedDeprecationInfo, UpgradeAssistantStatus } from '../../../common/types'; -import { ResponseError } from '../lib/api'; - -export interface UpgradeAssistantTabProps { - alertBanner?: React.ReactNode; - checkupData?: UpgradeAssistantStatus | null; - deprecations?: EnrichedDeprecationInfo[]; - refreshCheckupData: () => void; - error: ResponseError | null; - isLoading: boolean; - navigateToOverviewPage: () => void; -} - -// eslint-disable-next-line react/prefer-stateless-function -export class UpgradeAssistantTabComponent< - T extends UpgradeAssistantTabProps = UpgradeAssistantTabProps, - S = {} -> extends React.Component {} - export enum LoadingState { Loading, Success, @@ -39,3 +18,5 @@ export enum GroupByOption { index = 'index', node = 'node', } + +export type DeprecationTableColumns = 'type' | 'index' | 'message' | 'correctiveAction'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts index c4d9128baa56a..3c83a1ced107c 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts @@ -52,7 +52,7 @@ export class ApiService { }); } - public async sendTelemetryData(telemetryData: { [tabName: string]: boolean }) { + public async sendPageTelemetryData(telemetryData: { [tabName: string]: boolean }) { const result = await this.sendRequest({ path: `${API_BASE_PATH}/stats/ui_open`, method: 'put', @@ -122,6 +122,37 @@ export class ApiService { method: 'get', }); } + + public async sendReindexTelemetryData(telemetryData: { [key: string]: boolean }) { + const result = await this.sendRequest({ + path: `${API_BASE_PATH}/stats/ui_reindex`, + method: 'put', + body: JSON.stringify(telemetryData), + }); + + return result; + } + + public async getReindexStatus(indexName: string) { + return await this.sendRequest({ + path: `${API_BASE_PATH}/reindex/${indexName}`, + method: 'get', + }); + } + + public async startReindexTask(indexName: string) { + return await this.sendRequest({ + path: `${API_BASE_PATH}/reindex/${indexName}`, + method: 'post', + }); + } + + public async cancelReindexTask(indexName: string) { + return await this.sendRequest({ + path: `${API_BASE_PATH}/reindex/${indexName}/cancel`, + method: 'post', + }); + } } export const apiService = new ApiService(); diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts index 4220f0eef8d42..85cfd2a3fd16c 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts @@ -25,8 +25,7 @@ const i18nTexts = { upgradedMessage: i18n.translate( 'xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage', { - defaultMessage: - 'Your configuration is up to date. Kibana and all Elasticsearch nodes are running the same version.', + defaultMessage: 'All Elasticsearch nodes have been upgraded.', } ), loadingError: i18n.translate('xpack.upgradeAssistant.esDeprecationErrors.loadingErrorMessage', { diff --git a/x-pack/plugins/upgrade_assistant/public/shared_imports.ts b/x-pack/plugins/upgrade_assistant/public/shared_imports.ts index 9007fdc5db04d..afce2eff322a6 100644 --- a/x-pack/plugins/upgrade_assistant/public/shared_imports.ts +++ b/x-pack/plugins/upgrade_assistant/public/shared_imports.ts @@ -12,4 +12,5 @@ export { useRequest, UseRequestConfig, SectionLoading, + GlobalFlyout, } from '../../../../src/plugins/es_ui_shared/public/'; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index dc50482822909..d738d7c31335f 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -43,20 +43,27 @@ export async function getUpgradeAssistantStatus( }, ], index_settings: { - logs: [ + logs2: [ { level: 'warning', - message: "C Index name cannot contain ':'", + message: 'translog retention settings are ignored', url: 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_index_name', details: "This index is named [logs:apache], which contains the illegal character ':'.", }, + { + level: 'critical', + message: 'Index created before 7.0', + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html', + details: 'This index was created using version: 6.8.13', + }, ], }, ml_settings: [ { level: 'critical', - message: "D Cluster name cannot contain ':'", + message: 'model snapshot [1627343998] for job [my_job] needs to be deleted or upgraded', url: 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', details: From 233dad720dbe7f4a698b0e75cb4b6319c50c565e Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 5 Aug 2021 12:28:48 -0400 Subject: [PATCH 04/18] cleanup --- .../deprecation_types/default/table_row.tsx | 21 +- .../index_settings/flyout.tsx | 113 +++++-- .../index_settings/status_table_cell.tsx | 15 +- .../index_settings/table_row.tsx | 43 +-- .../deprecation_types/ml_snapshots/flyout.tsx | 59 ++-- .../ml_snapshots/table_row.tsx | 13 +- .../ml_snapshots/use_snapshot_state.tsx | 3 +- .../reindex/flyout/checklist_step.tsx | 2 +- .../deprecation_types/reindex/table_row.tsx | 19 +- .../reindex/use_reindex_state.tsx | 4 + .../es_deprecations/es_deprecations.tsx | 17 +- .../es_deprecations/es_deprecations_table.tsx | 292 ++++++++++-------- .../components/shared/no_deprecations.tsx | 17 +- .../public/application/components/types.ts | 2 + .../server/lib/es_migration_apis.ts | 64 ++++ 15 files changed, 437 insertions(+), 247 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx index 5d1f07a3901bc..7f4b2e3be3479 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/table_row.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { EuiTableRowCell } from '@elastic/eui'; import { GlobalFlyout } from '../../../../../shared_imports'; import { EnrichedDeprecationInfo } from '../../../../../../common/types'; @@ -21,13 +21,18 @@ interface Props { } export const DefaultTableRow: React.FunctionComponent = ({ rowFieldNames, deprecation }) => { - const [showFlyout, setShowFlyout] = useState(false); + const [showFlyout, setShowFlyout] = useState(false); const { addContent: addContentToGlobalFlyout, removeContent: removeContentFromGlobalFlyout, } = useGlobalFlyout(); + const closeFlyout = useCallback(() => { + setShowFlyout(false); + removeContentFromGlobalFlyout('deprecationDetails'); + }, [removeContentFromGlobalFlyout]); + useEffect(() => { if (showFlyout) { addContentToGlobalFlyout({ @@ -35,22 +40,16 @@ export const DefaultTableRow: React.FunctionComponent = ({ rowFieldNames, Component: DefaultDeprecationFlyout, props: { deprecation, - closeFlyout: () => setShowFlyout(false), + closeFlyout, }, flyoutProps: { - onClose: () => setShowFlyout(false), + onClose: closeFlyout, 'data-test-subj': 'defaultDeprecationDetails', 'aria-labelledby': 'defaultDeprecationDetailsFlyoutTitle', }, }); } - }, [addContentToGlobalFlyout, deprecation, showFlyout]); - - useEffect(() => { - if (showFlyout === false) { - removeContentFromGlobalFlyout('deprecationDetails'); - } - }, [showFlyout, removeContentFromGlobalFlyout]); + }, [addContentToGlobalFlyout, closeFlyout, deprecation, showFlyout]); return ( <> diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx index 6dd11f49e61cd..caf17114c08b3 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx @@ -21,13 +21,20 @@ import { EuiTextColor, EuiLink, EuiSpacer, + EuiCallOut, } from '@elastic/eui'; import { EnrichedDeprecationInfo, IndexSettingAction } from '../../../../../../common/types'; +import type { ResponseError } from '../../../../lib/api'; +import type { Status } from '../../../types'; export interface RemoveIndexSettingsFlyoutProps { deprecation: EnrichedDeprecationInfo; closeFlyout: () => void; removeIndexSettings: (index: string, settings: string[]) => Promise; + status: { + statusType: Status; + details?: ResponseError; + }; } const i18nTexts = { @@ -53,6 +60,18 @@ const i18nTexts = { defaultMessage: 'Remove deprecated settings', } ), + retryRemoveButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.retryRemoveButtonLabel', + { + defaultMessage: 'Retry removing deprecated settings', + } + ), + resolvedButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.resolvedButtonLabel', + { + defaultMessage: 'Resolved', + } + ), closeButtonLabel: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.cancelButtonLabel', { @@ -65,16 +84,23 @@ const i18nTexts = { defaultMessage: 'Remove the following deprecated index settings?', } ), + errorTitle: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.deleteErrorTitle', + { + defaultMessage: 'Error deleting index settings', + } + ), }; export const RemoveIndexSettingsFlyout = ({ deprecation, closeFlyout, removeIndexSettings, + status, }: RemoveIndexSettingsFlyoutProps) => { const { index, message, details, url, correctiveAction } = deprecation; + const { statusType, details: statusDetails } = status; - // TODO handle error banner/retry if error return ( <> @@ -88,6 +114,19 @@ export const RemoveIndexSettingsFlyout = ({ + {statusType === 'error' && ( + <> + + {statusDetails!.message} + + + + )}

{details}

@@ -97,25 +136,30 @@ export const RemoveIndexSettingsFlyout = ({

- + {/* Hide the prompt to remove settings if the deprecation has been resolved */} + {statusType !== 'complete' && ( + <> + - -

{i18nTexts.confirmationText}

-
+ +

{i18nTexts.confirmationText}

+
- + - -
    - {(correctiveAction as IndexSettingAction).deprecatedSettings.map( - (setting, settingIndex) => ( -
  • - {setting} -
  • - ) - )} -
-
+ +
    + {(correctiveAction as IndexSettingAction).deprecatedSettings.map( + (setting, settingIndex) => ( +
  • + {setting} +
  • + ) + )} +
+
+ + )}
@@ -124,21 +168,26 @@ export const RemoveIndexSettingsFlyout = ({ {i18nTexts.closeButtonLabel}
- - - removeIndexSettings( - index!, - (correctiveAction as IndexSettingAction).deprecatedSettings - ) - } - > - {i18nTexts.removeButtonLabel} - - + {/* Hide the "Remove settings" button if the deprecation has been resolved */} + {statusType !== 'complete' && ( + + + removeIndexSettings( + index!, + (correctiveAction as IndexSettingAction).deprecatedSettings + ) + } + > + {statusType === 'error' + ? i18nTexts.retryRemoveButtonLabel + : i18nTexts.removeButtonLabel} + + + )} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx index 93fb8bdbb34ee..214f6ce81c7ea 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiFlexItem, EuiText, EuiFlexGroup, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Status } from './table_row'; +import { Status } from '../../../types'; const i18nTexts = { deleteInProgressText: i18n.translate( @@ -21,7 +21,7 @@ const i18nTexts = { deleteCompleteText: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.indexSettings.deleteCompleteText', { - defaultMessage: 'Settings removal complete', + defaultMessage: 'Deprecated settings removed', } ), deleteFailedText: i18n.translate( @@ -33,11 +33,14 @@ const i18nTexts = { }; interface Props { - status: Status; + status: { + statusType: Status; + }; } export const IndexSettingsStatusCell: React.FunctionComponent = ({ status }) => { - if (status === 'in_progress') { + const { statusType } = status; + if (statusType === 'in_progress') { return ( @@ -50,7 +53,7 @@ export const IndexSettingsStatusCell: React.FunctionComponent = ({ status ); } - if (status === 'complete') { + if (statusType === 'complete') { return ( @@ -63,7 +66,7 @@ export const IndexSettingsStatusCell: React.FunctionComponent = ({ status ); } - if (status === 'error') { + if (statusType === 'error') { return ( diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx index ef0760493d66a..d8d5d31b79575 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx @@ -10,8 +10,9 @@ import { EuiTableRowCell } from '@elastic/eui'; import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { GlobalFlyout } from '../../../../../shared_imports'; import { useAppContext } from '../../../../app_context'; +import type { ResponseError } from '../../../../lib/api'; import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; -import { DeprecationTableColumns } from '../../../types'; +import { DeprecationTableColumns, Status } from '../../../types'; import { IndexSettingsStatusCell } from './status_table_cell'; import { RemoveIndexSettingsFlyout, RemoveIndexSettingsFlyoutProps } from './flyout'; @@ -22,36 +23,43 @@ interface Props { rowFieldNames: DeprecationTableColumns[]; } -export type Status = 'in_progress' | 'complete' | 'idle' | 'error'; - export const IndexSettingsTableRow: React.FunctionComponent = ({ rowFieldNames, deprecation, }) => { - const [showFlyout, setShowFlyout] = useState(false); - const [status, setStatus] = useState('idle'); + const [showFlyout, setShowFlyout] = useState(false); + const [status, setStatus] = useState<{ + statusType: Status; + details?: ResponseError; + }>({ statusType: 'idle' }); const { api } = useAppContext(); - const closeFlyout = useCallback(() => setShowFlyout(false), []); + const { + addContent: addContentToGlobalFlyout, + removeContent: removeContentFromGlobalFlyout, + } = useGlobalFlyout(); + + const closeFlyout = useCallback(() => { + setShowFlyout(false); + removeContentFromGlobalFlyout('indexSettingsFlyout'); + }, [removeContentFromGlobalFlyout]); const removeIndexSettings = useCallback( async (index: string, settings: string[]) => { - setStatus('in_progress'); + setStatus({ statusType: 'in_progress' }); const { error } = await api.updateIndexSettings(index, settings); - setStatus(error ? 'error' : 'complete'); + setStatus({ + statusType: error ? 'error' : 'complete', + details: error ?? undefined, + }); closeFlyout(); }, [api, closeFlyout] ); - const { - addContent: addContentToGlobalFlyout, - removeContent: removeContentFromGlobalFlyout, - } = useGlobalFlyout(); - useEffect(() => { if (showFlyout) { addContentToGlobalFlyout({ @@ -61,6 +69,7 @@ export const IndexSettingsTableRow: React.FunctionComponent = ({ closeFlyout, deprecation, removeIndexSettings, + status, }, flyoutProps: { onClose: closeFlyout, @@ -69,13 +78,7 @@ export const IndexSettingsTableRow: React.FunctionComponent = ({ }, }); } - }, [addContentToGlobalFlyout, deprecation, removeIndexSettings, showFlyout, closeFlyout]); - - useEffect(() => { - if (showFlyout === false) { - removeContentFromGlobalFlyout('indexSettingsFlyout'); - } - }, [showFlyout, removeContentFromGlobalFlyout]); + }, [addContentToGlobalFlyout, deprecation, removeIndexSettings, showFlyout, closeFlyout, status]); 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 81ff09f168e97..8ecf753414a5e 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 @@ -131,34 +131,37 @@ export const FixSnapshotsFlyout = ({ {i18nTexts.closeButtonLabel} - - - - - {snapshotState.action === 'delete' && snapshotState.error - ? i18nTexts.retryDeleteButtonLabel - : i18nTexts.deleteButtonLabel} - - - - - {snapshotState.action === 'upgrade' && snapshotState.error - ? i18nTexts.retryUpgradeButtonLabel - : i18nTexts.upgradeButtonLabel} - - - - + {/* Hide the upgrade/delete actions if the deprecation has been resolved */} + {snapshotState.status !== 'complete' && ( + + + + + {snapshotState.action === 'delete' && snapshotState.error + ? i18nTexts.retryDeleteButtonLabel + : i18nTexts.deleteButtonLabel} + + + + + {snapshotState.action === 'upgrade' && snapshotState.error + ? i18nTexts.retryUpgradeButtonLabel + : i18nTexts.upgradeButtonLabel} + + + + + )} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx index d16a58f7cf2c8..6a1150cc4effa 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx @@ -27,7 +27,7 @@ export const MlSnapshotsTableRowCells: React.FunctionComponent = rowFieldNames, deprecation, }) => { - const [showFlyout, setShowFlyout] = useState(false); + const [showFlyout, setShowFlyout] = useState(false); const snapshotState = useMlSnapshotContext(); const { @@ -35,7 +35,10 @@ export const MlSnapshotsTableRowCells: React.FunctionComponent = removeContent: removeContentFromGlobalFlyout, } = useGlobalFlyout(); - const closeFlyout = useCallback(() => setShowFlyout(false), []); + const closeFlyout = useCallback(() => { + setShowFlyout(false); + removeContentFromGlobalFlyout('mlFlyout'); + }, [removeContentFromGlobalFlyout]); useEffect(() => { if (showFlyout) { @@ -56,12 +59,6 @@ export const MlSnapshotsTableRowCells: React.FunctionComponent = } }, [snapshotState, addContentToGlobalFlyout, showFlyout, deprecation, closeFlyout]); - useEffect(() => { - if (showFlyout === false) { - removeContentFromGlobalFlyout('mlFlyout'); - } - }, [showFlyout, removeContentFromGlobalFlyout]); - return ( <> {rowFieldNames.map((field: DeprecationTableColumns) => { 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 7c5d770a04235..a724922563e05 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 @@ -8,13 +8,14 @@ import { useRef, useCallback, useState, useEffect } from 'react'; import { ApiService, ResponseError } from '../../../../lib/api'; +import { Status } from '../../../types'; const POLL_INTERVAL_MS = 1000; interface SnapshotStatus { snapshotId: string; jobId: string; - status: 'complete' | 'in_progress' | 'error' | 'idle'; + status: Status; action?: 'upgrade' | 'delete'; } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx index e30c42a0f95f5..856e2a57649df 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/checklist_step.tsx @@ -45,7 +45,7 @@ const buttonLabel = (status?: ReindexStatus) => { return ( ); case ReindexStatus.paused: diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx index 4803d2e4a0ec7..06fc4f454af64 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx @@ -27,15 +27,20 @@ export const ReindexTableRowCells: React.FunctionComponent = ({ rowFieldNames, deprecation, }) => { - const [showFlyout, setShowFlyout] = useState(false); + const [showFlyout, setShowFlyout] = useState(false); const reindexState = useReindexContext(); + const { api } = useAppContext(); const { addContent: addContentToGlobalFlyout, removeContent: removeContentFromGlobalFlyout, } = useGlobalFlyout(); - const closeFlyout = useCallback(() => setShowFlyout(false), []); + const closeFlyout = useCallback(async () => { + await api.sendReindexTelemetryData({ close: true }); + setShowFlyout(false); + removeContentFromGlobalFlyout('reindexFlyout'); + }, [api, removeContentFromGlobalFlyout]); useEffect(() => { if (showFlyout) { @@ -57,10 +62,14 @@ export const ReindexTableRowCells: React.FunctionComponent = ({ }, [addContentToGlobalFlyout, deprecation, showFlyout, reindexState, closeFlyout]); useEffect(() => { - if (showFlyout === false) { - removeContentFromGlobalFlyout('reindexFlyout'); + if (showFlyout) { + async function sendTelemetry() { + await api.sendReindexTelemetryData({ open: true }); + } + + sendTelemetry(); } - }, [showFlyout, removeContentFromGlobalFlyout]); + }, [showFlyout, api]); return ( <> diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx index eff3eefe8d776..15ae68d544033 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx @@ -130,6 +130,8 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A cancelLoadingState: undefined, }); + await api.sendReindexTelemetryData({ start: true }); + const { data, error } = await api.startReindexTask(indexName); if (error) { @@ -145,6 +147,8 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A }, [api, indexName, reindexState, updateStatus]); const cancelReindex = useCallback(async () => { + await api.sendReindexTelemetryData({ stop: true }); + const { error } = await api.cancelReindexTask(indexName); setReindexState({ 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 8abbda3896eca..f98bec30d63ee 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 @@ -6,6 +6,7 @@ */ import React, { useEffect } from 'react'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; import { EuiButton, @@ -23,6 +24,7 @@ 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 i18nTexts = { pageTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageTitle', { @@ -53,7 +55,7 @@ const i18nTexts = { }, }; -export const EsDeprecationsContent = () => { +export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProps) => { const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); const { data: esDeprecations, isLoading, error, resendRequest } = api.useLoadUpgradeStatus(); @@ -86,6 +88,17 @@ export const EsDeprecationsContent = () => { ); } + if (esDeprecations?.deprecations?.length === 0) { + return ( + + history.push('/overview')} + /> + + ); + } + return (
{
); -}; +}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx index 99e88962b5b1e..264ee432822a3 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import React from 'react'; +import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; +import { sortBy } from 'lodash'; import { EuiButton, EuiFlexGroup, @@ -14,10 +15,15 @@ import { EuiTableRow, EuiTableHeaderCell, EuiTableHeader, - EuiFieldSearch, + EuiSearchBar, EuiSpacer, EuiFlexItem, EuiTableBody, + EuiTablePagination, + EuiCallOut, + EuiTableRowCell, + Pager, + Query, } from '@elastic/eui'; import { EnrichedDeprecationInfo } from '../../../../common/types'; import { @@ -27,6 +33,7 @@ import { ReindexTableRow, } from './deprecation_types'; import { DeprecationTableColumns } from '../types'; +import { DEPRECATION_TYPE_MAP } from '../constants'; const i18nTexts = { criticalBadgeLabel: i18n.translate( @@ -44,7 +51,7 @@ const i18nTexts = { noDeprecationsMessage: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.table.noDeprecationsMessage', { - defaultMessage: 'No Elasticsearch deprecations found', + defaultMessage: 'No Elasticsearch deprecation issues found', } ), typeFilterLabel: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeFilterLabel', { @@ -82,108 +89,137 @@ const cellTypeToLabelMap = { ), }; -const headerLabels = Object.values(cellTypeToLabelMap); const cellTypes = Object.keys(cellTypeToLabelMap) as DeprecationTableColumns[]; +const pageSizeOptions = [10, 20, 50]; + +const renderTableRowCells = (deprecation: EnrichedDeprecationInfo) => { + const { correctiveAction } = deprecation; + + if (correctiveAction?.type === 'mlSnapshot') { + return ; + } + + if (correctiveAction?.type === 'indexSetting') { + return ; + } + + if (correctiveAction?.type === 'reindex') { + return ; + } + + return ; +}; interface Props { deprecations?: EnrichedDeprecationInfo[]; reload: () => void; } -export const EsDeprecationsTable: React.FunctionComponent = ({ deprecations, reload }) => { - // const pagination = { - // initialPageSize: 20, - // pageSizeOptions: [10, 20, 50], - // }; - - // const sorting = { - // sort: { - // field: 'isCritical', - // direction: 'desc', - // }, - // enableAllColumns: true, - // } as const; - - // const searchConfig = { - // box: { - // incremental: true, - // placeholder: i18nTexts.searchPlaceholderLabel, - // }, - // filters: [ - // { - // type: 'is', - // field: 'isCritical', - // name: i18nTexts.criticalFilterLabel, - // }, - // { - // type: 'field_value_selection', - // field: 'type', - // name: i18nTexts.typeFilterLabel, - // multiSelect: false, - // options: (Object.keys(DEPRECATION_TYPE_MAP) as Array< - // keyof typeof DEPRECATION_TYPE_MAP - // >).map((type) => ({ - // value: type, - // name: DEPRECATION_TYPE_MAP[type], - // })), - // }, - // ] as SearchFilterConfig[], - // toolsRight: [ - // - // {i18nTexts.refreshButtonLabel} - // , - // ], - // }; - - // return ( - // ({ - // 'data-test-subj': 'row', - // })} - // cellProps={() => ({ - // 'data-test-subj': 'cell', - // })} - // data-test-subj="esDeprecationsTable" - // message={i18nTexts.noDeprecationsMessage} - // tableLayout="auto" - // /> - // ); - - const renderTableRowCells = (deprecation: EnrichedDeprecationInfo, index: number) => { - const { correctiveAction } = deprecation; - - if (correctiveAction?.type === 'mlSnapshot') { - return ; - } +interface SortConfig { + isSortAscending: boolean; + sortField: DeprecationTableColumns; +} - if (correctiveAction?.type === 'indexSetting') { - return ; - } +const getSortedItems = (deprecations: EnrichedDeprecationInfo[], sortConfig: SortConfig) => { + const { isSortAscending, sortField } = sortConfig; + const sorted = sortBy(deprecations, [ + (deprecation) => { + if (sortField === 'correctiveAction') { + return deprecation.isCritical !== true; + } + return deprecation[sortField]; + }, + ]); + + return isSortAscending ? sorted : sorted.reverse(); +}; + +export const EsDeprecationsTable: React.FunctionComponent = ({ + deprecations = [], + reload, +}) => { + const [sortConfig, setSortConfig] = useState({ + isSortAscending: true, + sortField: 'correctiveAction', + }); + + const [itemsPerPage, setItemsPerPage] = useState(10); + const [currentPageIndex, setCurrentPageIndex] = useState(0); + const [searchQuery, setSearchQuery] = useState(EuiSearchBar.Query.MATCH_ALL); + const [searchError, setSearchError] = useState<{ message: string } | undefined>(undefined); - if (correctiveAction?.type === 'reindex') { - return ; + const [filteredDeprecations, setFilteredDeprecations] = useState( + getSortedItems(deprecations, sortConfig) + ); + + const pager = useMemo(() => new Pager(deprecations.length, itemsPerPage, currentPageIndex), [ + currentPageIndex, + deprecations, + itemsPerPage, + ]); + + const handleSort = useCallback( + (fieldName: DeprecationTableColumns) => { + const newSortConfig = { + isSortAscending: sortConfig.sortField === fieldName ? !sortConfig.isSortAscending : true, + sortField: fieldName, + }; + setSortConfig(newSortConfig); + }, + [sortConfig] + ); + + const handleSearch = useCallback(({ query, error }) => { + if (error) { + setSearchError(error); + } else { + setSearchError(undefined); + setSearchQuery(query); } + }, []); - return ; - }; + useEffect(() => { + const { firstItemIndex, lastItemIndex } = pager; + const deprecationsFilteredByQuery = EuiSearchBar.Query.execute(searchQuery, deprecations); + const deprecationsSortedByFieldType = getSortedItems(deprecationsFilteredByQuery, sortConfig); + // Filter deprecations by current page and number of items per page + const visibleDeprecations = deprecationsSortedByFieldType.slice( + firstItemIndex, + lastItemIndex + 1 + ); + setFilteredDeprecations(visibleDeprecations); + }, [deprecations, sortConfig, pager, searchQuery]); - // TODO implement commented-out table functionality return (
- + ).map((type) => ({ + value: type, + name: DEPRECATION_TYPE_MAP[type], + })), + }, + ]} + onChange={handleSearch} + /> = ({ deprecatio - + {searchError && ( + <> + - {/* - - - - - - */} + + + )} + + - {headerLabels.map((label) => { + {Object.entries(cellTypeToLabelMap).map(([fieldName, label]) => { return ( this.onSort(fieldName)} - // isSorted={isSorted} - // isSortAscending={isSortAscending} + onSort={() => handleSort(fieldName as DeprecationTableColumns)} + isSorted={sortConfig.sortField === fieldName} + isSortAscending={sortConfig.isSortAscending} > {label} @@ -226,30 +263,37 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ deprecatio })} - - {(deprecations || []).map((deprecation, index) => { - return ( - - {renderTableRowCells(deprecation, index)} - - ); - })} - - - {/* {this.renderFooterCells()} */} + {filteredDeprecations.length === 0 ? ( + + + + {i18nTexts.noDeprecationsMessage} + + + + ) : ( + + {filteredDeprecations.map((deprecation, index) => { + return ( + + {renderTableRowCells(deprecation)} + + ); + })} + + )} - {/* */} +
); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx index 3626151b63bbf..17bd1dc430883 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx @@ -12,14 +12,14 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; const i18nTexts = { - emptyPromptTitle: i18n.translate('xpack.upgradeAssistant.noDeprecationsPrompt.title', { - defaultMessage: 'Ready to upgrade!', - }), - getEmptyPromptDescription: (deprecationType: string) => + getEmptyPromptTitle: (deprecationType: string) => i18n.translate('xpack.upgradeAssistant.noDeprecationsPrompt.description', { - defaultMessage: 'Your configuration is up to date.', + defaultMessage: 'Your {deprecationType} configuration is up to date', + values: { + deprecationType, + }, }), - getEmptyPromptNextStepsDescription: (navigateToOverviewPage: () => void) => ( + getEmptyPromptDescription: (navigateToOverviewPage: () => void) => ( = ({ {i18nTexts.emptyPromptTitle}} + title={

{i18nTexts.getEmptyPromptTitle(deprecationType)}

} body={ <>

- {i18nTexts.getEmptyPromptDescription(deprecationType)} + {i18nTexts.getEmptyPromptDescription(navigateToOverviewPage)}

-

{i18nTexts.getEmptyPromptNextStepsDescription(navigateToOverviewPage)}

} /> diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts index 34e7dad6260d4..a7b57e23068e9 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -20,3 +20,5 @@ export enum GroupByOption { } export type DeprecationTableColumns = 'type' | 'index' | 'message' | 'correctiveAction'; + +export type Status = 'in_progress' | 'complete' | 'idle' | 'error'; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index d738d7c31335f..1332335dde4cd 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -31,6 +31,70 @@ export async function getUpgradeAssistantStatus( details: "This cluster is named [mycompany:logging], which contains the illegal character ':'.", }, + { + level: 'warning', + message: "A Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "A Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "A Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "D Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "E Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "F Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "G Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, + { + level: 'warning', + message: "A Cluster name cannot contain ':'", + url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + details: + "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + }, ], node_settings: [ { From ecad28c31d083ee2ea55d1cd3b270d2996976eb6 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 11 Aug 2021 20:32:20 -0400 Subject: [PATCH 05/18] update existing CITs --- ...{cluster.test.ts => elasticsearch.test.ts} | 273 ++++++++++++------ ...er.helpers.ts => elasticsearch.helpers.ts} | 32 +- .../helpers/http_requests.ts | 12 + .../client_integration/helpers/index.ts | 3 +- .../helpers/indices.helpers.ts | 75 ----- .../helpers/setup_environment.tsx | 11 +- .../client_integration/indices.test.ts | 242 ---------------- .../index_settings/flyout.tsx | 2 +- .../index_settings/status_table_cell.tsx | 12 +- .../deprecation_types/ml_snapshots/flyout.tsx | 4 +- .../ml_snapshots/status_table_cell.tsx | 6 +- .../es_deprecations/es_deprecations.tsx | 4 +- .../es_deprecations_table_cells.tsx | 5 +- .../server/lib/es_migration_apis.ts | 9 +- 14 files changed, 254 insertions(+), 436 deletions(-) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/{cluster.test.ts => elasticsearch.test.ts} (50%) rename x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/{cluster.helpers.ts => elasticsearch.helpers.ts} (65%) delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts similarity index 50% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index 412ce348d56e3..20aab48e0aa01 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/cluster.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -6,12 +6,13 @@ */ import { act } from 'react-dom/test-utils'; -import { MlAction, UpgradeAssistantStatus } from '../../common/types'; +import type { MlAction, UpgradeAssistantStatus } from '../../common/types'; +import { indexSettingDeprecations } from '../../common/constants'; -import { ClusterTestBed, setupClusterPage, setupEnvironment } from './helpers'; +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from './helpers'; -describe('Cluster tab', () => { - let testBed: ClusterTestBed; +describe('Elasticsearch deprecations', () => { + let testBed: ElasticsearchTestBed; const { server, httpRequestsMockHelpers } = setupEnvironment(); afterAll(() => { @@ -23,9 +24,10 @@ describe('Cluster tab', () => { const jobId = 'deprecation_check_job'; const upgradeStatusMockResponse: UpgradeAssistantStatus = { readyForUpgrade: false, - cluster: [ + deprecations: [ { - level: 'critical', + isCritical: true, + type: 'ml_settings', message: 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', details: @@ -37,72 +39,69 @@ describe('Cluster tab', () => { jobId, }, }, + { + isCritical: false, + type: 'index_settings', + message: indexSettingDeprecations.translog.deprecationMessage, + details: 'deprecation details', + url: 'doc_url', + index: 'my_index', + correctiveAction: { + type: 'indexSetting', + deprecatedSettings: indexSettingDeprecations.translog.settings, + }, + }, ], - indices: [], }; beforeEach(async () => { httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusMockResponse); - httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ isEnabled: true }); - - await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'idle', }); - const { actions, component } = testBed; - - component.update(); - - // Navigate to the cluster tab await act(async () => { - actions.clickTab('cluster'); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); }); - component.update(); + testBed.component.update(); }); test('renders deprecations', () => { - const { exists } = testBed; - expect(exists('clusterTabContent')).toBe(true); - expect(exists('deprecationsContainer')).toBe(true); - }); - - describe('fix ml snapshots button', () => { - let flyout: Element | null; - - beforeEach(async () => { - const { component, actions, exists, find } = testBed; + const { exists, find } = testBed; + // Verify container exists + expect(exists('esDeprecationsContent')).toBe(true); - expect(exists('deprecationsContainer')).toBe(true); + // Verify links exist + expect(exists('esDeprecationsContent.uaDocumentationLink')).toBe(true); + expect(exists('esDeprecationsContent.snapshotRestoreLink')).toBe(true); + expect(exists('esDeprecationsContent.esApiDocumentationLink')).toBe(true); - // Open all deprecations - actions.clickExpandAll(); + // Verify one deprecation in the table + expect(find('deprecationTableRow').length).toEqual(2); + }); - // The data-test-subj is derived from the deprecation message - const accordionTestSubj = `depgroup_${upgradeStatusMockResponse.cluster[0].message - .split(' ') - .join('_')}`; + describe('Machine Learning snapshots deprecation', () => { + beforeEach(async () => { + const { component, find } = testBed; await act(async () => { - find(`${accordionTestSubj}.fixMlSnapshotsButton`).simulate('click'); + find('deprecation-mlSnapshot').at(0).simulate('click'); }); component.update(); - // We need to read the document "body" as the flyout is added there and not inside - // the component DOM tree. - flyout = document.body.querySelector('[data-test-subj="fixSnapshotsFlyout"]'); - - expect(flyout).not.toBe(null); - expect(flyout!.textContent).toContain('Upgrade or delete model snapshot'); + expect(find('mlSnapshotDetails')).not.toBe(null); + expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( + 'Upgrade or delete model snapshot' + ); }); test('upgrades snapshots', async () => { - const { component } = testBed; - - const upgradeButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="upgradeSnapshotButton"]' - ); + const { component, find } = testBed; httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ nodeId: 'my_node', @@ -111,8 +110,17 @@ describe('Cluster tab', () => { status: 'in_progress', }); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'complete', + }); + + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); + await act(async () => { - upgradeButton!.click(); + find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); }); component.update(); @@ -128,15 +136,25 @@ describe('Cluster tab', () => { expect(statusRequest.url).toBe( `/api/upgrade_assistant/ml_snapshots/${jobId}/${snapshotId}` ); + + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').text()).toContain('Upgrade complete'); + + // Reopen the flyout + await act(async () => { + find('deprecation-mlSnapshot').at(0).simulate('click'); + }); + + component.update(); + + // Flyout actions should not be visible if deprecation was resolved + expect(find('mlSnapshotDetails.upgradeSnapshotButton').length).toBe(0); + expect(find('mlSnapshotDetails.deleteSnapshotButton').length).toBe(0); }); test('handles upgrade failure', async () => { const { component, find } = testBed; - const upgradeButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="upgradeSnapshotButton"]' - ); - const error = { statusCode: 500, error: 'Upgrade snapshot error', @@ -144,9 +162,16 @@ describe('Cluster tab', () => { }; httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'error', + error, + }); await act(async () => { - upgradeButton!.click(); + find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); }); component.update(); @@ -155,32 +180,41 @@ describe('Cluster tab', () => { expect(upgradeRequest.method).toBe('POST'); expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - const accordionTestSubj = `depgroup_${upgradeStatusMockResponse.cluster[0].message - .split(' ') - .join('_')}`; + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').text()).toContain('Upgrade failed'); - expect(find(`${accordionTestSubj}.fixMlSnapshotsButton`).text()).toEqual('Failed'); - }); + // Reopen the flyout + await act(async () => { + find('deprecation-mlSnapshot').at(0).simulate('click'); + }); - test('deletes snapshots', async () => { - const { component } = testBed; + component.update(); - const deleteButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="deleteSnapshotButton"]' + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error upgrading snapshot' ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Retry upgrade'); + }); + + test('deletes snapshots', async () => { + const { component, find } = testBed; httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ acknowledged: true, }); + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); + await act(async () => { - deleteButton!.click(); + find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); }); component.update(); const request = server.requests[server.requests.length - 1]; - const mlDeprecation = upgradeStatusMockResponse.cluster[0]; + const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; expect(request.method).toBe('DELETE'); expect(request.url).toBe( @@ -188,15 +222,21 @@ describe('Cluster tab', () => { (mlDeprecation.correctiveAction! as MlAction).jobId }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` ); + + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion complete'); + + // Reopen the flyout + await act(async () => { + find('deprecation-mlSnapshot').at(0).simulate('click'); + }); + + component.update(); }); test('handles delete failure', async () => { const { component, find } = testBed; - const deleteButton: HTMLButtonElement | null = flyout!.querySelector( - '[data-test-subj="deleteSnapshotButton"]' - ); - const error = { statusCode: 500, error: 'Upgrade snapshot error', @@ -206,13 +246,13 @@ describe('Cluster tab', () => { httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); await act(async () => { - deleteButton!.click(); + find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); }); component.update(); const request = server.requests[server.requests.length - 1]; - const mlDeprecation = upgradeStatusMockResponse.cluster[0]; + const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; expect(request.method).toBe('DELETE'); expect(request.url).toBe( @@ -221,11 +261,73 @@ describe('Cluster tab', () => { }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` ); - const accordionTestSubj = `depgroup_${upgradeStatusMockResponse.cluster[0].message - .split(' ') - .join('_')}`; + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion failed'); + + // Reopen the flyout + await act(async () => { + find('deprecation-mlSnapshot').at(0).simulate('click'); + }); + + component.update(); - expect(find(`${accordionTestSubj}.fixMlSnapshotsButton`).text()).toEqual('Failed'); + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error deleting snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Retry delete'); + }); + }); + + describe('Index settings deprecations', () => { + it('removes deprecated index settings', async () => { + const { component, find } = testBed; + const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; + + await act(async () => { + find('deprecation-indexSetting').at(0).simulate('click'); + }); + + component.update(); + + expect(find('indexSettingsDetails')).not.toBe(null); + expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( + indexSettingDeprecation.message + ); + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ + acknowledged: true, + }); + + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); + + component.update(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(200); + + // Verify the "Status" column of the table is updated + expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( + 'Deprecated settings removed' + ); + + // Reopen the flyout + await act(async () => { + find('deprecation-indexSetting').at(0).simulate('click'); + }); + + component.update(); + + // Verify the action button no longer displays + expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); }); }); }); @@ -234,25 +336,24 @@ describe('Cluster tab', () => { beforeEach(async () => { const noDeprecationsResponse = { readyForUpgrade: false, - cluster: [], - indices: [], + deprecations: [], }; httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); }); - const { component } = testBed; - - component.update(); + testBed.component.update(); }); test('renders prompt', () => { const { exists, find } = testBed; expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain('Ready to upgrade!'); + expect(find('noDeprecationsPrompt').text()).toContain( + 'Your Elasticsearch configuration is up to date' + ); }); }); @@ -267,7 +368,7 @@ describe('Cluster tab', () => { httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); }); const { component, exists, find } = testBed; @@ -295,7 +396,7 @@ describe('Cluster tab', () => { httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); }); const { component, exists, find } = testBed; @@ -304,7 +405,7 @@ describe('Cluster tab', () => { expect(exists('upgradedCallout')).toBe(true); expect(find('upgradedCallout').text()).toContain( - 'Your configuration is up to date. Kibana and all Elasticsearch nodes are running the same version.' + 'All Elasticsearch nodes have been upgraded.' ); }); @@ -321,7 +422,7 @@ describe('Cluster tab', () => { httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); }); const { component, exists, find } = testBed; @@ -344,7 +445,7 @@ describe('Cluster tab', () => { httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); await act(async () => { - testBed = await setupClusterPage({ isReadOnlyMode: false }); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); }); const { component, exists, find } = testBed; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts similarity index 65% rename from x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts rename to x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts index 2aedface1e32b..5821d90a38564 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/cluster.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts @@ -11,13 +11,13 @@ import { WithAppDependencies } from './setup_environment'; const testBedConfig: TestBedConfig = { memoryRouter: { - initialEntries: ['/es_deprecations/cluster'], - componentRoutePath: '/es_deprecations/:tabName', + initialEntries: ['/es_deprecations'], + componentRoutePath: '/es_deprecations', }, doMountAsync: true, }; -export type ClusterTestBed = TestBed & { +export type ElasticsearchTestBed = TestBed & { actions: ReturnType; }; @@ -25,25 +25,25 @@ const createActions = (testBed: TestBed) => { /** * User Actions */ - const clickTab = (tabName: string) => { - const { find } = testBed; - const camelcaseTabName = tabName.charAt(0).toUpperCase() + tabName.slice(1); + // const clickTab = (tabName: string) => { + // const { find } = testBed; + // const camelcaseTabName = tabName.charAt(0).toUpperCase() + tabName.slice(1); - find(`upgradeAssistant${camelcaseTabName}Tab`).simulate('click'); - }; + // find(`upgradeAssistant${camelcaseTabName}Tab`).simulate('click'); + // }; - const clickExpandAll = () => { - const { find } = testBed; - find('expandAll').simulate('click'); - }; + // const clickExpandAll = () => { + // const { find } = testBed; + // find('expandAll').simulate('click'); + // }; return { - clickTab, - clickExpandAll, + // clickTab, + // clickExpandAll, }; }; -export const setup = async (overrides?: Record): Promise => { +export const setup = async (overrides?: Record): Promise => { const initTestBed = registerTestBed( WithAppDependencies(EsDeprecationsContent, overrides), testBedConfig @@ -56,7 +56,7 @@ export const setup = async (overrides?: Record): Promise { ]); }; + const setUpgradeMlSnapshotStatusResponse = (response?: object, error?: ResponseError) => { + const status = error ? error.statusCode || 400 : 200; + const body = error ? error : response; + + server.respondWith('GET', `${API_BASE_PATH}/ml_snapshots/:jobId/:snapshotId`, [ + status, + { 'Content-Type': 'application/json' }, + JSON.stringify(body), + ]); + }; + const setDeleteMlSnapshotResponse = (response?: object, error?: ResponseError) => { const status = error ? error.statusCode || 400 : 200; const body = error ? error : response; @@ -91,6 +102,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { setUpdateIndexSettingsResponse, setUpgradeMlSnapshotResponse, setDeleteMlSnapshotResponse, + setUpgradeMlSnapshotStatusResponse, }; }; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts index 8e256680253be..b19c8b3d0f082 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/index.ts @@ -6,8 +6,7 @@ */ export { setup as setupOverviewPage, OverviewTestBed } from './overview.helpers'; -export { setup as setupIndicesPage, IndicesTestBed } from './indices.helpers'; -export { setup as setupClusterPage, ClusterTestBed } from './cluster.helpers'; +export { setup as setupElasticsearchPage, ElasticsearchTestBed } from './elasticsearch.helpers'; export { setup as setupKibanaPage, KibanaTestBed } from './kibana.helpers'; export { setupEnvironment } from './setup_environment'; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts deleted file mode 100644 index 5189ddc420b08..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/indices.helpers.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; -import { EsDeprecationsContent } from '../../../public/application/components/es_deprecations'; -import { WithAppDependencies } from './setup_environment'; - -const testBedConfig: TestBedConfig = { - memoryRouter: { - initialEntries: ['/es_deprecations/indices'], - componentRoutePath: '/es_deprecations/:tabName', - }, - doMountAsync: true, -}; - -export type IndicesTestBed = TestBed & { - actions: ReturnType; -}; - -const createActions = (testBed: TestBed) => { - /** - * User Actions - */ - const clickTab = (tabName: string) => { - const { find } = testBed; - const camelcaseTabName = tabName.charAt(0).toUpperCase() + tabName.slice(1); - - find(`upgradeAssistant${camelcaseTabName}Tab`).simulate('click'); - }; - - const clickFixButton = () => { - const { find } = testBed; - find('removeIndexSettingsButton').simulate('click'); - }; - - const clickExpandAll = () => { - const { find } = testBed; - find('expandAll').simulate('click'); - }; - - return { - clickTab, - clickFixButton, - clickExpandAll, - }; -}; - -export const setup = async (overrides?: Record): Promise => { - const initTestBed = registerTestBed( - WithAppDependencies(EsDeprecationsContent, overrides), - testBedConfig - ); - const testBed = await initTestBed(); - - return { - ...testBed, - actions: createActions(testBed), - }; -}; - -export type IndicesTestSubjects = - | 'expandAll' - | 'removeIndexSettingsButton' - | 'deprecationsContainer' - | 'permissionsError' - | 'requestError' - | 'indexCount' - | 'upgradedCallout' - | 'partiallyUpgradedWarning' - | 'noDeprecationsPrompt' - | string; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx index aae5500403322..f825a3063faee 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/setup_environment.tsx @@ -21,8 +21,11 @@ import { mockKibanaSemverVersion } from '../../../common/constants'; import { AppContextProvider } from '../../../public/application/app_context'; import { apiService } from '../../../public/application/lib/api'; import { breadcrumbService } from '../../../public/application/lib/breadcrumbs'; +import { GlobalFlyout } from '../../../public/shared_imports'; import { init as initHttpRequests } from './http_requests'; +const { GlobalFlyoutProvider } = GlobalFlyout; + const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); export const WithAppDependencies = (Comp: any, overrides: Record = {}) => ( @@ -48,9 +51,11 @@ export const WithAppDependencies = (Comp: any, overrides: Record - - + + + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts deleted file mode 100644 index b44a04eb15d86..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/indices.test.ts +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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'; -import { indexSettingDeprecations } from '../../common/constants'; -import { UpgradeAssistantStatus } from '../../common/types'; - -import { IndicesTestBed, setupIndicesPage, setupEnvironment } from './helpers'; - -describe('Indices tab', () => { - let testBed: IndicesTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); - - describe('with deprecations', () => { - const upgradeStatusMockResponse: UpgradeAssistantStatus = { - readyForUpgrade: false, - cluster: [], - indices: [ - { - level: 'warning', - message: indexSettingDeprecations.translog.deprecationMessage, - url: 'doc_url', - index: 'my_index', - correctiveAction: { - type: 'indexSetting', - deprecatedSettings: indexSettingDeprecations.translog.settings, - }, - }, - ], - }; - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusMockResponse); - httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ isEnabled: true }); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { actions, component } = testBed; - - component.update(); - - // Navigate to the indices tab - await act(async () => { - actions.clickTab('indices'); - }); - - component.update(); - }); - - test('renders deprecations', () => { - const { exists, find } = testBed; - expect(exists('indexTabContent')).toBe(true); - expect(exists('deprecationsContainer')).toBe(true); - expect(find('indexCount').text()).toEqual('1'); - }); - - describe('fix indices button', () => { - test('removes deprecated index settings', async () => { - const { component, actions, exists, find } = testBed; - - expect(exists('deprecationsContainer')).toBe(true); - - // Open all deprecations - actions.clickExpandAll(); - - const accordionTestSubj = `depgroup_${indexSettingDeprecations.translog.deprecationMessage - .split(' ') - .join('_')}`; - - await act(async () => { - find(`${accordionTestSubj}.removeIndexSettingsButton`).simulate('click'); - }); - - // We need to read the document "body" as the modal is added there and not inside - // the component DOM tree. - const modal = document.body.querySelector( - '[data-test-subj="indexSettingsDeleteConfirmModal"]' - ); - const confirmButton: HTMLButtonElement | null = modal!.querySelector( - '[data-test-subj="confirmModalConfirmButton"]' - ); - - expect(modal).not.toBe(null); - expect(modal!.textContent).toContain('Remove deprecated settings'); - - const indexName = upgradeStatusMockResponse.indices[0].index; - - httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ - acknowledged: true, - }); - - await act(async () => { - confirmButton!.click(); - }); - - component.update(); - - const request = server.requests[server.requests.length - 1]; - - expect(request.method).toBe('POST'); - expect(request.url).toBe(`/api/upgrade_assistant/${indexName}/index_settings`); - expect(request.status).toEqual(200); - }); - }); - }); - - describe('no deprecations', () => { - beforeEach(async () => { - const noDeprecationsResponse = { - readyForUpgrade: false, - cluster: [], - indices: [], - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component } = testBed; - - component.update(); - }); - - test('renders prompt', () => { - const { exists, find } = testBed; - expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain('Ready to upgrade!'); - }); - }); - - describe('error handling', () => { - test('handles 403', async () => { - const error = { - statusCode: 403, - error: 'Forbidden', - message: 'Forbidden', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('permissionsError')).toBe(true); - expect(find('permissionsError').text()).toContain( - 'You are not authorized to view Elasticsearch deprecations.' - ); - }); - - test('handles upgrade error', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - allNodesUpgraded: true, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('upgradedCallout')).toBe(true); - expect(find('upgradedCallout').text()).toContain( - 'Your configuration is up to date. Kibana and all Elasticsearch nodes are running the same version.' - ); - }); - - test('handles partially upgrade error', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - allNodesUpgraded: false, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('partiallyUpgradedWarning')).toBe(true); - expect(find('partiallyUpgradedWarning').text()).toContain( - 'Upgrade Kibana to the same version as your Elasticsearch cluster. One or more nodes in the cluster is running a different version than Kibana.' - ); - }); - - test('handles generic error', async () => { - const error = { - statusCode: 500, - error: 'Internal server error', - message: 'Internal server error', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupIndicesPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('requestError')).toBe(true); - expect(find('requestError').text()).toContain( - 'Could not retrieve Elasticsearch deprecations.' - ); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx index caf17114c08b3..b59584e72f89b 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx @@ -104,7 +104,7 @@ export const RemoveIndexSettingsFlyout = ({ return ( <> - +

{message}

diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx index 214f6ce81c7ea..bf1182b597a93 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx @@ -42,7 +42,11 @@ export const IndexSettingsStatusCell: React.FunctionComponent = ({ status const { statusType } = status; if (statusType === 'in_progress') { return ( - + @@ -55,7 +59,11 @@ export const IndexSettingsStatusCell: React.FunctionComponent = ({ status if (statusType === 'complete') { 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 8ecf753414a5e..95caac78509a8 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 @@ -98,7 +98,7 @@ export const FixSnapshotsFlyout = ({ return ( <> - +

{i18nTexts.flyoutTitle}

@@ -113,7 +113,7 @@ export const FixSnapshotsFlyout = ({ } color="danger" iconType="alert" - data-test-subj="upgradeSnapshotError" + data-test-subj="resolveSnapshotError" > {snapshotState.error.message} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx index 8013588206efc..b3261174ddeba 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx @@ -69,7 +69,7 @@ export const MlSnapshotsStatusCell: React.FunctionComponent = () => { if (snapshotState.status === 'in_progress') { return ( - + @@ -86,7 +86,7 @@ export const MlSnapshotsStatusCell: React.FunctionComponent = () => { if (snapshotState.status === 'complete') { return ( - + @@ -103,7 +103,7 @@ export const MlSnapshotsStatusCell: React.FunctionComponent = () => { if (snapshotState.status === 'error') { return ( - + 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 f98bec30d63ee..ce6aa27b93240 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 @@ -109,7 +109,7 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp href={docLinks.links.upgradeAssistant} target="_blank" iconType="help" - data-test-subj="documentationLink" + data-test-subj="uaDocumentationLink" > {i18nTexts.docLinkText} , @@ -120,6 +120,7 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp = ({ // "Issue" column if (fieldName === 'message') { return ( - + {deprecation.message} ); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index b74aaa2b84cf3..b90cb3ea6d353 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -132,6 +132,10 @@ export async function getUpgradeAssistantStatus( 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', details: "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + _meta: { + snapshot_id: '1627343998', + job_id: 'my_job', + }, }, ], }; @@ -148,14 +152,15 @@ export async function getUpgradeAssistantStatus( ] as MigrationDeprecationInfoDeprecation[]; const enrichedDeprecationInfo = deprecationsByType.map( - ({ details, level, message, url }) => { + // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse + ({ details, level, message, url, _meta: metadata }) => { return { details, message, url, type: deprecationType as keyof MigrationDeprecationInfoResponse, isCritical: level === 'critical', - correctiveAction: getCorrectiveAction(message), + correctiveAction: getCorrectiveAction(message, metadata), }; } ); From 5d3af6b4995689adbdf96ab97c25174ce3b30b53 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 12 Aug 2021 15:12:29 -0400 Subject: [PATCH 06/18] update tests --- .../client_integration/elasticsearch.test.ts | 129 ++++++++- .../helpers/http_requests.ts | 8 +- .../client_integration/kibana.test.ts | 4 +- .../client_integration/overview.test.ts | 16 +- .../plugins/upgrade_assistant/common/types.ts | 1 + .../public/application/app.tsx | 8 +- .../deprecation_types/default/flyout.tsx | 4 +- .../index_settings/flyout.tsx | 4 +- .../index_settings/status_table_cell.tsx | 6 +- .../reindex/flyout/container.tsx | 2 +- .../lib/__fixtures__/fake_deprecations.json | 42 ++- .../es_migration_apis.test.ts.snap | 124 +++++---- .../server/lib/es_migration_apis.ts | 261 ++++++++++-------- .../lib/telemetry/es_ui_open_apis.test.ts | 2 +- .../server/routes/cluster_checkup.test.ts | 17 +- 15 files changed, 408 insertions(+), 220 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index 20aab48e0aa01..8e256ebbbafa1 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -27,6 +27,7 @@ describe('Elasticsearch deprecations', () => { deprecations: [ { isCritical: true, + resolveDuringUpgrade: false, type: 'ml_settings', message: 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', @@ -41,6 +42,7 @@ describe('Elasticsearch deprecations', () => { }, { isCritical: false, + resolveDuringUpgrade: false, type: 'index_settings', message: indexSettingDeprecations.translog.deprecationMessage, details: 'deprecation details', @@ -51,6 +53,27 @@ describe('Elasticsearch deprecations', () => { deprecatedSettings: indexSettingDeprecations.translog.settings, }, }, + { + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'multi-fields within multi-fields', + details: 'deprecation details', + url: 'doc_url', + index: 'nested_multi-fields', + }, + { + isCritical: true, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'Index created before 7.0', + details: 'deprecation details', + url: 'doc_url', + index: 'reindex_index', + correctiveAction: { + type: 'reindex', + }, + }, ], }; @@ -80,11 +103,11 @@ describe('Elasticsearch deprecations', () => { expect(exists('esDeprecationsContent.snapshotRestoreLink')).toBe(true); expect(exists('esDeprecationsContent.esApiDocumentationLink')).toBe(true); - // Verify one deprecation in the table - expect(find('deprecationTableRow').length).toEqual(2); + // Verify all deprecations appear in the table + expect(find('deprecationTableRow').length).toEqual(upgradeStatusMockResponse.deprecations.length); }); - describe('Machine Learning snapshots deprecation', () => { + describe('ML snapshots deprecation', () => { beforeEach(async () => { const { component, find } = testBed; @@ -280,10 +303,12 @@ describe('Elasticsearch deprecations', () => { }); }); - describe('Index settings deprecations', () => { - it('removes deprecated index settings', async () => { + describe('index settings deprecation', () => { + const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; + + beforeEach(async () => { const { component, find } = testBed; - const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; + await act(async () => { find('deprecation-indexSetting').at(0).simulate('click'); @@ -295,6 +320,11 @@ describe('Elasticsearch deprecations', () => { expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( indexSettingDeprecation.message ); + expect(find('removeSettingsPrompt')).not.toBe(null); + }) + + it('removes deprecated index settings', async () => { + const { component, find } = testBed; httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ acknowledged: true, @@ -326,10 +356,97 @@ describe('Elasticsearch deprecations', () => { component.update(); + // Verify prompt to remove setting no longer displays + expect(find('removeSettingsPrompt').length).toEqual(0); // Verify the action button no longer displays expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); }); + + it('handles failure', async () => { + const { component, find } = testBed; + const error = { + statusCode: 500, + error: 'Remove index settings error', + message: 'Remove index settings error', + }; + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); + + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); + + component.update(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(500); + + // Verify the "Status" column of the table is updated + expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( + 'Settings removal failed' + ); + + // Reopen the flyout + await act(async () => { + find('deprecation-indexSetting').at(0).simulate('click'); + }); + + component.update(); + + // Verify the flyout shows an error message + expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( + 'Error deleting index settings' + ); + // Verify the remove settings button text changes + expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual('Retry removing deprecated settings'); + }) }); + + describe('default deprecation', () => { + it('renders a flyout with deprecation details', async () => { + const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[2]; + const { component, find } = testBed; + + + await act(async () => { + find('deprecation-default').at(0).simulate('click'); + }); + + component.update(); + + expect(find('defaultDeprecationDetails')).not.toBe(null); + expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( + multiFieldsDeprecation.message + ); + expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( + multiFieldsDeprecation.index + ); + }) + }) + + describe('reindex deprecation', () => { + it('renders a flyout with reindexing details', async () => { + const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; + const { component, find } = testBed; + + + await act(async () => { + find('deprecation-reindex').at(0).simulate('click'); + }); + + component.update(); + + expect(find('reindexDetails')).not.toBe(null); + expect(find('reindexDetails.flyoutTitle').text()).toContain( + `Reindex ${reindexDeprecation.index}` + ); + }) + }) }); describe('no deprecations', () => { diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts index a2962ca9506a9..4de18b83f3183 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/http_requests.ts @@ -54,11 +54,13 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { ]); }; - const setUpdateIndexSettingsResponse = (response?: object) => { + const setUpdateIndexSettingsResponse = (response?: object, error?: ResponseError) => { + const status = error ? error.statusCode || 400 : 200; + const body = error ? error : response; server.respondWith('POST', `${API_BASE_PATH}/:indexName/index_settings`, [ - 200, + status, { 'Content-Type': 'application/json' }, - JSON.stringify(response), + JSON.stringify(body), ]); }; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts index b14ec26e5c8af..182ef0ce52739 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/kibana.test.ts @@ -160,7 +160,9 @@ describe('Kibana deprecations', () => { test('renders prompt', () => { const { exists, find } = testBed; expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain('Ready to upgrade!'); + expect(find('noDeprecationsPrompt').text()).toContain( + 'Your Kibana configuration is up to date' + ); }); }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview.test.ts index 9b65b493a74c4..871e74a26c18f 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview.test.ts @@ -19,25 +19,31 @@ describe('Overview page', () => { beforeEach(async () => { const esDeprecationsMockResponse: UpgradeAssistantStatus = { readyForUpgrade: false, - cluster: [ + deprecations: [ { - level: 'critical', + isCritical: true, + type: 'cluster_settings', message: 'Index Lifecycle Management poll interval is set too low', url: 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html#ilm-poll-interval-limit', details: 'The Index Lifecycle Management poll interval setting [indices.lifecycle.poll_interval] is currently set to [500ms], but must be 1s or greater', + resolveDuringUpgrade: false, }, - ], - indices: [ { - level: 'warning', + isCritical: false, + type: 'index_settings', message: 'translog retention settings are ignored', url: 'https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-translog.html', details: 'translog retention settings [index.translog.retention.size] and [index.translog.retention.age] are ignored because translog is no longer used in peer recoveries with soft-deletes enabled (default in 7.0 or later)', index: 'settings', + resolveDuringUpgrade: false, + correctiveAction: { + type: 'indexSetting', + deprecatedSettings: ['index.translog.retention.size', 'index.translog.retention.age'], + }, }, ], }; diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index 61b3cc471bd10..06ad60f97d879 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -215,6 +215,7 @@ export interface EnrichedDeprecationInfo isCritical: boolean; index?: string; correctiveAction?: ReindexAction | MlAction | IndexSettingAction; + resolveDuringUpgrade: boolean; } export interface UpgradeAssistantStatus { diff --git a/x-pack/plugins/upgrade_assistant/public/application/app.tsx b/x-pack/plugins/upgrade_assistant/public/application/app.tsx index 40d4bd51d487a..033174db47242 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -50,11 +50,11 @@ export const AppWithRouter = ({ history }: { history: ScopedHistory }) => { export const RootComponent = ({ i18n, history, ...contextValue }: AppDependencies) => { return ( - - + + - - + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx index 053975d255978..94f156ef6b1d7 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx @@ -61,11 +61,11 @@ export const DefaultDeprecationFlyout = ({ return ( <> - +

{message}

{index && ( - +

{i18nTexts.getFlyoutDescription(index)}

diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx index b59584e72f89b..e9a0b3c1021cb 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx @@ -138,7 +138,7 @@ export const RemoveIndexSettingsFlyout = ({ {/* Hide the prompt to remove settings if the deprecation has been resolved */} {statusType !== 'complete' && ( - <> +
@@ -158,7 +158,7 @@ export const RemoveIndexSettingsFlyout = ({ )} - +
)} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx index bf1182b597a93..323494944c625 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx @@ -76,7 +76,11 @@ export const IndexSettingsStatusCell: React.FunctionComponent = ({ status if (statusType === 'error') { return ( - + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx index a01d48aff7e1a..f10e7b4cc687e 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/flyout/container.tsx @@ -126,7 +126,7 @@ export const ReindexFlyout: React.FunctionComponent = ({ return ( <> - +

{ - // const { body: deprecations } = await dataClient.asCurrentUser.migration.deprecations(); + const { body: deprecations } = await dataClient.asCurrentUser.migration.deprecations(); // TODO temp mock data - const deprecations: MigrationDeprecationInfoResponse = { - cluster_settings: [ - { - level: 'warning', - message: "A Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "A Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "A Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "A Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "D Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "E Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "F Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "G Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - { - level: 'warning', - message: "A Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - ], - node_settings: [ - { - level: 'critical', - message: "B Cluster name cannot contain ':'", - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - }, - ], - index_settings: { - logs2: [ - { - level: 'warning', - message: 'translog retention settings are ignored', - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_index_name', - details: "This index is named [logs:apache], which contains the illegal character ':'.", - }, - { - level: 'critical', - message: 'Index created before 7.0', - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html', - details: 'This index was created using version: 6.8.13', - }, - ], - }, - ml_settings: [ - { - level: 'critical', - message: 'model snapshot [1627343998] for job [my_job] needs to be deleted or upgraded', - url: - 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', - details: - "This cluster is named [mycompany:logging], which contains the illegal character ':'.", - _meta: { - snapshot_id: '1627343998', - job_id: 'my_job', - }, - }, - ], - }; + // const deprecations: MigrationDeprecationInfoResponse = { + // cluster_settings: [ + // { + // level: 'warning', + // message: "A Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "A Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "A Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "A Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "D Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "E Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "F Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "G Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // { + // level: 'warning', + // message: "A Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // ], + // node_settings: [ + // { + // level: 'critical', + // message: "B Cluster name cannot contain ':'", + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // }, + // ], + // index_settings: { + // logs2: [ + // { + // level: 'warning', + // message: 'translog retention settings are ignored', + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_index_name', + // details: "This index is named [logs:apache], which contains the illegal character ':'.", + // }, + // { + // level: 'critical', + // message: 'Index created before 7.0', + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html', + // details: 'This index was created using version: 6.8.13', + // }, + // ], + // }, + // ml_settings: [ + // { + // level: 'critical', + // message: 'model snapshot [1627343998] for job [my_job] needs to be deleted or upgraded', + // url: + // 'https://www.elastic.co/guide/en/elasticsearch/reference/7.0/breaking-changes-7.0.html#_literal_literal_is_no_longer_allowed_in_cluster_name', + // details: + // "This cluster is named [mycompany:logging], which contains the illegal character ':'.", + // _meta: { + // snapshot_id: '1627343998', + // job_id: 'my_job', + // }, + // }, + // ], + // }; const getCombinedDeprecations = async () => { const indices = await getCombinedIndexInfos(deprecations, dataClient); @@ -152,14 +152,23 @@ export async function getUpgradeAssistantStatus( ] as MigrationDeprecationInfoDeprecation[]; const enrichedDeprecationInfo = deprecationsByType.map( - // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse - ({ details, level, message, url, _meta: metadata }) => { + ({ + details, + level, + message, + url, + // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse + _meta: metadata, + // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse + resolve_during_rolling_upgrade: resolveDuringUpgrade, + }) => { return { details, message, url, type: deprecationType as keyof MigrationDeprecationInfoResponse, isCritical: level === 'critical', + resolveDuringUpgrade, correctiveAction: getCorrectiveAction(message, metadata), }; } @@ -193,7 +202,14 @@ const getCombinedIndexInfos = async ( (indexDeprecations, indexName) => { return indexDeprecations.concat( deprecations.index_settings[indexName].map( - ({ details, message, url, level }) => + ({ + details, + message, + url, + level, + // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse + resolve_during_rolling_upgrade: resolveDuringUpgrade, + }) => ({ details, message, @@ -202,6 +218,7 @@ const getCombinedIndexInfos = async ( type: 'index_settings', isCritical: level === 'critical', correctiveAction: getCorrectiveAction(message), + resolveDuringUpgrade, } as EnrichedDeprecationInfo) ) ); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts index 3db855fabffb9..caff78390b9d1 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts @@ -27,7 +27,7 @@ describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => { savedObjects: { createInternalRepository: () => internalRepo } as any, }); - expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(4); + expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(3); expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, diff --git a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts index 934fdb1c4eb37..154b50458a54b 100644 --- a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts @@ -44,9 +44,7 @@ describe('cluster checkup API', () => { describe('GET /api/upgrade_assistant/reindex/{indexName}.json', () => { it('returns state', async () => { MigrationApis.getUpgradeAssistantStatus.mockResolvedValue({ - cluster: [], - indices: [], - nodes: [], + deprecations: [], }); const resp = await routeDependencies.router.getHandler({ method: 'get', @@ -54,16 +52,17 @@ describe('cluster checkup API', () => { })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.status).toEqual(200); - expect(JSON.stringify(resp.payload)).toMatchInlineSnapshot( - `"{\\"cluster\\":[],\\"indices\\":[],\\"nodes\\":[]}"` - ); + expect(JSON.stringify(resp.payload)).toMatchInlineSnapshot(`"{\\"deprecations\\":[]}"`); }); it('returns an 403 error if it throws forbidden', async () => { - const e: any = new Error(`you can't go here!`); - e.statusCode = 403; + const error = { + name: 'ResponseError', + message: `you can't go here!`, + statusCode: 403, + }; - MigrationApis.getUpgradeAssistantStatus.mockRejectedValue(e); + MigrationApis.getUpgradeAssistantStatus.mockRejectedValue(error); const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/status', From c8636329b28be1c49bc768288700759cf11c6052 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 12 Aug 2021 20:31:29 -0400 Subject: [PATCH 07/18] fix prettier --- .../client_integration/elasticsearch.test.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index 8e256ebbbafa1..8536b915f6bad 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -104,7 +104,9 @@ describe('Elasticsearch deprecations', () => { expect(exists('esDeprecationsContent.esApiDocumentationLink')).toBe(true); // Verify all deprecations appear in the table - expect(find('deprecationTableRow').length).toEqual(upgradeStatusMockResponse.deprecations.length); + expect(find('deprecationTableRow').length).toEqual( + upgradeStatusMockResponse.deprecations.length + ); }); describe('ML snapshots deprecation', () => { @@ -309,7 +311,6 @@ describe('Elasticsearch deprecations', () => { beforeEach(async () => { const { component, find } = testBed; - await act(async () => { find('deprecation-indexSetting').at(0).simulate('click'); }); @@ -321,7 +322,7 @@ describe('Elasticsearch deprecations', () => { indexSettingDeprecation.message ); expect(find('removeSettingsPrompt')).not.toBe(null); - }) + }); it('removes deprecated index settings', async () => { const { component, find } = testBed; @@ -403,8 +404,10 @@ describe('Elasticsearch deprecations', () => { 'Error deleting index settings' ); // Verify the remove settings button text changes - expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual('Retry removing deprecated settings'); - }) + expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual( + 'Retry removing deprecated settings' + ); + }); }); describe('default deprecation', () => { @@ -412,7 +415,6 @@ describe('Elasticsearch deprecations', () => { const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[2]; const { component, find } = testBed; - await act(async () => { find('deprecation-default').at(0).simulate('click'); }); @@ -426,15 +428,14 @@ describe('Elasticsearch deprecations', () => { expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( multiFieldsDeprecation.index ); - }) - }) + }); + }); describe('reindex deprecation', () => { it('renders a flyout with reindexing details', async () => { const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; const { component, find } = testBed; - await act(async () => { find('deprecation-reindex').at(0).simulate('click'); }); @@ -445,8 +446,8 @@ describe('Elasticsearch deprecations', () => { expect(find('reindexDetails.flyoutTitle').text()).toContain( `Reindex ${reindexDeprecation.index}` ); - }) - }) + }); + }); }); describe('no deprecations', () => { From 6d576d2e788a19507737ad7aea6368bc5d433183 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 13 Aug 2021 14:53:12 -0400 Subject: [PATCH 08/18] address design feedback + more CITs --- .../client_integration/elasticsearch.test.ts | 134 ++++++++++++++++-- .../es_deprecations/es_deprecations.tsx | 21 +-- .../es_deprecations/es_deprecations_table.tsx | 97 +++++++------ 3 files changed, 181 insertions(+), 71 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index 8536b915f6bad..083053c93c48d 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -99,9 +99,7 @@ describe('Elasticsearch deprecations', () => { expect(exists('esDeprecationsContent')).toBe(true); // Verify links exist - expect(exists('esDeprecationsContent.uaDocumentationLink')).toBe(true); expect(exists('esDeprecationsContent.snapshotRestoreLink')).toBe(true); - expect(exists('esDeprecationsContent.esApiDocumentationLink')).toBe(true); // Verify all deprecations appear in the table expect(find('deprecationTableRow').length).toEqual( @@ -111,7 +109,7 @@ describe('Elasticsearch deprecations', () => { describe('ML snapshots deprecation', () => { beforeEach(async () => { - const { component, find } = testBed; + const { component, find, exists } = testBed; await act(async () => { find('deprecation-mlSnapshot').at(0).simulate('click'); @@ -119,7 +117,7 @@ describe('Elasticsearch deprecations', () => { component.update(); - expect(find('mlSnapshotDetails')).not.toBe(null); + expect(exists('mlSnapshotDetails')).toBe(true); expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( 'Upgrade or delete model snapshot' ); @@ -309,7 +307,7 @@ describe('Elasticsearch deprecations', () => { const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; beforeEach(async () => { - const { component, find } = testBed; + const { component, find, exists } = testBed; await act(async () => { find('deprecation-indexSetting').at(0).simulate('click'); @@ -317,11 +315,11 @@ describe('Elasticsearch deprecations', () => { component.update(); - expect(find('indexSettingsDetails')).not.toBe(null); + expect(exists('indexSettingsDetails')).toBe(true); expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( indexSettingDeprecation.message ); - expect(find('removeSettingsPrompt')).not.toBe(null); + expect(exists('removeSettingsPrompt')).toBe(true); }); it('removes deprecated index settings', async () => { @@ -413,7 +411,7 @@ describe('Elasticsearch deprecations', () => { describe('default deprecation', () => { it('renders a flyout with deprecation details', async () => { const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[2]; - const { component, find } = testBed; + const { component, find, exists } = testBed; await act(async () => { find('deprecation-default').at(0).simulate('click'); @@ -421,7 +419,7 @@ describe('Elasticsearch deprecations', () => { component.update(); - expect(find('defaultDeprecationDetails')).not.toBe(null); + expect(exists('defaultDeprecationDetails')).toBe(true); expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( multiFieldsDeprecation.message ); @@ -434,7 +432,7 @@ describe('Elasticsearch deprecations', () => { describe('reindex deprecation', () => { it('renders a flyout with reindexing details', async () => { const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; - const { component, find } = testBed; + const { component, find, exists } = testBed; await act(async () => { find('deprecation-reindex').at(0).simulate('click'); @@ -442,12 +440,126 @@ describe('Elasticsearch deprecations', () => { component.update(); - expect(find('reindexDetails')).not.toBe(null); + expect(exists('reindexDetails')).toBe(true); expect(find('reindexDetails.flyoutTitle').text()).toContain( `Reindex ${reindexDeprecation.index}` ); }); }); + + describe('search bar', () => { + it('filters results by "critical" status', async () => { + const { component, find } = testBed; + + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); + }); + + component.update(); + + const criticalDeprecations = upgradeStatusMockResponse.deprecations.filter( + (deprecation) => deprecation.isCritical + ); + + expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); + + // TODO move action to helpers file + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); + }); + + component.update(); + + expect(find('deprecationTableRow').length).toEqual( + upgradeStatusMockResponse.deprecations.length + ); + }); + + it('filters results by type', async () => { + const { component, find } = testBed; + + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer') + .find('.euiPopover') + .find('.euiFilterButton') + .at(0) + .simulate('click'); + }); + + component.update(); + + // We need to read the document "body" as the filter dropdown options are added there and not inside + // the component DOM tree. + const clusterFilterButton: HTMLButtonElement | null = document.body.querySelector( + '.euiFilterSelect__items .euiFilterSelectItem' + ); + + expect(clusterFilterButton).not.toBe(null); + + await act(async () => { + clusterFilterButton!.click(); + }); + + component.update(); + + const clusterDeprecations = upgradeStatusMockResponse.deprecations.filter( + (deprecation) => deprecation.type === 'cluster_settings' + ); + + expect(find('deprecationTableRow').length).toEqual(clusterDeprecations.length); + }); + + it('filters results by query string', async () => { + const { find, component } = testBed; + const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[3]; + + await act(async () => { + find('searchBarContainer') + .find('input') + .simulate('keyup', { target: { value: multiFieldsDeprecation.message } }); + }); + + component.update(); + + expect(find('deprecationTableRow').length).toEqual(1); + expect(find('deprecationTableRow').at(0).text()).toContain(multiFieldsDeprecation.message); + }); + + it('shows error for invalid search queries', async () => { + const { find, component, exists } = testBed; + + await act(async () => { + find('searchBarContainer') + .find('input') + .simulate('keyup', { target: { value: '%' } }); + }); + + component.update(); + + expect(exists('invalidSearchQueryMessage')).toBe(true); + expect(find('invalidSearchQueryMessage').text()).toContain('Invalid search'); + }); + + it('shows message when search query does not return results', async () => { + const { find, component, exists } = testBed; + + await act(async () => { + find('searchBarContainer') + .find('input') + .simulate('keyup', { target: { value: 'foobarbaz' } }); + }); + + component.update(); + + expect(exists('noDeprecationsRow')).toBe(true); + expect(find('noDeprecationsRow').text()).toContain( + 'No Elasticsearch deprecation issues found' + ); + }); + }); }); describe('no deprecations', () => { 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 ce6aa27b93240..7beb4774914e6 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 @@ -28,7 +28,7 @@ import { NoDeprecationsPrompt } from '../shared'; const i18nTexts = { pageTitle: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageTitle', { - defaultMessage: 'Elasticsearch deprecation issues', + defaultMessage: 'Elasticsearch deprecation warnings', }), pageDescription: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageDescription', { defaultMessage: @@ -48,11 +48,6 @@ const i18nTexts = { defaultMessage: 'Take a snapshot before you make any changes.', }), }, - deprecationIssuesButton: { - label: i18n.translate('xpack.upgradeAssistant.esDeprecations.deprecationIssuesButtonLabel', { - defaultMessage: 'Learn more about deprecation issues', - }), - }, }; export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProps) => { @@ -119,30 +114,16 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp {i18nTexts.backupDataButton.label} - - - {i18nTexts.deprecationIssuesButton.label} - - diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx index 264ee432822a3..8cc23af684a53 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -71,26 +71,35 @@ const i18nTexts = { ), }; -const cellTypeToLabelMap = { - type: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeColumnTitle', { - defaultMessage: 'Type', - }), - index: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.sourceColumnTitle', { - defaultMessage: 'Source', - }), - message: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle', { - defaultMessage: 'Issue', - }), - correctiveAction: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', - { +const cellToLabelMap = { + correctiveAction: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', { defaultMessage: 'Status', - } - ), + }), + width: '4px', + }, + message: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle', { + defaultMessage: 'Issue', + }), + width: '36px', + }, + type: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeColumnTitle', { + defaultMessage: 'Type', + }), + width: '10px', + }, + index: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.nameColumnTitle', { + defaultMessage: 'Name', + }), + width: '24px', + }, }; -const cellTypes = Object.keys(cellTypeToLabelMap) as DeprecationTableColumns[]; -const pageSizeOptions = [10, 20, 50]; +const cellTypes = Object.keys(cellToLabelMap) as DeprecationTableColumns[]; +const pageSizeOptions = [50, 100, 200]; const renderTableRowCells = (deprecation: EnrichedDeprecationInfo) => { const { correctiveAction } = deprecation; @@ -143,7 +152,7 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ sortField: 'correctiveAction', }); - const [itemsPerPage, setItemsPerPage] = useState(10); + const [itemsPerPage, setItemsPerPage] = useState(pageSizeOptions[0]); const [currentPageIndex, setCurrentPageIndex] = useState(0); const [searchQuery, setSearchQuery] = useState(EuiSearchBar.Query.MATCH_ALL); const [searchError, setSearchError] = useState<{ message: string } | undefined>(undefined); @@ -179,21 +188,23 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ }, []); useEffect(() => { - const { firstItemIndex, lastItemIndex } = pager; + const { setTotalItems, goToPageIndex } = pager; const deprecationsFilteredByQuery = EuiSearchBar.Query.execute(searchQuery, deprecations); const deprecationsSortedByFieldType = getSortedItems(deprecationsFilteredByQuery, sortConfig); - // Filter deprecations by current page and number of items per page - const visibleDeprecations = deprecationsSortedByFieldType.slice( - firstItemIndex, - lastItemIndex + 1 - ); - setFilteredDeprecations(visibleDeprecations); - }, [deprecations, sortConfig, pager, searchQuery]); + + setTotalItems(deprecationsSortedByFieldType.length); + setFilteredDeprecations(deprecationsSortedByFieldType); + + // Reset pagination if the filtered results return a different length + if (deprecationsSortedByFieldType.length !== filteredDeprecations.length) { + goToPageIndex(0); + } + }, [deprecations, sortConfig, pager, searchQuery, filteredDeprecations.length]); return (
- + = ({ {searchError && ( - <> +
= ({ color="danger" title={`Invalid search: ${searchError.message}`} /> - +
)} - {Object.entries(cellTypeToLabelMap).map(([fieldName, label]) => { + {Object.entries(cellToLabelMap).map(([fieldName, cell]) => { return ( handleSort(fieldName as DeprecationTableColumns)} isSorted={sortConfig.sortField === fieldName} isSortAscending={sortConfig.isSortAscending} > - {label} + {cell.label} ); })} @@ -265,7 +277,7 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ {filteredDeprecations.length === 0 ? ( - + {i18nTexts.noDeprecationsMessage} @@ -273,13 +285,18 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ ) : ( - {filteredDeprecations.map((deprecation, index) => { - return ( - - {renderTableRowCells(deprecation)} - - ); - })} + {filteredDeprecations + .slice(pager.firstItemIndex, pager.lastItemIndex + 1) + .map((deprecation, index) => { + return ( + + {renderTableRowCells(deprecation)} + + ); + })} )} From 23d9ca52769466c1e18a9c716619cc3d4a5db734 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 16 Aug 2021 12:37:33 -0400 Subject: [PATCH 09/18] add resolution column --- ...ble_cell.tsx => resolution_table_cell.tsx} | 36 +++++++++++++++++-- .../index_settings/table_row.tsx | 4 +-- ...ble_cell.tsx => resolution_table_cell.tsx} | 30 ++++++++++++++-- .../ml_snapshots/table_row.tsx | 4 +-- ...ble_cell.tsx => resolution_table_cell.tsx} | 29 +++++++++++---- .../deprecation_types/reindex/table_row.tsx | 8 ++--- .../es_deprecations/es_deprecations.tsx | 2 +- .../es_deprecations/es_deprecations_table.tsx | 14 +++++--- .../es_deprecations_table_cells.tsx | 29 +++++++++------ .../public/application/components/types.ts | 7 +++- .../public/application/lib/breadcrumbs.ts | 2 +- 11 files changed, 127 insertions(+), 38 deletions(-) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/{status_table_cell.tsx => resolution_table_cell.tsx} (69%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/{status_table_cell.tsx => resolution_table_cell.tsx} (78%) rename x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/{status_table_cell.tsx => resolution_table_cell.tsx} (82%) diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx similarity index 69% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx index 323494944c625..73cd814eca861 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx @@ -7,7 +7,14 @@ import React from 'react'; -import { EuiFlexItem, EuiText, EuiFlexGroup, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; +import { + EuiFlexItem, + EuiText, + EuiFlexGroup, + EuiIcon, + EuiLoadingSpinner, + EuiToolTip, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Status } from '../../../types'; @@ -30,6 +37,18 @@ const i18nTexts = { defaultMessage: 'Settings removal failed', } ), + resolutionText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionText', + { + defaultMessage: 'Remove settings', + } + ), + resolutionTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionTooltipLabel', + { + defaultMessage: 'This deprecation requires removing index settings from an index to resolve.', + } + ), }; interface Props { @@ -38,7 +57,7 @@ interface Props { }; } -export const IndexSettingsStatusCell: React.FunctionComponent = ({ status }) => { +export const IndexSettingsResolutionCell: React.FunctionComponent = ({ status }) => { const { statusType } = status; if (statusType === 'in_progress') { return ( @@ -91,5 +110,16 @@ export const IndexSettingsStatusCell: React.FunctionComponent = ({ status ); } - return <>{''}; + return ( + + + + {i18nTexts.resolutionText} + + + + + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx index d8d5d31b79575..3a1706b08c0ee 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/table_row.tsx @@ -13,7 +13,7 @@ import { useAppContext } from '../../../../app_context'; import type { ResponseError } from '../../../../lib/api'; import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; import { DeprecationTableColumns, Status } from '../../../types'; -import { IndexSettingsStatusCell } from './status_table_cell'; +import { IndexSettingsResolutionCell } from './resolution_table_cell'; import { RemoveIndexSettingsFlyout, RemoveIndexSettingsFlyoutProps } from './flyout'; const { useGlobalFlyout } = GlobalFlyout; @@ -93,7 +93,7 @@ export const IndexSettingsTableRow: React.FunctionComponent = ({ fieldName={field} openFlyout={() => setShowFlyout(true)} deprecation={deprecation} - statusTableCell={} + resolutionTableCell={} /> ); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx similarity index 78% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx index b3261174ddeba..c6535775f6377 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { - EuiBadge, + EuiToolTip, EuiFlexItem, EuiText, EuiFlexGroup, @@ -62,9 +62,22 @@ const i18nTexts = { defaultMessage: 'Critical', } ), + resolutionText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionText', + { + defaultMessage: 'Upgrade or delete snapshots', + } + ), + resolutionTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionTooltipLabel', + { + defaultMessage: + 'This deprecation requires upgrading or deleting a job model snapshot to resolve.', + } + ), }; -export const MlSnapshotsStatusCell: React.FunctionComponent = () => { +export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { const { snapshotState } = useMlSnapshotContext(); if (snapshotState.status === 'in_progress') { @@ -118,5 +131,16 @@ export const MlSnapshotsStatusCell: React.FunctionComponent = () => { ); } - return {i18nTexts.criticalBadgeLabel}; + return ( + + + + {i18nTexts.resolutionText} + + + + + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx index 6a1150cc4effa..73921b235d88c 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/table_row.tsx @@ -12,7 +12,7 @@ import { GlobalFlyout } from '../../../../../shared_imports'; import { useAppContext } from '../../../../app_context'; import { DeprecationTableColumns } from '../../../types'; import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; -import { MlSnapshotsStatusCell } from './status_table_cell'; +import { MlSnapshotsResolutionCell } from './resolution_table_cell'; import { FixSnapshotsFlyout, FixSnapshotsFlyoutProps } from './flyout'; import { MlSnapshotsStatusProvider, useMlSnapshotContext } from './context'; @@ -68,7 +68,7 @@ export const MlSnapshotsTableRowCells: React.FunctionComponent = fieldName={field} openFlyout={() => setShowFlyout(true)} deprecation={deprecation} - statusTableCell={} + resolutionTableCell={} /> ); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx similarity index 82% rename from x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx index b6919bdc1575c..46ad7d8cc3b53 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/status_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx @@ -14,7 +14,7 @@ import { EuiText, EuiFlexGroup, EuiFlexItem, - EuiBadge, + EuiToolTip, } from '@elastic/eui'; import { ReindexStatus } from '../../../../../../common/types'; import { LoadingState } from '../../../types'; @@ -57,15 +57,21 @@ const i18nTexts = { defaultMessage: 'Reindex paused', } ), - criticalBadgeLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.criticalBadgeLabel', + resolutionText: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionLabel', { - defaultMessage: 'Critical', + defaultMessage: 'Reindex', + } + ), + resolutionTooltipLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionTooltipLabel', + { + defaultMessage: 'This deprecation requires reindexing an index to resolve.', } ), }; -export const ReindexStatusCell: React.FunctionComponent = () => { +export const ReindexResolutionCell: React.FunctionComponent = () => { const { reindexState } = useReindexContext(); if (reindexState.loadingState === LoadingState.Loading) { @@ -139,5 +145,16 @@ export const ReindexStatusCell: React.FunctionComponent = () => { ); } - return {i18nTexts.criticalBadgeLabel}; + return ( + + + + {i18nTexts.resolutionText} + + + + + + + ); }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx index 06fc4f454af64..b08c5062b0abd 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx @@ -12,7 +12,7 @@ import { GlobalFlyout } from '../../../../../shared_imports'; import { useAppContext } from '../../../../app_context'; import { DeprecationTableColumns } from '../../../types'; import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells'; -import { ReindexStatusCell } from './status_table_cell'; +import { ReindexResolutionCell } from './resolution_table_cell'; import { ReindexFlyout, ReindexFlyoutProps } from './flyout'; import { ReindexStatusProvider, useReindexContext } from './context'; @@ -37,9 +37,9 @@ export const ReindexTableRowCells: React.FunctionComponent = ({ } = useGlobalFlyout(); const closeFlyout = useCallback(async () => { - await api.sendReindexTelemetryData({ close: true }); - setShowFlyout(false); removeContentFromGlobalFlyout('reindexFlyout'); + setShowFlyout(false); + await api.sendReindexTelemetryData({ close: true }); }, [api, removeContentFromGlobalFlyout]); useEffect(() => { @@ -84,7 +84,7 @@ export const ReindexTableRowCells: React.FunctionComponent = ({ fieldName={field} openFlyout={() => setShowFlyout(true)} deprecation={deprecation} - statusTableCell={} + resolutionTableCell={} /> ); 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 7beb4774914e6..988e36914c7eb 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 @@ -32,7 +32,7 @@ const i18nTexts = { }), pageDescription: i18n.translate('xpack.upgradeAssistant.esDeprecations.pageDescription', { defaultMessage: - 'Review your deprecation issues. Reindex indices or follow step-by-step instructions for any issues in need of manual configuration.', + 'You must resolve all critical issues before upgrading. Back up recommended. Make sure you have a current snapshot before modifying your configuration or reindexing.', }), docLinkText: i18n.translate('xpack.upgradeAssistant.esDeprecations.docLinkText', { defaultMessage: 'Documentation', diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx index 8cc23af684a53..9d4b6061304db 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -72,11 +72,11 @@ const i18nTexts = { }; const cellToLabelMap = { - correctiveAction: { + isCritical: { label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', { defaultMessage: 'Status', }), - width: '4px', + width: '6px', }, message: { label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle', { @@ -96,6 +96,12 @@ const cellToLabelMap = { }), width: '24px', }, + correctiveAction: { + label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.resolutionColumnTitle', { + defaultMessage: 'Resolution', + }), + width: '24px', + }, }; const cellTypes = Object.keys(cellToLabelMap) as DeprecationTableColumns[]; @@ -133,7 +139,7 @@ const getSortedItems = (deprecations: EnrichedDeprecationInfo[], sortConfig: Sor const { isSortAscending, sortField } = sortConfig; const sorted = sortBy(deprecations, [ (deprecation) => { - if (sortField === 'correctiveAction') { + if (sortField === 'isCritical') { return deprecation.isCritical !== true; } return deprecation[sortField]; @@ -149,7 +155,7 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ }) => { const [sortConfig, setSortConfig] = useState({ isSortAscending: true, - sortField: 'correctiveAction', + sortField: 'isCritical', }); const [itemsPerPage, setItemsPerPage] = useState(pageSizeOptions[0]); 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 60c62a94e9d67..dd187f19d5e96 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 @@ -13,7 +13,7 @@ import { DEPRECATION_TYPE_MAP } from '../constants'; import { DeprecationTableColumns } from '../types'; interface Props { - statusTableCell?: React.ReactNode; + resolutionTableCell?: React.ReactNode; fieldName: DeprecationTableColumns; deprecation: EnrichedDeprecationInfo; openFlyout: () => void; @@ -29,21 +29,14 @@ const i18nTexts = { }; export const EsDeprecationsTableCells: React.FunctionComponent = ({ - statusTableCell, + resolutionTableCell, fieldName, deprecation, openFlyout, }) => { - // "Type" column - if (fieldName === 'type') { - return <>{DEPRECATION_TYPE_MAP[deprecation.type as EnrichedDeprecationInfo['type']]}; - } - // "Status column" - if (fieldName === 'correctiveAction') { - if (statusTableCell) { - return <>{statusTableCell}; - } else if (deprecation.isCritical === true) { + if (fieldName === 'isCritical') { + if (deprecation.isCritical === true) { return {i18nTexts.criticalBadgeLabel}; } @@ -62,6 +55,20 @@ export const EsDeprecationsTableCells: React.FunctionComponent = ({ ); } + // "Type" column + if (fieldName === 'type') { + return <>{DEPRECATION_TYPE_MAP[deprecation.type as EnrichedDeprecationInfo['type']]}; + } + + // "Resolution column" + if (fieldName === 'correctiveAction') { + if (resolutionTableCell) { + return <>{resolutionTableCell}; + } + + return <>{''}; + } + // Default behavior: render value or empty string if undefined return <>{deprecation[fieldName] ?? ''}; }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts index a7b57e23068e9..4d4e5242d4513 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -19,6 +19,11 @@ export enum GroupByOption { node = 'node', } -export type DeprecationTableColumns = 'type' | 'index' | 'message' | 'correctiveAction'; +export type DeprecationTableColumns = + | 'type' + | 'index' + | 'message' + | 'correctiveAction' + | 'isCritical'; export type Status = 'in_progress' | 'complete' | 'idle' | 'error'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts index 00359988d5e2a..f36dc2096ddc7 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/breadcrumbs.ts @@ -16,7 +16,7 @@ const i18nTexts = { defaultMessage: 'Upgrade Assistant', }), esDeprecations: i18n.translate('xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel', { - defaultMessage: 'Elasticsearch deprecations', + defaultMessage: 'Elasticsearch deprecation warnings', }), kibanaDeprecations: i18n.translate( 'xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel', From 4a0c3719685ab870047a8c018d994089e03cbda6 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 17 Aug 2021 08:46:42 -0400 Subject: [PATCH 10/18] add more CITs --- .../client_integration/elasticsearch.test.ts | 735 ++++++++++-------- .../helpers/elasticsearch.helpers.ts | 127 ++- .../reindex/resolution_table_cell.tsx | 13 +- .../reindex/use_reindex_state.tsx | 2 + .../es_deprecations/es_deprecations.tsx | 12 +- .../es_deprecations/es_deprecations_table.tsx | 7 +- 6 files changed, 552 insertions(+), 344 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index 73c24ea987c62..c6244d1d86085 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -6,8 +6,8 @@ */ import { act } from 'react-dom/test-utils'; -import type { MlAction, ESUpgradeStatus } from '../../common/types'; -import { indexSettingDeprecations } from '../../common/constants'; +import type { MlAction, ESUpgradeStatus, EnrichedDeprecationInfo } from '../../common/types'; +import { API_BASE_PATH, indexSettingDeprecations } from '../../common/constants'; import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from './helpers'; @@ -107,356 +107,321 @@ describe('Elasticsearch deprecations', () => { ); }); - describe('ML snapshots deprecation', () => { - beforeEach(async () => { - const { component, find, exists } = testBed; - - await act(async () => { - find('deprecation-mlSnapshot').at(0).simulate('click'); - }); + test('refreshes deprecation data', async () => { + const { actions } = testBed; + const totalRequests = server.requests.length; - component.update(); - - expect(exists('mlSnapshotDetails')).toBe(true); - expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( - 'Upgrade or delete model snapshot' - ); - }); + await actions.clickRefreshButton(); - test('upgrades snapshots', async () => { - const { component, find } = testBed; + const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; + const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; - httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'in_progress', - }); + // Since upgradeStatusMockResponse includes ML and reindex actions (which require fetching status), there will be 3 requests made + expect(server.requests.length).toBe(totalRequests + 3); + expect(server.requests[server.requests.length - 3].url).toBe( + `${API_BASE_PATH}/es_deprecations` + ); + expect(server.requests[server.requests.length - 2].url).toBe( + `${API_BASE_PATH}/ml_snapshots/${(mlDeprecation.correctiveAction as MlAction).jobId}/${ + (mlDeprecation.correctiveAction as MlAction).snapshotId + }` + ); + expect(server.requests[server.requests.length - 1].url).toBe( + `${API_BASE_PATH}/reindex/${reindexDeprecation.index}` + ); + }); - httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'complete', - }); + describe('deprecation details', () => { + describe('ML snapshots deprecation', () => { + beforeEach(async () => { + const { find, exists, actions } = testBed; - expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); + await actions.clickMlDeprecationAt(0); - await act(async () => { - find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); + expect(exists('mlSnapshotDetails')).toBe(true); + expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( + 'Upgrade or delete model snapshot' + ); }); - component.update(); + test('upgrades snapshots', async () => { + const { find, actions } = testBed; - // First, we expect a POST request to upgrade the snapshot - const upgradeRequest = server.requests[server.requests.length - 2]; - expect(upgradeRequest.method).toBe('POST'); - expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - - // Next, we expect a GET request to check the status of the upgrade - const statusRequest = server.requests[server.requests.length - 1]; - expect(statusRequest.method).toBe('GET'); - expect(statusRequest.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${jobId}/${snapshotId}` - ); + httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'in_progress', + }); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').text()).toContain('Upgrade complete'); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'complete', + }); - // Reopen the flyout - await act(async () => { - find('deprecation-mlSnapshot').at(0).simulate('click'); - }); + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); - component.update(); + await actions.clickUpgradeMlSnapshot(); - // Flyout actions should not be visible if deprecation was resolved - expect(find('mlSnapshotDetails.upgradeSnapshotButton').length).toBe(0); - expect(find('mlSnapshotDetails.deleteSnapshotButton').length).toBe(0); - }); + // First, we expect a POST request to upgrade the snapshot + const upgradeRequest = server.requests[server.requests.length - 2]; + expect(upgradeRequest.method).toBe('POST'); + expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - test('handles upgrade failure', async () => { - const { component, find } = testBed; + // Next, we expect a GET request to check the status of the upgrade + const statusRequest = server.requests[server.requests.length - 1]; + expect(statusRequest.method).toBe('GET'); + expect(statusRequest.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${jobId}/${snapshotId}` + ); - const error = { - statusCode: 500, - error: 'Upgrade snapshot error', - message: 'Upgrade snapshot error', - }; + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').text()).toContain('Upgrade complete'); - httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); - httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'error', - error, - }); + // Reopen the flyout + await actions.clickMlDeprecationAt(0); - await act(async () => { - find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); + // Flyout actions should not be visible if deprecation was resolved + expect(find('mlSnapshotDetails.upgradeSnapshotButton').length).toBe(0); + expect(find('mlSnapshotDetails.deleteSnapshotButton').length).toBe(0); }); - component.update(); - - const upgradeRequest = server.requests[server.requests.length - 1]; - expect(upgradeRequest.method).toBe('POST'); - expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); + test('handles upgrade failure', async () => { + const { find, actions } = testBed; - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').text()).toContain('Upgrade failed'); + const error = { + statusCode: 500, + error: 'Upgrade snapshot error', + message: 'Upgrade snapshot error', + }; - // Reopen the flyout - await act(async () => { - find('deprecation-mlSnapshot').at(0).simulate('click'); - }); - - component.update(); + httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'error', + error, + }); - // Verify the flyout shows an error message - expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( - 'Error upgrading snapshot' - ); - // Verify the upgrade button text changes - expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Retry upgrade'); - }); + await actions.clickUpgradeMlSnapshot(); - test('deletes snapshots', async () => { - const { component, find } = testBed; + const upgradeRequest = server.requests[server.requests.length - 1]; + expect(upgradeRequest.method).toBe('POST'); + expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ - acknowledged: true, - }); + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').text()).toContain('Upgrade failed'); - expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); + // Reopen the flyout + await actions.clickMlDeprecationAt(0); - await act(async () => { - find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error upgrading snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Retry upgrade'); }); - component.update(); + test('deletes snapshots', async () => { + const { find, actions } = testBed; - const request = server.requests[server.requests.length - 1]; - const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; + httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ + acknowledged: true, + }); - expect(request.method).toBe('DELETE'); - expect(request.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${ - (mlDeprecation.correctiveAction! as MlAction).jobId - }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` - ); + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion complete'); + await actions.clickDeleteMlSnapshot(); - // Reopen the flyout - await act(async () => { - find('deprecation-mlSnapshot').at(0).simulate('click'); - }); + const request = server.requests[server.requests.length - 1]; + const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; - component.update(); - }); + expect(request.method).toBe('DELETE'); + expect(request.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${ + (mlDeprecation.correctiveAction! as MlAction).jobId + }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` + ); - test('handles delete failure', async () => { - const { component, find } = testBed; + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion complete'); - const error = { - statusCode: 500, - error: 'Upgrade snapshot error', - message: 'Upgrade snapshot error', - }; - - httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); - - await act(async () => { - find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); + // Reopen the flyout + await actions.clickMlDeprecationAt(0); }); - component.update(); + test('handles delete failure', async () => { + const { find, actions } = testBed; - const request = server.requests[server.requests.length - 1]; - const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; + const error = { + statusCode: 500, + error: 'Upgrade snapshot error', + message: 'Upgrade snapshot error', + }; - expect(request.method).toBe('DELETE'); - expect(request.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${ - (mlDeprecation.correctiveAction! as MlAction).jobId - }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` - ); + httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion failed'); + await actions.clickDeleteMlSnapshot(); - // Reopen the flyout - await act(async () => { - find('deprecation-mlSnapshot').at(0).simulate('click'); - }); + const request = server.requests[server.requests.length - 1]; + const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; - component.update(); + expect(request.method).toBe('DELETE'); + expect(request.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${ + (mlDeprecation.correctiveAction! as MlAction).jobId + }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` + ); - // Verify the flyout shows an error message - expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( - 'Error deleting snapshot' - ); - // Verify the upgrade button text changes - expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Retry delete'); - }); - }); + // Verify the "Status" column of the table is updated + expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion failed'); - describe('index settings deprecation', () => { - const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; + // Reopen the flyout + await actions.clickMlDeprecationAt(0); - beforeEach(async () => { - const { component, find, exists } = testBed; - - await act(async () => { - find('deprecation-indexSetting').at(0).simulate('click'); + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error deleting snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Retry delete'); }); - - component.update(); - - expect(exists('indexSettingsDetails')).toBe(true); - expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( - indexSettingDeprecation.message - ); - expect(exists('removeSettingsPrompt')).toBe(true); }); - it('removes deprecated index settings', async () => { - const { component, find } = testBed; + describe('index settings deprecation', () => { + const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; - httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ - acknowledged: true, - }); - - await act(async () => { - find('deleteSettingsButton').simulate('click'); - }); + beforeEach(async () => { + const { find, exists, actions } = testBed; - component.update(); - - const request = server.requests[server.requests.length - 1]; - - expect(request.method).toBe('POST'); - expect(request.url).toBe( - `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` - ); - expect(request.status).toEqual(200); + await actions.clickIndexSettingsDeprecationAt(0); - // Verify the "Status" column of the table is updated - expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( - 'Deprecated settings removed' - ); - - // Reopen the flyout - await act(async () => { - find('deprecation-indexSetting').at(0).simulate('click'); + expect(exists('indexSettingsDetails')).toBe(true); + expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( + indexSettingDeprecation.message + ); + expect(exists('removeSettingsPrompt')).toBe(true); }); - component.update(); + it('removes deprecated index settings', async () => { + const { component, find, actions } = testBed; - // Verify prompt to remove setting no longer displays - expect(find('removeSettingsPrompt').length).toEqual(0); - // Verify the action button no longer displays - expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); - }); - - it('handles failure', async () => { - const { component, find } = testBed; - const error = { - statusCode: 500, - error: 'Remove index settings error', - message: 'Remove index settings error', - }; + httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ + acknowledged: true, + }); - httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); - await act(async () => { - find('deleteSettingsButton').simulate('click'); - }); + component.update(); - component.update(); + const request = server.requests[server.requests.length - 1]; - const request = server.requests[server.requests.length - 1]; + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(200); - expect(request.method).toBe('POST'); - expect(request.url).toBe( - `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` - ); - expect(request.status).toEqual(500); + // Verify the "Status" column of the table is updated + expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( + 'Deprecated settings removed' + ); - // Verify the "Status" column of the table is updated - expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( - 'Settings removal failed' - ); + // Reopen the flyout + await actions.clickIndexSettingsDeprecationAt(0); - // Reopen the flyout - await act(async () => { - find('deprecation-indexSetting').at(0).simulate('click'); + // Verify prompt to remove setting no longer displays + expect(find('removeSettingsPrompt').length).toEqual(0); + // Verify the action button no longer displays + expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); }); - component.update(); - - // Verify the flyout shows an error message - expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( - 'Error deleting index settings' - ); - // Verify the remove settings button text changes - expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual( - 'Retry removing deprecated settings' - ); + it('handles failure', async () => { + const { component, find, actions } = testBed; + const error = { + statusCode: 500, + error: 'Remove index settings error', + message: 'Remove index settings error', + }; + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); + + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); + + component.update(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(500); + + // Verify the "Status" column of the table is updated + expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( + 'Settings removal failed' + ); + + // Reopen the flyout + await actions.clickIndexSettingsDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( + 'Error deleting index settings' + ); + // Verify the remove settings button text changes + expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual( + 'Retry removing deprecated settings' + ); + }); }); - }); - describe('default deprecation', () => { - it('renders a flyout with deprecation details', async () => { - const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[2]; - const { component, find, exists } = testBed; + describe('default deprecation', () => { + it('renders a flyout with deprecation details', async () => { + const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[2]; + const { actions, find, exists } = testBed; - await act(async () => { - find('deprecation-default').at(0).simulate('click'); - }); - - component.update(); + await actions.clickDefaultDeprecationAt(0); - expect(exists('defaultDeprecationDetails')).toBe(true); - expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( - multiFieldsDeprecation.message - ); - expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( - multiFieldsDeprecation.index - ); + expect(exists('defaultDeprecationDetails')).toBe(true); + expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( + multiFieldsDeprecation.message + ); + expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( + multiFieldsDeprecation.index + ); + }); }); - }); - describe('reindex deprecation', () => { - it('renders a flyout with reindexing details', async () => { - const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; - const { component, find, exists } = testBed; + describe('reindex deprecation', () => { + it('renders a flyout with reindexing details', async () => { + const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; + const { actions, find, exists } = testBed; - await act(async () => { - find('deprecation-reindex').at(0).simulate('click'); - }); - - component.update(); + await actions.clickReindexDeprecationAt(0); - expect(exists('reindexDetails')).toBe(true); - expect(find('reindexDetails.flyoutTitle').text()).toContain( - `Reindex ${reindexDeprecation.index}` - ); + expect(exists('reindexDetails')).toBe(true); + expect(find('reindexDetails.flyoutTitle').text()).toContain( + `Reindex ${reindexDeprecation.index}` + ); + }); }); }); describe('search bar', () => { it('filters results by "critical" status', async () => { - const { component, find } = testBed; + const { find, actions } = testBed; - await act(async () => { - // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector - find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); - }); - - component.update(); + await actions.clickCriticalFilterButton(); const criticalDeprecations = upgradeStatusMockResponse.deprecations.filter( (deprecation) => deprecation.isCritical @@ -464,13 +429,7 @@ describe('Elasticsearch deprecations', () => { expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); - // TODO move action to helpers file - await act(async () => { - // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector - find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); - }); - - component.update(); + await actions.clickCriticalFilterButton(); expect(find('deprecationTableRow').length).toEqual( upgradeStatusMockResponse.deprecations.length @@ -478,29 +437,20 @@ describe('Elasticsearch deprecations', () => { }); it('filters results by type', async () => { - const { component, find } = testBed; - - await act(async () => { - // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector - find('searchBarContainer') - .find('.euiPopover') - .find('.euiFilterButton') - .at(0) - .simulate('click'); - }); + const { component, find, actions } = testBed; - component.update(); + await actions.clickTypeFilterDropdownAt(0); // We need to read the document "body" as the filter dropdown options are added there and not inside // the component DOM tree. - const clusterFilterButton: HTMLButtonElement | null = document.body.querySelector( + const clusterTypeFilterButton: HTMLButtonElement | null = document.body.querySelector( '.euiFilterSelect__items .euiFilterSelectItem' ); - expect(clusterFilterButton).not.toBe(null); + expect(clusterTypeFilterButton).not.toBe(null); await act(async () => { - clusterFilterButton!.click(); + clusterTypeFilterButton!.click(); }); component.update(); @@ -513,51 +463,198 @@ describe('Elasticsearch deprecations', () => { }); it('filters results by query string', async () => { - const { find, component } = testBed; + const { find, actions } = testBed; const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[3]; - await act(async () => { - find('searchBarContainer') - .find('input') - .simulate('keyup', { target: { value: multiFieldsDeprecation.message } }); - }); - - component.update(); + await actions.setSearchInputValue(multiFieldsDeprecation.message); expect(find('deprecationTableRow').length).toEqual(1); expect(find('deprecationTableRow').at(0).text()).toContain(multiFieldsDeprecation.message); }); it('shows error for invalid search queries', async () => { - const { find, component, exists } = testBed; + const { find, exists, actions } = testBed; - await act(async () => { - find('searchBarContainer') - .find('input') - .simulate('keyup', { target: { value: '%' } }); - }); - - component.update(); + await actions.setSearchInputValue('%'); expect(exists('invalidSearchQueryMessage')).toBe(true); expect(find('invalidSearchQueryMessage').text()).toContain('Invalid search'); }); it('shows message when search query does not return results', async () => { - const { find, component, exists } = testBed; + const { find, actions, exists } = testBed; + + await actions.setSearchInputValue('foobarbaz'); + + expect(exists('noDeprecationsRow')).toBe(true); + expect(find('noDeprecationsRow').text()).toContain( + 'No Elasticsearch deprecation issues found' + ); + }); + }); + + describe('pagination', () => { + const mlDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: 20, + }, + () => ({ + isCritical: true, + resolveDuringUpgrade: false, + type: 'ml_settings', + message: + 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', + details: + 'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]', + url: 'doc_url', + correctiveAction: { + type: 'mlSnapshot', + snapshotId, + jobId, + }, + }) + ); + + const indexSettingsDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: 20, + }, + () => ({ + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: indexSettingDeprecations.translog.deprecationMessage, + details: 'deprecation details', + url: 'doc_url', + index: 'my_index', + correctiveAction: { + type: 'indexSetting', + deprecatedSettings: indexSettingDeprecations.translog.settings, + }, + }) + ); + + const reindexDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: 20, + }, + () => ({ + isCritical: true, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'Index created before 7.0', + details: 'deprecation details', + url: 'doc_url', + index: 'reindex_index', + correctiveAction: { + type: 'reindex', + }, + }) + ); + + const defaultDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: 20, + }, + () => ({ + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'multi-fields within multi-fields', + details: 'deprecation details', + url: 'doc_url', + index: 'nested_multi-fields', + }) + ); + + const deprecations: EnrichedDeprecationInfo[] = [ + ...defaultDeprecations, + ...reindexDeprecations, + ...indexSettingsDeprecations, + ...mlDeprecations, + ]; + + const upgradeStatusWithManyDeprecations: ESUpgradeStatus = { + totalCriticalDeprecations: 40, + deprecations, + }; + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusWithManyDeprecations); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId, + jobId, + status: 'idle', + }); await act(async () => { - find('searchBarContainer') - .find('input') - .simulate('keyup', { target: { value: 'foobarbaz' } }); + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('shows the correct number of pages and deprecations per page', async () => { + const { find, actions } = testBed; + + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( + Math.round(deprecations.length / 50) // Default rows per page is 50 + ); + expect(find('deprecationTableRow').length).toEqual(50); + + // Navigate to the next page + await actions.clickPaginationAt(1); + + // On the second (last) page, we expect to see the remaining deprecations + expect(find('deprecationTableRow').length).toEqual(deprecations.length - 50); + }); + + it('allows the number of viewable rows to change', async () => { + const { find, actions, component } = testBed; + + await actions.clickRowsPerPageDropdown(); + + // We need to read the document "body" as the rows-per-page dropdown options are added there and not inside + // the component DOM tree. + const rowsPerPageButton: HTMLButtonElement | null = document.body.querySelector( + '[data-test-subj="tablePagination-100-rows"]' + ); + + expect(rowsPerPageButton).not.toBe(null); + + await act(async () => { + rowsPerPageButton!.click(); }); component.update(); - expect(exists('noDeprecationsRow')).toBe(true); - expect(find('noDeprecationsRow').text()).toContain( - 'No Elasticsearch deprecation issues found' + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( + Math.round(deprecations.length / 100) // Rows per page is now 100 ); + expect(find('deprecationTableRow').length).toEqual(deprecations.length); + }); + + it('updates pagination when filters change', async () => { + const { actions, find } = testBed; + + const criticalDeprecations = deprecations.filter((deprecation) => deprecation.isCritical); + + await actions.clickCriticalFilterButton(); + + // Only 40 critical deprecations, so only one page should show + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); + expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); + }); + + it('updates pagination on search', async () => { + const { actions, find } = testBed; + + await actions.setSearchInputValue('Index created before 7.0'); + + // Only 20 deprecations that match, so only one page should show + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); + expect(find('deprecationTableRow').length).toEqual(reindexDeprecations.length); }); }); }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts index 5821d90a38564..32175b1009b62 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { act } from 'react-dom/test-utils'; import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; import { EsDeprecationsContent } from '../../../public/application/components/es_deprecations'; @@ -22,24 +23,128 @@ export type ElasticsearchTestBed = TestBed & { }; const createActions = (testBed: TestBed) => { + const { component, find } = testBed; + /** * User Actions */ - // const clickTab = (tabName: string) => { - // const { find } = testBed; - // const camelcaseTabName = tabName.charAt(0).toUpperCase() + tabName.slice(1); + const clickRefreshButton = async () => { + await act(async () => { + find('refreshButton').simulate('click'); + }); + + component.update(); + }; + + const clickMlDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-mlSnapshot').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickUpgradeMlSnapshot = async () => { + await act(async () => { + find('mlSnapshotDetails.upgradeSnapshotButton').simulate('click'); + }); + + component.update(); + }; + + const clickDeleteMlSnapshot = async () => { + await act(async () => { + find('mlSnapshotDetails.deleteSnapshotButton').simulate('click'); + }); + + component.update(); + }; + + const clickIndexSettingsDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-indexSetting').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickReindexDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-reindex').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickDefaultDeprecationAt = async (index: number) => { + await act(async () => { + find('deprecation-default').at(index).simulate('click'); + }); + + component.update(); + }; + + const clickCriticalFilterButton = async () => { + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer').find('.euiFilterButton').at(0).simulate('click'); + }); - // find(`upgradeAssistant${camelcaseTabName}Tab`).simulate('click'); - // }; + component.update(); + }; + + const clickTypeFilterDropdownAt = async (index: number) => { + await act(async () => { + // EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector + find('searchBarContainer') + .find('.euiPopover') + .find('.euiFilterButton') + .at(index) + .simulate('click'); + }); + + component.update(); + }; - // const clickExpandAll = () => { - // const { find } = testBed; - // find('expandAll').simulate('click'); - // }; + const setSearchInputValue = async (searchValue: string) => { + await act(async () => { + find('searchBarContainer') + .find('input') + .simulate('keyup', { target: { value: searchValue } }); + }); + + component.update(); + }; + + const clickPaginationAt = async (index: number) => { + await act(async () => { + find(`pagination-button-${index}`).simulate('click'); + }); + + component.update(); + }; + + const clickRowsPerPageDropdown = async () => { + await act(async () => { + find('tablePaginationPopoverButton').simulate('click'); + }); + + component.update(); + }; return { - // clickTab, - // clickExpandAll, + clickRefreshButton, + clickMlDeprecationAt, + clickUpgradeMlSnapshot, + clickDeleteMlSnapshot, + clickIndexSettingsDeprecationAt, + clickReindexDeprecationAt, + clickDefaultDeprecationAt, + clickCriticalFilterButton, + clickTypeFilterDropdownAt, + setSearchInputValue, + clickPaginationAt, + clickRowsPerPageDropdown, }; }; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx index 46ad7d8cc3b53..a31326d62d174 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx @@ -57,14 +57,11 @@ const i18nTexts = { defaultMessage: 'Reindex paused', } ), - resolutionText: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionLabel', - { - defaultMessage: 'Reindex', - } - ), + resolutionText: i18n.translate('xpack.upgradeAssistant.esDeprecations.reindex.resolutionLabel', { + defaultMessage: 'Reindex', + }), resolutionTooltipLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionTooltipLabel', + 'xpack.upgradeAssistant.esDeprecations.reindex.resolutionTooltipLabel', { defaultMessage: 'This deprecation requires reindexing an index to resolve.', } @@ -117,7 +114,7 @@ export const ReindexResolutionCell: React.FunctionComponent = () => { - {i18nTexts.reindexCompleteText} + {i18nTexts.reindexFailedText} ); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx index 15ae68d544033..6309c2aa7f067 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx @@ -99,6 +99,7 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A if (error) { setReindexState({ ...reindexState, + loadingState: LoadingState.Error, status: ReindexStatus.failed, }); return; @@ -137,6 +138,7 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A if (error) { setReindexState({ ...reindexState, + loadingState: LoadingState.Error, status: ReindexStatus.failed, }); return; 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 988e36914c7eb..569c925a67e8f 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 @@ -53,14 +53,20 @@ const i18nTexts = { export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProps) => { const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); - const { data: esDeprecations, isLoading, error, resendRequest } = api.useLoadUpgradeStatus(); + const { + data: esDeprecations, + isLoading, + error, + resendRequest, + isInitialRequest, + } = api.useLoadUpgradeStatus(); useEffect(() => { breadcrumbs.setBreadcrumbs('esDeprecations'); }, [breadcrumbs]); useEffect(() => { - if (isLoading === false) { + if (isLoading === false && isInitialRequest) { async function sendTelemetryData() { await api.sendPageTelemetryData({ elasticsearch: true, @@ -69,7 +75,7 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp sendTelemetryData(); } - }, [api, isLoading]); + }, [api, isLoading, isInitialRequest]); if (error) { return ; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx index 9d4b6061304db..00b1e05917d3e 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -76,7 +76,7 @@ const cellToLabelMap = { label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', { defaultMessage: 'Status', }), - width: '6px', + width: '8px', }, message: { label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle', { @@ -242,8 +242,8 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ {i18nTexts.refreshButtonLabel} @@ -310,6 +310,7 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ Date: Tue, 17 Aug 2021 11:52:10 -0400 Subject: [PATCH 11/18] cleanup --- .../client_integration/elasticsearch.test.ts | 43 +++++++------------ .../helpers/elasticsearch.helpers.ts | 9 ++++ .../index_settings/resolution_table_cell.tsx | 12 ++++-- .../ml_snapshots/resolution_table_cell.tsx | 14 ++---- .../es_deprecations/es_deprecations.tsx | 26 +---------- .../es_deprecations/es_deprecations_table.tsx | 4 +- 6 files changed, 40 insertions(+), 68 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index c6244d1d86085..4846cfd7fe3cd 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -98,9 +98,6 @@ describe('Elasticsearch deprecations', () => { // Verify container exists expect(exists('esDeprecationsContent')).toBe(true); - // Verify links exist - expect(exists('esDeprecationsContent.snapshotRestoreLink')).toBe(true); - // Verify all deprecations appear in the table expect(find('deprecationTableRow').length).toEqual( upgradeStatusMockResponse.deprecations.length @@ -177,8 +174,8 @@ describe('Elasticsearch deprecations', () => { `/api/upgrade_assistant/ml_snapshots/${jobId}/${snapshotId}` ); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').text()).toContain('Upgrade complete'); + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').text()).toContain('Upgrade complete'); // Reopen the flyout await actions.clickMlDeprecationAt(0); @@ -212,8 +209,8 @@ describe('Elasticsearch deprecations', () => { expect(upgradeRequest.method).toBe('POST'); expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').text()).toContain('Upgrade failed'); + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').text()).toContain('Upgrade failed'); // Reopen the flyout await actions.clickMlDeprecationAt(0); @@ -247,8 +244,8 @@ describe('Elasticsearch deprecations', () => { }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` ); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion complete'); + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion complete'); // Reopen the flyout await actions.clickMlDeprecationAt(0); @@ -277,8 +274,8 @@ describe('Elasticsearch deprecations', () => { }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` ); - // Verify the "Status" column of the table is updated - expect(find('mlActionStatusCell').at(0).text()).toEqual('Deletion failed'); + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion failed'); // Reopen the flyout await actions.clickMlDeprecationAt(0); @@ -308,17 +305,13 @@ describe('Elasticsearch deprecations', () => { }); it('removes deprecated index settings', async () => { - const { component, find, actions } = testBed; + const { find, actions } = testBed; httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ acknowledged: true, }); - await act(async () => { - find('deleteSettingsButton').simulate('click'); - }); - - component.update(); + await actions.clickDeleteSettingsButton(); const request = server.requests[server.requests.length - 1]; @@ -328,8 +321,8 @@ describe('Elasticsearch deprecations', () => { ); expect(request.status).toEqual(200); - // Verify the "Status" column of the table is updated - expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( + // Verify the "Resolution" column of the table is updated + expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( 'Deprecated settings removed' ); @@ -343,7 +336,7 @@ describe('Elasticsearch deprecations', () => { }); it('handles failure', async () => { - const { component, find, actions } = testBed; + const { find, actions } = testBed; const error = { statusCode: 500, error: 'Remove index settings error', @@ -352,11 +345,7 @@ describe('Elasticsearch deprecations', () => { httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); - await act(async () => { - find('deleteSettingsButton').simulate('click'); - }); - - component.update(); + await actions.clickDeleteSettingsButton(); const request = server.requests[server.requests.length - 1]; @@ -366,8 +355,8 @@ describe('Elasticsearch deprecations', () => { ); expect(request.status).toEqual(500); - // Verify the "Status" column of the table is updated - expect(find('indexSettingsActionStatusCell').at(0).text()).toEqual( + // Verify the "Resolution" column of the table is updated + expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( 'Settings removal failed' ); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts index 32175b1009b62..ed4944527e047 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts @@ -68,6 +68,14 @@ const createActions = (testBed: TestBed) => { component.update(); }; + const clickDeleteSettingsButton = async () => { + await act(async () => { + find('deleteSettingsButton').simulate('click'); + }); + + component.update(); + }; + const clickReindexDeprecationAt = async (index: number) => { await act(async () => { find('deprecation-reindex').at(index).simulate('click'); @@ -138,6 +146,7 @@ const createActions = (testBed: TestBed) => { clickUpgradeMlSnapshot, clickDeleteMlSnapshot, clickIndexSettingsDeprecationAt, + clickDeleteSettingsButton, clickReindexDeprecationAt, clickDefaultDeprecationAt, clickCriticalFilterButton, diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx index 73cd814eca861..bae81031d5781 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/resolution_table_cell.tsx @@ -64,7 +64,7 @@ export const IndexSettingsResolutionCell: React.FunctionComponent = ({ st @@ -81,7 +81,7 @@ export const IndexSettingsResolutionCell: React.FunctionComponent = ({ st @@ -98,7 +98,7 @@ export const IndexSettingsResolutionCell: React.FunctionComponent = ({ st @@ -112,7 +112,11 @@ export const IndexSettingsResolutionCell: React.FunctionComponent = ({ st return ( - + {i18nTexts.resolutionText} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx index c6535775f6377..2e02a2ecb6fb3 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx @@ -56,12 +56,6 @@ const i18nTexts = { defaultMessage: 'Deletion failed', } ), - criticalBadgeLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.criticalBadgeLabel', - { - defaultMessage: 'Critical', - } - ), resolutionText: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionText', { @@ -82,7 +76,7 @@ export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { if (snapshotState.status === 'in_progress') { return ( - + @@ -99,7 +93,7 @@ export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { if (snapshotState.status === 'complete') { return ( - + @@ -116,7 +110,7 @@ export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { if (snapshotState.status === 'error') { return ( - + @@ -133,7 +127,7 @@ export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { return ( - + {i18nTexts.resolutionText} 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 569c925a67e8f..e4eafb5d4d087 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 @@ -40,14 +40,6 @@ const i18nTexts = { isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { defaultMessage: 'Loading deprecations…', }), - backupDataButton: { - label: i18n.translate('xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel', { - defaultMessage: 'Back up your data', - }), - tooltipText: i18n.translate('xpack.upgradeAssistant.esDeprecations.backupDataTooltipText', { - defaultMessage: 'Take a snapshot before you make any changes.', - }), - }, }; export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProps) => { @@ -115,23 +107,7 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp {i18nTexts.docLinkText} , ]} - > - - - - - {i18nTexts.backupDataButton.label} - - - - - + /> diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx index 00b1e05917d3e..31bf4223d3228 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -208,7 +208,7 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ }, [deprecations, sortConfig, pager, searchQuery, filteredDeprecations.length]); return ( -
+ <> = ({ onChangeItemsPerPage={setItemsPerPage} onChangePage={setCurrentPageIndex} /> -
+ ); }; From 92dc99f15bad10f87f8b114baddc4d9a75fc74cf Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 17 Aug 2021 12:08:43 -0400 Subject: [PATCH 12/18] update translations --- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 2 files changed, 4 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f9555718f9ac2..b5a40515f9a7c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -24874,8 +24874,6 @@ "xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Kibanaをご使用のElasticsearchクラスターと同じバージョンにアップグレードしてください。クラスターの1つ以上のノードがKibanaとは異なるバージョンを実行しています。", "xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Elasticsearchの廃止予定を表示する権限がありません。", "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "構成は最新です。KibanaおよびすべてのElasticsearchノードは同じバージョンを実行しています。", - "xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel": "データをバックアップ", - "xpack.upgradeAssistant.esDeprecations.backupDataTooltipText": "変更を行う前にスナップショットを作成します。", "xpack.upgradeAssistant.esDeprecations.docLinkText": "ドキュメント", "xpack.upgradeAssistant.esDeprecations.loadingText": "廃止予定を読み込んでいます...", "xpack.upgradeAssistant.esDeprecations.pageDescription": "廃止予定のクラスターとインデックス設定をレビューします。アップグレード前に重要な問題を解決する必要があります。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1cb03a388c98e..2c7bfb76b00c7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25441,8 +25441,6 @@ "xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "将 Kibana 升级到与您的 Elasticsearch 集群相同的版本。集群中的一个或多个节点正在运行与 Kibana 不同的版本。", "xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "您无权查看 Elasticsearch 弃用。", "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "您的配置是最新的。Kibana 和索引 Elasticsearch 节点正在运行相同的版本。", - "xpack.upgradeAssistant.esDeprecations.backupDataButtonLabel": "备份您的数据", - "xpack.upgradeAssistant.esDeprecations.backupDataTooltipText": "在进行任何更改之前拍取快照。", "xpack.upgradeAssistant.esDeprecations.docLinkText": "文档", "xpack.upgradeAssistant.esDeprecations.loadingText": "正在加载弃用……", "xpack.upgradeAssistant.esDeprecations.pageDescription": "查看已弃用的群集和索引设置。在升级之前必须解决任何紧急问题。", From b3a22bc299d35e1fa4bd301d987470dc4f548523 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 17 Aug 2021 13:00:37 -0400 Subject: [PATCH 13/18] small design tweaks --- .../deprecation_types/ml_snapshots/flyout.tsx | 12 +++++++ .../es_deprecations/es_deprecations.tsx | 31 ++----------------- 2 files changed, 15 insertions(+), 28 deletions(-) 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 95caac78509a8..2755ce0dd073c 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 @@ -20,6 +20,7 @@ import { EuiText, EuiCallOut, EuiSpacer, + EuiLink, } from '@elastic/eui'; import { EnrichedDeprecationInfo } from '../../../../../../common/types'; @@ -76,6 +77,12 @@ const i18nTexts = { defaultMessage: 'Error upgrading snapshot', } ), + learnMoreLinkLabel: i18n.translate( + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.learnMoreLinkLabel', + { + defaultMessage: 'Learn more about this deprecation', + } + ), }; export const FixSnapshotsFlyout = ({ @@ -122,6 +129,11 @@ export const FixSnapshotsFlyout = ({ )}

{deprecation.details}

+

+ + {i18nTexts.learnMoreLinkLabel} + +

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 e4eafb5d4d087..cbaaececbc7cf 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 @@ -8,16 +8,7 @@ import React, { useEffect } from 'react'; import { withRouter, RouteComponentProps } from 'react-router-dom'; -import { - EuiButton, - EuiButtonEmpty, - EuiPageHeader, - EuiToolTip, - EuiSpacer, - EuiPageContent, - EuiFlexItem, - EuiFlexGroup, -} from '@elastic/eui'; +import { EuiPageHeader, EuiSpacer, EuiPageContent } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { SectionLoading } from '../../../shared_imports'; @@ -34,16 +25,13 @@ const i18nTexts = { defaultMessage: 'You must resolve all critical issues before upgrading. Back up recommended. Make sure you have a current snapshot before modifying your configuration or reindexing.', }), - docLinkText: i18n.translate('xpack.upgradeAssistant.esDeprecations.docLinkText', { - defaultMessage: 'Documentation', - }), isLoading: i18n.translate('xpack.upgradeAssistant.esDeprecations.loadingText', { defaultMessage: 'Loading deprecations…', }), }; export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProps) => { - const { api, breadcrumbs, getUrlForApp, docLinks } = useAppContext(); + const { api, breadcrumbs } = useAppContext(); const { data: esDeprecations, @@ -94,20 +82,7 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp return (
- - {i18nTexts.docLinkText} - , - ]} - /> + From 1bc44e9bdbb321433a556db4a822b645080fcda1 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 17 Aug 2021 13:29:57 -0400 Subject: [PATCH 14/18] update translations --- x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b5a40515f9a7c..9b4afa4ab7ffc 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -24874,7 +24874,6 @@ "xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Kibanaをご使用のElasticsearchクラスターと同じバージョンにアップグレードしてください。クラスターの1つ以上のノードがKibanaとは異なるバージョンを実行しています。", "xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Elasticsearchの廃止予定を表示する権限がありません。", "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "構成は最新です。KibanaおよびすべてのElasticsearchノードは同じバージョンを実行しています。", - "xpack.upgradeAssistant.esDeprecations.docLinkText": "ドキュメント", "xpack.upgradeAssistant.esDeprecations.loadingText": "廃止予定を読み込んでいます...", "xpack.upgradeAssistant.esDeprecations.pageDescription": "廃止予定のクラスターとインデックス設定をレビューします。アップグレード前に重要な問題を解決する必要があります。", "xpack.upgradeAssistant.esDeprecations.pageTitle": "Elasticsearch", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2c7bfb76b00c7..a4704a5f5bd4d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25441,7 +25441,6 @@ "xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "将 Kibana 升级到与您的 Elasticsearch 集群相同的版本。集群中的一个或多个节点正在运行与 Kibana 不同的版本。", "xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "您无权查看 Elasticsearch 弃用。", "xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "您的配置是最新的。Kibana 和索引 Elasticsearch 节点正在运行相同的版本。", - "xpack.upgradeAssistant.esDeprecations.docLinkText": "文档", "xpack.upgradeAssistant.esDeprecations.loadingText": "正在加载弃用……", "xpack.upgradeAssistant.esDeprecations.pageDescription": "查看已弃用的群集和索引设置。在升级之前必须解决任何紧急问题。", "xpack.upgradeAssistant.esDeprecations.pageTitle": "Elasticsearch", From 123e76a6fb8eb83a2ba0764f8c21c8f21237def8 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 18 Aug 2021 11:58:50 -0400 Subject: [PATCH 15/18] fix i18n --- .../translations/translations/ja-JP.json | 20 ------------------- .../translations/translations/zh-CN.json | 20 ------------------- 2 files changed, 40 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3cb9e0f09ffd0..299fab5accfd8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -24779,12 +24779,6 @@ "xpack.upgradeAssistant.esDeprecationStats.criticalDeprecationsTitle": "重大", "xpack.upgradeAssistant.esDeprecationStats.loadingText": "Elasticsearchの廃止統計情報を読み込んでいます...", "xpack.upgradeAssistant.esDeprecationStats.statsTitle": "Elasticsearch", -<<<<<<< HEAD - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTitle": "廃止予定", - "xpack.upgradeAssistant.esDeprecationStats.viewDeprecationsLinkText": "廃止予定を表示", -======= - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip": "このクラスターは{clusterCount}個の廃止予定のクラスター設定と{indexCount}個の廃止予定のインデックス設定を使用しています。", ->>>>>>> 8f7e10aaba344e28be2622b85441be4cff297717 "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorDescription": "エラーについては、Kibanaサーバーログを確認してください。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorTitle": "Kibana廃止予定を取得できませんでした", "xpack.upgradeAssistant.kibanaDeprecationErrors.pluginErrorDescription": "エラーについては、Kibanaサーバーログを確認してください。", @@ -24808,22 +24802,8 @@ "xpack.upgradeAssistant.kibanaDeprecationStats.loadingErrorMessage": "Kibana廃止予定の取得中にエラーが発生しました。", "xpack.upgradeAssistant.kibanaDeprecationStats.loadingText": "Kibana廃止予定統計情報を読み込んでいます…", "xpack.upgradeAssistant.kibanaDeprecationStats.statsTitle": "Kibana", -<<<<<<< HEAD - "xpack.upgradeAssistant.kibanaDeprecationStats.totalDeprecationsLabel": "Kibanaには合計{totalDeprecations}個の廃止予定があります", - "xpack.upgradeAssistant.kibanaDeprecationStats.totalDeprecationsTitle": "廃止予定", - "xpack.upgradeAssistant.kibanaDeprecationStats.viewDeprecationsLinkText": "廃止予定を表示", "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "他のスタック廃止予定については、{overviewButton}を確認してください。", "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "概要ページ", - "xpack.upgradeAssistant.overview.deprecationLogging.loadingLabel": "ロギング状態を取得しています", - "xpack.upgradeAssistant.overview.deprecationLoggingDescription": "{deprecationLoggingLink}を有効にすると、Elastic {nextMajor}にアップグレードした後に使用できない廃止予定の機能を使用しているかどうかがわかります。", - "xpack.upgradeAssistant.overview.deprecationLoggingTitle": "廃止ログ", - "xpack.upgradeAssistant.overview.deprecationLogs.disableButtonLabel": "廃止ログを無効にする", -======= - "xpack.upgradeAssistant.noDeprecationsPrompt.description": "構成は最新です。", - "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "他のスタック廃止予定については、{overviewButton}を確認してください。", - "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "概要ページ", - "xpack.upgradeAssistant.noDeprecationsPrompt.title": "アップグレードする準備ができました。", ->>>>>>> 8f7e10aaba344e28be2622b85441be4cff297717 "xpack.upgradeAssistant.overview.deprecationLogs.disabledToastMessage": "廃止予定のアクションをログに出力しません。", "xpack.upgradeAssistant.overview.deprecationLogs.enabledToastMessage": "廃止予定のアクションをログに出力します。", "xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "ログ情報を取得できませんでした。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0e5c1f538cc6a..0130ab0554343 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25343,12 +25343,6 @@ "xpack.upgradeAssistant.esDeprecationStats.criticalDeprecationsTitle": "紧急", "xpack.upgradeAssistant.esDeprecationStats.loadingText": "正在加载 Elasticsearch 弃用统计……", "xpack.upgradeAssistant.esDeprecationStats.statsTitle": "Elasticsearch", -<<<<<<< HEAD - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTitle": "弃用", - "xpack.upgradeAssistant.esDeprecationStats.viewDeprecationsLinkText": "查看弃用", -======= - "xpack.upgradeAssistant.esDeprecationStats.totalDeprecationsTooltip": "此集群正在使用 {clusterCount} 个已弃用集群设置和 {indexCount} 个已弃用的索引设置", ->>>>>>> 8f7e10aaba344e28be2622b85441be4cff297717 "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorDescription": "请在 Kibana 服务器日志中查看错误。", "xpack.upgradeAssistant.kibanaDeprecationErrors.loadingErrorTitle": "无法检索 Kibana 弃用", "xpack.upgradeAssistant.kibanaDeprecationErrors.pluginErrorDescription": "请在 Kibana 服务器日志中查看错误。", @@ -25372,22 +25366,8 @@ "xpack.upgradeAssistant.kibanaDeprecationStats.loadingErrorMessage": "检索 Kibana 弃用时发生错误。", "xpack.upgradeAssistant.kibanaDeprecationStats.loadingText": "正在加载 Kibana 弃用统计……", "xpack.upgradeAssistant.kibanaDeprecationStats.statsTitle": "Kibana", -<<<<<<< HEAD - "xpack.upgradeAssistant.kibanaDeprecationStats.totalDeprecationsLabel": "Kibana 总共有 {totalDeprecations} 个弃用", - "xpack.upgradeAssistant.kibanaDeprecationStats.totalDeprecationsTitle": "弃用", - "xpack.upgradeAssistant.kibanaDeprecationStats.viewDeprecationsLinkText": "查看弃用", "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "查看{overviewButton}以了解其他 Stack 弃用。", "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "“概览”页面", - "xpack.upgradeAssistant.overview.deprecationLogging.loadingLabel": "正在检索日志记录状态", - "xpack.upgradeAssistant.overview.deprecationLoggingDescription": "启用{deprecationLoggingLink}以查看是否正在使用升级到 Elastic {nextMajor} 后将不再可用的已弃用功能。", - "xpack.upgradeAssistant.overview.deprecationLoggingTitle": "弃用日志", - "xpack.upgradeAssistant.overview.deprecationLogs.disableButtonLabel": "禁用弃用日志记录", -======= - "xpack.upgradeAssistant.noDeprecationsPrompt.description": "您的配置是最新的。", - "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "查看{overviewButton}以了解其他 Stack 弃用。", - "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "“概览”页面", - "xpack.upgradeAssistant.noDeprecationsPrompt.title": "准备好升级!", ->>>>>>> 8f7e10aaba344e28be2622b85441be4cff297717 "xpack.upgradeAssistant.overview.deprecationLogs.disabledToastMessage": "不记录弃用的操作。", "xpack.upgradeAssistant.overview.deprecationLogs.enabledToastMessage": "记录弃用的操作。", "xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "无法检索日志记录信息。", From d253ca0586a0ae3f3de953cf81a796f7354fb50f Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 19 Aug 2021 11:47:51 -0400 Subject: [PATCH 16/18] address review comments --- .../public/doc_links/doc_links_service.ts | 1 - .../client_integration/elasticsearch.test.ts | 6 +- .../public/application/app.tsx | 4 +- .../__fixtures__/checkup_api_response.json | 870 ------------------ .../deprecation_types/default/flyout.tsx | 2 +- .../index_settings/flyout.tsx | 33 +- .../index_settings/resolution_table_cell.tsx | 7 +- .../deprecation_types/ml_snapshots/flyout.tsx | 9 +- .../ml_snapshots/resolution_table_cell.tsx | 6 +- .../reindex/resolution_table_cell.tsx | 7 +- .../deprecation_types/reindex/table_row.tsx | 2 +- .../reindex/use_reindex_state.tsx | 4 +- .../es_deprecations/es_deprecation_errors.tsx | 2 +- .../es_deprecations/es_deprecations.tsx | 4 +- .../es_deprecations/es_deprecations_table.tsx | 53 +- .../components/es_deprecations/index.ts | 2 +- .../review_logs_step/es_stats/es_stats.tsx | 5 +- .../es_stats/es_stats_error.tsx | 2 +- .../components/shared/no_deprecations.tsx | 2 +- .../public/application/lib/api.ts | 2 +- ..._errors.ts => get_es_deprecation_error.ts} | 0 .../server/lib/es_deprecations_status.ts | 9 +- 22 files changed, 83 insertions(+), 949 deletions(-) delete mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json rename x-pack/plugins/upgrade_assistant/public/application/lib/{es_deprecation_errors.ts => get_es_deprecation_error.ts} (100%) diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index b67515c14a161..88075b66ad045 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -200,7 +200,6 @@ export class DocLinksService { deprecationLogging: `${ELASTICSEARCH_DOCS}logging.html#deprecation-logging`, setupUpgrade: `${ELASTICSEARCH_DOCS}setup-upgrade.html`, releaseHighlights: `${ELASTICSEARCH_DOCS}release-highlights.html`, - deprecationInfo: `${ELASTICSEARCH_DOCS}migration-api-deprecation.html`, }, siem: { guide: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts index 4846cfd7fe3cd..39ba1ad7115ae 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts @@ -142,7 +142,7 @@ describe('Elasticsearch deprecations', () => { }); test('upgrades snapshots', async () => { - const { find, actions } = testBed; + const { find, actions, exists } = testBed; httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ nodeId: 'my_node', @@ -181,8 +181,8 @@ describe('Elasticsearch deprecations', () => { await actions.clickMlDeprecationAt(0); // Flyout actions should not be visible if deprecation was resolved - expect(find('mlSnapshotDetails.upgradeSnapshotButton').length).toBe(0); - expect(find('mlSnapshotDetails.deleteSnapshotButton').length).toBe(0); + expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false); + expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false); }); test('handles upgrade 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 7c302818a8a2f..864be6e5d996d 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -15,7 +15,7 @@ import { KibanaContextProvider } from '../shared_imports'; import { AppServicesContext } from '../types'; import { AppContextProvider, ContextValue, useAppContext } from './app_context'; import { ComingSoonPrompt } from './components/coming_soon_prompt'; -import { EsDeprecationsContent } from './components/es_deprecations'; +import { EsDeprecations } from './components/es_deprecations'; import { KibanaDeprecationsContent } from './components/kibana_deprecations'; import { Overview } from './components/overview'; import { RedirectAppLinks } from '../../../../../src/plugins/kibana_react/public'; @@ -39,7 +39,7 @@ const App: React.FunctionComponent = () => { return ( - + diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json deleted file mode 100644 index 531bc229b39ea..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/__fixtures__/checkup_api_response.json +++ /dev/null @@ -1,870 +0,0 @@ -{ - "cluster": [ - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3 4", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - }, - { - "level": "warning", - "message": "Template patterns are no longer using `template` field, but `index_patterns` instead 0 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - "details": "templates using `template` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template" - }, - { - "level": "warning", - "message": "one or more templates use deprecated mapping settings 0 1 2 3 4 5", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}" - } - ], - "nodes": [], - "indices": [ - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]", - "index": ".monitoring-es-6-2018.11.07" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: tweet, field: liked]]", - "index": "twitter" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: index-pattern, field: notExpandable], [type: config, field: xPackMonitoring:allowReport], [type: config, field: xPackMonitoring:showBanner], [type: dashboard, field: pause], [type: dashboard, field: timeRestore]]", - "index": ".kibana" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: notify], [type: doc, field: created], [type: doc, field: attach_payload], [type: doc, field: met]]", - "index": ".watcher-history-6-2018.11.07" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: doc, field: snapshot]]", - "index": ".monitoring-kibana-6-2018.11.07" - }, - { - "level": "warning", - "message": "Coercion of boolean fields", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - "details": "[[type: tweet, field: liked]]", - "index": "twitter2" - }, - { - "index": "twitter", - "level": "critical", - "message": "This index must be reindexed in order to upgrade the Elastic Stack.", - "details": "Reindexing is irreversible, so always back up your index before proceeding.", - "actions": [ - { - "label": "Reindex in Console", - "url": "/app/dev_tools#/console?load_from=%2Fapi%2Fupgrade_assistant%2Freindex%2Fconsole_template%2Ftwitter.json" - } - ], - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade.html" - }, - { - "index": ".triggered_watches", - "level": "critical", - "message": "This index must be upgraded in order to upgrade the Elastic Stack.", - "details": "Upgrading is irreversible, so always back up your index before proceeding.", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-upgrade.html" - }, - { - "index": ".reindex-status", - "level": "critical", - "message": "This index must be reindexed in order to upgrade the Elastic Stack.", - "details": "Reindexing is irreversible, so always back up your index before proceeding.", - "actions": [ - { - "label": "Reindex in Console", - "url": "/app/dev_tools#/console?load_from=%2Fapi%2Fupgrade_assistant%2Freindex%2Fconsole_template%2F.reindex-status.json" - } - ], - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade.html" - }, - { - "index": "twitter2", - "level": "critical", - "message": "This index must be reindexed in order to upgrade the Elastic Stack.", - "details": "Reindexing is irreversible, so always back up your index before proceeding.", - "actions": [ - { - "label": "Reindex in Console", - "url": "/app/dev_tools#/console?load_from=%2Fapi%2Fupgrade_assistant%2Freindex%2Fconsole_template%2Ftwitter2.json" - } - ], - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade.html" - }, - { - "index": ".watches", - "level": "critical", - "message": "This index must be upgraded in order to upgrade the Elastic Stack.", - "details": "Upgrading is irreversible, so always back up your index before proceeding.", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-upgrade.html" - } - ] -} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx index 94f156ef6b1d7..439062e027650 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/default/flyout.tsx @@ -45,7 +45,7 @@ const i18nTexts = { } ), closeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.cancelButtonLabel', + 'xpack.upgradeAssistant.esDeprecations.deprecationDetailsFlyout.closeButtonLabel', { defaultMessage: 'Close', } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx index e9a0b3c1021cb..1567562db53ee 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/index_settings/flyout.tsx @@ -73,17 +73,19 @@ const i18nTexts = { } ), closeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.cancelButtonLabel', + 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.closeButtonLabel', { defaultMessage: 'Close', } ), - confirmationText: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.description', - { - defaultMessage: 'Remove the following deprecated index settings?', - } - ), + getConfirmationText: (indexSettingsCount: number) => + i18n.translate('xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.description', { + defaultMessage: + 'Remove the following deprecated index {indexSettingsCount, plural, one {setting} other {settings}}?', + values: { + indexSettingsCount, + }, + }), errorTitle: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.deleteErrorTitle', { @@ -101,6 +103,9 @@ export const RemoveIndexSettingsFlyout = ({ const { index, message, details, url, correctiveAction } = deprecation; const { statusType, details: statusDetails } = status; + // Flag used to hide certain parts of the UI if the deprecation has been resolved or is in progress + const isResolvable = ['idle', 'error'].includes(statusType); + return ( <> @@ -127,6 +132,7 @@ export const RemoveIndexSettingsFlyout = ({ )} +

{details}

@@ -136,13 +142,16 @@ export const RemoveIndexSettingsFlyout = ({

- {/* Hide the prompt to remove settings if the deprecation has been resolved */} - {statusType !== 'complete' && ( + {isResolvable && (
-

{i18nTexts.confirmationText}

+

+ {i18nTexts.getConfirmationText( + (correctiveAction as IndexSettingAction).deprecatedSettings.length + )} +

@@ -168,8 +177,8 @@ export const RemoveIndexSettingsFlyout = ({ {i18nTexts.closeButtonLabel} - {/* Hide the "Remove settings" button if the deprecation has been resolved */} - {statusType !== 'complete' && ( + + {isResolvable && ( = ({ st data-test-subj="indexSettingsResolutionStatusCell" > - {i18nTexts.resolutionText} + - + {i18nTexts.resolutionText} 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 2755ce0dd073c..ba72faf2f8c3f 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 @@ -45,7 +45,7 @@ const i18nTexts = { } ), closeButtonLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.cancelButtonLabel', + 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.closeButtonLabel', { defaultMessage: 'Close', } @@ -92,6 +92,9 @@ 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(); @@ -143,8 +146,8 @@ export const FixSnapshotsFlyout = ({ {i18nTexts.closeButtonLabel} - {/* Hide the upgrade/delete actions if the deprecation has been resolved */} - {snapshotState.status !== 'complete' && ( + + {isResolvable && ( diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx index 2e02a2ecb6fb3..7963701b5c543 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/ml_snapshots/resolution_table_cell.tsx @@ -66,7 +66,7 @@ const i18nTexts = { 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.resolutionTooltipLabel', { defaultMessage: - 'This deprecation requires upgrading or deleting a job model snapshot to resolve.', + 'Resolve this deprecation by upgrading or deleting a job model snapshot. This is an automated resolution.', } ), }; @@ -129,10 +129,10 @@ export const MlSnapshotsResolutionCell: React.FunctionComponent = () => { - {i18nTexts.resolutionText} + - + {i18nTexts.resolutionText} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx index a31326d62d174..6ea9a0277059a 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/resolution_table_cell.tsx @@ -63,7 +63,8 @@ const i18nTexts = { resolutionTooltipLabel: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.reindex.resolutionTooltipLabel', { - defaultMessage: 'This deprecation requires reindexing an index to resolve.', + defaultMessage: + 'Resolve this deprecation by reindexing this index. This is an automated resolution.', } ), }; @@ -146,10 +147,10 @@ export const ReindexResolutionCell: React.FunctionComponent = () => { - {i18nTexts.resolutionText} + - + {i18nTexts.resolutionText} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx index b08c5062b0abd..95d65f1e77771 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/table_row.tsx @@ -23,7 +23,7 @@ interface TableRowProps { rowFieldNames: DeprecationTableColumns[]; } -export const ReindexTableRowCells: React.FunctionComponent = ({ +const ReindexTableRowCells: React.FunctionComponent = ({ rowFieldNames, deprecation, }) => { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx index 6309c2aa7f067..b87a509d25a55 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/reindex/use_reindex_state.tsx @@ -131,7 +131,7 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A cancelLoadingState: undefined, }); - await api.sendReindexTelemetryData({ start: true }); + api.sendReindexTelemetryData({ start: true }); const { data, error } = await api.startReindexTask(indexName); @@ -149,7 +149,7 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A }, [api, indexName, reindexState, updateStatus]); const cancelReindex = useCallback(async () => { - await api.sendReindexTelemetryData({ stop: true }); + api.sendReindexTelemetryData({ stop: true }); const { error } = await api.cancelReindexTask(indexName); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx index 239433808c5af..5e3c7a5fe6cef 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecation_errors.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiCallOut } from '@elastic/eui'; import { ResponseError } from '../../lib/api'; -import { getEsDeprecationError } from '../../lib/es_deprecation_errors'; +import { getEsDeprecationError } from '../../lib/get_es_deprecation_error'; interface Props { error: ResponseError; } 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 cbaaececbc7cf..38367bd3cfaff 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 @@ -30,7 +30,7 @@ const i18nTexts = { }), }; -export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProps) => { +export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => { const { api, breadcrumbs } = useAppContext(); const { @@ -39,7 +39,7 @@ export const EsDeprecationsContent = withRouter(({ history }: RouteComponentProp error, resendRequest, isInitialRequest, - } = api.useLoadUpgradeStatus(); + } = api.useLoadEsDeprecations(); useEffect(() => { breadcrumbs.setBreadcrumbs('esDeprecations'); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx index 31bf4223d3228..5f742a3c63ae6 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/es_deprecations_table.tsx @@ -36,12 +36,6 @@ import { DeprecationTableColumns } from '../types'; import { DEPRECATION_TYPE_MAP } from '../constants'; const i18nTexts = { - criticalBadgeLabel: i18n.translate( - 'xpack.upgradeAssistant.esDeprecations.table.criticalBadgeLabel', - { - defaultMessage: 'critical', - } - ), refreshButtonLabel: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.table.refreshButtonLabel', { @@ -108,21 +102,19 @@ const cellTypes = Object.keys(cellToLabelMap) as DeprecationTableColumns[]; const pageSizeOptions = [50, 100, 200]; const renderTableRowCells = (deprecation: EnrichedDeprecationInfo) => { - const { correctiveAction } = deprecation; + switch (deprecation.correctiveAction?.type) { + case 'mlSnapshot': + return ; - if (correctiveAction?.type === 'mlSnapshot') { - return ; - } + case 'indexSetting': + return ; - if (correctiveAction?.type === 'indexSetting') { - return ; - } + case 'reindex': + return ; - if (correctiveAction?.type === 'reindex') { - return ; + default: + return ; } - - return ; }; interface Props { @@ -140,6 +132,7 @@ const getSortedItems = (deprecations: EnrichedDeprecationInfo[], sortConfig: Sor const sorted = sortBy(deprecations, [ (deprecation) => { if (sortField === 'isCritical') { + // Critical deprecations should take precendence in ascending order return deprecation.isCritical !== true; } return deprecation[sortField]; @@ -173,6 +166,11 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ itemsPerPage, ]); + const visibleDeprecations = useMemo( + () => filteredDeprecations.slice(pager.firstItemIndex, pager.lastItemIndex + 1), + [filteredDeprecations, pager] + ); + const handleSort = useCallback( (fieldName: DeprecationTableColumns) => { const newSortConfig = { @@ -264,7 +262,7 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ - + {Object.entries(cellToLabelMap).map(([fieldName, cell]) => { return ( @@ -291,18 +289,13 @@ export const EsDeprecationsTable: React.FunctionComponent = ({ ) : ( - {filteredDeprecations - .slice(pager.firstItemIndex, pager.lastItemIndex + 1) - .map((deprecation, index) => { - return ( - - {renderTableRowCells(deprecation)} - - ); - })} + {visibleDeprecations.map((deprecation, index) => { + return ( + + {renderTableRowCells(deprecation)} + + ); + })} )} diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts index 0e69259adc609..1783745843070 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecations/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { EsDeprecationsContent } from './es_deprecations'; +export { EsDeprecations } from './es_deprecations'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx index 81f32baf66222..ef0b3f438da03 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats.tsx @@ -52,7 +52,8 @@ const i18nTexts = { }), getWarningDeprecationMessage: (warningDeprecations: number) => i18n.translate('xpack.upgradeAssistant.esDeprecationStats.warningDeprecationsTooltip', { - defaultMessage: 'This cluster has {warningDeprecations} non-critical deprecations', + defaultMessage: + 'This cluster has {warningDeprecations} non-critical {warningDeprecations, plural, one {deprecation} other {deprecations}}', values: { warningDeprecations, }, @@ -63,7 +64,7 @@ export const ESDeprecationStats: FunctionComponent = () => { const history = useHistory(); const { api } = useAppContext(); - const { data: esDeprecations, isLoading, error } = api.useLoadUpgradeStatus(); + const { data: esDeprecations, isLoading, error } = api.useLoadEsDeprecations(); const warningDeprecations = esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical === false) || []; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx index 5db5b80cc42eb..c717a8a2e12e8 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/review_logs_step/es_stats/es_stats_error.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiIconTip } from '@elastic/eui'; import { ResponseError } from '../../../../lib/api'; -import { getEsDeprecationError } from '../../../../lib/es_deprecation_errors'; +import { getEsDeprecationError } from '../../../../lib/get_es_deprecation_error'; interface Props { error: ResponseError; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx index 17bd1dc430883..7763450c6cfcf 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/shared/no_deprecations.tsx @@ -47,7 +47,7 @@ export const NoDeprecationsPrompt: FunctionComponent = ({ }) => { return ( {i18nTexts.getEmptyPromptTitle(deprecationType)}

} body={ diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts index 91d008a3facae..78070c5717496 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts @@ -45,7 +45,7 @@ export class ApiService { this.client = httpClient; } - public useLoadUpgradeStatus() { + public useLoadEsDeprecations() { return this.useRequest({ path: `${API_BASE_PATH}/es_deprecations`, method: 'get', diff --git a/x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts b/x-pack/plugins/upgrade_assistant/public/application/lib/get_es_deprecation_error.ts similarity index 100% rename from x-pack/plugins/upgrade_assistant/public/application/lib/es_deprecation_errors.ts rename to x-pack/plugins/upgrade_assistant/public/application/lib/get_es_deprecation_error.ts diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts index f894a5bada630..cd719cc0f32b5 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts @@ -25,7 +25,7 @@ export async function getESUpgradeStatus( return Object.keys(deprecations).reduce((combinedDeprecations, deprecationType) => { if (deprecationType === 'index_settings') { - combinedDeprecations = [...combinedDeprecations, ...indices]; + combinedDeprecations = combinedDeprecations.concat(indices); } else { const deprecationsByType = deprecations[ deprecationType as keyof MigrationDeprecationInfoResponse @@ -54,7 +54,7 @@ export async function getESUpgradeStatus( } ); - combinedDeprecations = [...combinedDeprecations, ...enrichedDeprecationInfo]; + combinedDeprecations = combinedDeprecations.concat(enrichedDeprecationInfo); } return combinedDeprecations; @@ -63,13 +63,10 @@ export async function getESUpgradeStatus( const combinedDeprecations = await getCombinedDeprecations(); const criticalWarnings = combinedDeprecations.filter(({ isCritical }) => isCritical === true); - const sortByCritical = (a: EnrichedDeprecationInfo, b: EnrichedDeprecationInfo) => { - return a.isCritical === b.isCritical ? 0 : a.isCritical ? -1 : 1; - }; return { totalCriticalDeprecations: criticalWarnings.length, - deprecations: combinedDeprecations.sort(sortByCritical), + deprecations: combinedDeprecations, }; } From 037ebb7c5ce5226b3a2bf1a7c364ea578b4b4d89 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 19 Aug 2021 13:52:20 -0400 Subject: [PATCH 17/18] refactor CITs --- .../client_integration/elasticsearch.test.ts | 777 ------------------ .../default_deprecation_flyout.test.ts | 52 ++ .../es_deprecations/deprecations_list.test.ts | 267 ++++++ .../es_deprecations/error_handling.test.ts | 115 +++ .../index_settings_deprecation_flyout.test.ts | 117 +++ .../ml_snapshots_deprecation_flyout.test.ts | 196 +++++ .../es_deprecations/mocked_responses.ts | 119 +++ .../reindex_deprecation_flyout.test.ts | 50 ++ .../helpers/elasticsearch.helpers.ts | 16 +- .../client_integration/kibana.test.ts | 2 +- 10 files changed, 920 insertions(+), 791 deletions(-) delete mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts deleted file mode 100644 index 39ba1ad7115ae..0000000000000 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/elasticsearch.test.ts +++ /dev/null @@ -1,777 +0,0 @@ -/* - * 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'; -import type { MlAction, ESUpgradeStatus, EnrichedDeprecationInfo } from '../../common/types'; -import { API_BASE_PATH, indexSettingDeprecations } from '../../common/constants'; - -import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from './helpers'; - -describe('Elasticsearch deprecations', () => { - let testBed: ElasticsearchTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); - - describe('with deprecations', () => { - const snapshotId = '1'; - const jobId = 'deprecation_check_job'; - const upgradeStatusMockResponse: ESUpgradeStatus = { - totalCriticalDeprecations: 2, - deprecations: [ - { - isCritical: true, - resolveDuringUpgrade: false, - type: 'ml_settings', - message: - 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', - details: - 'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]', - url: 'doc_url', - correctiveAction: { - type: 'mlSnapshot', - snapshotId, - jobId, - }, - }, - { - isCritical: false, - resolveDuringUpgrade: false, - type: 'index_settings', - message: indexSettingDeprecations.translog.deprecationMessage, - details: 'deprecation details', - url: 'doc_url', - index: 'my_index', - correctiveAction: { - type: 'indexSetting', - deprecatedSettings: indexSettingDeprecations.translog.settings, - }, - }, - { - isCritical: false, - resolveDuringUpgrade: false, - type: 'index_settings', - message: 'multi-fields within multi-fields', - details: 'deprecation details', - url: 'doc_url', - index: 'nested_multi-fields', - }, - { - isCritical: true, - resolveDuringUpgrade: false, - type: 'index_settings', - message: 'Index created before 7.0', - details: 'deprecation details', - url: 'doc_url', - index: 'reindex_index', - correctiveAction: { - type: 'reindex', - }, - }, - ], - }; - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusMockResponse); - httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'idle', - }); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - testBed.component.update(); - }); - - test('renders deprecations', () => { - const { exists, find } = testBed; - // Verify container exists - expect(exists('esDeprecationsContent')).toBe(true); - - // Verify all deprecations appear in the table - expect(find('deprecationTableRow').length).toEqual( - upgradeStatusMockResponse.deprecations.length - ); - }); - - test('refreshes deprecation data', async () => { - const { actions } = testBed; - const totalRequests = server.requests.length; - - await actions.clickRefreshButton(); - - const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; - const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; - - // Since upgradeStatusMockResponse includes ML and reindex actions (which require fetching status), there will be 3 requests made - expect(server.requests.length).toBe(totalRequests + 3); - expect(server.requests[server.requests.length - 3].url).toBe( - `${API_BASE_PATH}/es_deprecations` - ); - expect(server.requests[server.requests.length - 2].url).toBe( - `${API_BASE_PATH}/ml_snapshots/${(mlDeprecation.correctiveAction as MlAction).jobId}/${ - (mlDeprecation.correctiveAction as MlAction).snapshotId - }` - ); - expect(server.requests[server.requests.length - 1].url).toBe( - `${API_BASE_PATH}/reindex/${reindexDeprecation.index}` - ); - }); - - describe('deprecation details', () => { - describe('ML snapshots deprecation', () => { - beforeEach(async () => { - const { find, exists, actions } = testBed; - - await actions.clickMlDeprecationAt(0); - - expect(exists('mlSnapshotDetails')).toBe(true); - expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( - 'Upgrade or delete model snapshot' - ); - }); - - test('upgrades snapshots', async () => { - const { find, actions, exists } = testBed; - - httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'in_progress', - }); - - httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'complete', - }); - - expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); - - await actions.clickUpgradeMlSnapshot(); - - // First, we expect a POST request to upgrade the snapshot - const upgradeRequest = server.requests[server.requests.length - 2]; - expect(upgradeRequest.method).toBe('POST'); - expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - - // Next, we expect a GET request to check the status of the upgrade - const statusRequest = server.requests[server.requests.length - 1]; - expect(statusRequest.method).toBe('GET'); - expect(statusRequest.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${jobId}/${snapshotId}` - ); - - // Verify the "Resolution" column of the table is updated - expect(find('mlActionResolutionCell').text()).toContain('Upgrade complete'); - - // Reopen the flyout - await actions.clickMlDeprecationAt(0); - - // Flyout actions should not be visible if deprecation was resolved - expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false); - expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false); - }); - - test('handles upgrade failure', async () => { - const { find, actions } = testBed; - - const error = { - statusCode: 500, - error: 'Upgrade snapshot error', - message: 'Upgrade snapshot error', - }; - - httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); - httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'error', - error, - }); - - await actions.clickUpgradeMlSnapshot(); - - const upgradeRequest = server.requests[server.requests.length - 1]; - expect(upgradeRequest.method).toBe('POST'); - expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); - - // Verify the "Resolution" column of the table is updated - expect(find('mlActionResolutionCell').text()).toContain('Upgrade failed'); - - // Reopen the flyout - await actions.clickMlDeprecationAt(0); - - // Verify the flyout shows an error message - expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( - 'Error upgrading snapshot' - ); - // Verify the upgrade button text changes - expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Retry upgrade'); - }); - - test('deletes snapshots', async () => { - const { find, actions } = testBed; - - httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ - acknowledged: true, - }); - - expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); - - await actions.clickDeleteMlSnapshot(); - - const request = server.requests[server.requests.length - 1]; - const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; - - expect(request.method).toBe('DELETE'); - expect(request.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${ - (mlDeprecation.correctiveAction! as MlAction).jobId - }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` - ); - - // Verify the "Resolution" column of the table is updated - expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion complete'); - - // Reopen the flyout - await actions.clickMlDeprecationAt(0); - }); - - test('handles delete failure', async () => { - const { find, actions } = testBed; - - const error = { - statusCode: 500, - error: 'Upgrade snapshot error', - message: 'Upgrade snapshot error', - }; - - httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); - - await actions.clickDeleteMlSnapshot(); - - const request = server.requests[server.requests.length - 1]; - const mlDeprecation = upgradeStatusMockResponse.deprecations[0]; - - expect(request.method).toBe('DELETE'); - expect(request.url).toBe( - `/api/upgrade_assistant/ml_snapshots/${ - (mlDeprecation.correctiveAction! as MlAction).jobId - }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` - ); - - // Verify the "Resolution" column of the table is updated - expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion failed'); - - // Reopen the flyout - await actions.clickMlDeprecationAt(0); - - // Verify the flyout shows an error message - expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( - 'Error deleting snapshot' - ); - // Verify the upgrade button text changes - expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Retry delete'); - }); - }); - - describe('index settings deprecation', () => { - const indexSettingDeprecation = upgradeStatusMockResponse.deprecations[1]; - - beforeEach(async () => { - const { find, exists, actions } = testBed; - - await actions.clickIndexSettingsDeprecationAt(0); - - expect(exists('indexSettingsDetails')).toBe(true); - expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( - indexSettingDeprecation.message - ); - expect(exists('removeSettingsPrompt')).toBe(true); - }); - - it('removes deprecated index settings', async () => { - const { find, actions } = testBed; - - httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ - acknowledged: true, - }); - - await actions.clickDeleteSettingsButton(); - - const request = server.requests[server.requests.length - 1]; - - expect(request.method).toBe('POST'); - expect(request.url).toBe( - `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` - ); - expect(request.status).toEqual(200); - - // Verify the "Resolution" column of the table is updated - expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( - 'Deprecated settings removed' - ); - - // Reopen the flyout - await actions.clickIndexSettingsDeprecationAt(0); - - // Verify prompt to remove setting no longer displays - expect(find('removeSettingsPrompt').length).toEqual(0); - // Verify the action button no longer displays - expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); - }); - - it('handles failure', async () => { - const { find, actions } = testBed; - const error = { - statusCode: 500, - error: 'Remove index settings error', - message: 'Remove index settings error', - }; - - httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); - - await actions.clickDeleteSettingsButton(); - - const request = server.requests[server.requests.length - 1]; - - expect(request.method).toBe('POST'); - expect(request.url).toBe( - `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` - ); - expect(request.status).toEqual(500); - - // Verify the "Resolution" column of the table is updated - expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( - 'Settings removal failed' - ); - - // Reopen the flyout - await actions.clickIndexSettingsDeprecationAt(0); - - // Verify the flyout shows an error message - expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( - 'Error deleting index settings' - ); - // Verify the remove settings button text changes - expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual( - 'Retry removing deprecated settings' - ); - }); - }); - - describe('default deprecation', () => { - it('renders a flyout with deprecation details', async () => { - const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[2]; - const { actions, find, exists } = testBed; - - await actions.clickDefaultDeprecationAt(0); - - expect(exists('defaultDeprecationDetails')).toBe(true); - expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( - multiFieldsDeprecation.message - ); - expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( - multiFieldsDeprecation.index - ); - }); - }); - - describe('reindex deprecation', () => { - it('renders a flyout with reindexing details', async () => { - const reindexDeprecation = upgradeStatusMockResponse.deprecations[3]; - const { actions, find, exists } = testBed; - - await actions.clickReindexDeprecationAt(0); - - expect(exists('reindexDetails')).toBe(true); - expect(find('reindexDetails.flyoutTitle').text()).toContain( - `Reindex ${reindexDeprecation.index}` - ); - }); - }); - }); - - describe('search bar', () => { - it('filters results by "critical" status', async () => { - const { find, actions } = testBed; - - await actions.clickCriticalFilterButton(); - - const criticalDeprecations = upgradeStatusMockResponse.deprecations.filter( - (deprecation) => deprecation.isCritical - ); - - expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); - - await actions.clickCriticalFilterButton(); - - expect(find('deprecationTableRow').length).toEqual( - upgradeStatusMockResponse.deprecations.length - ); - }); - - it('filters results by type', async () => { - const { component, find, actions } = testBed; - - await actions.clickTypeFilterDropdownAt(0); - - // We need to read the document "body" as the filter dropdown options are added there and not inside - // the component DOM tree. - const clusterTypeFilterButton: HTMLButtonElement | null = document.body.querySelector( - '.euiFilterSelect__items .euiFilterSelectItem' - ); - - expect(clusterTypeFilterButton).not.toBe(null); - - await act(async () => { - clusterTypeFilterButton!.click(); - }); - - component.update(); - - const clusterDeprecations = upgradeStatusMockResponse.deprecations.filter( - (deprecation) => deprecation.type === 'cluster_settings' - ); - - expect(find('deprecationTableRow').length).toEqual(clusterDeprecations.length); - }); - - it('filters results by query string', async () => { - const { find, actions } = testBed; - const multiFieldsDeprecation = upgradeStatusMockResponse.deprecations[3]; - - await actions.setSearchInputValue(multiFieldsDeprecation.message); - - expect(find('deprecationTableRow').length).toEqual(1); - expect(find('deprecationTableRow').at(0).text()).toContain(multiFieldsDeprecation.message); - }); - - it('shows error for invalid search queries', async () => { - const { find, exists, actions } = testBed; - - await actions.setSearchInputValue('%'); - - expect(exists('invalidSearchQueryMessage')).toBe(true); - expect(find('invalidSearchQueryMessage').text()).toContain('Invalid search'); - }); - - it('shows message when search query does not return results', async () => { - const { find, actions, exists } = testBed; - - await actions.setSearchInputValue('foobarbaz'); - - expect(exists('noDeprecationsRow')).toBe(true); - expect(find('noDeprecationsRow').text()).toContain( - 'No Elasticsearch deprecation issues found' - ); - }); - }); - - describe('pagination', () => { - const mlDeprecations: EnrichedDeprecationInfo[] = Array.from( - { - length: 20, - }, - () => ({ - isCritical: true, - resolveDuringUpgrade: false, - type: 'ml_settings', - message: - 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', - details: - 'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]', - url: 'doc_url', - correctiveAction: { - type: 'mlSnapshot', - snapshotId, - jobId, - }, - }) - ); - - const indexSettingsDeprecations: EnrichedDeprecationInfo[] = Array.from( - { - length: 20, - }, - () => ({ - isCritical: false, - resolveDuringUpgrade: false, - type: 'index_settings', - message: indexSettingDeprecations.translog.deprecationMessage, - details: 'deprecation details', - url: 'doc_url', - index: 'my_index', - correctiveAction: { - type: 'indexSetting', - deprecatedSettings: indexSettingDeprecations.translog.settings, - }, - }) - ); - - const reindexDeprecations: EnrichedDeprecationInfo[] = Array.from( - { - length: 20, - }, - () => ({ - isCritical: true, - resolveDuringUpgrade: false, - type: 'index_settings', - message: 'Index created before 7.0', - details: 'deprecation details', - url: 'doc_url', - index: 'reindex_index', - correctiveAction: { - type: 'reindex', - }, - }) - ); - - const defaultDeprecations: EnrichedDeprecationInfo[] = Array.from( - { - length: 20, - }, - () => ({ - isCritical: false, - resolveDuringUpgrade: false, - type: 'index_settings', - message: 'multi-fields within multi-fields', - details: 'deprecation details', - url: 'doc_url', - index: 'nested_multi-fields', - }) - ); - - const deprecations: EnrichedDeprecationInfo[] = [ - ...defaultDeprecations, - ...reindexDeprecations, - ...indexSettingsDeprecations, - ...mlDeprecations, - ]; - - const upgradeStatusWithManyDeprecations: ESUpgradeStatus = { - totalCriticalDeprecations: 40, - deprecations, - }; - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusWithManyDeprecations); - httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ - nodeId: 'my_node', - snapshotId, - jobId, - status: 'idle', - }); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - testBed.component.update(); - }); - - it('shows the correct number of pages and deprecations per page', async () => { - const { find, actions } = testBed; - - expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( - Math.round(deprecations.length / 50) // Default rows per page is 50 - ); - expect(find('deprecationTableRow').length).toEqual(50); - - // Navigate to the next page - await actions.clickPaginationAt(1); - - // On the second (last) page, we expect to see the remaining deprecations - expect(find('deprecationTableRow').length).toEqual(deprecations.length - 50); - }); - - it('allows the number of viewable rows to change', async () => { - const { find, actions, component } = testBed; - - await actions.clickRowsPerPageDropdown(); - - // We need to read the document "body" as the rows-per-page dropdown options are added there and not inside - // the component DOM tree. - const rowsPerPageButton: HTMLButtonElement | null = document.body.querySelector( - '[data-test-subj="tablePagination-100-rows"]' - ); - - expect(rowsPerPageButton).not.toBe(null); - - await act(async () => { - rowsPerPageButton!.click(); - }); - - component.update(); - - expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( - Math.round(deprecations.length / 100) // Rows per page is now 100 - ); - expect(find('deprecationTableRow').length).toEqual(deprecations.length); - }); - - it('updates pagination when filters change', async () => { - const { actions, find } = testBed; - - const criticalDeprecations = deprecations.filter((deprecation) => deprecation.isCritical); - - await actions.clickCriticalFilterButton(); - - // Only 40 critical deprecations, so only one page should show - expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); - expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); - }); - - it('updates pagination on search', async () => { - const { actions, find } = testBed; - - await actions.setSearchInputValue('Index created before 7.0'); - - // Only 20 deprecations that match, so only one page should show - expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); - expect(find('deprecationTableRow').length).toEqual(reindexDeprecations.length); - }); - }); - }); - - describe('no deprecations', () => { - beforeEach(async () => { - const noDeprecationsResponse = { - totalCriticalDeprecations: 0, - deprecations: [], - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - testBed.component.update(); - }); - - test('renders prompt', () => { - const { exists, find } = testBed; - expect(exists('noDeprecationsPrompt')).toBe(true); - expect(find('noDeprecationsPrompt').text()).toContain( - 'Your Elasticsearch configuration is up to date' - ); - }); - }); - - describe('error handling', () => { - test('handles 403', async () => { - const error = { - statusCode: 403, - error: 'Forbidden', - message: 'Forbidden', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('permissionsError')).toBe(true); - expect(find('permissionsError').text()).toContain( - 'You are not authorized to view Elasticsearch deprecations.' - ); - }); - - test('shows upgraded message when all nodes have been upgraded', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - // This is marked true in the scenario where none of the nodes have the same major version of Kibana, - // and therefore we assume all have been upgraded - allNodesUpgraded: true, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('upgradedCallout')).toBe(true); - expect(find('upgradedCallout').text()).toContain( - 'All Elasticsearch nodes have been upgraded.' - ); - }); - - test('shows partially upgrade error when nodes are running different versions', async () => { - const error = { - statusCode: 426, - error: 'Upgrade required', - message: 'There are some nodes running a different version of Elasticsearch', - attributes: { - allNodesUpgraded: false, - }, - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('partiallyUpgradedWarning')).toBe(true); - expect(find('partiallyUpgradedWarning').text()).toContain( - 'Upgrade Kibana to the same version as your Elasticsearch cluster. One or more nodes in the cluster is running a different version than Kibana.' - ); - }); - - test('handles generic error', async () => { - const error = { - statusCode: 500, - error: 'Internal server error', - message: 'Internal server error', - }; - - httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); - - await act(async () => { - testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); - }); - - const { component, exists, find } = testBed; - - component.update(); - - expect(exists('requestError')).toBe(true); - expect(find('requestError').text()).toContain( - 'Could not retrieve Elasticsearch deprecations.' - ); - }); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..917fac8ef666a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/default_deprecation_flyout.test.ts @@ -0,0 +1,52 @@ +/* + * 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'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +describe('Default deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('renders a flyout with deprecation details', async () => { + const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2]; + const { actions, find, exists } = testBed; + + await actions.clickDefaultDeprecationAt(0); + + expect(exists('defaultDeprecationDetails')).toBe(true); + expect(find('defaultDeprecationDetails.flyoutTitle').text()).toContain( + multiFieldsDeprecation.message + ); + expect(find('defaultDeprecationDetails.flyoutDescription').text()).toContain( + multiFieldsDeprecation.index + ); + }); +}); 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 new file mode 100644 index 0000000000000..ceebc528f0bc4 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/deprecations_list.test.ts @@ -0,0 +1,267 @@ +/* + * 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'; + +import { API_BASE_PATH } from '../../../common/constants'; +import type { MlAction } from '../../../common/types'; +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { + esDeprecationsMockResponse, + MOCK_SNAPSHOT_ID, + MOCK_JOB_ID, + createEsDeprecationsMockResponse, +} from './mocked_responses'; + +describe('Deprecations table', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('renders deprecations', () => { + const { exists, find } = testBed; + // Verify container exists + expect(exists('esDeprecationsContent')).toBe(true); + + // Verify all deprecations appear in the table + expect(find('deprecationTableRow').length).toEqual( + esDeprecationsMockResponse.deprecations.length + ); + }); + + it('refreshes deprecation data', async () => { + const { actions } = testBed; + const totalRequests = server.requests.length; + + await actions.clickRefreshButton(); + + const mlDeprecation = esDeprecationsMockResponse.deprecations[0]; + const reindexDeprecation = esDeprecationsMockResponse.deprecations[3]; + + // Since upgradeStatusMockResponse includes ML and reindex actions (which require fetching status), there will be 3 requests made + expect(server.requests.length).toBe(totalRequests + 3); + expect(server.requests[server.requests.length - 3].url).toBe( + `${API_BASE_PATH}/es_deprecations` + ); + expect(server.requests[server.requests.length - 2].url).toBe( + `${API_BASE_PATH}/ml_snapshots/${(mlDeprecation.correctiveAction as MlAction).jobId}/${ + (mlDeprecation.correctiveAction as MlAction).snapshotId + }` + ); + expect(server.requests[server.requests.length - 1].url).toBe( + `${API_BASE_PATH}/reindex/${reindexDeprecation.index}` + ); + }); + + describe('search bar', () => { + it('filters results by "critical" status', async () => { + const { find, actions } = testBed; + + await actions.clickCriticalFilterButton(); + + const criticalDeprecations = esDeprecationsMockResponse.deprecations.filter( + (deprecation) => deprecation.isCritical + ); + + expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); + + await actions.clickCriticalFilterButton(); + + expect(find('deprecationTableRow').length).toEqual( + esDeprecationsMockResponse.deprecations.length + ); + }); + + it('filters results by type', async () => { + const { component, find, actions } = testBed; + + await actions.clickTypeFilterDropdownAt(0); + + // We need to read the document "body" as the filter dropdown options are added there and not inside + // the component DOM tree. + const clusterTypeFilterButton: HTMLButtonElement | null = document.body.querySelector( + '.euiFilterSelect__items .euiFilterSelectItem' + ); + + expect(clusterTypeFilterButton).not.toBeNull(); + + await act(async () => { + clusterTypeFilterButton!.click(); + }); + + component.update(); + + const clusterDeprecations = esDeprecationsMockResponse.deprecations.filter( + (deprecation) => deprecation.type === 'cluster_settings' + ); + + expect(find('deprecationTableRow').length).toEqual(clusterDeprecations.length); + }); + + it('filters results by query string', async () => { + const { find, actions } = testBed; + const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2]; + + await actions.setSearchInputValue(multiFieldsDeprecation.message); + + expect(find('deprecationTableRow').length).toEqual(1); + expect(find('deprecationTableRow').at(0).text()).toContain(multiFieldsDeprecation.message); + }); + + it('shows error for invalid search queries', async () => { + const { find, exists, actions } = testBed; + + await actions.setSearchInputValue('%'); + + expect(exists('invalidSearchQueryMessage')).toBe(true); + expect(find('invalidSearchQueryMessage').text()).toContain('Invalid search'); + }); + + it('shows message when search query does not return results', async () => { + const { find, actions, exists } = testBed; + + await actions.setSearchInputValue('foobarbaz'); + + expect(exists('noDeprecationsRow')).toBe(true); + expect(find('noDeprecationsRow').text()).toContain( + 'No Elasticsearch deprecation issues found' + ); + }); + }); + + describe('pagination', () => { + const esDeprecationsMockResponseWithManyDeprecations = createEsDeprecationsMockResponse(20); + const { deprecations } = esDeprecationsMockResponseWithManyDeprecations; + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse( + esDeprecationsMockResponseWithManyDeprecations + ); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('shows the correct number of pages and deprecations per page', async () => { + const { find, actions } = testBed; + + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( + Math.round(deprecations.length / 50) // Default rows per page is 50 + ); + expect(find('deprecationTableRow').length).toEqual(50); + + // Navigate to the next page + await actions.clickPaginationAt(1); + + // On the second (last) page, we expect to see the remaining deprecations + expect(find('deprecationTableRow').length).toEqual(deprecations.length - 50); + }); + + it('allows the number of viewable rows to change', async () => { + const { find, actions, component } = testBed; + + await actions.clickRowsPerPageDropdown(); + + // We need to read the document "body" as the rows-per-page dropdown options are added there and not inside + // the component DOM tree. + const rowsPerPageButton: HTMLButtonElement | null = document.body.querySelector( + '[data-test-subj="tablePagination-100-rows"]' + ); + + expect(rowsPerPageButton).not.toBeNull(); + + await act(async () => { + rowsPerPageButton!.click(); + }); + + component.update(); + + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual( + Math.round(deprecations.length / 100) // Rows per page is now 100 + ); + expect(find('deprecationTableRow').length).toEqual(deprecations.length); + }); + + it('updates pagination when filters change', async () => { + const { actions, find } = testBed; + + const criticalDeprecations = deprecations.filter((deprecation) => deprecation.isCritical); + + await actions.clickCriticalFilterButton(); + + // Only 40 critical deprecations, so only one page should show + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); + expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length); + }); + + it('updates pagination on search', async () => { + const { actions, find } = testBed; + const reindexDeprecations = deprecations.filter( + (deprecation) => deprecation.correctiveAction?.type === 'reindex' + ); + + await actions.setSearchInputValue('Index created before 7.0'); + + // Only 20 deprecations that match, so only one page should show + expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1); + expect(find('deprecationTableRow').length).toEqual(reindexDeprecations.length); + }); + }); + + describe('no deprecations', () => { + beforeEach(async () => { + const noDeprecationsResponse = { + totalCriticalDeprecations: 0, + deprecations: [], + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + test('renders prompt', () => { + const { exists, find } = testBed; + expect(exists('noDeprecationsPrompt')).toBe(true); + expect(find('noDeprecationsPrompt').text()).toContain( + 'Your Elasticsearch configuration is up to date' + ); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts new file mode 100644 index 0000000000000..8d3616a1b9d6b --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/error_handling.test.ts @@ -0,0 +1,115 @@ +/* + * 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'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +describe('Error handling', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + it('handles 403', async () => { + const error = { + statusCode: 403, + error: 'Forbidden', + message: 'Forbidden', + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('permissionsError')).toBe(true); + expect(find('permissionsError').text()).toContain( + 'You are not authorized to view Elasticsearch deprecations.' + ); + }); + + it('shows upgraded message when all nodes have been upgraded', async () => { + const error = { + statusCode: 426, + error: 'Upgrade required', + message: 'There are some nodes running a different version of Elasticsearch', + attributes: { + // This is marked true in the scenario where none of the nodes have the same major version of Kibana, + // and therefore we assume all have been upgraded + allNodesUpgraded: true, + }, + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('upgradedCallout')).toBe(true); + expect(find('upgradedCallout').text()).toContain('All Elasticsearch nodes have been upgraded.'); + }); + + it('shows partially upgrade error when nodes are running different versions', async () => { + const error = { + statusCode: 426, + error: 'Upgrade required', + message: 'There are some nodes running a different version of Elasticsearch', + attributes: { + allNodesUpgraded: false, + }, + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('partiallyUpgradedWarning')).toBe(true); + expect(find('partiallyUpgradedWarning').text()).toContain( + 'Upgrade Kibana to the same version as your Elasticsearch cluster. One or more nodes in the cluster is running a different version than Kibana.' + ); + }); + + it('handles generic error', async () => { + const error = { + statusCode: 500, + error: 'Internal server error', + message: 'Internal server error', + }; + + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(undefined, error); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { component, exists, find } = testBed; + + component.update(); + + expect(exists('requestError')).toBe(true); + expect(find('requestError').text()).toContain('Could not retrieve Elasticsearch deprecations.'); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..efeb78a507160 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/index_settings_deprecation_flyout.test.ts @@ -0,0 +1,117 @@ +/* + * 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'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +describe('Index settings deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + const indexSettingDeprecation = esDeprecationsMockResponse.deprecations[1]; + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { find, exists, actions, component } = testBed; + + component.update(); + + await actions.clickIndexSettingsDeprecationAt(0); + + expect(exists('indexSettingsDetails')).toBe(true); + expect(find('indexSettingsDetails.flyoutTitle').text()).toContain( + indexSettingDeprecation.message + ); + expect(exists('removeSettingsPrompt')).toBe(true); + }); + + it('removes deprecated index settings', async () => { + const { find, actions } = testBed; + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ + acknowledged: true, + }); + + await actions.clickDeleteSettingsButton(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(200); + + // Verify the "Resolution" column of the table is updated + expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( + 'Deprecated settings removed' + ); + + // Reopen the flyout + await actions.clickIndexSettingsDeprecationAt(0); + + // Verify prompt to remove setting no longer displays + expect(find('removeSettingsPrompt').length).toEqual(0); + // Verify the action button no longer displays + expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); + }); + + it('handles failure', async () => { + const { find, actions } = testBed; + const error = { + statusCode: 500, + error: 'Remove index settings error', + message: 'Remove index settings error', + }; + + httpRequestsMockHelpers.setUpdateIndexSettingsResponse(undefined, error); + + await actions.clickDeleteSettingsButton(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('POST'); + expect(request.url).toBe( + `/api/upgrade_assistant/${indexSettingDeprecation.index!}/index_settings` + ); + expect(request.status).toEqual(500); + + // Verify the "Resolution" column of the table is updated + expect(find('indexSettingsResolutionStatusCell').at(0).text()).toEqual( + 'Settings removal failed' + ); + + // Reopen the flyout + await actions.clickIndexSettingsDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('indexSettingsDetails.deleteSettingsError').text()).toContain( + 'Error deleting index settings' + ); + // Verify the remove settings button text changes + expect(find('indexSettingsDetails.deleteSettingsButton').text()).toEqual( + 'Retry removing deprecated settings' + ); + }); +}); 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 new file mode 100644 index 0000000000000..909976355cd31 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/ml_snapshots_deprecation_flyout.test.ts @@ -0,0 +1,196 @@ +/* + * 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'; + +import type { MlAction } from '../../../common/types'; +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +describe('Machine learning deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + const mlDeprecation = esDeprecationsMockResponse.deprecations[0]; + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + const { find, exists, actions, component } = testBed; + + component.update(); + + await actions.clickMlDeprecationAt(0); + + expect(exists('mlSnapshotDetails')).toBe(true); + expect(find('mlSnapshotDetails.flyoutTitle').text()).toContain( + 'Upgrade or delete model snapshot' + ); + }); + + describe('upgrade snapshots', () => { + it('successfully upgrades snapshots', async () => { + const { find, actions, exists } = testBed; + + httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'in_progress', + }); + + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'complete', + }); + + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); + + await actions.clickUpgradeMlSnapshot(); + + // First, we expect a POST request to upgrade the snapshot + const upgradeRequest = server.requests[server.requests.length - 2]; + expect(upgradeRequest.method).toBe('POST'); + expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); + + // Next, we expect a GET request to check the status of the upgrade + const statusRequest = server.requests[server.requests.length - 1]; + expect(statusRequest.method).toBe('GET'); + expect(statusRequest.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${MOCK_JOB_ID}/${MOCK_SNAPSHOT_ID}` + ); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').text()).toContain('Upgrade complete'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + + // Flyout actions should not be visible if deprecation was resolved + expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false); + expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false); + }); + + it('handles upgrade failure', async () => { + const { find, actions } = testBed; + + const error = { + statusCode: 500, + error: 'Upgrade snapshot error', + message: 'Upgrade snapshot error', + }; + + httpRequestsMockHelpers.setUpgradeMlSnapshotResponse(undefined, error); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'error', + error, + }); + + await actions.clickUpgradeMlSnapshot(); + + const upgradeRequest = server.requests[server.requests.length - 1]; + expect(upgradeRequest.method).toBe('POST'); + expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots'); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').text()).toContain('Upgrade failed'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error upgrading snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Retry upgrade'); + }); + }); + + describe('delete snapshots', () => { + it('successfully deletes snapshots', async () => { + const { find, actions } = testBed; + + httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ + acknowledged: true, + }); + + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); + + await actions.clickDeleteMlSnapshot(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('DELETE'); + expect(request.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${ + (mlDeprecation.correctiveAction! as MlAction).jobId + }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` + ); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion complete'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + }); + + it('handles delete failure', async () => { + const { find, actions } = testBed; + + const error = { + statusCode: 500, + error: 'Upgrade snapshot error', + message: 'Upgrade snapshot error', + }; + + httpRequestsMockHelpers.setDeleteMlSnapshotResponse(undefined, error); + + await actions.clickDeleteMlSnapshot(); + + const request = server.requests[server.requests.length - 1]; + + expect(request.method).toBe('DELETE'); + expect(request.url).toBe( + `/api/upgrade_assistant/ml_snapshots/${ + (mlDeprecation.correctiveAction! as MlAction).jobId + }/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}` + ); + + // Verify the "Resolution" column of the table is updated + expect(find('mlActionResolutionCell').at(0).text()).toEqual('Deletion failed'); + + // Reopen the flyout + await actions.clickMlDeprecationAt(0); + + // Verify the flyout shows an error message + expect(find('mlSnapshotDetails.resolveSnapshotError').text()).toContain( + 'Error deleting snapshot' + ); + // Verify the upgrade button text changes + expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Retry delete'); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts new file mode 100644 index 0000000000000..ddf477195063c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/mocked_responses.ts @@ -0,0 +1,119 @@ +/* + * 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 type { ESUpgradeStatus, EnrichedDeprecationInfo } from '../../../common/types'; +import { indexSettingDeprecations } from '../../../common/constants'; + +export const MOCK_SNAPSHOT_ID = '1'; +export const MOCK_JOB_ID = 'deprecation_check_job'; + +export const MOCK_ML_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: true, + resolveDuringUpgrade: false, + type: 'ml_settings', + message: 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', + details: + 'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]', + url: 'doc_url', + correctiveAction: { + type: 'mlSnapshot', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + }, +}; + +const MOCK_REINDEX_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: true, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'Index created before 7.0', + details: 'deprecation details', + url: 'doc_url', + index: 'reindex_index', + correctiveAction: { + type: 'reindex', + }, +}; + +const MOCK_INDEX_SETTING_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: indexSettingDeprecations.translog.deprecationMessage, + details: 'deprecation details', + url: 'doc_url', + index: 'my_index', + correctiveAction: { + type: 'indexSetting', + deprecatedSettings: indexSettingDeprecations.translog.settings, + }, +}; + +const MOCK_DEFAULT_DEPRECATION: EnrichedDeprecationInfo = { + isCritical: false, + resolveDuringUpgrade: false, + type: 'index_settings', + message: 'multi-fields within multi-fields', + details: 'deprecation details', + url: 'doc_url', + index: 'nested_multi-fields', +}; + +export const esDeprecationsMockResponse: ESUpgradeStatus = { + totalCriticalDeprecations: 2, + deprecations: [ + MOCK_ML_DEPRECATION, + MOCK_INDEX_SETTING_DEPRECATION, + MOCK_DEFAULT_DEPRECATION, + MOCK_REINDEX_DEPRECATION, + ], +}; + +// Useful for testing pagination where a large number of deprecations are needed +export const createEsDeprecationsMockResponse = ( + numDeprecationsPerType: number +): ESUpgradeStatus => { + const mlDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_ML_DEPRECATION + ); + + const indexSettingsDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_INDEX_SETTING_DEPRECATION + ); + + const reindexDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_REINDEX_DEPRECATION + ); + + const defaultDeprecations: EnrichedDeprecationInfo[] = Array.from( + { + length: numDeprecationsPerType, + }, + () => MOCK_DEFAULT_DEPRECATION + ); + + const deprecations: EnrichedDeprecationInfo[] = [ + ...defaultDeprecations, + ...reindexDeprecations, + ...indexSettingsDeprecations, + ...mlDeprecations, + ]; + + return { + totalCriticalDeprecations: mlDeprecations.length + reindexDeprecations.length, + deprecations, + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts new file mode 100644 index 0000000000000..c93cdcb1f4d97 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/es_deprecations/reindex_deprecation_flyout.test.ts @@ -0,0 +1,50 @@ +/* + * 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'; + +import { ElasticsearchTestBed, setupElasticsearchPage, setupEnvironment } from '../helpers'; + +import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './mocked_responses'; + +// Note: The reindexing flyout UX is subject to change; more tests should be added here once functionality is built out +describe('Reindex deprecation flyout', () => { + let testBed: ElasticsearchTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse); + httpRequestsMockHelpers.setUpgradeMlSnapshotStatusResponse({ + nodeId: 'my_node', + snapshotId: MOCK_SNAPSHOT_ID, + jobId: MOCK_JOB_ID, + status: 'idle', + }); + + await act(async () => { + testBed = await setupElasticsearchPage({ isReadOnlyMode: false }); + }); + + testBed.component.update(); + }); + + it('renders a flyout with reindexing details', async () => { + const reindexDeprecation = esDeprecationsMockResponse.deprecations[3]; + const { actions, find, exists } = testBed; + + await actions.clickReindexDeprecationAt(0); + + expect(exists('reindexDetails')).toBe(true); + expect(find('reindexDetails.flyoutTitle').text()).toContain( + `Reindex ${reindexDeprecation.index}` + ); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts index ed4944527e047..86737d4925927 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/elasticsearch.helpers.ts @@ -7,7 +7,7 @@ import { act } from 'react-dom/test-utils'; import { registerTestBed, TestBed, TestBedConfig } from '@kbn/test/jest'; -import { EsDeprecationsContent } from '../../../public/application/components/es_deprecations'; +import { EsDeprecations } from '../../../public/application/components/es_deprecations'; import { WithAppDependencies } from './setup_environment'; const testBedConfig: TestBedConfig = { @@ -18,7 +18,7 @@ const testBedConfig: TestBedConfig = { doMountAsync: true, }; -export type ElasticsearchTestBed = TestBed & { +export type ElasticsearchTestBed = TestBed & { actions: ReturnType; }; @@ -159,7 +159,7 @@ const createActions = (testBed: TestBed) => { export const setup = async (overrides?: Record): Promise => { const initTestBed = registerTestBed( - WithAppDependencies(EsDeprecationsContent, overrides), + WithAppDependencies(EsDeprecations, overrides), testBedConfig ); const testBed = await initTestBed(); @@ -169,13 +169,3 @@ export const setup = async (overrides?: Record): Promise { // the component DOM tree. let modal = document.body.querySelector('[data-test-subj="stepsModal"]'); - expect(modal).not.toBe(null); + expect(modal).not.toBeNull(); expect(modal!.textContent).toContain(`Resolve deprecation in '${deprecation.domainId}'`); const steps: NodeListOf | null = modal!.querySelectorAll( From eecfc0c3056c8f6863b211e06304e937b91206d5 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 19 Aug 2021 20:38:12 -0400 Subject: [PATCH 18/18] update jest snapshot --- .../es_deprecations_status.test.ts.snap | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap index 6f8da9ae07579..be9ea11a4886e 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap +++ b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap @@ -3,6 +3,33 @@ exports[`getESUpgradeStatus returns the correct shape of data 1`] = ` Object { "deprecations": Array [ + Object { + "correctiveAction": undefined, + "details": "templates using \`template\` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template", + "isCritical": false, + "message": "Template patterns are no longer using \`template\` field, but \`index_patterns\` instead", + "resolveDuringUpgrade": false, + "type": "cluster_settings", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", + }, + Object { + "correctiveAction": undefined, + "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}", + "isCritical": false, + "message": "one or more templates use deprecated mapping settings", + "resolveDuringUpgrade": false, + "type": "cluster_settings", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", + }, + Object { + "correctiveAction": undefined, + "details": "[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]", + "isCritical": false, + "message": "Datafeed [deprecation-datafeed] uses deprecated query options", + "resolveDuringUpgrade": false, + "type": "ml_settings", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#breaking_70_search_changes", + }, Object { "correctiveAction": Object { "jobId": "deprecation_check_job", @@ -25,6 +52,26 @@ Object { "type": "node_settings", "url": "http://nodeissue.com", }, + Object { + "correctiveAction": undefined, + "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]", + "index": ".monitoring-es-6-2018.11.07", + "isCritical": false, + "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", + }, + Object { + "correctiveAction": undefined, + "details": "[[type: tweet, field: liked]]", + "index": "twitter", + "isCritical": false, + "message": "Coercion of boolean fields", + "resolveDuringUpgrade": false, + "type": "index_settings", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", + }, Object { "correctiveAction": Object { "blockerForReindexing": undefined, @@ -51,53 +98,6 @@ Object { "type": "index_settings", "url": "https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html", }, - Object { - "correctiveAction": undefined, - "details": "templates using \`template\` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template", - "isCritical": false, - "message": "Template patterns are no longer using \`template\` field, but \`index_patterns\` instead", - "resolveDuringUpgrade": false, - "type": "cluster_settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html#_index_templates_use_literal_index_patterns_literal_instead_of_literal_template_literal", - }, - Object { - "correctiveAction": undefined, - "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}", - "isCritical": false, - "message": "one or more templates use deprecated mapping settings", - "resolveDuringUpgrade": false, - "type": "cluster_settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_indices_changes.html", - }, - Object { - "correctiveAction": undefined, - "details": "[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]", - "isCritical": false, - "message": "Datafeed [deprecation-datafeed] uses deprecated query options", - "resolveDuringUpgrade": false, - "type": "ml_settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#breaking_70_search_changes", - }, - Object { - "correctiveAction": undefined, - "details": "[[type: doc, field: spins], [type: doc, field: mlockall], [type: doc, field: node_master], [type: doc, field: primary]]", - "index": ".monitoring-es-6-2018.11.07", - "isCritical": false, - "message": "Coercion of boolean fields", - "resolveDuringUpgrade": false, - "type": "index_settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - }, - Object { - "correctiveAction": undefined, - "details": "[[type: tweet, field: liked]]", - "index": "twitter", - "isCritical": false, - "message": "Coercion of boolean fields", - "resolveDuringUpgrade": false, - "type": "index_settings", - "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", - }, Object { "correctiveAction": Object { "deprecatedSettings": Array [