Skip to content

Commit

Permalink
[gloablHeader/apps] use lastSubUrl when appropriate (#28735)
Browse files Browse the repository at this point in the history
When we added the k7 header we never brought over the `lastSubUrl` feature used to resume a previous state of an app that was left. This re-implements the feature by deep watching the navLinks (which are mutated directly in a number of locations) and re-emitting the list of navLinks they are updated.

The logic for when to render the `navLink.lastSubUrl` was taken [from the current navigation](https://github.com/elastic/kibana/blob/master/src/ui/public/chrome/directives/global_nav/app_switcher/app_switcher.html#L8).
  • Loading branch information
Spencer committed Jan 15, 2019
1 parent 1078782 commit ba30b72
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/ui/public/chrome/api/angular.js
Expand Up @@ -68,6 +68,7 @@ export function initAngularApi(chrome, internals) {
})
.run(internals.capture$httpLoadingCount)
.run(internals.$setupBreadcrumbsAutoClear)
.run(internals.$initNavLinksDeepWatch)
.run(($location, $rootScope, Private, config) => {
chrome.getFirstPathSegment = () => {
return $location.path().split('/')[1];
Expand Down
18 changes: 18 additions & 0 deletions src/ui/public/chrome/api/nav.js
Expand Up @@ -17,15 +17,33 @@
* under the License.
*/

import * as Rx from 'rxjs';
import { mapTo } from 'rxjs/operators';
import { remove } from 'lodash';
import { relativeToAbsolute } from '../../url/relative_to_absolute';
import { absoluteToParsedUrl } from '../../url/absolute_to_parsed_url';

export function initChromeNavApi(chrome, internals) {
const navUpdate$ = new Rx.BehaviorSubject(undefined);

chrome.getNavLinks = function () {
return internals.nav;
};

chrome.getNavLinks$ = function () {
return navUpdate$.pipe(mapTo(internals.nav));
};

// track navLinks with $rootScope.$watch like the old nav used to, necessary
// as long as random parts of the app are directly mutating the navLinks
internals.$initNavLinksDeepWatch = function ($rootScope) {
$rootScope.$watch(
() => internals.nav,
() => navUpdate$.next(),
true
);
};

chrome.navLinkExists = (id) => {
return !!internals.nav.find(link => link.id === id);
};
Expand Down
Expand Up @@ -46,7 +46,7 @@ interface Props {
breadcrumbs$: Rx.Observable<Breadcrumb[]>;
homeHref: string;
isVisible: boolean;
navLinks: NavLink[];
navLinks$: Rx.Observable<NavLink[]>;
navControls: ChromeHeaderNavControlsRegistry;
intl: InjectedIntl;
}
Expand All @@ -67,7 +67,7 @@ class HeaderUI extends Component<Props> {
}

public render() {
const { appTitle, breadcrumbs$, isVisible, navControls, navLinks } = this.props;
const { appTitle, breadcrumbs$, isVisible, navControls, navLinks$ } = this.props;

if (!isVisible) {
return null;
Expand All @@ -90,7 +90,7 @@ class HeaderUI extends Component<Props> {
<HeaderNavControls navControls={rightNavControls} />

<EuiHeaderSectionItem>
<HeaderAppMenu navLinks={navLinks} />
<HeaderAppMenu navLinks$={navLinks$} />
</EuiHeaderSectionItem>
</EuiHeaderSection>
</EuiHeader>
Expand Down
Expand Up @@ -18,6 +18,7 @@
*/

import React, { Component } from 'react';
import * as Rx from 'rxjs';

import {
// TODO: add type annotations
Expand All @@ -36,25 +37,45 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import { NavLink } from '../';

interface Props {
navLinks: NavLink[];
navLinks$: Rx.Observable<NavLink[]>;
intl: InjectedIntl;
}

interface State {
isOpen: boolean;
navLinks: NavLink[];
}

class HeaderAppMenuUI extends Component<Props, State> {
private subscription?: Rx.Subscription;

constructor(props: Props) {
super(props);

this.state = {
isOpen: false,
navLinks: [],
};
}

public componentDidMount() {
this.subscription = this.props.navLinks$.subscribe({
next: navLinks => {
this.setState({ navLinks });
},
});
}

public componentWillUnmount() {
if (this.subscription) {
this.subscription.unsubscribe();
this.subscription = undefined;
}
}

public render() {
const { navLinks = [], intl } = this.props;
const { intl } = this.props;
const { navLinks } = this.state;

const button = (
<EuiHeaderSectionItemButton
Expand Down Expand Up @@ -103,7 +124,7 @@ class HeaderAppMenuUI extends Component<Props, State> {
private renderNavLink = (navLink: NavLink) => (
<EuiKeyPadMenuItem
label={navLink.title}
href={navLink.url}
href={navLink.active || !navLink.lastSubUrl ? navLink.url : navLink.lastSubUrl}
key={navLink.id}
onClick={this.closeMenu}
>
Expand Down
Expand Up @@ -27,7 +27,6 @@ const module = uiModules.get('kibana');

module.directive('headerGlobalNav', (reactDirective, chrome, Private) => {
const navControls = Private(chromeHeaderNavControlsRegistry);
const navLinks = chrome.getNavLinks();
const homeHref = chrome.addBasePath('/app/kibana#/home');

return reactDirective(injectI18nProvider(Header), [
Expand All @@ -39,7 +38,7 @@ module.directive('headerGlobalNav', (reactDirective, chrome, Private) => {
// angular injected React props
{
breadcrumbs$: chrome.breadcrumbs.get$(),
navLinks,
navLinks$: chrome.getNavLinks$(),
navControls,
homeHref
});
Expand Down
2 changes: 2 additions & 0 deletions src/ui/public/chrome/directives/header_global_nav/index.ts
Expand Up @@ -37,4 +37,6 @@ export interface NavLink {
url: string;
id: string;
euiIconType: IconType;
lastSubUrl?: string;
active: boolean;
}

0 comments on commit ba30b72

Please sign in to comment.