Skip to content

Commit

Permalink
[Workplace Search] Add AccountHeader to Personal dashboard (#96353) (#…
Browse files Browse the repository at this point in the history
…96458)

* Revert change to wrap setContext in useEffect

A recommendation was made to wrap the setContext call in a previous PR, which lets the app know if the context is org or account, in a useEffect call, for potential performance reasons. Unfortunately, this causes the lifecycle to change so that changing routes from org to personal dashboard does not register the change in time. This commit changes it back to a working state.

* Add constants and routes for Account nav

* Add AccountHeader component

* Add header to layout and fix height

The main layout stylesheet, https://github.com/elastic/kibana/blob/master/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.scss gives a static height that includes the main Kibana navigation. The height with the account nav only is added to the existing privateSourcesLayout css class

* Refactor test

Co-authored-by: Scotty Bollinger <scotty.bollinger@elastic.co>
  • Loading branch information
kibanamachine and scottybollinger committed Apr 7, 2021
1 parent 9ed462a commit eb5eff7
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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__';

import React from 'react';

import { shallow } from 'enzyme';

import { EuiHeader, EuiPopover } from '@elastic/eui';

import { AccountHeader } from './';

describe('AccountHeader', () => {
const mockValues = {
account: {
isAdmin: true,
},
};

beforeEach(() => {
setMockValues({ ...mockValues });
});

it('renders', () => {
const wrapper = shallow(<AccountHeader />);

expect(wrapper.find(EuiHeader)).toHaveLength(1);
});

describe('accountSubNav', () => {
it('handles popover trigger click', () => {
const wrapper = shallow(<AccountHeader />);
const popover = wrapper.find(EuiPopover);
const onClick = popover.dive().find('[data-test-subj="AccountButton"]').prop('onClick');
onClick!({} as any);

expect(onClick).toBeDefined();
});

it('handles close popover', () => {
const wrapper = shallow(<AccountHeader />);
const popover = wrapper.find(EuiPopover);
popover.prop('closePopover')!();

expect(popover.prop('isOpen')).toEqual(false);
});
});
});
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 React, { useState } from 'react';

import { useValues } from 'kea';

import {
EuiButton,
EuiButtonEmpty,
EuiHeader,
EuiHeaderLogo,
EuiHeaderLinks,
EuiHeaderSection,
EuiHeaderSectionItem,
EuiText,
EuiContextMenuPanel,
EuiContextMenuItem,
EuiPopover,
} from '@elastic/eui';

import { getWorkplaceSearchUrl } from '../../../../shared/enterprise_search_url';
import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers';
import { AppLogic } from '../../../app_logic';
import { WORKPLACE_SEARCH_TITLE, ACCOUNT_NAV } from '../../../constants';
import {
ALPHA_PATH,
PERSONAL_SOURCES_PATH,
LOGOUT_ROUTE,
KIBANA_ACCOUNT_ROUTE,
} from '../../../routes';

