[UA] Move Es deprecations logs to a flyout (#215482)

Fixes https://github.com/elastic/kibana/issues/211496

## Summary
This PR introduces some UI changes in the UA step 3: Address API
deprecations. Instead of opening the deprecations info in a new window,
the info is now displayed in a flyout. Also, a direct button to
Discovery has been added in the overview page.
This commit is contained in:
Sonia Sanz Vivas 2025-04-03 11:34:17 +02:00 committed by GitHub
parent 6f035f590e
commit c26e868c90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 727 additions and 647 deletions

View file

@ -50340,7 +50340,6 @@
"xpack.upgradeAssistant.app.deniedPrivilegeDescription": "Afin d'utiliser l'assistant de mise à niveau et de résoudre les problèmes de déclassement, vous devez disposer d'un accès permettant de gérer tous les espaces Kibana.",
"xpack.upgradeAssistant.app.deniedPrivilegeTitle": "Rôle d'administrateur Kibana requis",
"xpack.upgradeAssistant.appTitle": "Assistant de mise à niveau",
"xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel": "Logs de déclassements Elasticsearch",
"xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel": "Problèmes de déclassement Elasticsearch",
"xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Problèmes de déclassement Kibana",
"xpack.upgradeAssistant.breadcrumb.overviewLabel": "Assistant de mise à niveau",
@ -50422,8 +50421,6 @@
"xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Mettez à niveau Kibana vers la même version que votre cluster Elasticsearch. Un ou plusieurs nœuds du cluster exécutent une version différente de celle de Kibana.",
"xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Vous n'êtes pas autorisé à afficher les problèmes de déclassement Elasticsearch.",
"xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "Tous les nœuds Elasticsearch ont été mis à niveau.",
"xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText": "Documentation",
"xpack.upgradeAssistant.esDeprecationLogs.pageDescription": "Consultez les logs de déclassement pour déterminer si vos applications utilisent des API déclassées. Mettez à jour vos applications pour empêcher des erreurs ou des changements de comportement après votre mise à niveau.",
"xpack.upgradeAssistant.esDeprecationLogs.pageTitle": "Logs de déclassements Elasticsearch",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsLink": "API de réindexation par lots",
"xpack.upgradeAssistant.esDeprecations.clusterDeprecationTypeLabel": "Cluster",
@ -50672,7 +50669,6 @@
"xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "Impossible de récupérer les informations de logging.",
"xpack.upgradeAssistant.overview.deprecationLogs.reloadButtonLabel": "Réessayer",
"xpack.upgradeAssistant.overview.deprecationLogs.updateErrorMessage": "Impossible de mettre à jour l'état de logging.",
"xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "Résoudre les problèmes de déclassement et vérifier vos modifications",
"xpack.upgradeAssistant.overview.documentationLinkText": "Documentation",
"xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "Une erreur s'est produite lors de la récupération du statut de mise à niveau",
"xpack.upgradeAssistant.overview.fixIssuesStepDescription": "Vous devez résoudre tous les problèmes critiques de configuration Elasticsearch et Kibana avant d'effectuer la mise à niveau vers la version suivante de la Suite Elastic. Si vous ignorez les avertissements, des différences de comportement pourront apparaître après votre mise à niveau.",
@ -50690,7 +50686,6 @@
"xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle": "Vous avez besoin de privilèges d'index pour analyser les logs de déclassement",
"xpack.upgradeAssistant.overview.logsStep.retryButton": "Réessayer",
"xpack.upgradeAssistant.overview.logsStep.title": "Traiter les déclassements d'API",
"xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel": "Afficher les logs",
"xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes": "points forts de la toute dernière version",
"xpack.upgradeAssistant.overview.observe.discoveryDescription": "Recherchez et filtrez les logs de déclassement pour comprendre les types de modifications que vous devez effectuer.",
"xpack.upgradeAssistant.overview.pageDescription": "Préparez-vous pour la prochaine version de la Suite Elastic !",

View file

@ -50300,7 +50300,6 @@
"xpack.upgradeAssistant.app.deniedPrivilegeDescription": "アップグレードアシスタントを使用して、廃止予定の問題を解決するには、すべてのKibanaスペースを管理するためのアクセス権が必要です。",
"xpack.upgradeAssistant.app.deniedPrivilegeTitle": "Kibana管理者ロールが必要です",
"xpack.upgradeAssistant.appTitle": "アップグレードアシスタント",
"xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel": "Elasticsearchの廃止予定ログ",
"xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel": "Elasticsearchの廃止予定の問題",
"xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibanaの廃止予定の問題",
"xpack.upgradeAssistant.breadcrumb.overviewLabel": "アップグレードアシスタント",
@ -50381,8 +50380,6 @@
"xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Kibanaをご使用のElasticsearchクラスターと同じバージョンにアップグレードしてください。クラスターの1つ以上のードがKibanaとは異なるバージョンを実行しています。",
"xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Elasticsearchの廃止予定の問題を表示する権限がありません。",
"xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "すべての Elasticsearch ノードがアップグレードされました。",
"xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText": "ドキュメント",
"xpack.upgradeAssistant.esDeprecationLogs.pageDescription": "廃止予定ログを確認し、アプリケーションが廃止予定のAPIを使用しているかどうかを判断してください。アップグレード後に、エラーまたは動作の変更を防止するには、アプリケーションを更新します。",
"xpack.upgradeAssistant.esDeprecationLogs.pageTitle": "Elasticsearchの廃止予定ログ",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsDescription": "1つの要求で複数のインデックスのアップグレードを開始するには、Kibana {docsLink}を使用します。注このAPIはデータストリームをサポートしていません。",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsLink": "バッチ再インデックスAPI",
@ -50632,7 +50629,6 @@
"xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "ログ情報を取得できませんでした。",
"xpack.upgradeAssistant.overview.deprecationLogs.reloadButtonLabel": "再試行",
"xpack.upgradeAssistant.overview.deprecationLogs.updateErrorMessage": "ログ状態を更新できませんでした。",
"xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "廃止予定の問題を解決して変更を検証",
"xpack.upgradeAssistant.overview.documentationLinkText": "ドキュメント",
"xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "アップグレードステータスの取得中にエラーが発生しました",
"xpack.upgradeAssistant.overview.fixIssuesStepDescription": "次のバージョンのElastic Stackにアップグレードする前に、重大なElasticsearchおよびKibana構成の問題を解決する必要があります。警告を無視すると、アップグレード後に動作が変更される場合があります。",
@ -50650,7 +50646,6 @@
"xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle": "廃止予定ログを分析するには、インデックス権限が必要です",
"xpack.upgradeAssistant.overview.logsStep.retryButton": "再試行",
"xpack.upgradeAssistant.overview.logsStep.title": "API廃止予定に対処",
"xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel": "ログを表示",
"xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes": "最新リリースのハイライト",
"xpack.upgradeAssistant.overview.observe.discoveryDescription": "廃止予定ログを検索およびフィルターし、必要な変更のタイプを把握します。",
"xpack.upgradeAssistant.overview.pageDescription": "次のバージョンのElastic Stackをお待ちください。",

View file

@ -50383,7 +50383,6 @@
"xpack.upgradeAssistant.app.deniedPrivilegeDescription": "要使用升级助手并解决弃用问题,必须具有管理所有 Kibana 工作区的访问权限。",
"xpack.upgradeAssistant.app.deniedPrivilegeTitle": "需要 Kibana 管理员角色",
"xpack.upgradeAssistant.appTitle": "升级助手",
"xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel": "Elasticsearch 弃用日志",
"xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel": "Elasticsearch 弃用问题",
"xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibana 弃用问题",
"xpack.upgradeAssistant.breadcrumb.overviewLabel": "升级助手",
@ -50465,8 +50464,6 @@
"xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "将 Kibana 升级到与您的 Elasticsearch 集群相同的版本。集群中的一个或多个节点正在运行与 Kibana 不同的版本。",
"xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "您无权查看 Elasticsearch 弃用问题。",
"xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "所有 Elasticsearch 节点已升级。",
"xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText": "文档",
"xpack.upgradeAssistant.esDeprecationLogs.pageDescription": "请复查弃用日志以确定您的应用程序是否正使用任何已弃用的 API。在升级后请更新应用程序以防止错误或行为更改。",
"xpack.upgradeAssistant.esDeprecationLogs.pageTitle": "Elasticsearch 弃用日志",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsDescription": "要在单一请求中开始升级多个索引,请使用 Kibana {docsLink}。注意:此 API 不支持数据流。",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsLink": "批量重新索引 API",
@ -50716,7 +50713,6 @@
"xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "无法检索日志记录信息。",
"xpack.upgradeAssistant.overview.deprecationLogs.reloadButtonLabel": "重试",
"xpack.upgradeAssistant.overview.deprecationLogs.updateErrorMessage": "无法更新日志记录状态。",
"xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "解决弃用问题并验证您的更改",
"xpack.upgradeAssistant.overview.documentationLinkText": "文档",
"xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "检索升级状态时出错",
"xpack.upgradeAssistant.overview.fixIssuesStepDescription": "在升级到下一版本的 Elastic Stack 之前,必须解决任何严重的 Elasticsearch 和 Kibana 配置问题。在您升级后,忽略警告可能会导致行为差异。",
@ -50734,7 +50730,6 @@
"xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle": "您需要索引权限才能分析弃用日志",
"xpack.upgradeAssistant.overview.logsStep.retryButton": "重试",
"xpack.upgradeAssistant.overview.logsStep.title": "解决 API 弃用",
"xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel": "查看日志",
"xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes": "最新发布亮点",
"xpack.upgradeAssistant.overview.observe.discoveryDescription": "搜索并筛选弃用日志以了解需要进行的更改类型。",
"xpack.upgradeAssistant.overview.pageDescription": "准备使用下一版 Elastic Stack",

View file

@ -8,13 +8,13 @@
import { act } from 'react-dom/test-utils';
import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers';
import { HttpSetup } from '@kbn/core/public';
import { EsDeprecationLogs } from '../../../public/application/components';
import { Overview } from '../../../public/application/components';
import { WithAppDependencies } from '../helpers';
const testBedConfig: AsyncTestBedConfig = {
memoryRouter: {
initialEntries: ['/es_deprecation_logs'],
componentRoutePath: '/es_deprecation_logs',
initialEntries: [`/overview`],
componentRoutePath: '/overview',
},
doMountAsync: true,
};
@ -28,21 +28,30 @@ const createActions = (testBed: TestBed) => {
* User Actions
*/
const clickDeprecationToggle = async () => {
const clickOpenFlyoutLoggingEnabled = async () => {
const { find, component } = testBed;
await act(async () => {
find('deprecationLoggingToggle').simulate('click');
find('viewDetailsLink').simulate('click');
});
component.update();
};
const clickOpenFlyoutLoggingDisabled = async () => {
const { find, component } = testBed;
await act(async () => {
find('enableLogsLink').simulate('click');
});
component.update();
};
const clickRetryButton = async () => {
const clickDeprecationToggle = async () => {
const { find, component } = testBed;
await act(async () => {
find('retryButton').simulate('click');
find('deprecationLoggingToggle').simulate('click');
});
component.update();
@ -57,11 +66,22 @@ const createActions = (testBed: TestBed) => {
component.update();
};
const clickCloseFlyout = async () => {
const { find, component } = testBed;
await act(async () => {
find('closeEsDeprecationLogs').simulate('click');
});
component.update();
};
return {
clickOpenFlyoutLoggingEnabled,
clickOpenFlyoutLoggingDisabled,
clickDeprecationToggle,
clickRetryButton,
clickResetButton,
clickCloseFlyout,
};
};
@ -70,7 +90,7 @@ export const setupESDeprecationLogsPage = async (
overrides?: Record<string, unknown>
): Promise<EsDeprecationLogsTestBed> => {
const initTestBed = registerTestBed(
WithAppDependencies(EsDeprecationLogs, httpSetup, overrides),
WithAppDependencies(Overview, httpSetup, overrides),
testBedConfig
);
const testBed = await initTestBed();

View file

@ -10,15 +10,14 @@ import {
EsDeprecationLogsTestBed,
setupESDeprecationLogsPage,
} from './es_deprecation_logs.helpers';
import { setupEnvironment, advanceTime } from '../helpers';
import { setupEnvironment } from '../helpers';
import { DeprecationLoggingStatus } from '../../../common/types';
import {
DEPRECATION_LOGS_INDEX,
DEPRECATION_LOGS_COUNT_POLL_INTERVAL_MS,
APPS_WITH_DEPRECATION_LOGS,
DEPRECATION_LOGS_ORIGIN_FIELD,
DEPRECATION_LOGS_COUNT_POLL_INTERVAL_MS,
} from '../../../common/constants';
import { advanceTime } from '../helpers';
// Once the logs team register the kibana locators in their app, we should be able
// to remove this mock and follow a similar approach to how discover link is tested.
// See: https://github.com/elastic/kibana/issues/104855
@ -37,7 +36,7 @@ const getLoggingResponse = (toggle: boolean): DeprecationLoggingStatus => ({
isDeprecationLoggingEnabled: toggle,
});
describe('ES deprecation logs', () => {
describe('ES deprecation logs flyout', () => {
let testBed: EsDeprecationLogsTestBed;
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
@ -47,23 +46,89 @@ describe('ES deprecation logs', () => {
httpSetup = mockEnvironment.httpSetup;
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(true));
testBed = await setupESDeprecationLogsPage(httpSetup);
testBed.component.update();
});
test('opens flyout with logging enabled', async () => {
const { exists, actions, find } = testBed;
describe('Documentation link', () => {
test('Has a link for migration info api docs in page header', () => {
const { exists } = testBed;
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('documentationLink')).toBe(true);
expect(exists('flyoutTitle')).toBe(true);
expect(find('flyoutTitle').text()).toContain('Elasticsearch deprecation logs');
expect(exists('noWarningsCallout')).toBe(true);
expect(exists('closeEsDeprecationLogs')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(true);
expect(exists('deprecationLogsDescription')).toBe(true);
expect(exists('deprecationLoggingToggle')).toBe(true);
expect(exists('viewDiscoverLogs')).toBe(true);
expect(exists('apiCompatibilityNoteTitle')).toBe(true);
await actions.clickCloseFlyout();
expect(exists('flyoutTitle')).toBe(false);
});
test('opens flyout with logging disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(false));
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component, actions, find } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingDisabled();
expect(exists('flyoutTitle')).toBe(true);
expect(find('flyoutTitle').text()).toContain('Elasticsearch deprecation logs');
expect(exists('noWarningsCallout')).toBe(false);
expect(exists('hasWarningsCallout')).toBe(false);
expect(exists('deprecationLogsDescription')).toBe(true);
expect(exists('deprecationLoggingToggle')).toBe(true);
expect(exists('viewDiscoverLogs')).toBe(false);
expect(exists('apiCompatibilityNoteTitle')).toBe(false);
expect(exists('closeEsDeprecationLogs')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(false);
await actions.clickCloseFlyout();
expect(exists('flyoutTitle')).toBe(false);
});
describe('banner', () => {
test('shows success callout if no warnings', async () => {
const { exists, actions, find } = testBed;
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('noWarningsCallout')).toBe(true);
expect(find('noWarningsCallout').text()).toContain('No deprecation issues');
});
test('shows callout with the number of warnings', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component, actions, find } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('hasWarningsCallout')).toBe(true);
expect(find('hasWarningsCallout').text()).toContain('10');
});
});
describe('Step 1 - Toggle log writing and collecting', () => {
describe('Flyout - Toggle log writing and collecting', () => {
test('toggles deprecation logging', async () => {
const { find, actions } = testBed;
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(false));
await actions.clickOpenFlyoutLoggingEnabled();
expect(find('deprecationLoggingToggle').props()['aria-checked']).toBe(true);
@ -73,25 +138,6 @@ describe('ES deprecation logs', () => {
`/api/upgrade_assistant/deprecation_logging`,
expect.objectContaining({ body: JSON.stringify({ isEnabled: false }) })
);
expect(find('deprecationLoggingToggle').props()['aria-checked']).toBe(false);
});
test('shows callout when only loggerDeprecation is enabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: false,
isDeprecationLoggingEnabled: true,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component } = testBed;
component.update();
expect(exists('deprecationWarningCallout')).toBe(true);
});
test('handles network error when updating logging state', async () => {
@ -100,69 +146,44 @@ describe('ES deprecation logs', () => {
error: 'Internal server error',
message: 'Internal server error',
};
const { actions, exists } = testBed;
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(false));
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(undefined, error);
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, actions, component } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingDisabled();
await actions.clickDeprecationToggle();
expect(exists('updateLoggingError')).toBe(true);
});
test('handles network error when fetching logging state', async () => {
const error = {
statusCode: 500,
error: 'Internal server error',
message: 'Internal server error',
};
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(undefined, error);
test('does not show external links and deprecations count when toggle is disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(false));
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { component, exists } = testBed;
component.update();
expect(exists('fetchLoggingError')).toBe(true);
});
test('It doesnt show external links and deprecations count when toggle is disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: false,
isDeprecationLoggingEnabled: false,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component } = testBed;
const { exists, actions, component } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingDisabled();
expect(exists('externalLinksTitle')).toBe(false);
expect(exists('deprecationsCountTitle')).toBe(false);
expect(exists('apiCompatibilityNoteTitle')).toBe(false);
});
});
describe('Step 2 - Analyze logs', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
});
describe('analyze logs', () => {
test('has a link to see logs in discover app', async () => {
const { exists, find, actions } = testBed;
test('Has a link to see logs in discover app', async () => {
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component, find } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('viewDiscoverLogs')).toBe(true);
@ -184,74 +205,11 @@ describe('ES deprecation logs', () => {
});
});
describe('Step 3 - Resolve log issues', () => {
describe('reset counter', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
httpRequestsMockHelpers.setDeleteLogsCacheResponse('ok');
});
test('With deprecation warnings', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { find, exists, component } = testBed;
component.update();
expect(exists('hasWarningsCallout')).toBe(true);
expect(find('hasWarningsCallout').text()).toContain('10');
});
test('No deprecation issues', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { find, exists, component } = testBed;
component.update();
expect(exists('noWarningsCallout')).toBe(true);
expect(find('noWarningsCallout').text()).toContain('No deprecation issues');
});
test('Handles errors and can retry', async () => {
const error = {
statusCode: 500,
error: 'Internal server error',
message: 'Internal server error',
};
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse(undefined, error);
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, actions, component } = testBed;
component.update();
expect(exists('errorCallout')).toBe(true);
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});
await actions.clickRetryButton();
expect(exists('noWarningsCallout')).toBe(true);
});
test('Allows user to reset last stored date', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
@ -265,6 +223,7 @@ describe('ES deprecation logs', () => {
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('hasWarningsCallout')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(true);
@ -307,6 +266,7 @@ describe('ES deprecation logs', () => {
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ count: 0 });
await actions.clickResetButton();
@ -336,8 +296,9 @@ describe('ES deprecation logs', () => {
});
test('success state is followed by an error state', async () => {
const { exists } = testBed;
const { exists, actions } = testBed;
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('resetLastStoredDate')).toBe(true);
// second request will error
@ -356,57 +317,4 @@ describe('ES deprecation logs', () => {
});
});
});
describe('Step 4 - API compatibility header', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
});
test('It shows copy with compatibility api header advice', async () => {
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component } = testBed;
component.update();
expect(exists('apiCompatibilityNoteTitle')).toBe(true);
});
});
describe('Privileges check', () => {
test(`permissions warning callout is hidden if user has the right privileges`, async () => {
const { exists } = testBed;
// Index privileges warning callout should not be shown
expect(exists('noIndexPermissionsCallout')).toBe(false);
// Analyze logs and Resolve logs sections should be shown
expect(exists('externalLinksTitle')).toBe(true);
expect(exists('deprecationsCountTitle')).toBe(true);
});
test(`doesn't show analyze and resolve logs if it doesn't have the right privileges`, async () => {
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup, {
privileges: {
hasAllPrivileges: false,
missingPrivileges: {
index: [DEPRECATION_LOGS_INDEX],
},
},
});
});
const { exists, component } = testBed;
component.update();
// No index privileges warning callout should be shown
expect(exists('noIndexPermissionsCallout')).toBe(true);
// Analyze logs and Resolve logs sections should be hidden
expect(exists('externalLinksTitle')).toBe(false);
expect(exists('deprecationsCountTitle')).toBe(false);
});
});
});

