Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [KibanaPageTemplate] Adds collapsibility to solutionNav (#103192) #103747

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

1,871 changes: 655 additions & 1,216 deletions src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap

Large diffs are not rendered by default.

11 changes: 2 additions & 9 deletions src/core/public/chrome/ui/header/collapsible_nav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function mockProps() {
navigateToApp: () => Promise.resolve(),
navigateToUrl: () => Promise.resolve(),
customNavLink$: new BehaviorSubject(undefined),
button: <button />,
};
}

Expand All @@ -76,19 +77,11 @@ function clickGroup(component: ReactWrapper, group: string) {
describe('CollapsibleNav', () => {
// this test is mostly an "EUI works as expected" sanity check
it('renders the default nav', () => {
const onLock = sinon.spy();
const component = mount(<CollapsibleNav {...mockProps()} onIsLockedUpdate={onLock} />);
const component = mount(<CollapsibleNav {...mockProps()} />);
expect(component).toMatchSnapshot();

component.setProps({ isOpen: true });
expect(component).toMatchSnapshot();

component.setProps({ isLocked: true });
expect(component).toMatchSnapshot();

// limit the find to buttons because jest also renders data-test-subj on a JSX wrapper element
component.find('button[data-test-subj="collapsible-nav-lock"]').simulate('click');
expect(onLock.callCount).toEqual(1);
});

it('renders links grouped by category', () => {
Expand Down
57 changes: 34 additions & 23 deletions src/core/public/chrome/ui/header/collapsible_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import {
EuiListGroup,
EuiListGroupItem,
EuiShowFor,
EuiText,
EuiCollapsibleNavProps,
EuiButton,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { groupBy, sortBy } from 'lodash';
import React, { Fragment, useRef } from 'react';
import useObservable from 'react-use/lib/useObservable';
Expand Down Expand Up @@ -78,6 +80,7 @@ interface Props {
navigateToApp: InternalApplicationStart['navigateToApp'];
navigateToUrl: InternalApplicationStart['navigateToUrl'];
customNavLink$: Rx.Observable<ChromeNavLink | undefined>;
button: EuiCollapsibleNavProps['button'];
}

export function CollapsibleNav({
Expand All @@ -91,6 +94,7 @@ export function CollapsibleNav({
closeNav,
navigateToApp,
navigateToUrl,
button,
...observables
}: Props) {
const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden);
Expand Down Expand Up @@ -121,8 +125,10 @@ export function CollapsibleNav({
defaultMessage: 'Primary',
})}
isOpen={isNavOpen}
isDocked={isLocked}
onClose={closeNav}
button={button}
ownFocus={false}
size={240}
>
{customNavLink && (
<Fragment>
Expand Down Expand Up @@ -192,16 +198,18 @@ export function CollapsibleNav({
</EuiFlexItem>

{/* Recently viewed */}
<EuiCollapsibleNavGroup
key="recentlyViewed"
background="light"
title={i18n.translate('core.ui.recentlyViewed', { defaultMessage: 'Recently viewed' })}
isCollapsible={true}
initialIsOpen={getIsCategoryOpen('recentlyViewed', storage)}
onToggle={(isCategoryOpen) => setIsCategoryOpen('recentlyViewed', isCategoryOpen, storage)}
data-test-subj="collapsibleNavGroup-recentlyViewed"
>
{recentlyAccessed.length > 0 ? (
{recentlyAccessed.length > 0 && (
<EuiCollapsibleNavGroup
key="recentlyViewed"
background="light"
title={i18n.translate('core.ui.recentlyViewed', { defaultMessage: 'Recently viewed' })}
isCollapsible={true}
initialIsOpen={getIsCategoryOpen('recentlyViewed', storage)}
onToggle={(isCategoryOpen) =>
setIsCategoryOpen('recentlyViewed', isCategoryOpen, storage)
}
data-test-subj="collapsibleNavGroup-recentlyViewed"
>
<EuiListGroup
aria-label={i18n.translate('core.ui.recentlyViewedAriaLabel', {
defaultMessage: 'Recently viewed links',
Expand Down Expand Up @@ -233,16 +241,8 @@ export function CollapsibleNav({
size="s"
className="kbnCollapsibleNav__recentsListGroup"
/>
) : (
<EuiText size="s" color="subdued" style={{ padding: '0 8px 8px' }}>
<p>
{i18n.translate('core.ui.EmptyRecentlyViewed', {
defaultMessage: 'No recently viewed items',
})}
</p>
</EuiText>
)}
</EuiCollapsibleNavGroup>
</EuiCollapsibleNavGroup>
)}

<EuiHorizontalRule margin="none" />

Expand All @@ -255,6 +255,7 @@ export function CollapsibleNav({
<EuiCollapsibleNavGroup
key={category.id}
iconType={category.euiIconType}
iconSize="m"
title={category.label}
isCollapsible={true}
initialIsOpen={getIsCategoryOpen(category.id, storage)}
Expand Down Expand Up @@ -286,7 +287,7 @@ export function CollapsibleNav({
))}

{/* Docking button only for larger screens that can support it*/}
<EuiShowFor sizes={['l', 'xl']}>
<EuiShowFor sizes={'none'}>
<EuiCollapsibleNavGroup>
<EuiListGroup flush>
<EuiListGroupItem
Expand Down Expand Up @@ -324,6 +325,16 @@ export function CollapsibleNav({
</EuiCollapsibleNavGroup>
</EuiShowFor>
</EuiFlexItem>
{/* Quick addition of that "ADD DATA" button everyone wants :) Feel free to remove though. */}
<EuiFlexItem grow={false}>
{/* Span fakes the nav group into not being the first item and therefore adding a top border */}
<span />
<EuiCollapsibleNavGroup>
<EuiButton fill fullWidth iconType="plusInCircleFilled">
<FormattedMessage id="core.ui.primaryNavSection.addDataBtn" defaultMessage="Add Data" />
</EuiButton>
</EuiCollapsibleNavGroup>
</EuiFlexItem>
</EuiCollapsibleNav>
);
}
69 changes: 35 additions & 34 deletions src/core/public/chrome/ui/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,19 +160,41 @@ export function Header({
<EuiHeader position="fixed" className="header__secondBar">
<EuiHeaderSection grow={false}>
<EuiHeaderSectionItem border="right" className="header__toggleNavButtonSection">
<EuiHeaderSectionItemButton
data-test-subj="toggleNavButton"
aria-label={i18n.translate('core.ui.primaryNav.toggleNavAriaLabel', {
defaultMessage: 'Toggle primary navigation',
})}
onClick={() => setIsNavOpen(!isNavOpen)}
aria-expanded={isNavOpen}
aria-pressed={isNavOpen}
aria-controls={navId}
ref={toggleCollapsibleNavRef}
>
<EuiIcon type="menu" size="m" />
</EuiHeaderSectionItemButton>
<CollapsibleNav
appId$={application.currentAppId$}
id={navId}
isLocked={isLocked}
navLinks$={observables.navLinks$}
recentlyAccessed$={observables.recentlyAccessed$}
isNavOpen={isNavOpen}
homeHref={homeHref}
basePath={basePath}
navigateToApp={application.navigateToApp}
navigateToUrl={application.navigateToUrl}
onIsLockedUpdate={onIsLockedUpdate}
closeNav={() => {
setIsNavOpen(false);
if (toggleCollapsibleNavRef.current) {
toggleCollapsibleNavRef.current.focus();
}
}}
customNavLink$={observables.customNavLink$}
button={
<EuiHeaderSectionItemButton
data-test-subj="toggleNavButton"
aria-label={i18n.translate('core.ui.primaryNav.toggleNavAriaLabel', {
defaultMessage: 'Toggle primary navigation',
})}
onClick={() => setIsNavOpen(!isNavOpen)}
aria-expanded={isNavOpen}
aria-pressed={isNavOpen}
aria-controls={navId}
ref={toggleCollapsibleNavRef}
>
<EuiIcon type="menu" size="m" />
</EuiHeaderSectionItemButton>
}
/>
</EuiHeaderSectionItem>

<HeaderNavControls side="left" navControls$={observables.navControlsLeft$} />
Expand Down Expand Up @@ -205,27 +227,6 @@ export function Header({
</EuiHeaderSection>
</EuiHeader>
</div>

<CollapsibleNav
appId$={application.currentAppId$}
id={navId}
isLocked={isLocked}
navLinks$={observables.navLinks$}
recentlyAccessed$={observables.recentlyAccessed$}
isNavOpen={isNavOpen}
homeHref={homeHref}
basePath={basePath}
navigateToApp={application.navigateToApp}
navigateToUrl={application.navigateToUrl}
onIsLockedUpdate={onIsLockedUpdate}
closeNav={() => {
setIsNavOpen(false);
if (toggleCollapsibleNavRef.current) {
toggleCollapsibleNavRef.current.focus();
}
}}
customNavLink$={observables.customNavLink$}
/>
</header>
</>
);
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 7 additions & 11 deletions src/plugins/kibana_react/public/page_template/page_template.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
$euiSideNavEmphasizedBackgroundColor: transparentize($euiColorLightShade, .7);

.kbnPageTemplate__pageSideBar {
padding: $euiSizeL;
background:
linear-gradient(160deg, $euiSideNavEmphasizedBackgroundColor 0, $euiSideNavEmphasizedBackgroundColor $euiSizeXL, rgba(#FFF, 0) 0),
linear-gradient(175deg, $euiSideNavEmphasizedBackgroundColor 0, $euiSideNavEmphasizedBackgroundColor $euiSize, rgba(#FFF, 0) 0);
}
overflow: hidden;

@include euiCanAnimate {
transition: min-width $euiAnimSpeedFast $euiAnimSlightResistance;
}

@include euiBreakpoint('xs','s') {
.kbnPageTemplate__pageSideBar {
width: auto;
padding: 0;
&.kbnPageTemplate__pageSideBar--shrink {
min-width: $euiSizeXXL + $euiSize;
}
}
Loading