[gloablHeader/apps] use lastSubUrl when appropriate (#28735)

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).
This commit is contained in:
Spencer 2019-01-15 12:19:08 -08:00 committed by GitHub
parent 1078782106
commit ba30b72c90
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 8 deletions

View file

@ -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];

View file

@ -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);
};

View file

@ -46,7 +46,7 @@ interface Props {
breadcrumbs$: Rx.Observable<Breadcrumb[]>;
homeHref: string;
isVisible: boolean;
navLinks: NavLink[];
navLinks$: Rx.Observable<NavLink[]>;
navControls: ChromeHeaderNavControlsRegistry;
intl: InjectedIntl;
}
@ -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;
@ -90,7 +90,7 @@ class HeaderUI extends Component<Props> {
<HeaderNavControls navControls={rightNavControls} />
<EuiHeaderSectionItem>
<HeaderAppMenu navLinks={navLinks} />
<HeaderAppMenu navLinks$={navLinks$} />
</EuiHeaderSectionItem>
</EuiHeaderSection>
</EuiHeader>

View file

@ -18,6 +18,7 @@
*/
import React, { Component } from 'react';
import * as Rx from 'rxjs';
import {
// TODO: add type annotations
@ -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
@ -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}
>

View file

@ -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), [
@ -39,7 +38,7 @@ module.directive('headerGlobalNav', (reactDirective, chrome, Private) => {
// angular injected React props
{
breadcrumbs$: chrome.breadcrumbs.get$(),
navLinks,
navLinks$: chrome.getNavLinks$(),
navControls,
homeHref
});

View file

@ -37,4 +37,6 @@ export interface NavLink {
url: string;
id: string;
euiIconType: IconType;
lastSubUrl?: string;
active: boolean;
}