-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Enterprise Search] Set up initial KibanaPageTemplate (#102170)
* Set up shared EnterpriseSearchPageTemplate component * Set up product-specific page templates + setPageChrome + misc tech debt - create AS components/layout/index.ts for imports * Set up navigation helpers for EuiSideNav usage - Update react_router_helpers to pass back props as a plain JS obj instead of only working with React components (+ update react components to use new simpler helper) - Convert SideNavLink active logic to a plain JS helper * Set up top-level product navigations NYI: sub navigations (future separate PRs) * Set up test_helpers for inspecting pageHeaders - primarily useful for rightSideItems, which often contain conditional logic * Initial example: Convert RoleMappings views to new page template Minor refactors: + remove unnecessary type union + fix un-i18n'ed product names + add full stop to documentation sentence + add semantic HTML tags around various page landmarks (header, section) * EUI feedback: add empty root parent section * Revert Role Mappings union type removal - but shenanigans it a bit to take our i18n'd shared product names (requires as const assertion) - done to reduce merge conflicts for Scotty / make his life (hopefully) a bit easier between ent-search and Kibana Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
a816dae
commit 66c9d80
Showing
33 changed files
with
1,181 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
* 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 { AppSearchPageTemplate } from './page_template'; | ||
export { useAppSearchNav } from './nav'; | ||
export { KibanaHeaderActions } from './kibana_header_actions'; |
107 changes: 107 additions & 0 deletions
107
...k/plugins/enterprise_search/public/applications/app_search/components/layout/nav.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* 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 { setMockValues } from '../../../__mocks__/kea_logic'; | ||
|
||
jest.mock('../../../shared/layout', () => ({ | ||
generateNavLink: jest.fn(({ to }) => ({ href: to })), | ||
})); | ||
|
||
import { useAppSearchNav } from './nav'; | ||
|
||
describe('useAppSearchNav', () => { | ||
it('always generates a default engines nav item', () => { | ||
setMockValues({ myRole: {} }); | ||
|
||
expect(useAppSearchNav()).toEqual([ | ||
{ | ||
id: '', | ||
name: '', | ||
items: [ | ||
{ | ||
id: 'engines', | ||
name: 'Engines', | ||
href: '/engines', | ||
items: [], | ||
}, | ||
], | ||
}, | ||
]); | ||
}); | ||
|
||
it('generates a settings nav item if the user can view settings', () => { | ||
setMockValues({ myRole: { canViewSettings: true } }); | ||
|
||
expect(useAppSearchNav()).toEqual([ | ||
{ | ||
id: '', | ||
name: '', | ||
items: [ | ||
{ | ||
id: 'engines', | ||
name: 'Engines', | ||
href: '/engines', | ||
items: [], | ||
}, | ||
{ | ||
id: 'settings', | ||
name: 'Settings', | ||
href: '/settings', | ||
}, | ||
], | ||
}, | ||
]); | ||
}); | ||
|
||
it('generates a credentials nav item if the user can view credentials', () => { | ||
setMockValues({ myRole: { canViewAccountCredentials: true } }); | ||
|
||
expect(useAppSearchNav()).toEqual([ | ||
{ | ||
id: '', | ||
name: '', | ||
items: [ | ||
{ | ||
id: 'engines', | ||
name: 'Engines', | ||
href: '/engines', | ||
items: [], | ||
}, | ||
{ | ||
id: 'credentials', | ||
name: 'Credentials', | ||
href: '/credentials', | ||
}, | ||
], | ||
}, | ||
]); | ||
}); | ||
|
||
it('generates a users & roles nav item if the user can view role mappings', () => { | ||
setMockValues({ myRole: { canViewRoleMappings: true } }); | ||
|
||
expect(useAppSearchNav()).toEqual([ | ||
{ | ||
id: '', | ||
name: '', | ||
items: [ | ||
{ | ||
id: 'engines', | ||
name: 'Engines', | ||
href: '/engines', | ||
items: [], | ||
}, | ||
{ | ||
id: 'usersRoles', | ||
name: 'Users & roles', | ||
href: '/role_mappings', | ||
}, | ||
], | ||
}, | ||
]); | ||
}); | ||
}); |
63 changes: 63 additions & 0 deletions
63
x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/nav.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* 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 { useValues } from 'kea'; | ||
|
||
import { EuiSideNavItemType } from '@elastic/eui'; | ||
|
||
import { generateNavLink } from '../../../shared/layout'; | ||
import { ROLE_MAPPINGS_TITLE } from '../../../shared/role_mapping/constants'; | ||
|
||
import { AppLogic } from '../../app_logic'; | ||
import { ENGINES_PATH, SETTINGS_PATH, CREDENTIALS_PATH, ROLE_MAPPINGS_PATH } from '../../routes'; | ||
import { CREDENTIALS_TITLE } from '../credentials'; | ||
import { ENGINES_TITLE } from '../engines'; | ||
import { SETTINGS_TITLE } from '../settings'; | ||
|
||
export const useAppSearchNav = () => { | ||
const { | ||
myRole: { canViewSettings, canViewAccountCredentials, canViewRoleMappings }, | ||
} = useValues(AppLogic); | ||
|
||
const navItems: Array<EuiSideNavItemType<unknown>> = [ | ||
{ | ||
id: 'engines', | ||
name: ENGINES_TITLE, | ||
...generateNavLink({ to: ENGINES_PATH, isRoot: true }), | ||
items: [], // TODO: Engine nav | ||
}, | ||
]; | ||
|
||
if (canViewSettings) { | ||
navItems.push({ | ||
id: 'settings', | ||
name: SETTINGS_TITLE, | ||
...generateNavLink({ to: SETTINGS_PATH }), | ||
}); | ||
} | ||
|
||
if (canViewAccountCredentials) { | ||
navItems.push({ | ||
id: 'credentials', | ||
name: CREDENTIALS_TITLE, | ||
...generateNavLink({ to: CREDENTIALS_PATH }), | ||
}); | ||
} | ||
|
||
if (canViewRoleMappings) { | ||
navItems.push({ | ||
id: 'usersRoles', | ||
name: ROLE_MAPPINGS_TITLE, | ||
...generateNavLink({ to: ROLE_MAPPINGS_PATH }), | ||
}); | ||
} | ||
|
||
// Root level items are meant to be section headers, but the AS nav (currently) | ||
// isn't organized this way. So we create a fake empty parent item here | ||
// to cause all our navItems to properly render as nav links. | ||
return [{ id: '', name: '', items: navItems }]; | ||
}; |
69 changes: 69 additions & 0 deletions
69
...enterprise_search/public/applications/app_search/components/layout/page_template.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
jest.mock('./nav', () => ({ | ||
useAppSearchNav: () => [], | ||
})); | ||
|
||
import React from 'react'; | ||
|
||
import { shallow } from 'enzyme'; | ||
|
||
import { SetAppSearchChrome } from '../../../shared/kibana_chrome'; | ||
import { EnterpriseSearchPageTemplate } from '../../../shared/layout'; | ||
import { SendAppSearchTelemetry } from '../../../shared/telemetry'; | ||
|
||
import { AppSearchPageTemplate } from './page_template'; | ||
|
||
describe('AppSearchPageTemplate', () => { | ||
it('renders', () => { | ||
const wrapper = shallow( | ||
<AppSearchPageTemplate> | ||
<div className="hello">world</div> | ||
</AppSearchPageTemplate> | ||
); | ||
|
||
expect(wrapper.type()).toEqual(EnterpriseSearchPageTemplate); | ||
expect(wrapper.prop('solutionNav')).toEqual({ name: 'App Search', items: [] }); | ||
expect(wrapper.find('.hello').text()).toEqual('world'); | ||
}); | ||
|
||
describe('page chrome', () => { | ||
it('takes a breadcrumb array & renders a product-specific page chrome', () => { | ||
const wrapper = shallow(<AppSearchPageTemplate pageChrome={['Some page']} />); | ||
const setPageChrome = wrapper.find(EnterpriseSearchPageTemplate).prop('setPageChrome') as any; | ||
|
||
expect(setPageChrome.type).toEqual(SetAppSearchChrome); | ||
expect(setPageChrome.props.trail).toEqual(['Some page']); | ||
}); | ||
}); | ||
|
||
describe('page telemetry', () => { | ||
it('takes a metric & renders product-specific telemetry viewed event', () => { | ||
const wrapper = shallow(<AppSearchPageTemplate pageViewTelemetry="some_page" />); | ||
|
||
expect(wrapper.find(SendAppSearchTelemetry).prop('action')).toEqual('viewed'); | ||
expect(wrapper.find(SendAppSearchTelemetry).prop('metric')).toEqual('some_page'); | ||
}); | ||
}); | ||
|
||
it('passes down any ...pageTemplateProps that EnterpriseSearchPageTemplate accepts', () => { | ||
const wrapper = shallow( | ||
<AppSearchPageTemplate | ||
pageHeader={{ pageTitle: 'hello world' }} | ||
isLoading={false} | ||
emptyState={<div />} | ||
/> | ||
); | ||
|
||
expect(wrapper.find(EnterpriseSearchPageTemplate).prop('pageHeader')!.pageTitle).toEqual( | ||
'hello world' | ||
); | ||
expect(wrapper.find(EnterpriseSearchPageTemplate).prop('isLoading')).toEqual(false); | ||
expect(wrapper.find(EnterpriseSearchPageTemplate).prop('emptyState')).toEqual(<div />); | ||
}); | ||
}); |
36 changes: 36 additions & 0 deletions
36
...gins/enterprise_search/public/applications/app_search/components/layout/page_template.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* 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 { APP_SEARCH_PLUGIN } from '../../../../../common/constants'; | ||
import { SetAppSearchChrome } from '../../../shared/kibana_chrome'; | ||
import { EnterpriseSearchPageTemplate, PageTemplateProps } from '../../../shared/layout'; | ||
import { SendAppSearchTelemetry } from '../../../shared/telemetry'; | ||
|
||
import { useAppSearchNav } from './nav'; | ||
|
||
export const AppSearchPageTemplate: React.FC<PageTemplateProps> = ({ | ||
children, | ||
pageChrome, | ||
pageViewTelemetry, | ||
...pageTemplateProps | ||
}) => { | ||
return ( | ||
<EnterpriseSearchPageTemplate | ||
{...pageTemplateProps} | ||
solutionNav={{ | ||
name: APP_SEARCH_PLUGIN.NAME, | ||
items: useAppSearchNav(), | ||
}} | ||
setPageChrome={pageChrome && <SetAppSearchChrome trail={pageChrome} />} | ||
> | ||
{pageViewTelemetry && <SendAppSearchTelemetry action="viewed" metric={pageViewTelemetry} />} | ||
{children} | ||
</EnterpriseSearchPageTemplate> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.