diff --git a/x-pack/plugins/snapshot_restore/kibana.json b/x-pack/plugins/snapshot_restore/kibana.json index bd2a85126c0c6..66c4023337af1 100644 --- a/x-pack/plugins/snapshot_restore/kibana.json +++ b/x-pack/plugins/snapshot_restore/kibana.json @@ -7,7 +7,7 @@ "name": "Stack Management", "githubTeam": "kibana-stack-management" }, - "requiredPlugins": ["licensing", "management", "features"], + "requiredPlugins": ["licensing", "management", "features", "share"], "optionalPlugins": ["usageCollection", "security", "cloud", "home"], "configPath": ["xpack", "snapshot_restore"], "requiredBundles": ["esUiShared", "kibanaReact", "home"] diff --git a/x-pack/plugins/snapshot_restore/public/locator.ts b/x-pack/plugins/snapshot_restore/public/locator.ts new file mode 100644 index 0000000000000..ba57446a03887 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/locator.ts @@ -0,0 +1,45 @@ +/* + * 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 { SerializableRecord } from '@kbn/utility-types'; +import { ManagementAppLocator } from 'src/plugins/management/common'; +import { LocatorDefinition } from '../../../../src/plugins/share/public/'; +import { linkToSnapshots } from './application/services/navigation'; +import { PLUGIN } from '../common/constants'; + +export const SNAPSHOT_RESTORE_LOCATOR_ID = 'SNAPSHOT_RESTORE_LOCATOR'; + +export interface SnapshotRestoreLocatorParams extends SerializableRecord { + page: 'snapshots'; +} + +export interface SnapshotRestoreLocatorDefinitionDependencies { + managementAppLocator: ManagementAppLocator; +} + +export class SnapshotRestoreLocatorDefinition + implements LocatorDefinition { + constructor(protected readonly deps: SnapshotRestoreLocatorDefinitionDependencies) {} + + public readonly id = SNAPSHOT_RESTORE_LOCATOR_ID; + + public readonly getLocation = async (params: SnapshotRestoreLocatorParams) => { + const location = await this.deps.managementAppLocator.getLocation({ + sectionId: 'data', + appId: PLUGIN.id, + }); + + switch (params.page) { + case 'snapshots': { + return { + ...location, + path: location.path + linkToSnapshots(), + }; + } + } + }; +} diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts index fbd59db531d9e..bb091a1fd1831 100644 --- a/x-pack/plugins/snapshot_restore/public/plugin.ts +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -7,13 +7,14 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, PluginInitializerContext } from 'src/core/public'; - -import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; -import { ManagementSetup } from '../../../../src/plugins/management/public'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; +import { ManagementSetup } from 'src/plugins/management/public'; +import { SharePluginSetup } from 'src/plugins/share/public'; import { FeatureCatalogueCategory, HomePublicPluginSetup, } from '../../../../src/plugins/home/public'; + import { PLUGIN } from '../common/constants'; import { ClientConfigType } from './types'; @@ -22,10 +23,12 @@ import { httpService, setUiMetricService } from './application/services/http'; import { textService } from './application/services/text'; import { UiMetricService } from './application/services'; import { UIM_APP_NAME } from './application/constants'; +import { SnapshotRestoreLocatorDefinition } from './locator'; interface PluginsDependencies { usageCollection: UsageCollectionSetup; management: ManagementSetup; + share: SharePluginSetup; home?: HomePublicPluginSetup; } @@ -79,6 +82,12 @@ export class SnapshotRestoreUIPlugin { order: 630, }); } + + plugins.share.url.locators.create( + new SnapshotRestoreLocatorDefinition({ + managementAppLocator: plugins.management.locator, + }) + ); } public start() {} diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts index ce9a1fbf79197..b8d8e3d2505ef 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts @@ -11,12 +11,24 @@ import { notificationServiceMock, applicationServiceMock, } from 'src/core/public/mocks'; +import { sharePluginMock } from 'src/plugins/share/public/mocks'; import { HttpSetup } from 'src/core/public'; import { mockKibanaSemverVersion } from '../../../common/constants'; import { apiService } from '../../../public/application/lib/api'; import { breadcrumbService } from '../../../public/application/lib/breadcrumbs'; +// We'll mock these values to avoid testing the locators themselves. +const idToUrlMap = { + SNAPSHOT_RESTORE_LOCATOR: 'snapshotAndRestoreUrl', +}; + +const shareMock = sharePluginMock.createSetupContract(); +shareMock.url.locators.get = (id) => ({ + // @ts-expect-error This object is missing some properties that we're not using in the UI + getUrl: (): string | undefined => idToUrlMap[id], +}); + export const getAppContextMock = (mockHttpClient: HttpSetup) => ({ http: mockHttpClient, docLinks: docLinksServiceMock.createStartContract(), @@ -31,4 +43,5 @@ export const getAppContextMock = (mockHttpClient: HttpSetup) => ({ breadcrumbs: breadcrumbService, getUrlForApp: applicationServiceMock.createStartContract().getUrlForApp, deprecations: deprecationsServiceMock.createStartContract(), + share: shareMock, }); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx new file mode 100644 index 0000000000000..ab571790d56c6 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/backup_step/backup_step.test.tsx @@ -0,0 +1,31 @@ +/* + * 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 { setupEnvironment } from '../../helpers'; +import { OverviewTestBed, setupOverviewPage } from '../overview.helpers'; + +describe('Overview - Backup Step', () => { + let testBed: OverviewTestBed; + const { server } = setupEnvironment(); + + beforeEach(async () => { + testBed = await setupOverviewPage(); + testBed.component.update(); + }); + + afterAll(() => { + server.restore(); + }); + + describe('On-prem', () => { + test('Shows link to Snapshot and Restore', () => { + const { exists, find } = testBed; + expect(exists('snapshotRestoreLink')).toBe(true); + expect(find('snapshotRestoreLink').props().href).toBe('snapshotAndRestoreUrl'); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx index 617aea19a129d..61fc6b45fa4c7 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/upgrade_step/upgrade_step.test.tsx @@ -23,15 +23,17 @@ describe('Overview - Upgrade Step', () => { server.restore(); }); - describe('Step 3 - Upgrade stack', () => { - test('Shows link to setup upgrade docs for on-prem installations', () => { + describe('On-prem', () => { + test('Shows link to setup upgrade docs', () => { const { exists } = testBed; expect(exists('upgradeSetupDocsLink')).toBe(true); expect(exists('upgradeSetupCloudLink')).toBe(false); }); + }); - test('Shows upgrade cta and link to docs for cloud installations', async () => { + describe('On Cloud', () => { + test('Shows upgrade CTA and link to docs', async () => { await act(async () => { testBed = await setupOverviewPage({ kibanaContextOverrides: { @@ -47,8 +49,8 @@ describe('Overview - Upgrade Step', () => { const { component, exists, find } = testBed; component.update(); - expect(exists('upgradeSetupCloudLink')).toBe(true); expect(exists('upgradeSetupDocsLink')).toBe(true); + expect(exists('upgradeSetupCloudLink')).toBe(true); expect(find('upgradeSetupCloudLink').props().href).toBe( 'https://cloud.elastic.co./deployments/bfdad4ef99a24212a06d387593686d63' diff --git a/x-pack/plugins/upgrade_assistant/kibana.json b/x-pack/plugins/upgrade_assistant/kibana.json index e66f25318a28c..a250ecd55f1a9 100644 --- a/x-pack/plugins/upgrade_assistant/kibana.json +++ b/x-pack/plugins/upgrade_assistant/kibana.json @@ -8,7 +8,7 @@ "githubTeam": "kibana-stack-management" }, "configPath": ["xpack", "upgrade_assistant"], - "requiredPlugins": ["management", "discover", "data", "licensing", "features", "infra"], + "requiredPlugins": ["management", "discover", "data", "licensing", "features", "infra", "share"], "optionalPlugins": ["usageCollection", "cloud"], "requiredBundles": ["esUiShared", "kibanaReact"] } diff --git a/x-pack/plugins/upgrade_assistant/public/application/app_context.tsx b/x-pack/plugins/upgrade_assistant/public/application/app_context.tsx index 88b5bd4721c36..9543c1c4db385 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/app_context.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app_context.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React, { createContext, useContext } from 'react'; import { CoreStart, DeprecationsServiceStart, @@ -12,7 +13,7 @@ import { HttpSetup, NotificationsStart, } from 'src/core/public'; -import React, { createContext, useContext } from 'react'; +import { SharePluginSetup } from 'src/plugins/share/public'; import { ApiService } from './lib/api'; import { BreadcrumbService } from './lib/breadcrumbs'; @@ -32,6 +33,7 @@ export interface ContextValue { breadcrumbs: BreadcrumbService; getUrlForApp: CoreStart['application']['getUrlForApp']; deprecations: DeprecationsServiceStart; + share: SharePluginSetup; } export const AppContext = createContext({} as any); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/backup_step/backup_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/backup_step/backup_step.tsx new file mode 100644 index 0000000000000..006d8ed3d38ae --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/backup_step/backup_step.tsx @@ -0,0 +1,76 @@ +/* + * 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 { EuiText, EuiButton, EuiSpacer } from '@elastic/eui'; +import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; + +import { useAppContext } from '../../../app_context'; + +const i18nTexts = { + backupStepTitle: i18n.translate('xpack.upgradeAssistant.overview.backupStepTitle', { + defaultMessage: 'Back up your data', + }), + + backupStepDescription: i18n.translate('xpack.upgradeAssistant.overview.backupStepDescription', { + defaultMessage: 'Back up your data before addressing any deprecation issues.', + }), +}; + +const SnapshotRestoreAppLink: React.FunctionComponent = () => { + const { share } = useAppContext(); + + const [snapshotRestoreUrl, setSnapshotRestoreUrl] = useState(); + + useEffect(() => { + const getSnapshotRestoreUrl = async () => { + const locator = share.url.locators.get('SNAPSHOT_RESTORE_LOCATOR'); + + if (!locator) { + return; + } + + const url = await locator.getUrl({ + page: 'snapshots', + }); + setSnapshotRestoreUrl(url); + }; + + getSnapshotRestoreUrl(); + }, [share]); + + return ( + + {i18n.translate('xpack.upgradeAssistant.overview.snapshotRestoreLink', { + defaultMessage: 'Create snapshot', + })} + + ); +}; + +const BackupStep: React.FunctionComponent = () => { + return ( + <> + +

{i18nTexts.backupStepDescription}

+
+ + + + + + ); +}; + +export const getBackupStep = (): EuiStepProps => { + return { + title: i18nTexts.backupStepTitle, + status: 'incomplete', + children: , + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/backup_step/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/backup_step/index.ts new file mode 100644 index 0000000000000..8daac9645fa12 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/backup_step/index.ts @@ -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 { getBackupStep } from './backup_step'; 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 3f6bf25e9abf0..cae6a6e263550 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 @@ -21,6 +21,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { useAppContext } from '../../app_context'; +import { getBackupStep } from './backup_step'; import { getFixIssuesStep } from './fix_issues_step'; import { getFixLogsStep } from './fix_logs_step'; import { getUpgradeStep } from './upgrade_step'; @@ -83,6 +84,7 @@ export const Overview: FunctionComponent = () => { { + const { element, ...appDependencies } = deps; + render(, element); + return () => { + unmountComponentAtNode(element); + }; +}; + export async function mountManagementSection( coreSetup: CoreSetup, params: ManagementAppMountParams, kibanaVersionInfo: KibanaVersionContext, readonly: boolean, + share: SharePluginSetup, services: AppServicesContext ) { const [ @@ -44,6 +61,7 @@ export async function mountManagementSection( getUrlForApp: application.getUrlForApp, deprecations, application, + share, services, }); } diff --git a/x-pack/plugins/upgrade_assistant/public/application/render_app.tsx b/x-pack/plugins/upgrade_assistant/public/application/render_app.tsx deleted file mode 100644 index 248e6961a74e5..0000000000000 --- a/x-pack/plugins/upgrade_assistant/public/application/render_app.tsx +++ /dev/null @@ -1,22 +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 { render, unmountComponentAtNode } from 'react-dom'; -import { AppDependencies, RootComponent } from './app'; - -interface BootDependencies extends AppDependencies { - element: HTMLElement; -} - -export const renderApp = (deps: BootDependencies) => { - const { element, ...appDependencies } = deps; - render(, element); - return () => { - unmountComponentAtNode(element); - }; -}; diff --git a/x-pack/plugins/upgrade_assistant/public/plugin.ts b/x-pack/plugins/upgrade_assistant/public/plugin.ts index 558deffe43d94..ca7ee174b20f5 100644 --- a/x-pack/plugins/upgrade_assistant/public/plugin.ts +++ b/x-pack/plugins/upgrade_assistant/public/plugin.ts @@ -15,7 +15,7 @@ import { Config } from '../common/config'; export class UpgradeAssistantUIPlugin implements Plugin { constructor(private ctx: PluginInitializerContext) {} - setup(coreSetup: CoreSetup, { management, cloud }: SetupDependencies) { + setup(coreSetup: CoreSetup, { management, cloud, share }: SetupDependencies) { const { enabled, readonly } = this.ctx.config.get(); if (!enabled) { @@ -56,6 +56,7 @@ export class UpgradeAssistantUIPlugin params, kibanaVersionInfo, readonly, + share, services ); diff --git a/x-pack/plugins/upgrade_assistant/public/types.ts b/x-pack/plugins/upgrade_assistant/public/types.ts index a2b49305c32d4..356a2e22c3c7f 100644 --- a/x-pack/plugins/upgrade_assistant/public/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/types.ts @@ -8,19 +8,22 @@ import { DiscoverStart } from 'src/plugins/discover/public'; import { ManagementSetup } from 'src/plugins/management/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { SharePluginSetup } from 'src/plugins/share/public'; import { CloudSetup } from '../../cloud/public'; import { LicensingPluginStart } from '../../licensing/public'; export interface AppServicesContext { - cloud?: CloudSetup; discover: DiscoverStart; data: DataPublicPluginStart; + cloud?: CloudSetup; } export interface SetupDependencies { management: ManagementSetup; + share: SharePluginSetup; cloud?: CloudSetup; } + export interface StartDependencies { licensing: LicensingPluginStart; discover: DiscoverStart;