diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index 788ec1f145e2a5..46f09a8ebb8796 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -203,6 +203,7 @@ export function renderApp( }); return () => { + chrome.docTitle.reset(); ReactDOM.unmountComponentAtNode(element); unlisten(); }; diff --git a/x-pack/plugins/cross_cluster_replication/public/plugin.ts b/x-pack/plugins/cross_cluster_replication/public/plugin.ts index 7aa0d19fa976f7..80e67110c20c71 100644 --- a/x-pack/plugins/cross_cluster_replication/public/plugin.ts +++ b/x-pack/plugins/cross_cluster_replication/public/plugin.ts @@ -45,12 +45,15 @@ export class CrossClusterReplicationPlugin implements Plugin { const [coreStart] = await getStartServices(); const { + chrome: { docTitle }, i18n: { Context: I18nContext }, docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, application: { getUrlForApp }, } = coreStart; - return mountApp({ + docTitle.change(PLUGIN.TITLE); + + const unmountAppCallback = await mountApp({ element, setBreadcrumbs, I18nContext, @@ -59,6 +62,11 @@ export class CrossClusterReplicationPlugin implements Plugin { history, getUrlForApp, }); + + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); diff --git a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx index 832d066dfa33b9..1d26aa53752a96 100644 --- a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx @@ -44,18 +44,26 @@ export class IndexLifecycleManagementPlugin { mount: async ({ element, history }) => { const [coreStart] = await getStartServices(); const { + chrome: { docTitle }, i18n: { Context: I18nContext }, docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, application: { navigateToApp }, } = coreStart; + docTitle.change(PLUGIN.TITLE); + // Initialize additional services. initDocumentation( `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/` ); const { renderApp } = await import('./application'); - return renderApp(element, I18nContext, history, navigateToApp); + const unmountAppCallback = renderApp(element, I18nContext, history, navigateToApp); + + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); diff --git a/x-pack/plugins/index_management/public/application/mount_management_section.ts b/x-pack/plugins/index_management/public/application/mount_management_section.ts index 6145ea410b0e8d..6257b68430cf07 100644 --- a/x-pack/plugins/index_management/public/application/mount_management_section.ts +++ b/x-pack/plugins/index_management/public/application/mount_management_section.ts @@ -4,11 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { CoreSetup } from 'src/core/public'; import { ManagementAppMountParams } from 'src/plugins/management/public/'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { IngestManagerSetup } from '../../../ingest_manager/public'; +import { PLUGIN } from '../../common/constants'; import { ExtensionsService } from '../services'; import { IndexMgmtMetricsType } from '../types'; import { AppDependencies } from './app_context'; @@ -34,7 +36,14 @@ export async function mountManagementSection( ) { const { element, setBreadcrumbs, history } = params; const [core] = await coreSetup.getStartServices(); - const { docLinks, fatalErrors, application } = core; + const { + docLinks, + fatalErrors, + application, + chrome: { docTitle }, + } = core; + + docTitle.change(PLUGIN.getI18nName(i18n)); breadcrumbService.setup(setBreadcrumbs); documentationService.setup(docLinks); @@ -53,5 +62,10 @@ export async function mountManagementSection( setBreadcrumbs, }; - return renderApp(element, { core, dependencies: appDependencies }); + const unmountAppCallback = renderApp(element, { core, dependencies: appDependencies }); + + return () => { + docTitle.reset(); + unmountAppCallback(); + }; } diff --git a/x-pack/plugins/ingest_pipelines/public/plugin.ts b/x-pack/plugins/ingest_pipelines/public/plugin.ts index 945e825c88fbd3..339068f185d1d4 100644 --- a/x-pack/plugins/ingest_pipelines/public/plugin.ts +++ b/x-pack/plugins/ingest_pipelines/public/plugin.ts @@ -14,22 +14,36 @@ import { Dependencies } from './types'; export class IngestPipelinesPlugin implements Plugin { public setup(coreSetup: CoreSetup, plugins: Dependencies): void { const { management, usageCollection } = plugins; - const { http } = coreSetup; + const { http, getStartServices } = coreSetup; // Initialize services uiMetricService.setup(usageCollection); apiService.setup(http, uiMetricService); + const pluginName = i18n.translate('xpack.ingestPipelines.appTitle', { + defaultMessage: 'Ingest Node Pipelines', + }); + management.sections.section.ingest.registerApp({ id: PLUGIN_ID, order: 1, - title: i18n.translate('xpack.ingestPipelines.appTitle', { - defaultMessage: 'Ingest Node Pipelines', - }), + title: pluginName, mount: async (params) => { + const [coreStart] = await getStartServices(); + + const { + chrome: { docTitle }, + } = coreStart; + + docTitle.change(pluginName); + const { mountManagementSection } = await import('./application/mount_management_section'); + const unmountAppCallback = await mountManagementSection(coreSetup, params); - return await mountManagementSection(coreSetup, params); + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); } diff --git a/x-pack/plugins/license_management/public/plugin.ts b/x-pack/plugins/license_management/public/plugin.ts index b99ea387121ee8..27e31726f9a196 100644 --- a/x-pack/plugins/license_management/public/plugin.ts +++ b/x-pack/plugins/license_management/public/plugin.ts @@ -55,22 +55,27 @@ export class LicenseManagementUIPlugin title: PLUGIN.title, order: 0, mount: async ({ element, setBreadcrumbs, history }) => { - const [core, { telemetry }] = await getStartServices(); + const [coreStart, { telemetry }] = await getStartServices(); const initialLicense = await plugins.licensing.license$.pipe(first()).toPromise(); // Setup documentation links - const { docLinks } = core; + const { + docLinks, + chrome: { docTitle }, + } = coreStart; const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks; const esBase = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}`; const appDocLinks = { security: `${esBase}/security-settings.html`, }; + docTitle.change(PLUGIN.title); + // Setup services this.breadcrumbService.setup(setBreadcrumbs); const appDependencies: AppDependencies = { - core, + core: coreStart, config, plugins: { licensing, @@ -87,8 +92,12 @@ export class LicenseManagementUIPlugin }; const { renderApp } = await import('./application'); + const unmountAppCallback = renderApp(element, appDependencies); - return renderApp(element, appDependencies); + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); diff --git a/x-pack/plugins/remote_clusters/public/plugin.ts b/x-pack/plugins/remote_clusters/public/plugin.ts index 33222dd7052e9c..24cb148d24d843 100644 --- a/x-pack/plugins/remote_clusters/public/plugin.ts +++ b/x-pack/plugins/remote_clusters/public/plugin.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, Plugin, CoreStart, PluginInitializerContext } from 'kibana/public'; +import { PLUGIN } from '../common/constants'; import { init as initBreadcrumbs } from './application/services/breadcrumb'; import { init as initDocumentation } from './application/services/documentation'; import { init as initHttp } from './application/services/http'; @@ -43,11 +44,14 @@ export class RemoteClustersUIPlugin mount: async ({ element, setBreadcrumbs, history }) => { const [core] = await getStartServices(); const { + chrome: { docTitle }, i18n: { Context: i18nContext }, docLinks, fatalErrors, } = core; + docTitle.change(PLUGIN.getI18nName()); + // Initialize services initBreadcrumbs(setBreadcrumbs); initDocumentation(docLinks); @@ -58,7 +62,17 @@ export class RemoteClustersUIPlugin const isCloudEnabled = Boolean(cloud?.isCloudEnabled); const { renderApp } = await import('./application'); - return renderApp(element, i18nContext, { isCloudEnabled }, history); + const unmountAppCallback = await renderApp( + element, + i18nContext, + { isCloudEnabled }, + history + ); + + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); } diff --git a/x-pack/plugins/rollup/public/plugin.ts b/x-pack/plugins/rollup/public/plugin.ts index 73ee675b089c82..49545f090d9232 100644 --- a/x-pack/plugins/rollup/public/plugin.ts +++ b/x-pack/plugins/rollup/public/plugin.ts @@ -75,21 +75,31 @@ export class RollupPlugin implements Plugin { }); } + const pluginName = i18n.translate('xpack.rollupJobs.appTitle', { + defaultMessage: 'Rollup Jobs', + }); + management.sections.section.data.registerApp({ id: 'rollup_jobs', - title: i18n.translate('xpack.rollupJobs.appTitle', { defaultMessage: 'Rollup Jobs' }), + title: pluginName, order: 4, async mount(params) { - params.setBreadcrumbs([ - { - text: i18n.translate('xpack.rollupJobs.breadcrumbsTitle', { - defaultMessage: 'Rollup Jobs', - }), - }, - ]); + const [coreStart] = await core.getStartServices(); + + const { + chrome: { docTitle }, + } = coreStart; + + docTitle.change(pluginName); + params.setBreadcrumbs([{ text: pluginName }]); + const { renderApp } = await import('./application'); + const unmountAppCallback = await renderApp(core, params); - return renderApp(core, params); + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); } diff --git a/x-pack/plugins/snapshot_restore/public/application/mount_management_section.ts b/x-pack/plugins/snapshot_restore/public/application/mount_management_section.ts index b06a60a5c830fb..eb2046f065e17d 100644 --- a/x-pack/plugins/snapshot_restore/public/application/mount_management_section.ts +++ b/x-pack/plugins/snapshot_restore/public/application/mount_management_section.ts @@ -48,7 +48,6 @@ export async function mountManagementSection( const unmountAppCallback = renderApp(element, appDependencies); return () => { - // Change tab label back to Kibana. docTitle.reset(); unmountAppCallback(); }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c1f0dc4c0c60c3..4175f76ad7ba8d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -12332,7 +12332,6 @@ "xpack.reporting.shareContextMenu.pdfReportsButtonLabel": "PDF レポート", "xpack.reporting.shareContextMenu.pngReportsButtonLabel": "PNG レポート", "xpack.rollupJobs.appTitle": "ロールアップジョブ", - "xpack.rollupJobs.breadcrumbsTitle": "ロールアップジョブ", "xpack.rollupJobs.create.backButton.label": "戻る", "xpack.rollupJobs.create.dateTypeField": "日付", "xpack.rollupJobs.create.errors.dateHistogramFieldMissing": "日付フィールドが必要です。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0f2a51c8ff8891..33d60dbd17700a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -12338,7 +12338,6 @@ "xpack.reporting.shareContextMenu.pdfReportsButtonLabel": "PDF 报告", "xpack.reporting.shareContextMenu.pngReportsButtonLabel": "PNG 报告", "xpack.rollupJobs.appTitle": "汇总/打包作业", - "xpack.rollupJobs.breadcrumbsTitle": "汇总/打包作业", "xpack.rollupJobs.create.backButton.label": "上一步", "xpack.rollupJobs.create.dateTypeField": "日期", "xpack.rollupJobs.create.errors.dateHistogramFieldMissing": "“日期”字段必填。", diff --git a/x-pack/plugins/upgrade_assistant/public/plugin.ts b/x-pack/plugins/upgrade_assistant/public/plugin.ts index 01c1a6a4659d55..98f1b8351b88b8 100644 --- a/x-pack/plugins/upgrade_assistant/public/plugin.ts +++ b/x-pack/plugins/upgrade_assistant/public/plugin.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import { i18n } from '@kbn/i18n'; import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/public'; @@ -21,22 +22,38 @@ export class UpgradeAssistantUIPlugin implements Plugin { constructor(private ctx: PluginInitializerContext) {} setup(coreSetup: CoreSetup, { cloud, management }: Dependencies) { const { enabled } = this.ctx.config.get(); + if (!enabled) { return; } + const appRegistrar = management.sections.section.stack; const isCloudEnabled = Boolean(cloud?.isCloudEnabled); + const pluginName = i18n.translate('xpack.upgradeAssistant.appTitle', { + defaultMessage: '{version} Upgrade Assistant', + values: { version: `${NEXT_MAJOR_VERSION}.0` }, + }); + appRegistrar.registerApp({ id: 'upgrade_assistant', - title: i18n.translate('xpack.upgradeAssistant.appTitle', { - defaultMessage: '{version} Upgrade Assistant', - values: { version: `${NEXT_MAJOR_VERSION}.0` }, - }), + title: pluginName, order: 1, async mount(params) { + const [coreStart] = await coreSetup.getStartServices(); + + const { + chrome: { docTitle }, + } = coreStart; + + docTitle.change(pluginName); const { mountManagementSection } = await import('./application/mount_management_section'); - return mountManagementSection(coreSetup, isCloudEnabled, params); + const unmountAppCallback = await mountManagementSection(coreSetup, isCloudEnabled, params); + + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, }); } diff --git a/x-pack/plugins/watcher/public/application/boot.tsx b/x-pack/plugins/watcher/public/application/index.tsx similarity index 94% rename from x-pack/plugins/watcher/public/application/boot.tsx rename to x-pack/plugins/watcher/public/application/index.tsx index 8461bd65bbd5e5..70a63e6a04dd62 100644 --- a/x-pack/plugins/watcher/public/application/boot.tsx +++ b/x-pack/plugins/watcher/public/application/index.tsx @@ -17,7 +17,7 @@ interface BootDeps extends AppDeps { I18nContext: any; } -export const boot = (bootDeps: BootDeps) => { +export const renderApp = (bootDeps: BootDeps) => { const { I18nContext, element, savedObjects, ...appDeps } = bootDeps; setHttpClient(appDeps.http); @@ -29,6 +29,7 @@ export const boot = (bootDeps: BootDeps) => { , element ); + return () => { unmountComponentAtNode(element); }; diff --git a/x-pack/plugins/watcher/public/plugin.ts b/x-pack/plugins/watcher/public/plugin.ts index 6b66c341497b7a..98b49af15019be 100644 --- a/x-pack/plugins/watcher/public/plugin.ts +++ b/x-pack/plugins/watcher/public/plugin.ts @@ -30,20 +30,31 @@ export class WatcherUIPlugin implements Plugin { ) { const esSection = management.sections.section.insightsAndAlerting; + const pluginName = i18n.translate( + 'xpack.watcher.sections.watchList.managementSection.watcherDisplayName', + { defaultMessage: 'Watcher' } + ); + const watcherESApp = esSection.registerApp({ id: 'watcher', - title: i18n.translate( - 'xpack.watcher.sections.watchList.managementSection.watcherDisplayName', - { defaultMessage: 'Watcher' } - ), + title: pluginName, order: 3, mount: async ({ element, setBreadcrumbs, history }) => { - const [core] = await getStartServices(); - const { i18n: i18nDep, docLinks, savedObjects, application } = core; - const { boot } = await import('./application/boot'); + const [coreStart] = await getStartServices(); + const { + chrome: { docTitle }, + i18n: i18nDep, + docLinks, + savedObjects, + application, + } = coreStart; + + docTitle.change(pluginName); + + const { renderApp } = await import('./application'); const { TimeBuckets } = await import('./legacy'); - return boot({ + const unmountAppCallback = renderApp({ // Skip the first license status, because that's already been used to determine // whether to include Watcher. licenseStatus$: licensing.license$.pipe(skip(1), map(licenseToLicenseStatus)), @@ -60,6 +71,11 @@ export class WatcherUIPlugin implements Plugin { history, getUrlForApp: application.getUrlForApp, }); + + return () => { + docTitle.reset(); + unmountAppCallback(); + }; }, });