View file

@ -9,6 +9,8 @@ import { act } from 'react-dom/test-utils';
import {
DEPRECATION_LOGS_INDEX,
APP_LOGS_COUNT_CLUSTER_PRIVILEGES,
DEPRECATION_LOGS_ORIGIN_FIELD,
APPS_WITH_DEPRECATION_LOGS,
} from '../../../../common/constants';
import { setupEnvironment } from '../../helpers';
import { OverviewTestBed, setupOverviewPage } from '../overview.helpers';
@ -32,6 +34,10 @@ describe('Overview - Logs Step', () => {
};
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse(undefined, error);
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: true,
isDeprecationLoggingEnabled: true,
});
await act(async () => {
testBed = await setupOverviewPage(httpSetup);
@ -40,10 +46,27 @@ describe('Overview - Logs Step', () => {
testBed.component.update();
});
test('is rendered', () => {
const { exists } = testBed;
test('is rendered and allows retry', async () => {
const { exists, actions } = testBed;
expect(exists('deprecationLogsErrorCallout')).toBe(true);
expect(exists('deprecationLogsRetryButton')).toBe(true);
expect(exists('logsCountDescription')).toBe(false);
expect(exists('viewDiscoverLogsButton')).toBe(false);
expect(exists('viewDetailsLink')).toBe(false);
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});
await actions.clickRetryLogsButton();
expect(exists('logsCountDescription')).toBe(true);
expect(exists('viewDiscoverLogsButton')).toBe(true);
expect(exists('viewDetailsLink')).toBe(true);
expect(exists('deprecationLogsErrorCallout')).toBe(false);
expect(exists('deprecationLogsRetryButton')).toBe(false);
});
});
@ -102,7 +125,37 @@ describe('Overview - Logs Step', () => {
component.update();
expect(find('logsCountDescription').text()).toContain('You have 10 deprecation issues');
expect(find('viewLogsLink').text()).toContain('View logs');
});
test('displays discover and verify changes buttons', async () => {
const { exists, find } = testBed;
expect(exists('viewDiscoverLogsButton')).toBe(true);
expect(exists('viewDetailsLink')).toBe(true);
expect(find('viewDiscoverLogsButton').text()).toContain('Analyze logs in Discover');
expect(find('viewDetailsLink').text()).toContain('View details');
expect(exists('enableLogsLink')).toBe(false);
});
test('has a link to see logs in discover app', async () => {
const { exists, find } = testBed;
expect(exists('viewDiscoverLogsButton')).toBe(true);
const decodedUrl = decodeURIComponent(find('viewDiscoverLogsButton').props().href);
expect(decodedUrl).toContain('discoverUrl');
[
'"language":"kuery"',
'"query":"@timestamp+>',
'filters=',
DEPRECATION_LOGS_ORIGIN_FIELD,
...APPS_WITH_DEPRECATION_LOGS,
].forEach((param) => {
try {
expect(decodedUrl).toContain(param);
} catch (e) {
throw new Error(`Expected [${param}] not found in ${decodedUrl}`);
}
});
});
});
@ -127,6 +180,8 @@ describe('Overview - Logs Step', () => {
expect(exists('logsCountDescription')).toBe(false);
expect(find('enableLogsLink').text()).toContain('Enable logging');
expect(exists('viewDiscoverLogsButton')).toBe(false);
expect(exists('viewDetailsLink')).toBe(false);
});
});
});

