Skip to content

Commit

Permalink
[wip] move nav to core
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdover committed Apr 3, 2019
1 parent 0ca2422 commit 9ddf3f8
Show file tree
Hide file tree
Showing 23 changed files with 333 additions and 200 deletions.
26 changes: 8 additions & 18 deletions src/core/public/chrome/chrome_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ import * as Url from 'url';
import { i18n } from '@kbn/i18n';
import * as Rx from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { BasePathSetup } from '../base_path';
import { InjectedMetadataSetup } from '../injected_metadata';
import { NotificationsSetup } from '../notifications';
import { NavLinksService } from './nav_links/nav_links_service';

const IS_COLLAPSED_KEY = 'core.chrome.isCollapsed';

Expand All @@ -50,19 +52,21 @@ interface ConstructorParams {
}

interface SetupDeps {
basePath: BasePathSetup;
injectedMetadata: InjectedMetadataSetup;
notifications: NotificationsSetup;
}

export class ChromeService {
private readonly stop$ = new Rx.ReplaySubject(1);
private readonly browserSupportsCsp: boolean;
private readonly navLinks = new NavLinksService();

public constructor({ browserSupportsCsp }: ConstructorParams) {
this.browserSupportsCsp = browserSupportsCsp;
}

public setup({ injectedMetadata, notifications }: SetupDeps) {
public setup({ basePath, injectedMetadata, notifications }: SetupDeps) {
const FORCE_HIDDEN = isEmbedParamInHash();

const brand$ = new Rx.BehaviorSubject<ChromeBrand>({});
Expand Down Expand Up @@ -96,14 +100,8 @@ export class ChromeService {
*
*/
setBrand: (brand: ChromeBrand) => {
brand$.next(
Object.freeze({
logo: brand.logo,
smallLogo: brand.smallLogo,
})
);
brand$.next(Object.freeze({ logo: brand.logo, smallLogo: brand.smallLogo }));
},

/**
* Get an observable of the current brand information.
*/
Expand All @@ -117,7 +115,6 @@ export class ChromeService {
setIsVisible: (visibility: boolean) => {
isVisible$.next(visibility);
},

/**
* Get an observable of the current visibility state of the chrome.
*/
Expand All @@ -126,7 +123,6 @@ export class ChromeService {
map(visibility => (FORCE_HIDDEN ? false : visibility)),
takeUntil(this.stop$)
),

/**
* Set the collapsed state of the chrome navigation.
*/
Expand All @@ -138,12 +134,10 @@ export class ChromeService {
localStorage.removeItem(IS_COLLAPSED_KEY);
}
},

/**
* Get an observable of the current collapsed state of the chrome.
*/
getIsCollapsed$: () => isCollapsed$.pipe(takeUntil(this.stop$)),

/**
* Add a className that should be set on the application container.
*/
Expand All @@ -152,7 +146,6 @@ export class ChromeService {
update.add(className);
applicationClasses$.next(update);
},

/**
* Remove a className added with `addApplicationClass()`. If className is unknown it is ignored.
*/
Expand All @@ -161,7 +154,6 @@ export class ChromeService {
update.delete(className);
applicationClasses$.next(update);
},

/**
* Get the current set of classNames that will be set on the application container.
*/
Expand All @@ -170,34 +162,32 @@ export class ChromeService {
map(set => [...set]),
takeUntil(this.stop$)
),

/**
* Get an observable of the current list of breadcrumbs
*/
getBreadcrumbs$: () => breadcrumbs$.pipe(takeUntil(this.stop$)),

/**
* Override the current set of breadcrumbs
*/
setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => {
breadcrumbs$.next(newBreadcrumbs);
},

/**
* Get an observable of the current custom help conttent
*/
getHelpExtension$: () => helpExtension$.pipe(takeUntil(this.stop$)),

/**
* Override the current set of breadcrumbs
*/
setHelpExtension: (helpExtension?: ChromeHelpExtension) => {
helpExtension$.next(helpExtension);
},
navLinks: this.navLinks.setup(basePath),
};
}

public stop() {
this.navLinks.stop();
this.stop$.next();
}
}
Expand Down
55 changes: 55 additions & 0 deletions src/core/public/chrome/nav_links/nav_link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { BasePathSetup } from '../../base_path';

export interface NavLinkProperties {
disabled: boolean;
euiIconType?: string;
hidden: boolean;
icon?: string;
id: string;
linkToLastSubUrl: boolean;
order: number;
title: string;
tooltip: string;
url: string;
}

export class NavLink {
public readonly id: string;
public readonly properties: Readonly<NavLinkProperties>;

constructor(properties: NavLinkProperties, private readonly basePath: BasePathSetup) {
if (!properties || !properties.id) {
throw new Error('`id` is required.');
}

this.id = properties.id;
this.properties = Object.freeze(properties);
}

public getUrl() {
return this.basePath.addToPath(this.properties.url);
}

public update(newProps: Partial<NavLinkProperties>) {
return new NavLink({ ...this.properties, ...newProps }, this.basePath);
}
}
88 changes: 88 additions & 0 deletions src/core/public/chrome/nav_links/nav_links_service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { sortBy } from 'lodash';
import { BehaviorSubject, ReplaySubject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { BasePathSetup } from '../../base_path';
import { NavLink, NavLinkProperties } from './nav_link';

export class NavLinksService {
private readonly stop$ = new ReplaySubject(1);

public setup(basePath: BasePathSetup) {
const navLinks$ = new BehaviorSubject<ReadonlyArray<NavLink>>([]);

return {
getNavLinks$: () => {
return navLinks$.pipe(
map(sortNavLinks),
takeUntil(this.stop$)
);
},

add(navLink: NavLinkProperties) {
navLinks$.next([...navLinks$.value, new NavLink(navLink, basePath)]);
},

clear() {
navLinks$.next([]);
},

get(id: string) {
const link = navLinks$.value.find(l => l.id === id);
return link ? link.properties : undefined;
},

getAll() {
return sortNavLinks(navLinks$.value);
},

exists(id: string) {
return this.get(id) !== undefined;
},

showOnly(id: string) {
navLinks$.next(navLinks$.value.filter(link => link.id === id));
},

update(id: string, values: Partial<NavLinkProperties>) {
if (!this.exists(id)) {
return;
}

navLinks$.next(
navLinks$.value.map(link => {
return link.id === id ? link.update(values) : link;
})
);

return this.get(id);
},
};
}

public stop() {
this.stop$.next();
}
}

function sortNavLinks(navLinks: ReadonlyArray<NavLink>) {
return sortBy(navLinks.map(link => link.properties), 'order');
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface InjectedMetadataParams {
app: unknown;
translations: unknown;
bundleId: string;
nav: unknown;
nav: any[];
version: string;
branch: string;
buildNum: number;
Expand Down
2 changes: 2 additions & 0 deletions src/core/public/legacy/legacy_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export class LegacyPlatformService {
require('ui/chrome/api/breadcrumbs').__newPlatformInit__(chrome);
require('ui/chrome/services/global_nav_state').__newPlatformInit__(chrome);

injectedMetadata.getLegacyMetadata().nav.forEach(navLink => chrome.navLinks.add(navLink));

// Load the bootstrap module before loading the legacy platform files so that
// the bootstrap module can modify the environment a bit first
const bootstrapModule = this.loadBootstrapModule();
Expand Down
5 changes: 4 additions & 1 deletion src/legacy/core_plugins/kibana/public/context/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import { i18n } from '@kbn/i18n';
import './app';
import contextAppRouteTemplate from './index.html';
import { getRootBreadcrumbs } from '../discover/breadcrumbs';
import { getNewPlatform } from 'ui/new_platform';

const core = getNewPlatform().setup.core;

uiRoutes
.when('/context/:indexPatternId/:type/:id*', {
Expand Down Expand Up @@ -85,7 +88,7 @@ function ContextAppRouteController(
this.anchorType = $routeParams.type;
this.anchorId = $routeParams.id;
this.indexPattern = indexPattern;
this.discoverUrl = chrome.getNavLinkById('kibana:discover').lastSubUrl;
this.discoverUrl = core.chrome.navLinks.get('kibana:discover').lastSubUrl;
this.filters = _.cloneDeep(queryFilter.getFilters());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import expect from '@kbn/expect';
import sinon from 'sinon';

import chrome from 'ui/chrome';
import { hideEmptyDevTools } from '../hide_empty_tools';
import { getNewPlatform } from 'ui/new_platform';

const coreNavLinks = getNewPlatform().setup.core.chrome.navLinks;

describe('hide dev tools', function () {
let navlinks;
let updateNavLink;

function PrivateWithoutTools() {
return [];
Expand All @@ -35,12 +37,11 @@ describe('hide dev tools', function () {
}

function isHidden() {
return !!chrome.getNavLinkById('kibana:dev_tools').hidden;
return updateNavLink.calledWith('kibana:dev_tools', { hidden: true });
}

beforeEach(function () {
navlinks = {};
sinon.stub(chrome, 'getNavLinkById').returns(navlinks);
updateNavLink = sinon.spy(coreNavLinks, 'update');
});

it('should hide the app if there are no dev tools', function () {
Expand All @@ -54,6 +55,6 @@ describe('hide dev tools', function () {
});

afterEach(function () {
chrome.getNavLinkById.restore();
updateNavLink.restore();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@
*/

import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome';
import { DevToolsRegistryProvider } from 'ui/registry/dev_tools';
import { getNewPlatform } from 'ui/new_platform';

const core = getNewPlatform().setup.core;

export function hideEmptyDevTools(Private) {
const hasTools = !!Private(DevToolsRegistryProvider).length;
if (!hasTools) {
const navLink = chrome.getNavLinkById('kibana:dev_tools');
navLink.hidden = true;
core.chrome.navLinks.update('kibana:dev_tools', {
hidden: true
});
}
}

Expand Down
Loading

0 comments on commit 9ddf3f8

Please sign in to comment.