From 51fa931ac237017ae2faa61c6d9e8435b96cda3b Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 22 Feb 2021 14:12:03 -0500 Subject: [PATCH] Adds doc titles to security management sections (#91013) (#92235) Co-authored-by: Larry Gregory --- .../mount_management_section.tsx | 3 ++ .../management_section/mount_section.tsx | 1 + .../public/management/mount_section.tsx | 4 +++ .../saved_objects_tagging/public/plugin.ts | 8 +++-- .../api_keys/api_keys_management_app.test.tsx | 9 ++++- .../api_keys/api_keys_management_app.tsx | 14 ++++---- .../role_mappings_management_app.test.tsx | 27 +++++++++++--- .../role_mappings_management_app.tsx | 14 ++++---- .../roles/roles_management_app.test.tsx | 35 +++++++++++++++---- .../management/roles/roles_management_app.tsx | 15 ++++++-- .../management/users/users_management_app.tsx | 8 +++-- .../management/spaces_management_app.test.tsx | 21 ++++++++--- .../management/spaces_management_app.tsx | 17 +++++---- .../translations/translations/ja-JP.json | 4 --- .../translations/translations/zh-CN.json | 4 --- 15 files changed, 133 insertions(+), 51 deletions(-) diff --git a/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx b/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx index 611b9bbc51f14..3a4ec83e28963 100644 --- a/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx +++ b/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx @@ -67,6 +67,8 @@ export async function mountManagementSection( chrome.setBadge(readOnlyBadge); } + chrome.docTitle.change(title); + ReactDOM.render( @@ -90,6 +92,7 @@ export async function mountManagementSection( params.element ); return () => { + chrome.docTitle.reset(); ReactDOM.unmountComponentAtNode(params.element); }; } diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index b855850ed185d..a21ad6b7a440a 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -103,6 +103,7 @@ export const mountManagementSection = async ({ ); return () => { + coreStart.chrome.docTitle.reset(); ReactDOM.unmountComponentAtNode(element); }; }; diff --git a/x-pack/plugins/saved_objects_tagging/public/management/mount_section.tsx b/x-pack/plugins/saved_objects_tagging/public/management/mount_section.tsx index a9390f59517e6..2cd412593f492 100644 --- a/x-pack/plugins/saved_objects_tagging/public/management/mount_section.tsx +++ b/x-pack/plugins/saved_objects_tagging/public/management/mount_section.tsx @@ -21,6 +21,7 @@ interface MountSectionParams { assignmentService: ITagAssignmentService; core: CoreSetup<{}, SavedObjectTaggingPluginStart>; mountParams: ManagementAppMountParams; + title: string; } const RedirectToHomeIfUnauthorized: FC<{ @@ -40,11 +41,13 @@ export const mountSection = async ({ assignmentService, core, mountParams, + title, }: MountSectionParams) => { const [coreStart] = await core.getStartServices(); const { element, setBreadcrumbs } = mountParams; const capabilities = getTagsCapabilities(coreStart.application.capabilities); const assignableTypes = await assignmentService.getAssignableTypes(); + coreStart.chrome.docTitle.change(title); ReactDOM.render( @@ -64,6 +67,7 @@ export const mountSection = async ({ ); return () => { + coreStart.chrome.docTitle.reset(); ReactDOM.unmountComponentAtNode(element); }; }; diff --git a/x-pack/plugins/saved_objects_tagging/public/plugin.ts b/x-pack/plugins/saved_objects_tagging/public/plugin.ts index d4e3f8678fe1f..243ef686eed1e 100644 --- a/x-pack/plugins/saved_objects_tagging/public/plugin.ts +++ b/x-pack/plugins/saved_objects_tagging/public/plugin.ts @@ -39,11 +39,12 @@ export class SavedObjectTaggingPlugin { management, savedObjectsTaggingOss }: SetupDeps ) { const kibanaSection = management.sections.section.kibana; + const title = i18n.translate('xpack.savedObjectsTagging.management.sectionLabel', { + defaultMessage: 'Tags', + }); kibanaSection.registerApp({ id: tagManagementSectionId, - title: i18n.translate('xpack.savedObjectsTagging.management.sectionLabel', { - defaultMessage: 'Tags', - }), + title, order: 1.5, mount: async (mountParams) => { const { mountSection } = await import('./management'); @@ -53,6 +54,7 @@ export class SavedObjectTaggingPlugin assignmentService: this.assignmentService!, core, mountParams, + title, }); }, }); diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx index ee69fa745f40c..1606dc7af7c5b 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx @@ -28,11 +28,15 @@ describe('apiKeysManagementApp', () => { it('mount() works for the `grid` page', async () => { const { getStartServices } = coreMock.createSetup(); + + const startServices = await getStartServices(); + const docTitle = startServices[0].chrome.docTitle; + const container = document.createElement('div'); const setBreadcrumbs = jest.fn(); const unmount = await apiKeysManagementApp - .create({ getStartServices: getStartServices as any }) + .create({ getStartServices: () => Promise.resolve(startServices) as any }) .mount({ basePath: '/some-base-path', element: container, @@ -42,6 +46,8 @@ describe('apiKeysManagementApp', () => { expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: '/', text: 'API Keys' }]); + expect(docTitle.change).toHaveBeenCalledWith('API Keys'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Page: {"notifications":{"toasts":{}},"apiKeysAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}}} @@ -49,6 +55,7 @@ describe('apiKeysManagementApp', () => { `); unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); expect(container).toMatchInlineSnapshot(`
`); }); diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx index ca9f208f20c34..45d00ecec124d 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx @@ -20,18 +20,17 @@ interface CreateParams { export const apiKeysManagementApp = Object.freeze({ id: 'api_keys', create({ getStartServices }: CreateParams) { + const title = i18n.translate('xpack.security.management.apiKeysTitle', { + defaultMessage: 'API Keys', + }); return { id: this.id, order: 30, - title: i18n.translate('xpack.security.management.apiKeysTitle', { - defaultMessage: 'API Keys', - }), + title, async mount({ element, setBreadcrumbs }) { setBreadcrumbs([ { - text: i18n.translate('xpack.security.apiKeys.breadcrumb', { - defaultMessage: 'API Keys', - }), + text: title, href: `/`, }, ]); @@ -42,6 +41,8 @@ export const apiKeysManagementApp = Object.freeze({ import('./api_keys_api_client'), ]); + core.chrome.docTitle.change(title); + render( @@ -55,6 +56,7 @@ export const apiKeysManagementApp = Object.freeze({ ); return () => { + core.chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx index eea505dafef69..934601a6f4b48 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx @@ -30,8 +30,10 @@ async function mountApp(basePath: string, pathname: string) { const container = document.createElement('div'); const setBreadcrumbs = jest.fn(); + const startServices = await coreMock.createSetup().getStartServices(); + const unmount = await roleMappingsManagementApp - .create({ getStartServices: coreMock.createSetup().getStartServices as any }) + .create({ getStartServices: () => Promise.resolve(startServices) as any }) .mount({ basePath, element: container, @@ -39,7 +41,7 @@ async function mountApp(basePath: string, pathname: string) { history: scopedHistoryMock.create({ pathname }), }); - return { unmount, container, setBreadcrumbs }; + return { unmount, container, setBreadcrumbs, docTitle: startServices[0].chrome.docTitle }; } describe('roleMappingsManagementApp', () => { @@ -59,10 +61,12 @@ describe('roleMappingsManagementApp', () => { }); it('mount() works for the `grid` page', async () => { - const { setBreadcrumbs, container, unmount } = await mountApp('/', '/'); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Role Mappings' }]); + expect(docTitle.change).toHaveBeenCalledWith('Role Mappings'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Role Mappings Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}}} @@ -71,17 +75,21 @@ describe('roleMappingsManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); it('mount() works for the `create role mapping` page', async () => { - const { setBreadcrumbs, container, unmount } = await mountApp('/', '/edit'); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/edit'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Role Mappings' }, { text: 'Create' }, ]); + expect(docTitle.change).toHaveBeenCalledWith('Role Mappings'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Role Mapping Edit Page: {"roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}}} @@ -90,19 +98,26 @@ describe('roleMappingsManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); it('mount() works for the `edit role mapping` page', async () => { const roleMappingName = 'role@mapping'; - const { setBreadcrumbs, container, unmount } = await mountApp('/', `/edit/${roleMappingName}`); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp( + '/', + `/edit/${roleMappingName}` + ); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Role Mappings' }, { href: `/edit/${encodeURIComponent(roleMappingName)}`, text: roleMappingName }, ]); + expect(docTitle.change).toHaveBeenCalledWith('Role Mappings'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Role Mapping Edit Page: {"name":"role@mapping","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@mapping","search":"","hash":""}}} @@ -111,6 +126,8 @@ describe('roleMappingsManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx index f6f49c8563cb5..24d197d1c64e7 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx @@ -22,23 +22,24 @@ interface CreateParams { export const roleMappingsManagementApp = Object.freeze({ id: 'role_mappings', create({ getStartServices }: CreateParams) { + const title = i18n.translate('xpack.security.management.roleMappingsTitle', { + defaultMessage: 'Role Mappings', + }); return { id: this.id, order: 40, - title: i18n.translate('xpack.security.management.roleMappingsTitle', { - defaultMessage: 'Role Mappings', - }), + title, async mount({ element, setBreadcrumbs, history }) { const [coreStart] = await getStartServices(); const roleMappingsBreadcrumbs = [ { - text: i18n.translate('xpack.security.roleMapping.breadcrumb', { - defaultMessage: 'Role Mappings', - }), + text: title, href: `/`, }, ]; + coreStart.chrome.docTitle.change(title); + const [ [core], { RoleMappingsGridPage }, @@ -117,6 +118,7 @@ export const roleMappingsManagementApp = Object.freeze({ ); return () => { + coreStart.chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx index 19726720b5ea2..c576aac7a8169 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx @@ -28,6 +28,7 @@ async function mountApp(basePath: string, pathname: string) { const setBreadcrumbs = jest.fn(); const featuresStart = featuresPluginMock.createStart(); + const coreStart = coreMock.createStart(); const unmount = await rolesManagementApp .create({ @@ -35,7 +36,7 @@ async function mountApp(basePath: string, pathname: string) { fatalErrors, getStartServices: jest .fn() - .mockResolvedValue([coreMock.createStart(), { data: {}, features: featuresStart }]), + .mockResolvedValue([coreStart, { data: {}, features: featuresStart }]), }) .mount({ basePath, @@ -44,7 +45,7 @@ async function mountApp(basePath: string, pathname: string) { history: scopedHistoryMock.create({ pathname }), }); - return { unmount, container, setBreadcrumbs }; + return { unmount, container, setBreadcrumbs, docTitle: coreStart.chrome.docTitle }; } describe('rolesManagementApp', () => { @@ -68,10 +69,12 @@ describe('rolesManagementApp', () => { }); it('mount() works for the `grid` page', async () => { - const { setBreadcrumbs, container, unmount } = await mountApp('/', '/'); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Roles' }]); + expect(docTitle.change).toHaveBeenCalledWith('Roles'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Roles Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}}} @@ -80,14 +83,18 @@ describe('rolesManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); it('mount() works for the `create role` page', async () => { - const { setBreadcrumbs, container, unmount } = await mountApp('/', '/edit'); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/edit'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Roles' }, { text: 'Create' }]); + expect(docTitle.change).toHaveBeenCalledWith('Roles'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Role Edit Page: {"action":"edit","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}}} @@ -96,19 +103,26 @@ describe('rolesManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); it('mount() works for the `edit role` page', async () => { const roleName = 'role@name'; - const { setBreadcrumbs, container, unmount } = await mountApp('/', `/edit/${roleName}`); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp( + '/', + `/edit/${roleName}` + ); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Roles' }, { href: `/edit/${encodeURIComponent(roleName)}`, text: roleName }, ]); + expect(docTitle.change).toHaveBeenCalledWith('Roles'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Role Edit Page: {"action":"edit","roleName":"role@name","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@name","search":"","hash":""}}} @@ -117,16 +131,23 @@ describe('rolesManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); it('mount() works for the `clone role` page', async () => { const roleName = 'someRoleName'; - const { setBreadcrumbs, container, unmount } = await mountApp('/', `/clone/${roleName}`); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp( + '/', + `/clone/${roleName}` + ); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Roles' }, { text: 'Create' }]); + expect(docTitle.change).toHaveBeenCalledWith('Roles'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
Role Edit Page: {"action":"clone","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/clone/someRoleName","search":"","hash":""}}} @@ -135,6 +156,8 @@ describe('rolesManagementApp', () => { unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); + expect(container).toMatchInlineSnapshot(`
`); }); diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx index c4dc4fe607cad..dd2198d10f53c 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx @@ -24,20 +24,26 @@ interface CreateParams { export const rolesManagementApp = Object.freeze({ id: 'roles', create({ license, fatalErrors, getStartServices }: CreateParams) { + const title = i18n.translate('xpack.security.management.rolesTitle', { + defaultMessage: 'Roles', + }); return { id: this.id, order: 20, - title: i18n.translate('xpack.security.management.rolesTitle', { defaultMessage: 'Roles' }), + title, async mount({ element, setBreadcrumbs, history }) { const rolesBreadcrumbs = [ { - text: i18n.translate('xpack.security.roles.breadcrumb', { defaultMessage: 'Roles' }), + text: title, href: `/`, }, ]; const [ - [{ application, docLinks, http, i18n: i18nStart, notifications }, { data, features }], + [ + { application, docLinks, http, i18n: i18nStart, notifications, chrome }, + { data, features }, + ], { RolesGridPage }, { EditRolePage }, { RolesAPIClient }, @@ -54,6 +60,8 @@ export const rolesManagementApp = Object.freeze({ import('../users'), ]); + chrome.docTitle.change(title); + const rolesAPIClient = new RolesAPIClient(http); const RolesGridPageWithBreadcrumbs = () => { setBreadcrumbs(rolesBreadcrumbs); @@ -125,6 +133,7 @@ export const rolesManagementApp = Object.freeze({ ); return () => { + chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx index 136b13fa4610f..0fc2e90e44c46 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx @@ -37,10 +37,13 @@ interface EditUserParams { export const usersManagementApp = Object.freeze({ id: 'users', create({ authc, getStartServices }: CreateParams) { + const title = i18n.translate('xpack.security.management.usersTitle', { + defaultMessage: 'Users', + }); return { id: this.id, order: 10, - title: i18n.translate('xpack.security.management.usersTitle', { defaultMessage: 'Users' }), + title, async mount({ element, setBreadcrumbs, history }) { const [ [coreStart], @@ -49,7 +52,7 @@ export const usersManagementApp = Object.freeze({ { UserAPIClient }, { RolesAPIClient }, ] = await Promise.all([ - getStartServices(), + getStartServices(), // TODO: remove this and write test. import('./users_grid'), import('./edit_user'), import('./user_api_client'), @@ -115,6 +118,7 @@ export const usersManagementApp = Object.freeze({ ); return () => { + coreStart.chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx index c0175b4aeda57..cd6befac300c9 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx @@ -53,7 +53,7 @@ async function mountApp(basePath: string, pathname: string, spaceId?: string) { history: scopedHistoryMock.create({ pathname }), }); - return { unmount, container, setBreadcrumbs }; + return { unmount, container, setBreadcrumbs, docTitle: coreStart.chrome.docTitle }; } describe('spacesManagementApp', () => { @@ -74,10 +74,12 @@ describe('spacesManagementApp', () => { }); it('mount() works for the `grid` page', async () => { - const { setBreadcrumbs, container, unmount } = await mountApp('/', '/'); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `/`, text: 'Spaces' }]); + expect(docTitle.change).toHaveBeenCalledWith('Spaces'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
{ unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); expect(container).toMatchInlineSnapshot(`
`); }); it('mount() works for the `create space` page', async () => { - const { setBreadcrumbs, container, unmount } = await mountApp('/', '/create'); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp('/', '/create'); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Spaces' }, { text: 'Create' }, ]); + expect(docTitle.change).toHaveBeenCalledWith('Spaces'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
{ `); unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); expect(container).toMatchInlineSnapshot(`
`); }); @@ -119,13 +125,19 @@ describe('spacesManagementApp', () => { it('mount() works for the `edit space` page', async () => { const spaceId = 'some-space'; - const { setBreadcrumbs, container, unmount } = await mountApp('/', `/edit/${spaceId}`, spaceId); + const { setBreadcrumbs, container, unmount, docTitle } = await mountApp( + '/', + `/edit/${spaceId}`, + spaceId + ); expect(setBreadcrumbs).toHaveBeenCalledTimes(1); expect(setBreadcrumbs).toHaveBeenCalledWith([ { href: `/`, text: 'Spaces' }, { href: `/edit/${spaceId}`, text: `space with id some-space` }, ]); + expect(docTitle.change).toHaveBeenCalledWith('Spaces'); + expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
{ `); unmount(); + expect(docTitle.reset).toHaveBeenCalledTimes(1); expect(container).toMatchInlineSnapshot(`
`); }); diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.tsx index 8a7582e4da447..c94baface8058 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.tsx @@ -26,27 +26,29 @@ interface CreateParams { export const spacesManagementApp = Object.freeze({ id: 'spaces', create({ getStartServices, spacesManager }: CreateParams) { + const title = i18n.translate('xpack.spaces.displayName', { + defaultMessage: 'Spaces', + }); + return { id: this.id, order: 2, - title: i18n.translate('xpack.spaces.displayName', { - defaultMessage: 'Spaces', - }), + title, async mount({ element, setBreadcrumbs, history }) { const [ - { notifications, i18n: i18nStart, application }, + { notifications, i18n: i18nStart, application, chrome }, { features }, ] = await getStartServices(); const spacesBreadcrumbs = [ { - text: i18n.translate('xpack.spaces.management.breadcrumb', { - defaultMessage: 'Spaces', - }), + text: title, href: `/`, }, ]; + chrome.docTitle.change(title); + const SpacesGridPageWithBreadcrumbs = () => { setBreadcrumbs(spacesBreadcrumbs); return ( @@ -132,6 +134,7 @@ export const spacesManagementApp = Object.freeze({ ); return () => { + chrome.docTitle.reset(); unmountComponentAtNode(element); }; }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f3e8433459afa..139da00e48517 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16548,7 +16548,6 @@ "xpack.security.account.passwordsDoNotMatch": "パスワードが一致していません。", "xpack.security.account.usernameGroupDescription": "この情報は変更できません。", "xpack.security.account.usernameGroupTitle": "ユーザー名とメールアドレス", - "xpack.security.apiKeys.breadcrumb": "API キー", "xpack.security.authentication.login.validateLogin.requiredPasswordErrorMessage": "パスワードが必要です", "xpack.security.authentication.login.validateLogin.requiredUsernameErrorMessage": "ユーザー名が必要です", "xpack.security.checkup.dismissButtonText": "閉じる", @@ -16951,9 +16950,7 @@ "xpack.security.role_mappings.validation.invalidRoleRule": "1つ以上のルールが必要です。", "xpack.security.role_mappings.validation.invalidRoles": "1つ以上のロールが必要です。", "xpack.security.role_mappings.validation.invalidRoleTemplates": "1つ以上のロールテンプレートが必要です。", - "xpack.security.roleMapping.breadcrumb": "ロールマッピング", "xpack.security.roleMappings.createBreadcrumb": "作成", - "xpack.security.roles.breadcrumb": "ロール", "xpack.security.roles.createBreadcrumb": "作成", "xpack.security.users.breadcrumb": "ユーザー", "xpack.securitySolution.accessibility.tooltipWithKeyboardShortcut.pressTooltipLabel": "プレス", @@ -20444,7 +20441,6 @@ "xpack.spaces.featureDescription": "ダッシュボードやその他の保存済みオブジェクトを、わかりやすいカテゴリー別に整理することができます。", "xpack.spaces.management.advancedSettingsSubtitle.applyingSettingsOnPageToSpaceDescription": "このページの設定は、別途指定されていない限り {spaceName}’スペースに適用されます。’", "xpack.spaces.management.advancedSettingsTitle.settingsTitle": "設定", - "xpack.spaces.management.breadcrumb": "スペース", "xpack.spaces.management.confirmAlterActiveSpaceModal.cancelButton": "キャンセル", "xpack.spaces.management.confirmAlterActiveSpaceModal.reloadWarningMessage": "このスペースで表示される機能を更新しました。保存後にページが更新されます。", "xpack.spaces.management.confirmAlterActiveSpaceModal.title": "スペースの更新の確認", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0896722bb616f..e747254e67ef4 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16589,7 +16589,6 @@ "xpack.security.account.passwordsDoNotMatch": "密码不匹配。", "xpack.security.account.usernameGroupDescription": "不能更改此信息。", "xpack.security.account.usernameGroupTitle": "用户名和电子邮件", - "xpack.security.apiKeys.breadcrumb": "API 密钥", "xpack.security.authentication.login.validateLogin.requiredPasswordErrorMessage": "“密码”必填", "xpack.security.authentication.login.validateLogin.requiredUsernameErrorMessage": "“用户名”必填", "xpack.security.checkup.dismissButtonText": "关闭", @@ -16994,9 +16993,7 @@ "xpack.security.role_mappings.validation.invalidRoleRule": "至少需要一个规则。", "xpack.security.role_mappings.validation.invalidRoles": "至少需要一个角色。", "xpack.security.role_mappings.validation.invalidRoleTemplates": "至少需要一个角色模板。", - "xpack.security.roleMapping.breadcrumb": "角色映射", "xpack.security.roleMappings.createBreadcrumb": "创建", - "xpack.security.roles.breadcrumb": "角色", "xpack.security.roles.createBreadcrumb": "创建", "xpack.security.users.breadcrumb": "用户", "xpack.securitySolution.accessibility.tooltipWithKeyboardShortcut.pressTooltipLabel": "按", @@ -20490,7 +20487,6 @@ "xpack.spaces.featureDescription": "将仪表板和其他已保存的对象管理为有意义的类别。", "xpack.spaces.management.advancedSettingsSubtitle.applyingSettingsOnPageToSpaceDescription": "除非已指定,否则此页面上的设置适用于 {spaceName} 空间。", "xpack.spaces.management.advancedSettingsTitle.settingsTitle": "设置", - "xpack.spaces.management.breadcrumb": "工作区", "xpack.spaces.management.confirmAlterActiveSpaceModal.cancelButton": "取消", "xpack.spaces.management.confirmAlterActiveSpaceModal.reloadWarningMessage": "您已更新此工作区中的可见功能。保存后,您的页面将重新加载。", "xpack.spaces.management.confirmAlterActiveSpaceModal.title": "确认更新工作区",