View file

@ -48,9 +48,20 @@ const createActions = (testBed: TestBed) => {
component.update();
};
const clickRetryLogsButton = async () => {
const { find, component } = testBed;
await act(async () => {
find('deprecationLogsRetryButton').simulate('click');
});
component.update();
};
return {
clickViewSystemIndicesState,
clickRetrySystemIndicesButton,
clickRetryLogsButton,
};
};

View file

@ -26,7 +26,7 @@ import {
} from '../shared_imports';
import { AppDependencies } from '../types';
import { AppContextProvider, useAppContext } from './app_context';
import { EsDeprecations, EsDeprecationLogs, KibanaDeprecations, Overview } from './components';
import { EsDeprecations, KibanaDeprecations, Overview } from './components';
const { GlobalFlyoutProvider } = GlobalFlyout;
@ -121,7 +121,6 @@ const AppHandlingClusterUpgradeState: React.FunctionComponent = () => {
<Routes>
<Route exact path="/overview" component={Overview} />
<Route exact path="/es_deprecations" component={EsDeprecations} />
<Route exact path="/es_deprecation_logs" component={EsDeprecationLogs} />
<Route exact path="/kibana_deprecations" component={KibanaDeprecations} />
<Redirect from="/" to="/overview" />
</Routes>

View file

@ -1,74 +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, useEffect } from 'react';
import {
EuiPageHeader,
EuiButtonEmpty,
EuiSpacer,
EuiPageBody,
EuiPageSection,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import { FormattedMessage } from '@kbn/i18n-react';
import { useAppContext } from '../../app_context';
import { uiMetricService, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD } from '../../lib/ui_metric';
import { FixDeprecationLogs } from './fix_deprecation_logs';
export const EsDeprecationLogs: FunctionComponent = () => {
const {
services: {
breadcrumbs,
core: { docLinks },
},
} = useAppContext();
useEffect(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD);
}, []);
useEffect(() => {
breadcrumbs.setBreadcrumbs('esDeprecationLogs');
}, [breadcrumbs]);
return (
<EuiPageBody restrictWidth data-test-subj="esDeprecationLogs" css={{ width: '100%' }}>
<EuiPageSection color="transparent" paddingSize="none">
<EuiPageHeader
bottomBorder
pageTitle={i18n.translate('xpack.upgradeAssistant.esDeprecationLogs.pageTitle', {
defaultMessage: 'Elasticsearch deprecation logs',
})}
description={i18n.translate('xpack.upgradeAssistant.esDeprecationLogs.pageDescription', {
defaultMessage:
'Review the deprecation logs to determine if your applications are using any deprecated APIs. Update your applications to prevent errors or changes in behavior after you upgrade.',
})}
rightSideItems={[
<EuiButtonEmpty
href={docLinks.links.elasticsearch.migrationApiDeprecation}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText"
defaultMessage="Documentation"
/>
</EuiButtonEmpty>,
]}
/>
<EuiSpacer size="l" />
<FixDeprecationLogs />
</EuiPageSection>
</EuiPageBody>
);
};

