diff --git a/src/core_plugins/console/public/tests/tests.js b/src/core_plugins/console/public/tests/tests.js index 27b022c1b870c..449677915683d 100644 --- a/src/core_plugins/console/public/tests/tests.js +++ b/src/core_plugins/console/public/tests/tests.js @@ -1,10 +1,6 @@ require('ace'); require('ui/chrome') - .setTabs([{ - id: '', - title: 'Sense Tests' - }]) .setRootTemplate(require('./index.html')) .setRootController(function () { window.QUnit = require('qunit-1.10.0'); diff --git a/src/core_plugins/kibana/public/kibana.js b/src/core_plugins/kibana/public/kibana.js index 41ec204bde5a1..222964447c3a6 100644 --- a/src/core_plugins/kibana/public/kibana.js +++ b/src/core_plugins/kibana/public/kibana.js @@ -28,11 +28,6 @@ routes }); chrome -.setTabDefaults({ - resetWhenActive: true, - lastUrlStore: window.sessionStorage, - activeIndicatorColor: '#656a76' -}) .setRootController('kibana', function ($scope, courier, config) { // wait for the application to finish loading $scope.$on('application.load', function () { diff --git a/src/ui/public/chrome/__tests__/tab.js b/src/ui/public/chrome/__tests__/tab.js deleted file mode 100644 index cc3d3ab1b4ba2..0000000000000 --- a/src/ui/public/chrome/__tests__/tab.js +++ /dev/null @@ -1,254 +0,0 @@ -import sinon from 'auto-release-sinon'; - -import Tab from '../tab'; -import expect from 'expect.js'; -import StubBrowserStorage from './fixtures/stub_browser_storage'; - -describe('Chrome Tab', function () { - describe('construction', function () { - it('accepts id, title, resetWhenActive, trackLastUrl, activeIndicatorColor, baseUrl', function () { - const tab = new Tab({ - id: 'foo', - title: 'Foo App', - resetWhenActive: false, - activeIndicatorColor: true, - baseUrl: 'proto:host.domain:999' - }); - - expect(tab.id).to.equal('foo'); - expect(tab.title).to.equal('Foo App'); - expect(tab.resetWhenActive).to.equal(false); - expect(tab.activeIndicatorColor).to.equal(true); - expect(tab.rootUrl).to.equal('proto:host.domain:999/foo'); - - const tab2 = new Tab({ - id: 'bar', - title: 'Bar App', - resetWhenActive: true, - activeIndicatorColor: false, - baseUrl: 'proto:host.domain:999/sub/#/' - }); - - expect(tab2.id).to.equal('bar'); - expect(tab2.title).to.equal('Bar App'); - expect(tab2.resetWhenActive).to.equal(true); - expect(tab2.activeIndicatorColor).to.equal(null); - expect(tab2.rootUrl).to.equal('proto:host.domain:999/sub/#/bar'); - }); - - it('starts inactive', function () { - const tab = new Tab(); - expect(tab.active).to.equal(false); - }); - - it('uses the id to set the rootUrl', function () { - const id = 'foo'; - const tab = new Tab({ id }); - expect(tab.id).to.equal(id); - expect(tab.rootUrl).to.equal(`/${id}`); - }); - - it('creates a regexp for matching the rootUrl', function () { - const tab = new Tab({ id: 'foo' }); - - expect('/foo').to.match(tab.rootRegExp); - expect('/foo/bar').to.match(tab.rootRegExp); - expect('/foo/bar/max').to.match(tab.rootRegExp); - expect('/foo?bar=baz').to.match(tab.rootRegExp); - expect('/foo/?bar=baz').to.match(tab.rootRegExp); - expect('/foo#?bar=baz').to.match(tab.rootRegExp); - - expect('/foobar').to.not.match(tab.rootRegExp); - expect('site.com/foo#?bar=baz').to.not.match(tab.rootRegExp); - expect('http://site.com/foo#?bar=baz').to.not.match(tab.rootRegExp); - }); - - it('includes the baseUrl in the rootRegExp if specified', function () { - const tab = new Tab({ - id: 'foo', - baseUrl: 'http://spiderman.com/kibana' - }); - - expect('http://spiderman.com/kibana/foo/bar').to.match(tab.rootRegExp); - - expect('/foo').to.not.match(tab.rootRegExp); - expect('https://spiderman.com/kibana/foo/bar').to.not.match(tab.rootRegExp); - }); - - it('accepts a function for activeIndicatorColor', function () { - let i = 0; - const tab = new Tab({ - activeIndicatorColor: function () { - return i++; - } - }); - expect(tab.activeIndicatorColor).to.equal(0); - expect(tab.activeIndicatorColor).to.equal(1); - expect(tab.activeIndicatorColor).to.equal(2); - expect(tab.activeIndicatorColor).to.equal(3); - }); - - it('discovers the lastUrl', function () { - const lastUrlStore = new StubBrowserStorage(); - const tab = new Tab({ id: 'foo', lastUrlStore }); - expect(tab.lastUrl).to.not.equal('/foo/bar'); - - tab.setLastUrl('/foo/bar'); - expect(tab.lastUrl).to.equal('/foo/bar'); - - const tab2 = new Tab({ id: 'foo', lastUrlStore }); - expect(tab2.lastUrl).to.equal('/foo/bar'); - }); - - it('logs a warning about last urls that do not match the rootUrl', function () { - const lastUrlStore = new StubBrowserStorage(); - const tab = new Tab({ id: 'foo', baseUrl: '/bar', lastUrlStore }); - tab.setLastUrl('/bar/foo/1'); - - const stub = sinon.stub(console, 'log'); - const tab2 = new Tab({ id: 'foo', baseUrl: '/baz', lastUrlStore }); - sinon.assert.calledOnce(stub); - expect(tab2.lastUrl).to.equal(null); - }); - }); - - - describe('#setLastUrl()', function () { - it('updates the lastUrl and storage value if passed a lastUrlStore', function () { - const lastUrlStore = new StubBrowserStorage(); - const tab = new Tab({ id: 'foo', lastUrlStore }); - - expect(tab.lastUrl).to.not.equal('foo'); - tab.setLastUrl('foo'); - expect(tab.lastUrl).to.equal('foo'); - expect(lastUrlStore.getItem(tab.lastUrlStoreKey)).to.equal('foo'); - }); - - it('only updates lastUrl if no lastUrlStore', function () { - const tab = new Tab({ id: 'foo' }); - - expect(tab.lastUrl).to.equal(null); - tab.setLastUrl('foo'); - expect(tab.lastUrl).to.equal('foo'); - - const tab2 = new Tab({ id: 'foo' }); - expect(tab2.lastUrl).to.not.equal('foo'); - }); - }); - - - describe('#href()', function () { - it('returns the rootUrl/id be default', function () { - const tab = new Tab({ id: 'foo' }); - expect(tab.href()).to.equal(tab.rootUrl); - }); - - it('returns the lastUrl if tracking is on', function () { - const tab = new Tab({ id: 'foo' }); - tab.setLastUrl('okay'); - expect(tab.href()).to.equal('okay'); - }); - - describe('when the tab is active', function () { - it('returns the rootUrl when resetWhenActive: true', function () { - const id = 'foo'; - const resetWhenActive = true; - const tab = new Tab({ id, resetWhenActive }); - - tab.active = true; - - expect(tab.href()).to.not.equal('butt'); - expect(tab.href()).to.equal(tab.rootUrl); - }); - - it('or returns null when not', function () { - const tab = new Tab({ id: 'foo', resetWhenActive: false }); - tab.active = true; - - expect(tab.href()).to.not.equal('butt'); - expect(tab.href()).to.equal(null); - }); - }); - }); - - describe('#getLastPath()', function () { - it('parses a path out of the lastUrl by removing the baseUrl', function () { - const baseUrl = 'http://local:5601/app/visualize#'; - const tab = new Tab({ baseUrl }); - - tab.setLastUrl('http://local:5601/app/visualize#/index'); - expect(tab.getLastPath()).to.equal('/index'); - }); - - it('logs a warning if the lastUrl does not extend the root url', function () { - const baseUrl = 'http://local:5601/app/visualize#'; - const tab = new Tab({ baseUrl }); - sinon.stub(console, 'log'); - - tab.setLastUrl('http://local:5601/'); - tab.getLastPath(); - sinon.assert.calledOnce(console.log);// eslint-disable-line no-console - }); - }); - - describe('updateLastUrlGlobalState', function () { - const bases = [ - 'http://local:5601', - '', - 'weird.domain/with/subpath?path#', - 'weird.domain/with/#hashpath', - ]; - - context('with new state sets _g properly', function () { - const paths = [ - [ '/', '/?_g=newState' ], - [ '/?first', '/?first=&_g=newState' ], - [ '/path?first=1&_g=afterHash', '/path?first=1&_g=newState' ], - [ '/?first=1&_g=second', '/?first=1&_g=newState' ], - [ '/?g=first', '/?g=first&_g=newState' ], - [ '/a?first=1&_g=second', '/a?first=1&_g=newState' ], - [ '/?first=1&_g=second', '/?first=1&_g=newState' ], - [ '/?first&g=second', '/?first=&g=second&_g=newState' ], - ]; - - bases.forEach(baseUrl => { - paths.forEach(([pathFrom, pathTo]) => { - const fromUrl = `${baseUrl}${pathFrom}`; - const toUrl = `${baseUrl}${pathTo}`; - it(`${fromUrl} => ${toUrl}`, function () { - const tab = new Tab({ baseUrl }); - tab.setLastUrl(fromUrl); - tab.updateLastUrlGlobalState('newState'); - expect(tab.getLastUrl()).to.equal(toUrl); - }); - }); - }); - }); - - context('with new empty state removes _g', function () { - const paths = [ - [ '/', '/' ], - [ '/?first', '/?first=' ], - [ '/path?first=1&_g=afterHash', '/path?first=1' ], - [ '/?first=1&_g=second', '/?first=1' ], - [ '/?g=first', '/?g=first' ], - [ '/a?first=1&_g=second', '/a?first=1' ], - [ '/?first=1&_g=second', '/?first=1' ], - [ '/?first&g=second', '/?first=&g=second' ], - ]; - - bases.forEach(baseUrl => { - paths.forEach(([pathFrom, pathTo]) => { - const fromUrl = `${baseUrl}${pathFrom}`; - const toUrl = `${baseUrl}${pathTo}`; - it(`${fromUrl}`, function () { - const tab = new Tab({ baseUrl }); - tab.setLastUrl(fromUrl); - tab.updateLastUrlGlobalState(); - expect(tab.getLastUrl()).to.equal(toUrl); - }); - }); - }); - }); - }); -}); diff --git a/src/ui/public/chrome/__tests__/tab_collection.js b/src/ui/public/chrome/__tests__/tab_collection.js deleted file mode 100644 index 1bfa9c20b8f34..0000000000000 --- a/src/ui/public/chrome/__tests__/tab_collection.js +++ /dev/null @@ -1,73 +0,0 @@ -import expect from 'expect.js'; - -import StubBrowserStorage from './fixtures/stub_browser_storage'; -import TabCollection from '../tab_collection'; -import Tab from '../tab'; -import { indexBy, random } from 'lodash'; - -describe('Chrome TabCollection', function () { - describe('empty state', function () { - it('has no tabs', function () { - const tabs = new TabCollection(); - expect(tabs.get()).to.eql([]); - }); - - it('has no active tab', function () { - const tabs = new TabCollection(); - expect(!tabs.getActive()).to.equal(true); - }); - }); - - describe('#set()', function () { - it('consumes an ordered list of Tab specs', function () { - const tabs = new TabCollection(); - tabs.set([ - { id: 'foo' }, - { id: 'bar' } - ]); - - const ts = tabs.get(); - expect(ts.length).to.equal(2); - expect(ts[0].id).to.equal('foo'); - expect(ts[1].id).to.equal('bar'); - }); - }); - - describe('#setDefaults()', function () { - it('applies the defaults used to create tabs', function () { - const tabs = new TabCollection(); - tabs.setDefaults({ id: 'thing' }); - tabs.set([ {} ]); - - expect(tabs.get()[0].id).to.equal('thing'); - }); - - it('recreates existing tabs with new defaults', function () { - const tabs = new TabCollection(); - tabs.set([ {} ]); - expect(!tabs.get()[0].id).to.equal(true); - - tabs.setDefaults({ id: 'thing' }); - expect(tabs.get()[0].id).to.equal('thing'); - }); - }); - - describe('#consumeRouteUpdate()', function () { - it('updates the active tab', function () { - const store = new StubBrowserStorage(); - const baseUrl = `http://localhost:${random(1000, 9999)}`; - const tabs = new TabCollection({ store, defaults: { baseUrl } }); - tabs.set([ - { id: 'a' }, - { id: 'b' } - ]); - - tabs.consumeRouteUpdate(`${baseUrl}/a`); - const {a, b} = indexBy(tabs.get(), 'id'); - expect(a.active).to.equal(true); - expect(b.active).to.equal(false); - expect(tabs.getActive()).to.equal(a); - }); - }); - -}); diff --git a/src/ui/public/chrome/api/nav.js b/src/ui/public/chrome/api/nav.js index f78ea3a364162..a90b6fb57a612 100644 --- a/src/ui/public/chrome/api/nav.js +++ b/src/ui/public/chrome/api/nav.js @@ -101,19 +101,13 @@ export default function (chrome, internals) { const { appId, globalState: newGlobalState } = decodeKibanaUrl(url); for (const link of internals.nav) { - const matchingTab = find(internals.tabs, { rootUrl: link.url }); - link.active = startsWith(url, link.url); if (link.active) { setLastUrl(link, url); continue; } - if (matchingTab) { - setLastUrl(link, matchingTab.getLastUrl()); - } else { - refreshLastUrl(link); - } + refreshLastUrl(link); if (newGlobalState) { injectNewGlobalState(link, appId, newGlobalState); diff --git a/src/ui/public/chrome/api/tabs.js b/src/ui/public/chrome/api/tabs.js deleted file mode 100644 index aba3734cfd1ce..0000000000000 --- a/src/ui/public/chrome/api/tabs.js +++ /dev/null @@ -1,93 +0,0 @@ -import _ from 'lodash'; -import TabCollection from '../tab_collection'; - -module.exports = function (chrome, internals) { - - internals.tabs = new TabCollection({ - defaults: { - baseUrl: `${chrome.getAppUrl()}#/` - } - }); - - /** - * ui/chrome tabs API - * - * The navbar at the top of the page can be assigned links which will - * pile up on the left. Each of these links has several properties that define - * how it is rendered, how it looks when it's "active" and what happens when - * it's clicked. - * - * To define a set of tabs, pass setTabs an array of TabSpec objects, - * which are just plain objects with the following properties: - * - * id {string} - * a unique value for this tab, should match the first path segment of - * routes that are supposed to belong to this tab and is matched against the route - * everytime it changes. When clicking the tab for the first time the user will be - * sent to the '/${tab.id}' url which you can use to redirect to another url if needed - * - * title {string} - * the text the tab should show - * - * resetWhenActive {boolean} - * when the the tab is considered active, should clicking it - * cause a redirect to just the id? - * - * trackLastUrl {boolean} - * When this tab is active, should the current path be tracked - * and persisted to session storage, then used as the tabs href attribute when the user navigates - * away from the tab? - * - * activeIndicatorColor {string} - * css color string that will be used to style the active - * indicator applied to tabs which are currently active. - */ - - /** - * @param {TabSpec[]} tabSpecs - * @return {chrome} - */ - chrome.setTabs = function (tabSpecs) { - internals.tabs.set(tabSpecs); - return chrome; - }; - - /** - * @param {Object} defaults - defaults used for each tab - * @return {chrome} - */ - chrome.setTabDefaults = function (defaults) { - internals.tabs.setDefaults(defaults); - return chrome; - }; - - /** - * @return {Tab[]} - */ - chrome.getTabs = function () { - return internals.tabs.get(); - }; - - - /** - * @return {Tab} - */ - chrome.getActiveTab = function () { - return internals.tabs.getActive(); - }; - - /** - * @param {any} def - the default value if there isn't any active tab - * @return {any} - */ - chrome.getActiveTabTitle = activeGetter('title'); - - // create a getter for properties of the active tab - function activeGetter(prop) { - return function (def) { - let active = chrome.getActiveTab(); - return !active ? def : active[prop]; - }; - } - -}; diff --git a/src/ui/public/chrome/chrome.html b/src/ui/public/chrome/chrome.html index f0cf8395d6a83..419615d665dda 100644 --- a/src/ui/public/chrome/chrome.html +++ b/src/ui/public/chrome/chrome.html @@ -1,71 +1,45 @@
- -
+
diff --git a/src/ui/public/chrome/chrome.js b/src/ui/public/chrome/chrome.js index c0f980c993b0e..6e7a2b8d6f4bc 100644 --- a/src/ui/public/chrome/chrome.js +++ b/src/ui/public/chrome/chrome.js @@ -7,6 +7,7 @@ import metadata from 'ui/metadata'; import 'babel/polyfill'; import $ from 'jquery'; import 'ui/timefilter'; +import 'ui/notify'; import 'ui/private'; import 'ui/promises'; import 'ui/directives/kbn_src'; @@ -37,7 +38,6 @@ require('./api/xsrf')(chrome, internals); require('./api/nav')(chrome, internals); require('./api/angular')(chrome, internals); require('./api/controls')(chrome, internals); -require('./api/tabs')(chrome, internals); require('./api/template')(chrome, internals); require('./api/theme')(chrome, internals); diff --git a/src/ui/public/chrome/directives/kbn_chrome.js b/src/ui/public/chrome/directives/kbn_chrome.js index 6f788b0ee61ee..b2d70eb967d7f 100644 --- a/src/ui/public/chrome/directives/kbn_chrome.js +++ b/src/ui/public/chrome/directives/kbn_chrome.js @@ -33,8 +33,6 @@ export default function (chrome, internals) { // listen for route changes, propogate to tabs const onRouteChange = function () { let { href } = window.location; - let persist = chrome.getVisible(); - internals.tabs.consumeRouteUpdate(href, persist); internals.trackPossibleSubUrl(href); }; diff --git a/src/ui/public/chrome/tab.js b/src/ui/public/chrome/tab.js deleted file mode 100644 index 7cc9a108ab9ae..0000000000000 --- a/src/ui/public/chrome/tab.js +++ /dev/null @@ -1,82 +0,0 @@ -import notify from 'ui/notify'; -import _ from 'lodash'; -import { escapeRegExp as reEsc } from 'lodash'; -import { parse, format } from 'url'; - -const urlJoin = (a, b) => { - if (!b) return a; - return `${a}${ a.endsWith('/') ? '' : '/' }${b}`; -}; - -export default class Tab { - constructor(spec = {}) { - this.id = spec.id || ''; - this.title = spec.title || ''; - this.resetWhenActive = !!spec.resetWhenActive; - this.activeIndicatorColor = spec.activeIndicatorColor || null; - if (_.isFunction(this.activeIndicatorColor)) { - // convert to a getter - Object.defineProperty(this, 'activeIndicatorColor', { - get: this.activeIndicatorColor - }); - } - - this.active = false; - - this.baseUrl = spec.baseUrl || '/'; - this.rootUrl = urlJoin(this.baseUrl, this.id); - this.rootRegExp = new RegExp(`^${reEsc(this.rootUrl)}(/|$|\\?|#)`); - - this.lastUrlStoreKey = `lastUrl:${this.id}`; - this.lastUrlStore = spec.lastUrlStore; - - this.lastUrl = null; - if (this.lastUrlStore) { - this.lastUrl = this.lastUrlStore.getItem(this.lastUrlStoreKey); - if (this.lastUrl && !this.lastUrl.startsWith(this.rootUrl)) { - notify.log(`Found invalid lastUrl for tab with root url ${this.rootUrl}: "${this.lastUrl}"`); - this.lastUrl = null; - this.lastUrlStore.removeItem(this.lastUrlStoreKey); - } - } - } - - href() { - if (this.active) { - return this.resetWhenActive ? this.rootUrl : null; - } - return this.lastUrl || this.rootUrl; - } - - updateLastUrlGlobalState(globalState) { - let lastPath = this.getLastPath(); - let { pathname, query, hash } = parse(lastPath, true); - - query = query || {}; - if (!globalState) delete query._g; - else query._g = globalState; - - this.setLastUrl(`${this.rootUrl}${format({ pathname, query, hash })}`); - } - - getLastPath() { - let { id, rootUrl } = this; - let lastUrl = this.getLastUrl(); - - if (!lastUrl.startsWith(rootUrl)) { - notify.log(`Tab "${id}" has invalid root "${rootUrl}" for last url "${lastUrl}"`); - lastUrl = rootUrl; - } - - return lastUrl.slice(rootUrl.length); - } - - setLastUrl(url) { - this.lastUrl = url; - if (this.lastUrlStore) this.lastUrlStore.setItem(this.lastUrlStoreKey, this.lastUrl); - } - - getLastUrl() { - return this.lastUrl || this.rootUrl; - } -} diff --git a/src/ui/public/chrome/tab_collection.js b/src/ui/public/chrome/tab_collection.js deleted file mode 100644 index 67759bb7e0d83..0000000000000 --- a/src/ui/public/chrome/tab_collection.js +++ /dev/null @@ -1,53 +0,0 @@ -import _ from 'lodash'; -import Tab from 'ui/chrome/tab'; -import { startsWith, get, set, omit, wrap, pick } from 'lodash'; -import { parse } from 'url'; - -function TabCollection(opts = {}) { - let tabs = []; - let specs = null; - let defaults = opts.defaults || {}; - let activeTab = null; - - this.set = function (_specs) { - specs = _.cloneDeep([].concat(_specs || [])); - this._rebuildTabs(); - }; - - this.setDefaults = function () { - defaults = _.defaults({}, arguments[0], defaults); - this._rebuildTabs(); - }; - - this.get = function () { - return [].concat(tabs || []); - }; - - this._rebuildTabs = function () { - _.invoke(this.get(), 'destroy'); - tabs = _.map(specs, function (spec) { - return new Tab(_.defaults({}, spec, defaults)); - }); - }; - - this.getActive = function () { - return activeTab; - }; - - this.consumeRouteUpdate = function (href, persist) { - tabs.forEach(function (tab) { - tab.active = tab.rootRegExp.test(href); - if (tab.active) { - activeTab = tab; - activeTab.setLastUrl(href); - } - }); - - if (!persist || !activeTab) return; - - let globalState = get(parse(activeTab.getLastPath(), true), 'query._g'); - tabs.forEach(tab => tab.updateLastUrlGlobalState(globalState)); - }; -} - -module.exports = TabCollection; diff --git a/src/ui/public/doc_title/__tests__/doc_title.js b/src/ui/public/doc_title/__tests__/doc_title.js index 1d58586f55c65..faf38f9521473 100644 --- a/src/ui/public/doc_title/__tests__/doc_title.js +++ b/src/ui/public/doc_title/__tests__/doc_title.js @@ -61,25 +61,12 @@ describe('docTitle Service', function () { }); describe('#change', function () { - let getActiveTabStub; - - beforeEach(function () { - getActiveTabStub = sinon.stub(require('ui/chrome'), 'getActiveTab'); - }); - it('writes the first param to as the first part of the doc name', function () { expect(document.title).to.be(MAIN_TITLE); docTitle.change('some secondary title'); expect(document.title).to.be('some secondary title - ' + MAIN_TITLE); }); - it('includes the title of the active tab if available', function () { - expect(document.title).to.be(MAIN_TITLE); - getActiveTabStub.returns({ title: 'fancy pants' }); - docTitle.change('some secondary title'); - expect(document.title).to.be('some secondary title - fancy pants - ' + MAIN_TITLE); - }); - it('will write just the first param if the second param is true', function () { expect(document.title).to.be(MAIN_TITLE); docTitle.change('entire name', true); diff --git a/src/ui/public/doc_title/doc_title.js b/src/ui/public/doc_title/doc_title.js index 5bd02d6af0f3c..6f58e162ae5e5 100644 --- a/src/ui/public/doc_title/doc_title.js +++ b/src/ui/public/doc_title/doc_title.js @@ -8,7 +8,6 @@ uiModules.get('kibana') $rootScope.$on('$routeChangeStart', docTitle.reset); $rootScope.$on('$routeChangeError', docTitle.update); $rootScope.$on('$routeChangeSuccess', docTitle.update); - $rootScope.$watch(_.bindKey(chrome, 'getActiveTabTitle'), docTitle.update); }) .service('docTitle', function ($rootScope) { let baseTitle = document.title; @@ -20,9 +19,6 @@ uiModules.get('kibana') lastChange = lastChange || []; let parts = [lastChange[0]]; - let activeTabTitle = chrome.getActiveTabTitle(); - - if (activeTabTitle) parts.push(activeTabTitle); if (!lastChange[1]) parts.push(baseTitle);