diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index 61b83cb38c9d0..686c55ebd099b 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -40,6 +40,7 @@ module.exports = function (kibana) { links: [ { + id: 'kibana:discover', title: 'Discover', order: -1003, url: '/app/kibana#/discover', @@ -47,6 +48,7 @@ module.exports = function (kibana) { icon: 'plugins/kibana/assets/discover.svg', }, { + id: 'kibana:visualize', title: 'Visualize', order: -1002, url: '/app/kibana#/visualize', @@ -54,6 +56,7 @@ module.exports = function (kibana) { icon: 'plugins/kibana/assets/visualize.svg', }, { + id: 'kibana:dashboard', title: 'Dashboard', order: -1001, url: '/app/kibana#/dashboard', @@ -61,6 +64,7 @@ module.exports = function (kibana) { icon: 'plugins/kibana/assets/dashboard.svg', }, { + id: 'kibana:management', title: 'Management', order: 1000, url: '/app/kibana#/management', diff --git a/src/ui/__tests__/ui_nav_link.js b/src/ui/__tests__/ui_nav_link.js new file mode 100644 index 0000000000000..f264ccf426ecc --- /dev/null +++ b/src/ui/__tests__/ui_nav_link.js @@ -0,0 +1,159 @@ +import expect from 'expect.js'; + +import UiNavLink from '../ui_nav_link'; + +describe('UiNavLink', () => { + describe('constructor', () => { + it ('initializes the object properties as expected', () => { + const uiExports = { + urlBasePath: 'http://localhost:5601/rnd' + }; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + hidden: true, + disabled: true + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.id).to.be(spec.id); + expect(link.title).to.be(spec.title); + expect(link.order).to.be(spec.order); + expect(link.url).to.be(`${uiExports.urlBasePath}${spec.url}`); + expect(link.description).to.be(spec.description); + expect(link.icon).to.be(spec.icon); + expect(link.hidden).to.be(spec.hidden); + expect(link.disabled).to.be(spec.disabled); + }); + + it ('initializes the url property without a base path when one is not specified in the spec', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.url).to.be(spec.url); + }); + + it ('initializes the order property to 0 when order is not specified in the spec', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.order).to.be(0); + }); + + it ('initializes the linkToLastSubUrl property to false when false is specified in the spec', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + linkToLastSubUrl: false + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.linkToLastSubUrl).to.be(false); + }); + + it ('initializes the linkToLastSubUrl property to true by default', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.linkToLastSubUrl).to.be(true); + }); + + it ('initializes the hidden property to false by default', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.hidden).to.be(false); + }); + + it ('initializes the disabled property to false by default', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.disabled).to.be(false); + }); + + it ('initializes the tooltip property to an empty string by default', () => { + const uiExports = {}; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + + expect(link.tooltip).to.be(''); + }); + }); + + describe('#toJSON', () => { + it ('returns the expected properties', () => { + const uiExports = { + urlBasePath: 'http://localhost:5601/rnd' + }; + const spec = { + id: 'kibana:discover', + title: 'Discover', + order: -1003, + url: '/app/kibana#/discover', + description: 'interactively explore your data', + icon: 'plugins/kibana/assets/discover.svg', + }; + const link = new UiNavLink(uiExports, spec); + const json = link.toJSON(); + + ['id', 'title', 'url', 'order', 'description', 'icon', 'linkToLastSubUrl', 'hidden', 'disabled', 'tooltip'] + .forEach(expectedProperty => expect(json).to.have.property(expectedProperty)); + }); + }); +}); diff --git a/src/ui/public/chrome/api/__tests__/nav.js b/src/ui/public/chrome/api/__tests__/nav.js index 8dffa7e4eebbe..735cde4683987 100644 --- a/src/ui/public/chrome/api/__tests__/nav.js +++ b/src/ui/public/chrome/api/__tests__/nav.js @@ -45,6 +45,35 @@ describe('chrome nav apis', function () { }); }); + describe('#getNavLinkById', () => { + it ('retrieves the correct nav link, given its ID', () => { + const appUrlStore = new StubBrowserStorage(); + const nav = [ + { id: 'kibana:discover', title: 'Discover' } + ]; + const { chrome, internals } = init({ appUrlStore, nav }); + + const navLink = chrome.getNavLinkById('kibana:discover'); + expect(navLink).to.eql(nav[0]); + }); + + it ('throws an error if the nav link with the given ID is not found', () => { + const appUrlStore = new StubBrowserStorage(); + const nav = [ + { id: 'kibana:discover', title: 'Discover' } + ]; + const { chrome, internals } = init({ appUrlStore, nav }); + + let errorThrown = false; + try { + const navLink = chrome.getNavLinkById('nonexistent'); + } catch (e) { + errorThrown = true; + } + expect(errorThrown).to.be(true); + }); + }); + describe('internals.trackPossibleSubUrl()', function () { it('injects the globalState of the current url to all links for the same app', function () { const appUrlStore = new StubBrowserStorage(); diff --git a/src/ui/public/chrome/api/nav.js b/src/ui/public/chrome/api/nav.js index fc815a34163a8..f78ea3a364162 100644 --- a/src/ui/public/chrome/api/nav.js +++ b/src/ui/public/chrome/api/nav.js @@ -6,6 +6,14 @@ export default function (chrome, internals) { return internals.nav; }; + chrome.getNavLinkById = (id) => { + const navLink = internals.nav.find(link => link.id === id); + if (!navLink) { + throw new Error(`Nav link for id = ${id} not found`); + } + return navLink; + }; + chrome.getBasePath = function () { return internals.basePath || ''; }; diff --git a/src/ui/public/chrome/directives/app_switcher/app_switcher.html b/src/ui/public/chrome/directives/app_switcher/app_switcher.html index 1e0a0d0e665da..10f5697bc8afa 100644 --- a/src/ui/public/chrome/directives/app_switcher/app_switcher.html +++ b/src/ui/public/chrome/directives/app_switcher/app_switcher.html @@ -1,13 +1,20 @@