View file

@ -137,7 +137,7 @@ export const DeprecationLoggingToggle: FunctionComponent<Props> = ({
<EuiFlexItem grow={false}>
<EuiSwitch
data-test-subj="deprecationLoggingToggle"
label={i18nTexts.buttonLabel}
label={<EuiText>{i18nTexts.buttonLabel}</EuiText>}
checked={!!isDeprecationLogIndexingEnabled}
onChange={toggleLogging}
disabled={Boolean(fetchError) || isUpdating}

View file

@ -5,15 +5,12 @@
* 2.0.
*/
import React, { FunctionComponent, useState } from 'react';
import moment from 'moment-timezone';
import React, { FunctionComponent } from 'react';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n-react';
import { METRIC_TYPE } from '@kbn/analytics';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiButton, EuiSkeletonText } from '@elastic/eui';
import { EuiCallOut, EuiSkeletonText, EuiButton } from '@elastic/eui';
import { useAppContext } from '../../../../app_context';
import { uiMetricService, UIM_RESET_LOGS_COUNTER_CLICK } from '../../../../lib/ui_metric';
const i18nTexts = {
calloutTitle: (warningsCount: number, previousCheck: string) => (
@ -40,34 +37,17 @@ const i18nTexts = {
retryButton: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.retryButton', {
defaultMessage: 'Try again',
}),
resetCounterButton: i18n.translate(
'xpack.upgradeAssistant.overview.verifyChanges.resetCounterButton',
{
defaultMessage: 'Reset counter',
}
),
errorToastTitle: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle', {
defaultMessage: 'Could not delete deprecation logs cache',
}),
};
interface Props {
checkpoint: string;
setCheckpoint: (value: string) => void;
}
export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
checkpoint,
setCheckpoint,
}) => {
const [isDeletingCache, setIsDeletingCache] = useState(false);
export const DeprecationsCountCallout: FunctionComponent<Props> = ({ checkpoint }) => {
const {
services: {
api,
core: { notifications },
},
services: { api },
} = useAppContext();
const { data, error, isLoading, resendRequest, isInitialRequest } =
const { data, error, isLoading, isInitialRequest, resendRequest } =
api.getDeprecationLogsCount(checkpoint);
const logsCount = data?.count || 0;
@ -76,24 +56,6 @@ export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
const calloutIcon = hasLogs ? 'warning' : 'check';
const calloutTestId = hasLogs ? 'hasWarningsCallout' : 'noWarningsCallout';
const onResetClick = async () => {
setIsDeletingCache(true);
const { error: deleteLogsCacheError } = await api.deleteDeprecationLogsCache();
setIsDeletingCache(false);
if (deleteLogsCacheError) {
notifications.toasts.addDanger({
title: i18nTexts.errorToastTitle,
text: deleteLogsCacheError.message.toString(),
});
return;
}
const now = moment().toISOString();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_RESET_LOGS_COUNTER_CLICK);
setCheckpoint(now);
};
if (isInitialRequest && isLoading) {
return <EuiSkeletonText lines={6} />;
}
@ -122,16 +84,6 @@ export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
color={calloutTint}
iconType={calloutIcon}
data-test-subj={calloutTestId}
>
<p>{i18nTexts.calloutBody}</p>
<EuiButton
color={calloutTint}
onClick={onResetClick}
isLoading={isDeletingCache || isLoading}
data-test-subj="resetLastStoredDate"
>
{i18nTexts.resetCounterButton}
</EuiButton>
</EuiCallOut>
/>
);
};

View file

