diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.test.tsx index d7ce8053c71f027..350a0d7bf6162b1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.test.tsx @@ -12,10 +12,13 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { Loading } from '../../../shared/loading'; -import { RoleMappingsTable, RoleMappingsHeading } from '../../../shared/role_mapping'; +import { EuiButton } from '@elastic/eui'; + +import { RoleMappingsTable } from '../../../shared/role_mapping'; import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; +import { getPageHeaderActions } from '../../../test_helpers'; + import { RoleMapping } from './role_mapping'; import { RoleMappings } from './role_mappings'; @@ -44,13 +47,6 @@ describe('RoleMappings', () => { expect(wrapper.find(RoleMappingsTable)).toHaveLength(1); }); - it('returns Loading when loading', () => { - setMockValues({ ...mockValues, dataLoading: true }); - const wrapper = shallow(); - - expect(wrapper.find(Loading)).toHaveLength(1); - }); - it('renders RoleMapping flyout', () => { setMockValues({ ...mockValues, roleMappingFlyoutOpen: true }); const wrapper = shallow(); @@ -60,8 +56,9 @@ describe('RoleMappings', () => { it('handles onClick', () => { const wrapper = shallow(); - wrapper.find(RoleMappingsHeading).prop('onClick')(); + const actions = getPageHeaderActions(wrapper); + actions.find(EuiButton).simulate('click'); expect(initializeRoleMapping).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx index 78d0a5cbc8638ec..903e6b54a9bb291 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/role_mappings.tsx @@ -9,11 +9,13 @@ import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; -import { FlashMessages } from '../../../shared/flash_messages'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { Loading } from '../../../shared/loading'; -import { RoleMappingsTable, RoleMappingsHeading } from '../../../shared/role_mapping'; -import { ROLE_MAPPINGS_TITLE } from '../../../shared/role_mapping/constants'; +import { APP_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { + ROLE_MAPPINGS_TITLE, + getRoleMappingsHeader, + RoleMappingsTable, +} from '../../../shared/role_mapping'; +import { AppSearchPageTemplate } from '../layout'; import { ROLE_MAPPINGS_ENGINE_ACCESS_HEADING } from './constants'; import { RoleMapping } from './role_mapping'; @@ -38,11 +40,16 @@ export const RoleMappings: React.FC = () => { return resetState; }, []); - if (dataLoading) return ; - - const roleMappingsSection = ( - <> - initializeRoleMapping()} /> + return ( + initializeRoleMapping(), + })} + isLoading={dataLoading} + > + {roleMappingFlyoutOpen && } { shouldShowAuthProvider={multipleAuthProvidersConfig} handleDeleteMapping={handleDeleteMapping} /> - > - ); - - return ( - <> - - {roleMappingFlyoutOpen && } - - {roleMappingsSection} - > + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 20f65ba2c346ca0..caf0f805e8ca7eb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -92,6 +92,11 @@ export const AppSearchConfigured: React.FC> = (props) = )} + {canViewRoleMappings && ( + + + + )} } readOnlyMode={readOnlyMode}> @@ -110,11 +115,6 @@ export const AppSearchConfigured: React.FC> = (props) = - {canViewRoleMappings && ( - - - - )} {canManageEngines && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts index 47d481630510e26..e5312c6c0343f7a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts @@ -7,8 +7,6 @@ import { i18n } from '@kbn/i18n'; -import { ProductName } from '../types'; - export const ANY_AUTH_PROVIDER = '*'; export const ANY_AUTH_PROVIDER_OPTION_LABEL = i18n.translate( @@ -184,7 +182,7 @@ export const ROLE_MAPPINGS_HEADING_TITLE = i18n.translate( { defaultMessage: 'Role mappings' } ); -export const ROLE_MAPPINGS_HEADING_DESCRIPTION = (productName: ProductName) => +export const ROLE_MAPPINGS_HEADING_DESCRIPTION = (productName: string) => i18n.translate('xpack.enterpriseSearch.roleMapping.roleMappingsHeadingDescription', { defaultMessage: 'Role mappings provide an interface to associate native or SAML-governed role attributes with {productName} permissions.', @@ -193,7 +191,7 @@ export const ROLE_MAPPINGS_HEADING_DESCRIPTION = (productName: ProductName) => export const ROLE_MAPPINGS_HEADING_DOCS_LINK = i18n.translate( 'xpack.enterpriseSearch.roleMapping.roleMappingsHeadingDocsLink', - { defaultMessage: 'Learn more about role mappings' } + { defaultMessage: 'Learn more about role mappings.' } ); export const ROLE_MAPPINGS_HEADING_BUTTON = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/index.ts index b0d10e9692714f6..d254c712617a79b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/index.ts @@ -5,10 +5,11 @@ * 2.0. */ +export { ROLE_MAPPINGS_TITLE } from './constants'; export { AttributeSelector } from './attribute_selector'; export { RoleMappingsTable } from './role_mappings_table'; export { RoleOptionLabel } from './role_option_label'; export { RoleSelector } from './role_selector'; export { RoleMappingFlyout } from './role_mapping_flyout'; -export { RoleMappingsHeading } from './role_mappings_heading'; +export { getRoleMappingsHeader } from './role_mappings_header'; export { UsersAndRolesRowActions } from './users_and_roles_row_actions'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_header.test.tsx new file mode 100644 index 000000000000000..36b883afdd2e227 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_header.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiLink, EuiButton } from '@elastic/eui'; + +import { getRoleMappingsHeader } from './role_mappings_header'; + +describe('getRoleMappingsHeader', () => { + const onClick = jest.fn(); + const pageHeader = getRoleMappingsHeader({ productName: 'Workplace Search', onClick }); + + it('returns an EuiPageHeader object', () => { + expect(pageHeader.pageTitle).toEqual('Role mappings'); + }); + + it('renders the passed productName in the description', () => { + const Description = () => <>{pageHeader.description}>; + const wrapper = shallow(); + + expect(wrapper.text()).toEqual( + expect.stringContaining('role attributes with Workplace Search permissions') + ); + expect(wrapper.find(EuiLink)).toHaveLength(1); + }); + + it('renders an action button with a passed onClick', () => { + const Button = () => <>{pageHeader.rightSideItems[0]}>; + const wrapper = shallow(); + + wrapper.find(EuiButton).simulate('click'); + expect(onClick).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_header.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_header.tsx new file mode 100644 index 000000000000000..929da9cf2835a93 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_header.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiButton, EuiLink } from '@elastic/eui'; + +import { + ROLE_MAPPINGS_HEADING_TITLE, + ROLE_MAPPINGS_HEADING_DESCRIPTION, + ROLE_MAPPINGS_HEADING_DOCS_LINK, + ROLE_MAPPINGS_HEADING_BUTTON, +} from './constants'; + +interface Props { + productName: string; + onClick(): void; +} + +// TODO: Replace EuiLink href with actual docs link when available +const ROLE_MAPPINGS_DOCS_HREF = '#TODO'; + +export const getRoleMappingsHeader = ({ productName, onClick }: Props) => ({ + pageTitle: ROLE_MAPPINGS_HEADING_TITLE, + description: ( + <> + {ROLE_MAPPINGS_HEADING_DESCRIPTION(productName)}{' '} + + {ROLE_MAPPINGS_HEADING_DOCS_LINK} + + > + ), + rightSideItems: [ + + {ROLE_MAPPINGS_HEADING_BUTTON} + , + ], +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_heading.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_heading.test.tsx deleted file mode 100644 index f0bf86fb306c658..000000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_heading.test.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiTitle, EuiLink, EuiButton, EuiText } from '@elastic/eui'; - -import { RoleMappingsHeading } from './role_mappings_heading'; - -describe('RoleMappingsHeading', () => { - it('renders ', () => { - const wrapper = shallow(); - - expect(wrapper.find(EuiTitle)).toHaveLength(1); - expect(wrapper.find(EuiText)).toHaveLength(1); - expect(wrapper.find(EuiLink)).toHaveLength(1); - expect(wrapper.find(EuiButton)).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_heading.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_heading.tsx deleted file mode 100644 index b2143c6ff440289..000000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/role_mappings_heading.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; - -import { ProductName } from '../types'; - -import { - ROLE_MAPPINGS_HEADING_TITLE, - ROLE_MAPPINGS_HEADING_DESCRIPTION, - ROLE_MAPPINGS_HEADING_DOCS_LINK, - ROLE_MAPPINGS_HEADING_BUTTON, -} from './constants'; - -interface Props { - productName: ProductName; - onClick(): void; -} - -// TODO: Replace EuiLink href with acutal docs link when available -const ROLE_MAPPINGS_DOCS_HREF = '#TODO'; - -export const RoleMappingsHeading: React.FC = ({ productName, onClick }) => ( - <> - - - - {ROLE_MAPPINGS_HEADING_TITLE} - - - - - {ROLE_MAPPINGS_HEADING_DESCRIPTION(productName)}{' '} - - {ROLE_MAPPINGS_HEADING_DOCS_LINK} - - - - - - - {ROLE_MAPPINGS_HEADING_BUTTON} - - - - - > -); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts index f450ca556ebe25f..2cdadc1c6b0d304 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts @@ -35,5 +35,3 @@ export interface RoleMapping { content: string; }; } - -export type ProductName = 'App Search' | 'Workplace Search'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index 0fc8a6e7c7c0d05..4682969f71c6c6c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -129,9 +129,7 @@ export const WorkplaceSearchConfigured: React.FC = (props) => { - } restrictWidth readOnlyMode={readOnlyMode}> - - + } restrictWidth readOnlyMode={readOnlyMode}> diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx index d7ce8053c71f027..350a0d7bf6162b1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx @@ -12,10 +12,13 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { Loading } from '../../../shared/loading'; -import { RoleMappingsTable, RoleMappingsHeading } from '../../../shared/role_mapping'; +import { EuiButton } from '@elastic/eui'; + +import { RoleMappingsTable } from '../../../shared/role_mapping'; import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; +import { getPageHeaderActions } from '../../../test_helpers'; + import { RoleMapping } from './role_mapping'; import { RoleMappings } from './role_mappings'; @@ -44,13 +47,6 @@ describe('RoleMappings', () => { expect(wrapper.find(RoleMappingsTable)).toHaveLength(1); }); - it('returns Loading when loading', () => { - setMockValues({ ...mockValues, dataLoading: true }); - const wrapper = shallow(); - - expect(wrapper.find(Loading)).toHaveLength(1); - }); - it('renders RoleMapping flyout', () => { setMockValues({ ...mockValues, roleMappingFlyoutOpen: true }); const wrapper = shallow(); @@ -60,8 +56,9 @@ describe('RoleMappings', () => { it('handles onClick', () => { const wrapper = shallow(); - wrapper.find(RoleMappingsHeading).prop('onClick')(); + const actions = getPageHeaderActions(wrapper); + actions.find(EuiButton).simulate('click'); expect(initializeRoleMapping).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx index 46c426c3dad2a54..e91ed825387415f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx @@ -9,11 +9,13 @@ import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; -import { FlashMessages } from '../../../shared/flash_messages'; -import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { Loading } from '../../../shared/loading'; -import { RoleMappingsTable, RoleMappingsHeading } from '../../../shared/role_mapping'; -import { ROLE_MAPPINGS_TITLE } from '../../../shared/role_mapping/constants'; +import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { + ROLE_MAPPINGS_TITLE, + getRoleMappingsHeader, + RoleMappingsTable, +} from '../../../shared/role_mapping'; +import { WorkplaceSearchPageTemplate } from '../../components/layout'; import { ROLE_MAPPINGS_TABLE_HEADER } from './constants'; @@ -36,11 +38,16 @@ export const RoleMappings: React.FC = () => { initializeRoleMappings(); }, []); - if (dataLoading) return ; - - const roleMappingsSection = ( - <> - initializeRoleMapping()} /> + return ( + initializeRoleMapping(), + })} + isLoading={dataLoading} + > + {roleMappingFlyoutOpen && } { initializeRoleMapping={initializeRoleMapping} handleDeleteMapping={handleDeleteMapping} /> - > - ); - - return ( - <> - - {roleMappingFlyoutOpen && } - - {roleMappingsSection} - > + ); };
- {ROLE_MAPPINGS_HEADING_DESCRIPTION(productName)}{' '} - - {ROLE_MAPPINGS_HEADING_DOCS_LINK} - -