export const AccountHeader: React.FC = () => {
const [isPopoverOpen, setPopover] = useState(false);
const onButtonClick = () => {
setPopover(!isPopoverOpen);
};
const closePopover = () => {
setPopover(false);
};

const {
account: { isAdmin },
} = useValues(AppLogic);

const accountNavItems = [
<EuiContextMenuItem key="accountSettings">
{/* TODO: Once auth is completed, we need to have non-admins redirect to the self-hosted form */}
<EuiButtonEmpty href={KIBANA_ACCOUNT_ROUTE}>{ACCOUNT_NAV.SETTINGS}</EuiButtonEmpty>
</EuiContextMenuItem>,
<EuiContextMenuItem key="logout">
<EuiButtonEmpty href={LOGOUT_ROUTE}>{ACCOUNT_NAV.LOGOUT}</EuiButtonEmpty>
</EuiContextMenuItem>,
];

const accountButton = (
<EuiButtonEmpty
size="s"
data-test-subj="AccountButton"
iconType="arrowDown"
iconSide="right"
onClick={onButtonClick}
>
{ACCOUNT_NAV.ACCOUNT}
</EuiButtonEmpty>
);

return (
<EuiHeader>
<EuiHeaderSection grow={false}>
<EuiHeaderSectionItem>
<EuiHeaderLogo iconType="logoWorkplaceSearch" />
<EuiText>{WORKPLACE_SEARCH_TITLE}</EuiText>
</EuiHeaderSectionItem>
<EuiHeaderSectionItem>
<EuiHeaderLinks>
<EuiButtonEmptyTo to={PERSONAL_SOURCES_PATH}>{ACCOUNT_NAV.SOURCES}</EuiButtonEmptyTo>
</EuiHeaderLinks>
</EuiHeaderSectionItem>
</EuiHeaderSection>
<EuiHeaderSection grow={false} side="right">
<EuiHeaderLinks>
{isAdmin && (
<EuiButtonEmptyTo to={ALPHA_PATH}>{ACCOUNT_NAV.ORG_DASHBOARD}</EuiButtonEmptyTo>
)}
<EuiPopover
id="accountSubNav"
button={accountButton}
isOpen={isPopoverOpen}
closePopover={closePopover}
panelPaddingSize="none"
anchorPosition="downLeft"
>
<EuiContextMenuPanel size="s" items={accountNavItems} />
</EuiPopover>
<EuiButton href={getWorkplaceSearchUrl('/search')} iconType="search">
{ACCOUNT_NAV.SEARCH}
</EuiButton>
</EuiHeaderLinks>
</EuiHeaderSection>
</EuiHeader>
);
};
Original file line number Diff line number Diff line change
@@ -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 { AccountHeader } from './account_header';
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

export { WorkplaceSearchNav } from './nav';
export { WorkplaceSearchHeaderActions } from './kibana_header_actions';
export { AccountHeader } from './account_header';
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import { i18n } from '@kbn/i18n';

import { UPDATE_BUTTON_LABEL, SAVE_BUTTON_LABEL, CANCEL_BUTTON_LABEL } from '../shared/constants';

export const WORKPLACE_SEARCH_TITLE = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.title',
{
defaultMessage: 'Workplace Search',
}
);

export const NAV = {
OVERVIEW: i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.overview', {
defaultMessage: 'Overview',
Expand Down Expand Up @@ -76,6 +83,30 @@ export const NAV = {
}),
};

export const ACCOUNT_NAV = {
SOURCES: i18n.translate('xpack.enterpriseSearch.workplaceSearch.accountNav.sources.link', {
defaultMessage: 'Content sources',
}),
ORG_DASHBOARD: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.accountNav.orgDashboard.link',
{
defaultMessage: 'Go to organizational dashboard',
}
),
SEARCH: i18n.translate('xpack.enterpriseSearch.workplaceSearch.accountNav.search.link', {
defaultMessage: 'Search',
}),
ACCOUNT: i18n.translate('xpack.enterpriseSearch.workplaceSearch.accountNav.account.link', {
defaultMessage: 'My account',
}),
SETTINGS: i18n.translate('xpack.enterpriseSearch.workplaceSearch.accountNav.settings.link', {
defaultMessage: 'Account settings',
}),
LOGOUT: i18n.translate('xpack.enterpriseSearch.workplaceSearch.accountNav.logout.link', {
defaultMessage: 'Logout',
}),
};

export const MAX_TABLE_ROW_ICONS = 3;