@ -0,0 +1,71 @@
/*
* 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, useState } from 'react';
import moment from 'moment-timezone';
import { METRIC_TYPE } from '@kbn/analytics';
import { i18n } from '@kbn/i18n';
import { EuiButton } from '@elastic/eui';
import { useAppContext } from '../../../../app_context';
import { uiMetricService, UIM_RESET_LOGS_COUNTER_CLICK } from '../../../../lib/ui_metric';
const i18nTexts = {
resetCounterButton: i18n.translate(
'xpack.upgradeAssistant.overview.verifyChanges.resetCounterButton',
{
defaultMessage: 'Reset counter',
}
),
errorToastTitle: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle', {
defaultMessage: 'Could not delete deprecation logs cache',
}),
};
interface Props {
setCheckpoint: (value: string) => void;
}
export const ResetCounterButton: FunctionComponent<Props> = ({ setCheckpoint }) => {
const [isDeletingCache, setIsDeletingCache] = useState(false);
const {
services: {
api,
core: { notifications },
},
} = useAppContext();
const onResetClick = async () => {
setIsDeletingCache(true);
const { error: deleteLogsCacheError } = await api.deleteDeprecationLogsCache();
setIsDeletingCache(false);
if (deleteLogsCacheError) {
notifications.toasts.addDanger({
title: i18nTexts.errorToastTitle,
text: deleteLogsCacheError.message.toString(),
});
return;
}
const now = moment().toISOString();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_RESET_LOGS_COUNTER_CLICK);
setCheckpoint(now);
};
return (
<EuiButton
color="primary"
fill
onClick={onResetClick}
isLoading={isDeletingCache}
data-test-subj="resetLastStoredDate"
>
{i18nTexts.resetCounterButton}
</EuiButton>
);
};

View file

@ -5,4 +5,5 @@
* 2.0.
*/
export { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint';
export { ResetCounterButton } from './deprecations_count_reset_button';
export { DeprecationsCountCallout } from './deprecations_count_callout';

View file

@ -0,0 +1,295 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiText,
EuiSpacer,
EuiLink,
EuiCallOut,
EuiCode,
EuiFlyoutHeader,
EuiTitle,
EuiButtonEmpty,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import { useAppContext } from '../../../app_context';
import { DiscoverExternalLinks } from './external_links';
import { DeprecationsCountCallout, ResetCounterButton } from './deprecations_count_checkpoint';
import { useDeprecationLogging } from './use_deprecation_logging';
import { DeprecationLoggingToggle } from './deprecation_logging_toggle';
import { loadLogsCheckpoint, saveLogsCheckpoint } from '../../../lib/logs_checkpoint';
import { DEPRECATION_LOGS_INDEX } from '../../../../../common/constants';
import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports';
import { uiMetricService, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD } from '../../../lib/ui_metric';
const i18nTexts = {
analyzeTitle: i18n.translate('xpack.upgradeAssistant.overview.analyzeTitle', {
defaultMessage: 'Analyze deprecation logs',
}),
apiCompatibilityNoteTitle: i18n.translate(
'xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle',
{
defaultMessage: 'Apply API compatibility headers (optional)',
}
),
apiCompatibilityNoteBody: (docLink: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteBody"
defaultMessage="We recommend you resolve all deprecation issues before upgrading. If needed, you can apply API compatibility headers to requests that use deprecated features. {learnMoreLink}."
values={{
learnMoreLink: (
<EuiLink href={docLink} target="_blank">
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
),
onlyLogWritingEnabledTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningTitle',
{
defaultMessage: 'Your logs are being written to the logs directory',
}
),
onlyLogWritingEnabledBody: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningBody',
{
defaultMessage:
'Go to your logs directory to view the deprecation logs or enable deprecation log collection to see them in Kibana.',
}
),
deniedPrivilegeTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeTitle',
{
defaultMessage: 'You need index privileges to analyze the deprecation logs',
}
),
deniedPrivilegeDescription: (privilegesMissing: MissingPrivileges) => (
// NOTE: hardcoding the missing privilege because the WithPrivileges HOC
// doesnt provide a way to retrieve which specific privileges an index
// is missing.
<FormattedMessage
id="xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeDescription"
defaultMessage="The deprecation logs will continue to be indexed, but you won't be able to analyze them until you have the read index {privilegesCount, plural, one {privilege} other {privileges}} for: {missingPrivileges}"
values={{
missingPrivileges: (
<EuiCode transparentBackground={true}>{privilegesMissing?.index?.join(', ')}</EuiCode>
),
privilegesCount: privilegesMissing?.index?.length,
}}
/>
),
reviewDeprecationLogsInfo: (docLink: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.reviewDeprecationLogsInfo"
defaultMessage="Review the deprecation logs to determine if your applications are using any deprecated APIs. Update your applications to prevent errors or changes in behavior after you upgrade. {learnMoreLink}."
values={{
learnMoreLink: (
<EuiLink href={docLink} target="_blank" data-test-subj="documentationLink">
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
),
};
const callOut = (
hasPrivileges: boolean,
privilegesMissing: MissingPrivileges,
onlyDeprecationLogWritingEnabled: boolean,
isDeprecationLogIndexingEnabled: boolean,
checkpoint: string
) => {
if (onlyDeprecationLogWritingEnabled) {
return (
<EuiCallOut
title={i18nTexts.onlyLogWritingEnabledTitle}
color="warning"
iconType="help"
data-test-subj="deprecationWarningCallout"
>
<p>{i18nTexts.onlyLogWritingEnabledBody}</p>
</EuiCallOut>
);
}
if (!hasPrivileges && isDeprecationLogIndexingEnabled) {
return (
<EuiCallOut
iconType="help"
color="warning"
title={i18nTexts.deniedPrivilegeTitle}
data-test-subj="noIndexPermissionsCallout"
>
<p>{i18nTexts.deniedPrivilegeDescription(privilegesMissing)}</p>
</EuiCallOut>
);
}
if (hasPrivileges && isDeprecationLogIndexingEnabled) {
return <DeprecationsCountCallout checkpoint={checkpoint} />;
}
};
export interface EsDeprecationLogsFlyoutProps {
closeFlyout: () => void;
handleToggleChange: () => void;
}
export const EsDeprecationLogsFlyout = ({
closeFlyout,
handleToggleChange,
}: EsDeprecationLogsFlyoutProps) => {
const {
services: {
core: { docLinks },
},
} = useAppContext();
const {
isDeprecationLogIndexingEnabled,
onlyDeprecationLogWritingEnabled,
isLoading,
isUpdating,
fetchError,
updateError,
resendRequest,
toggleLogging,
} = useDeprecationLogging();
const [checkpoint, setCheckpoint] = useState(loadLogsCheckpoint());
useEffect(() => {
handleToggleChange();
}, [handleToggleChange, toggleLogging]);
useEffect(() => {
saveLogsCheckpoint(checkpoint);
}, [checkpoint]);
useEffect(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD);
}, []);
return (
<>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.pageTitle"
defaultMessage="Elasticsearch deprecation logs"
/>
</h2>
</EuiTitle>
<EuiSpacer size="m" />
</EuiFlyoutHeader>
<WithPrivileges privileges={`index.${DEPRECATION_LOGS_INDEX}`}>
{({ hasPrivileges, privilegesMissing }) => (
<EuiFlyoutBody
banner={callOut(
hasPrivileges,
privilegesMissing,
onlyDeprecationLogWritingEnabled,
isDeprecationLogIndexingEnabled,
checkpoint
)}
>
<EuiText>
<p data-test-subj="deprecationLogsDescription">
{i18nTexts.reviewDeprecationLogsInfo(
docLinks.links.elasticsearch.migrationApiDeprecation
)}
</p>
</EuiText>
<EuiSpacer size="xl" />
<DeprecationLoggingToggle
isDeprecationLogIndexingEnabled={isDeprecationLogIndexingEnabled}
isLoading={isLoading}
isUpdating={isUpdating}
fetchError={fetchError}
updateError={updateError}
resendRequest={resendRequest}
toggleLogging={toggleLogging}
/>
{hasPrivileges && isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="xl" />
<EuiText data-test-subj="externalLinksTitle">
<h4>{i18nTexts.analyzeTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<DiscoverExternalLinks
checkpoint={checkpoint}
showInfoParagraph={true}
isButtonFormat={false}
/>
<EuiSpacer size="xl" />
<EuiText data-test-subj="apiCompatibilityNoteTitle">
<h4>{i18nTexts.apiCompatibilityNoteTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<EuiText>
<p>
{i18nTexts.apiCompatibilityNoteBody(
docLinks.links.elasticsearch.apiCompatibilityHeader
)}
</p>
</EuiText>
</>
)}
</EuiFlyoutBody>
)}
</WithPrivileges>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={closeFlyout}
flush="left"
data-test-subj="closeEsDeprecationLogs"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.closeFlyout"
defaultMessage="Close"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<WithPrivileges privileges={`index.${DEPRECATION_LOGS_INDEX}`}>
{({ hasPrivileges }) => (
<>
{hasPrivileges && isDeprecationLogIndexingEnabled && (
<ResetCounterButton setCheckpoint={setCheckpoint} />
)}
</>
)}
</WithPrivileges>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</>
);
};

View file

@ -10,7 +10,7 @@ import { buildPhrasesFilter, PhrasesFilter } from '@kbn/es-query';
import { FormattedMessage } from '@kbn/i18n-react';
import { METRIC_TYPE } from '@kbn/analytics';
import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
import { EuiLink, EuiSpacer, EuiText, EuiButton } from '@elastic/eui';
import { DataView } from '@kbn/data-views-plugin/common';
import {
APPS_WITH_DEPRECATION_LOGS,
@ -25,6 +25,8 @@ import { DEPRECATION_LOGS_INDEX_PATTERN } from '../../../../../common/constants'
interface Props {
checkpoint: string;
deprecationDataView: DataView;
isButtonFormat: boolean;
showInfoParagraph: boolean;
}
export const getDeprecationDataView = async (dataService: DataPublicPluginStart) => {
@ -56,7 +58,11 @@ export const getDeprecationDataView = async (dataService: DataPublicPluginStart)
}
};
const DiscoverAppLink: FunctionComponent<Props> = ({ checkpoint, deprecationDataView }) => {
const DiscoverAppLink: FunctionComponent<Omit<Props, 'showInfoParagraph'>> = ({
checkpoint,
deprecationDataView,
isButtonFormat,
}) => {
const {
services: { data: dataService },
plugins: { share },
@ -104,25 +110,39 @@ const DiscoverAppLink: FunctionComponent<Props> = ({ checkpoint, deprecationData
return null;
}
return (
const handleClick = () => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_DISCOVER_CLICK);
};
const content = (
<FormattedMessage
id="xpack.upgradeAssistant.overview.viewDiscoverResultsAction"
defaultMessage="Analyze logs in Discover"
/>
);
return isButtonFormat ? (
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink
<EuiButton
href={discoveryUrl}
onClick={() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_DISCOVER_CLICK);
}}
data-test-subj="viewDiscoverLogs"
onClick={handleClick}
data-test-subj="viewDiscoverLogsButton"
fill
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.viewDiscoverResultsAction"
defaultMessage="Analyze logs in Discover"
/>
{content}
</EuiButton>
) : (
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink href={discoveryUrl} onClick={handleClick} data-test-subj="viewDiscoverLogs">
<EuiText> {content}</EuiText>
</EuiLink>
);
};
export const ExternalLinks: FunctionComponent<Omit<Props, 'deprecationDataView'>> = ({
export const DiscoverExternalLinks: FunctionComponent<Omit<Props, 'deprecationDataView'>> = ({
checkpoint,
showInfoParagraph,
isButtonFormat,
}) => {
const {
services: { data: dataService },
@ -140,19 +160,27 @@ export const ExternalLinks: FunctionComponent<Omit<Props, 'deprecationDataView'>
}, [dataService, checkpoint, share.url.locators]);
return (
<>
<EuiText size="s">
<p>
<FormattedMessage
id="xpack.upgradeAssistant.overview.observe.discoveryDescription"
defaultMessage="Search and filter the deprecation logs to understand the types of changes you need to make."
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<React.Fragment>
{showInfoParagraph && (
<>
<EuiText>
<p>
<FormattedMessage
id="xpack.upgradeAssistant.overview.observe.discoveryDescription"
defaultMessage="Search and filter the deprecation logs to understand the types of changes you need to make."
/>
</p>
</EuiText>
<EuiSpacer size="m" />
</>
)}
{deprecationDataView ? (
<DiscoverAppLink checkpoint={checkpoint} deprecationDataView={deprecationDataView} />
<DiscoverAppLink
checkpoint={checkpoint}
deprecationDataView={deprecationDataView}
isButtonFormat={isButtonFormat}
/>
) : null}
</>
</React.Fragment>
);
};

View file

@ -1,204 +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, useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiText, EuiSpacer, EuiLink, EuiCallOut, EuiCode } from '@elastic/eui';
import { useAppContext } from '../../../app_context';
import { ExternalLinks } from './external_links';
import { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint';
import { useDeprecationLogging } from './use_deprecation_logging';
import { DeprecationLoggingToggle } from './deprecation_logging_toggle';
import { loadLogsCheckpoint, saveLogsCheckpoint } from '../../../lib/logs_checkpoint';
import { DEPRECATION_LOGS_INDEX } from '../../../../../common/constants';
import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports';
const i18nTexts = {
analyzeTitle: i18n.translate('xpack.upgradeAssistant.overview.analyzeTitle', {
defaultMessage: 'Analyze deprecation logs',
}),
deprecationsCountCheckpointTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle',
{
defaultMessage: 'Resolve deprecation issues and verify your changes',
}
),
apiCompatibilityNoteTitle: i18n.translate(
'xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle',
{
defaultMessage: 'Apply API compatibility headers (optional)',
}
),
apiCompatibilityNoteBody: (docLink: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteBody"
defaultMessage="We recommend you resolve all deprecation issues before upgrading. If needed, you can apply API compatibility headers to requests that use deprecated features. {learnMoreLink}."
values={{
learnMoreLink: (
<EuiLink href={docLink} target="_blank">
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
),
onlyLogWritingEnabledTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningTitle',
{
defaultMessage: 'Your logs are being written to the logs directory',
}
),
onlyLogWritingEnabledBody: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningBody',
{
defaultMessage:
'Go to your logs directory to view the deprecation logs or enable deprecation log collection to see them in Kibana.',
}
),
deniedPrivilegeTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeTitle',
{
defaultMessage: 'You require index privileges to analyze the deprecation logs',
}
),
deniedPrivilegeDescription: (privilegesMissing: MissingPrivileges) => (
// NOTE: hardcoding the missing privilege because the WithPrivileges HOC
// doesnt provide a way to retrieve which specific privileges an index
// is missing.
<FormattedMessage
id="xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeDescription"
defaultMessage="The deprecation logs will continue to be indexed, but you won't be able to analyze them until you have the read index {privilegesCount, plural, one {privilege} other {privileges}} for: {missingPrivileges}"
values={{
missingPrivileges: (
<EuiCode transparentBackground={true}>{privilegesMissing?.index?.join(', ')}</EuiCode>
),
privilegesCount: privilegesMissing?.index?.length,
}}
/>
),
};
interface Props {
hasPrivileges: boolean;
privilegesMissing: MissingPrivileges;
}
const FixDeprecationLogsUI: FunctionComponent<Props> = ({ hasPrivileges, privilegesMissing }) => {
const {
services: {
core: { docLinks },
},
} = useAppContext();
const {
isDeprecationLogIndexingEnabled,
onlyDeprecationLogWritingEnabled,
isLoading,
isUpdating,
fetchError,
updateError,
resendRequest,
toggleLogging,
} = useDeprecationLogging();
const [checkpoint, setCheckpoint] = useState(loadLogsCheckpoint());
useEffect(() => {
saveLogsCheckpoint(checkpoint);
}, [checkpoint]);
return (
<>
<DeprecationLoggingToggle
isDeprecationLogIndexingEnabled={isDeprecationLogIndexingEnabled}
isLoading={isLoading}
isUpdating={isUpdating}
fetchError={fetchError}
updateError={updateError}
resendRequest={resendRequest}
toggleLogging={toggleLogging}
/>
{onlyDeprecationLogWritingEnabled && (
<>
<EuiSpacer size="m" />
<EuiCallOut
title={i18nTexts.onlyLogWritingEnabledTitle}
color="warning"
iconType="help"
data-test-subj="deprecationWarningCallout"
>
<p>{i18nTexts.onlyLogWritingEnabledBody}</p>
</EuiCallOut>
</>
)}
{!hasPrivileges && isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="m" />
<EuiCallOut
iconType="help"
color="warning"
title={i18nTexts.deniedPrivilegeTitle}
data-test-subj="noIndexPermissionsCallout"
>
<p>{i18nTexts.deniedPrivilegeDescription(privilegesMissing)}</p>
</EuiCallOut>
</>
)}
{hasPrivileges && isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="xl" />
<EuiText data-test-subj="externalLinksTitle">
<h4>{i18nTexts.analyzeTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<ExternalLinks checkpoint={checkpoint} />
<EuiSpacer size="xl" />
<EuiText data-test-subj="deprecationsCountTitle">
<h4>{i18nTexts.deprecationsCountCheckpointTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<DeprecationsCountCheckpoint checkpoint={checkpoint} setCheckpoint={setCheckpoint} />
<EuiSpacer size="xl" />
<EuiText data-test-subj="apiCompatibilityNoteTitle">
<h4>{i18nTexts.apiCompatibilityNoteTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<EuiText>
<p>
{i18nTexts.apiCompatibilityNoteBody(
docLinks.links.elasticsearch.apiCompatibilityHeader
)}
</p>
</EuiText>
</>
)}
</>
);
};
export const FixDeprecationLogs = () => {
return (
<WithPrivileges privileges={`index.${DEPRECATION_LOGS_INDEX}`}>
{({ hasPrivileges, privilegesMissing, isLoading }) => (
<FixDeprecationLogsUI
hasPrivileges={!isLoading && hasPrivileges}
privilegesMissing={privilegesMissing}
/>
)}
</WithPrivileges>
);
};

View file

@ -4,6 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { FixDeprecationLogs } from './fix_deprecation_logs';
export { EsDeprecationLogsFlyout as FixDeprecationLogsFlyout } from './es_deprecation_logs_flyout';
export type { EsDeprecationLogsFlyoutProps as FixDeprecationLogsFlyoutProps } from './es_deprecation_logs_flyout';
export { useDeprecationLogging } from './use_deprecation_logging';

View file

@ -5,5 +5,4 @@
* 2.0.
*/
export { EsDeprecationLogs } from './es_deprecation_logs';
export { useDeprecationLogging } from './fix_deprecation_logs';

View file

@ -7,5 +7,4 @@
export { KibanaDeprecations } from './kibana_deprecations';
export { EsDeprecations } from './es_deprecations';
export { EsDeprecationLogs } from './es_deprecation_logs';
export { Overview } from './overview';

View file

@ -5,9 +5,17 @@
* 2.0.
*/
import React, { useEffect } from 'react';
import React, { useEffect, useState, useCallback } from 'react';
import { EuiText, EuiSpacer, EuiButton, EuiCallOut, EuiSkeletonText, EuiCode } from '@elastic/eui';
import {
EuiText,
EuiSpacer,
EuiButton,
EuiCallOut,
EuiSkeletonText,
EuiCode,
EuiFlexGroup,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n-react';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';
@ -17,11 +25,16 @@ import {
APP_LOGS_COUNT_CLUSTER_PRIVILEGES,
APP_LOGS_COUNT_INDEX_PRIVILEGES,
} from '../../../../../common/constants';
import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports';
import { WithPrivileges, MissingPrivileges, GlobalFlyout } from '../../../../shared_imports';
import { useAppContext } from '../../../app_context';
import { loadLogsCheckpoint } from '../../../lib/logs_checkpoint';
import type { OverviewStepProps } from '../../types';
import { useDeprecationLogging } from '../../es_deprecation_logs';
import { DiscoverExternalLinks } from '../../es_deprecation_logs/fix_deprecation_logs/external_links';
import {
EsDeprecationLogsFlyout,
EsDeprecationLogsFlyoutProps,
} from '../../es_deprecation_logs/fix_deprecation_logs/es_deprecation_logs_flyout';
const i18nTexts = {
logsStepTitle: i18n.translate('xpack.upgradeAssistant.overview.logsStep.title', {
@ -30,10 +43,10 @@ const i18nTexts = {
logsStepDescription: i18n.translate('xpack.upgradeAssistant.overview.logsStep.description', {
defaultMessage: `Review the Elasticsearch deprecation logs to ensure you're not using deprecated APIs.`,
}),
viewLogsButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel',
viewDetailsButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.logsStep.viewDetailsButtonLabel',
{
defaultMessage: 'View logs',
defaultMessage: 'View details',
}
),
enableLogsButtonLabel: i18n.translate(
@ -101,11 +114,13 @@ const i18nTexts = {
}),
};
const FLYOUT_ID = 'deprecationLogsFlyout';
const { useGlobalFlyout } = GlobalFlyout;
interface LogStepProps {
setIsComplete: (isComplete: boolean) => void;
hasPrivileges: boolean;
privilegesMissing: MissingPrivileges;
navigateToEsDeprecationLogs: () => void;
}
const LogStepDescription = () => (
@ -114,17 +129,13 @@ const LogStepDescription = () => (
</EuiText>
);
const LogsStep = ({
setIsComplete,
hasPrivileges,
privilegesMissing,
navigateToEsDeprecationLogs,
}: LogStepProps) => {
const LogsStep = ({ setIsComplete, hasPrivileges, privilegesMissing }: LogStepProps) => {
const {
services: { api },
} = useAppContext();
const { isDeprecationLogIndexingEnabled } = useDeprecationLogging();
const { isDeprecationLogIndexingEnabled, resendRequest: refreshDeprecationLogging } =
useDeprecationLogging();
const checkpoint = loadLogsCheckpoint();
@ -147,6 +158,36 @@ const LogsStep = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDeprecationLogIndexingEnabled, logsCount]);
const [showFlyout, setShowFlyout] = useState(false);
const { addContent: addContentToGlobalFlyout, removeContent: removeContentFromGlobalFlyout } =
useGlobalFlyout();
const closeFlyout = useCallback(() => {
setShowFlyout(false);
removeContentFromGlobalFlyout(FLYOUT_ID);
}, [removeContentFromGlobalFlyout]);
const handleToggleChange = useCallback(() => {
refreshDeprecationLogging();
}, [refreshDeprecationLogging]);
useEffect(() => {
if (showFlyout) {
addContentToGlobalFlyout<EsDeprecationLogsFlyoutProps>({
id: FLYOUT_ID,
Component: EsDeprecationLogsFlyout,
props: {
closeFlyout,
handleToggleChange,
},
flyoutProps: {
onClose: closeFlyout,
},
});
}
}, [addContentToGlobalFlyout, closeFlyout, handleToggleChange, showFlyout]);
if (hasPrivileges === false && isDeprecationLogIndexingEnabled) {
return (
<>
@ -223,16 +264,22 @@ const LogsStep = ({
</EuiText>
<EuiSpacer />
<EuiButton onClick={navigateToEsDeprecationLogs} data-test-subj="viewLogsLink">
{i18nTexts.viewLogsButtonLabel}
</EuiButton>
<EuiFlexGroup responsive={false} wrap gutterSize="s" alignItems="center">
<DiscoverExternalLinks
checkpoint={checkpoint}
showInfoParagraph={false}
isButtonFormat={true}
/>
<EuiButton onClick={() => setShowFlyout(true)} data-test-subj="viewDetailsLink">
{i18nTexts.viewDetailsButtonLabel}
</EuiButton>
</EuiFlexGroup>
</>
) : (
<>
<EuiSpacer />
<EuiButton onClick={navigateToEsDeprecationLogs} data-test-subj="enableLogsLink">
<EuiButton onClick={() => setShowFlyout(true)} data-test-subj="enableLogsLink">
{i18nTexts.enableLogsButtonLabel}
</EuiButton>
</>
@ -242,15 +289,7 @@ const LogsStep = ({
);
};
interface CustomProps {
navigateToEsDeprecationLogs: () => void;
}
export const getLogsStep = ({
isComplete,
setIsComplete,
navigateToEsDeprecationLogs,
}: OverviewStepProps & CustomProps): EuiStepProps => {
export const getLogsStep = ({ isComplete, setIsComplete }: OverviewStepProps): EuiStepProps => {
const status = isComplete ? 'complete' : 'incomplete';
const requiredPrivileges = [
@ -268,7 +307,6 @@ export const getLogsStep = ({
<LogsStep
setIsComplete={setIsComplete}
hasPrivileges={!isLoading && hasPrivileges}
navigateToEsDeprecationLogs={navigateToEsDeprecationLogs}
privilegesMissing={privilegesMissing}
/>
)}

View file

@ -135,7 +135,6 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => {
getLogsStep({
isComplete: isStepComplete('logs'),
setIsComplete: setCompletedStep.bind(null, 'logs'),
navigateToEsDeprecationLogs: () => history.push('/es_deprecation_logs'),
}),
getUpgradeStep(),
].filter(Boolean) as EuiStepProps[]

View file

@ -18,9 +18,6 @@ const i18nTexts = {
esDeprecations: i18n.translate('xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel', {
defaultMessage: 'Elasticsearch deprecation issues',
}),
esDeprecationLogs: i18n.translate('xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel', {
defaultMessage: 'Elasticsearch deprecation logs',
}),
kibanaDeprecations: i18n.translate(
'xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel',
{
@ -51,15 +48,6 @@ export class BreadcrumbService {
text: i18nTexts.breadcrumbs.esDeprecations,
},
],
esDeprecationLogs: [
{
text: i18nTexts.breadcrumbs.overview,
href: '/',
},
{
text: i18nTexts.breadcrumbs.esDeprecationLogs,
},
],
kibanaDeprecations: [
{
text: i18nTexts.breadcrumbs.overview,
@ -77,9 +65,7 @@ export class BreadcrumbService {
this.setBreadcrumbsHandler = setBreadcrumbsHandler;
}
public setBreadcrumbs(
type: 'overview' | 'esDeprecations' | 'esDeprecationLogs' | 'kibanaDeprecations'
): void {
public setBreadcrumbs(type: 'overview' | 'esDeprecations' | 'kibanaDeprecations'): void {
if (!this.setBreadcrumbsHandler) {
throw new Error('Breadcrumb service has not been initialized');
}

View file

@ -66,12 +66,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
});
describe('ES deprecations logs page', () => {
describe('ES deprecations logs flyout', () => {
beforeEach(async () => {
await PageObjects.upgradeAssistant.navigateToEsDeprecationLogs();
await PageObjects.upgradeAssistant.navigateToPage();
});
it('with logs collection disabled', async () => {
await PageObjects.upgradeAssistant.clickOpenEsDeprecationsFlyoutButton();
const loggingEnabled = await PageObjects.upgradeAssistant.isDeprecationLoggingEnabled();
if (loggingEnabled) {
await PageObjects.upgradeAssistant.clickDeprecationLoggingToggle();
@ -84,6 +85,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('with logs collection enabled', async () => {
await PageObjects.upgradeAssistant.clickOpenEsDeprecationsFlyoutButton();
const loggingEnabled = await PageObjects.upgradeAssistant.isDeprecationLoggingEnabled();
if (!loggingEnabled) {
await PageObjects.upgradeAssistant.clickDeprecationLoggingToggle();

View file

@ -16,7 +16,7 @@ export default function upgradeAssistantESDeprecationLogsPageFunctionalTests({
const testSubjects = getService('testSubjects');
const es = getService('es');
describe('ES deprecation logs page', function () {
describe('ES deprecation logs flyout', function () {
this.tags(['skipFirefox', 'upgradeAssistant']);
before(async () => {
@ -30,7 +30,8 @@ export default function upgradeAssistantESDeprecationLogsPageFunctionalTests({
});
beforeEach(async () => {
await PageObjects.upgradeAssistant.navigateToEsDeprecationLogs();
await PageObjects.upgradeAssistant.navigateToPage();
await PageObjects.upgradeAssistant.clickVerifyLoggingButton();
});
it('Shows warnings callout if there are deprecations', async () => {

View file

@ -48,7 +48,7 @@ import { SnapshotRestorePageProvider } from './snapshot_restore_page';
import { SpaceSelectorPageObject } from './space_selector_page';
import { StatusPageObject } from './status_page';
import { TagManagementPageObject } from './tag_management_page';
import { UpgradeAssistantPageObject } from './upgrade_assistant_page';
import { UpgradeAssistantFlyoutObject } from './upgrade_assistant_page';
import { UptimePageObject } from './uptime_page';
import { UserProfilePageProvider } from './user_profile_page';
import { WatcherPageObject } from './watcher_page';
@ -106,7 +106,7 @@ export const pageObjects = {
spaceSelector: SpaceSelectorPageObject,
statusPage: StatusPageObject,
tagManagement: TagManagementPageObject,
upgradeAssistant: UpgradeAssistantPageObject,
upgradeAssistant: UpgradeAssistantFlyoutObject,
uptime: UptimePageObject,
userProfiles: UserProfilePageProvider,
watcher: WatcherPageObject,

View file

@ -7,7 +7,7 @@
import { FtrService } from '../ftr_provider_context';
export class UpgradeAssistantPageObject extends FtrService {
export class UpgradeAssistantFlyoutObject extends FtrService {
private readonly retry = this.ctx.getService('retry');
private readonly log = this.ctx.getService('log');
private readonly browser = this.ctx.getService('browser');
@ -30,18 +30,27 @@ export class UpgradeAssistantPageObject extends FtrService {
});
}
async navigateToEsDeprecationLogs() {
async clickVerifyLoggingButton() {
return await this.retry.try(async () => {
await this.common.navigateToUrl('management', 'stack/upgrade_assistant/es_deprecation_logs', {
shouldUseHashForSubUrl: false,
});
await this.retry.waitFor(
'url to contain /upgrade_assistant/es_deprecation_logs',
async () => {
const url = await this.browser.getCurrentUrl();
return url.includes('/es_deprecation_logs');
}
);
await this.testSubjects.click('viewDetailsLink');
});
}
async clickEnableLoggingButton() {
return await this.retry.try(async () => {
await this.testSubjects.click('enableLogsLink');
});
}
async clickOpenEsDeprecationsFlyoutButton() {
return await this.retry.try(async () => {
if (await this.testSubjects.exists('enableLogsLink')) {
await this.clickEnableLoggingButton();
} else if (await this.testSubjects.exists('viewDetailsLink')) {
await this.clickVerifyLoggingButton();
} else {
this.log.debug('No relevant button found to open ES Deprecations Flyout');
}
});
}