export const SOURCE_STATUSES = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@ export const WorkplaceSearchConfigured: React.FC<InitialAppData> = (props) => {
* Personal dashboard urls begin with /p/
* EX: http://localhost:5601/app/enterprise_search/workplace_search/p/sources
*/
useEffect(() => {
const personalSourceUrlRegex = /^\/p\//g; // matches '/p/*'
const isOrganization = !pathname.match(personalSourceUrlRegex); // TODO: Once auth is figured out, we need to have a check for the equivilent of `isAdmin`.

setContext(isOrganization);
const personalSourceUrlRegex = /^\/p\//g; // matches '/p/*'
const isOrganization = !pathname.match(personalSourceUrlRegex); // TODO: Once auth is figured out, we need to have a check for the equivilent of `isAdmin`.

setContext(isOrganization);

useEffect(() => {
setChromeIsVisible(isOrganization);
}, [pathname]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { docLinks } from '../shared/doc_links';
export const SETUP_GUIDE_PATH = '/setup_guide';

export const NOT_FOUND_PATH = '/404';
export const LOGOUT_ROUTE = '/logout';
export const KIBANA_ACCOUNT_ROUTE = '/security/account';

export const LEAVE_FEEDBACK_EMAIL = 'support@elastic.co';
export const LEAVE_FEEDBACK_URL = `mailto:${LEAVE_FEEDBACK_EMAIL}?Subject=Elastic%20Workplace%20Search%20Feedback`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { shallow } from 'enzyme';

import { EuiCallOut } from '@elastic/eui';

import { AccountHeader } from '../../components/layout';
import { ViewContentHeader } from '../../components/shared/view_content_header';

import { SourceSubNav } from './components/source_sub_nav';
Expand Down Expand Up @@ -43,6 +44,7 @@ describe('PrivateSourcesLayout', () => {

expect(wrapper.find('[data-test-subj="TestChildren"]')).toHaveLength(1);
expect(wrapper.find(SourceSubNav)).toHaveLength(1);
expect(wrapper.find(AccountHeader)).toHaveLength(1);
});

it('uses correct title and description when private sources are enabled', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useValues } from 'kea';
import { EuiPage, EuiPageSideBar, EuiPageBody, EuiCallOut } from '@elastic/eui';

import { AppLogic } from '../../app_logic';
import { AccountHeader } from '../../components/layout';
import { ViewContentHeader } from '../../components/shared/view_content_header';

import { SourceSubNav } from './components/source_sub_nav';
Expand Down Expand Up @@ -48,22 +49,25 @@ export const PrivateSourcesLayout: React.FC<LayoutProps> = ({
: PRIVATE_VIEW_ONLY_PAGE_DESCRIPTION;

return (
<EuiPage className="enterpriseSearchLayout privateSourcesLayout">
<EuiPageSideBar className="enterpriseSearchLayout__sideBar privateSourcesLayout__sideBar">
<ViewContentHeader title={PAGE_TITLE} description={PAGE_DESCRIPTION} />
<SourceSubNav />
</EuiPageSideBar>
<EuiPageBody className="enterpriseSearchLayout__body" restrictWidth={restrictWidth}>
{readOnlyMode && (
<EuiCallOut
className="enterpriseSearchLayout__readOnlyMode"
color="warning"
iconType="lock"
title={PRIVATE_DASHBOARD_READ_ONLY_MODE_WARNING}
/>
)}
{children}
</EuiPageBody>
</EuiPage>
<>
<AccountHeader />
<EuiPage className="enterpriseSearchLayout privateSourcesLayout">
<EuiPageSideBar className="enterpriseSearchLayout__sideBar privateSourcesLayout__sideBar">
<ViewContentHeader title={PAGE_TITLE} description={PAGE_DESCRIPTION} />
<SourceSubNav />
</EuiPageSideBar>
<EuiPageBody className="enterpriseSearchLayout__body" restrictWidth={restrictWidth}>
{readOnlyMode && (
<EuiCallOut
className="enterpriseSearchLayout__readOnlyMode"
color="warning"
iconType="lock"
title={PRIVATE_DASHBOARD_READ_ONLY_MODE_WARNING}
/>
)}
{children}
</EuiPageBody>
</EuiPage>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@

.privateSourcesLayout {
$sideBarWidth: $euiSize * 30;
$consoleHeaderHeight: 48px; // NOTE: Keep an eye on this for changes
$pageHeight: calc(100vh - #{$consoleHeaderHeight});

left: $sideBarWidth;
width: calc(100% - #{$sideBarWidth});
min-height: $pageHeight;

&__sideBar {
padding: 32px 40px 40px;
width: $sideBarWidth;
margin-left: -$sideBarWidth;
height: $pageHeight;
}
}

Expand Down

0 comments on commit eb5eff7

Please sign in to comment.