mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Merge pull request #4755 from spalger/implement/exportLinks
Properly merge global state into links
This commit is contained in:
commit
b475997dab
7 changed files with 101 additions and 26 deletions
|
@ -1,9 +1,9 @@
|
|||
const store = Symbol('store');
|
||||
|
||||
export default class TabFakeStore {
|
||||
export default class StubBrowserStorage {
|
||||
constructor() { this[store] = new Map(); }
|
||||
getItem(k) { return this[store].get(k); }
|
||||
setItem(k, v) { return this[store].set(k, v); }
|
||||
setItem(k, v) { return this[store].set(k, String(v)); }
|
||||
removeItem(k) { return this[store].delete(k); }
|
||||
getKeys() { return [ ...this[store].keys() ]; }
|
||||
getValues() { return [ ...this[store].values() ]; }
|
|
@ -1,7 +1,8 @@
|
|||
import sinon from 'auto-release-sinon';
|
||||
|
||||
import Tab from '../tab';
|
||||
import expect from 'expect.js';
|
||||
import TabFakeStore from './_tab_fake_store';
|
||||
import StubBrowserStorage from './fixtures/stub_browser_storage';
|
||||
|
||||
describe('Chrome Tab', function () {
|
||||
describe('construction', function () {
|
||||
|
@ -88,7 +89,7 @@ describe('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
it('discovers the lastUrl', function () {
|
||||
const lastUrlStore = new TabFakeStore();
|
||||
const lastUrlStore = new StubBrowserStorage();
|
||||
const tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
expect(tab.lastUrl).to.not.equal('/foo/bar');
|
||||
|
||||
|
@ -100,7 +101,7 @@ describe('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
it('logs a warning about last urls that do not match the rootUrl', function () {
|
||||
const lastUrlStore = new TabFakeStore();
|
||||
const lastUrlStore = new StubBrowserStorage();
|
||||
const tab = new Tab({ id: 'foo', baseUrl: '/bar', lastUrlStore });
|
||||
tab.setLastUrl('/bar/foo/1');
|
||||
|
||||
|
@ -114,7 +115,7 @@ describe('Chrome Tab', function () {
|
|||
|
||||
describe('#setLastUrl()', function () {
|
||||
it('updates the lastUrl and storage value if passed a lastUrlStore', function () {
|
||||
const lastUrlStore = new TabFakeStore();
|
||||
const lastUrlStore = new StubBrowserStorage();
|
||||
const tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
|
||||
expect(tab.lastUrl).to.not.equal('foo');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
import TabFakeStore from './_tab_fake_store';
|
||||
import StubBrowserStorage from './fixtures/stub_browser_storage';
|
||||
import TabCollection from '../tab_collection';
|
||||
import Tab from '../tab';
|
||||
import { indexBy, random } from 'lodash';
|
||||
|
@ -54,7 +54,7 @@ describe('Chrome TabCollection', function () {
|
|||
|
||||
describe('#consumeRouteUpdate()', function () {
|
||||
it('updates the active tab', function () {
|
||||
const store = new TabFakeStore();
|
||||
const store = new StubBrowserStorage();
|
||||
const baseUrl = `http://localhost:${random(1000, 9999)}`;
|
||||
const tabs = new TabCollection({ store, defaults: { baseUrl } });
|
||||
tabs.set([
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
import kbnAngular from '../angular';
|
||||
import TabFakeStore from '../../__tests__/_tab_fake_store';
|
||||
import { noop } from 'lodash';
|
||||
|
||||
describe('Chrome API :: Angular', () => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
import setup from '../apps';
|
||||
import TabFakeStore from '../../__tests__/_tab_fake_store';
|
||||
import StubBrowserStorage from '../../__tests__/fixtures/stub_browser_storage';
|
||||
|
||||
describe('Chrome API :: apps', function () {
|
||||
describe('#get/setShowAppsLink()', function () {
|
||||
|
@ -147,7 +147,7 @@ describe('Chrome API :: apps', function () {
|
|||
describe('#get/setLastUrlFor()', function () {
|
||||
it('reads/writes last url from storage', function () {
|
||||
const chrome = {};
|
||||
const store = new TabFakeStore();
|
||||
const store = new StubBrowserStorage();
|
||||
setup(chrome, { appUrlStore: store });
|
||||
expect(chrome.getLastUrlFor('app')).to.equal(undefined);
|
||||
chrome.setLastUrlFor('app', 'url');
|
||||
|
|
|
@ -1,45 +1,73 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
import initChromeNavApi from 'ui/chrome/api/nav';
|
||||
import StubBrowserStorage from '../../__tests__/fixtures/stub_browser_storage';
|
||||
|
||||
const basePath = '/someBasePath';
|
||||
|
||||
function getChrome(customInternals = { basePath }) {
|
||||
function init(customInternals = { basePath }) {
|
||||
const chrome = {};
|
||||
initChromeNavApi(chrome, {
|
||||
const internals = {
|
||||
nav: [],
|
||||
...customInternals,
|
||||
});
|
||||
return chrome;
|
||||
};
|
||||
initChromeNavApi(chrome, internals);
|
||||
return { chrome, internals };
|
||||
}
|
||||
|
||||
describe('chrome nav apis', function () {
|
||||
describe('#getBasePath()', function () {
|
||||
it('returns the basePath', function () {
|
||||
const chrome = getChrome();
|
||||
const { chrome } = init();
|
||||
expect(chrome.getBasePath()).to.be(basePath);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addBasePath()', function () {
|
||||
it('returns undefined when nothing is passed', function () {
|
||||
const chrome = getChrome();
|
||||
const { chrome } = init();
|
||||
expect(chrome.addBasePath()).to.be(undefined);
|
||||
});
|
||||
|
||||
it('prepends the base path when the input is a path', function () {
|
||||
const chrome = getChrome();
|
||||
const { chrome } = init();
|
||||
expect(chrome.addBasePath('/other/path')).to.be(`${basePath}/other/path`);
|
||||
});
|
||||
|
||||
it('ignores non-path urls', function () {
|
||||
const chrome = getChrome();
|
||||
const { chrome } = init();
|
||||
expect(chrome.addBasePath('http://github.com/elastic/kibana')).to.be('http://github.com/elastic/kibana');
|
||||
});
|
||||
|
||||
it('includes the query string', function () {
|
||||
const chrome = getChrome();
|
||||
const { chrome } = init();
|
||||
expect(chrome.addBasePath('/app/kibana?a=b')).to.be(`${basePath}/app/kibana?a=b`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('internals.trackPossibleSubUrl()', function () {
|
||||
it('injects the globalState of the current url to all links for the same app', function () {
|
||||
const appUrlStore = new StubBrowserStorage();
|
||||
const nav = [
|
||||
{ url: 'https://localhost:9200/app/kibana#discover' },
|
||||
{ url: 'https://localhost:9200/app/kibana#visualize' },
|
||||
{ url: 'https://localhost:9200/app/kibana#dashboard' },
|
||||
].map(l => {
|
||||
l.lastSubUrl = l.url;
|
||||
return l;
|
||||
});
|
||||
|
||||
const { chrome, internals } = init({ appUrlStore, nav });
|
||||
|
||||
internals.trackPossibleSubUrl('https://localhost:9200/app/kibana#dashboard?_g=globalstate');
|
||||
expect(internals.nav[0].lastSubUrl).to.be('https://localhost:9200/app/kibana#discover?_g=globalstate');
|
||||
expect(internals.nav[0].active).to.be(false);
|
||||
|
||||
expect(internals.nav[1].lastSubUrl).to.be('https://localhost:9200/app/kibana#visualize?_g=globalstate');
|
||||
expect(internals.nav[1].active).to.be(false);
|
||||
|
||||
expect(internals.nav[2].lastSubUrl).to.be('https://localhost:9200/app/kibana#dashboard?_g=globalstate');
|
||||
expect(internals.nav[2].active).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,25 +40,72 @@ export default function (chrome, internals) {
|
|||
}
|
||||
|
||||
function refreshLastUrl(link) {
|
||||
link.lastSubUrl = internals.appUrlStore.getItem(lastSubUrlKey(link));
|
||||
link.lastSubUrl = internals.appUrlStore.getItem(lastSubUrlKey(link)) || link.lastSubUrl || link.url;
|
||||
}
|
||||
|
||||
function getAppId(url) {
|
||||
const pathname = parse(url).pathname;
|
||||
const pathnameWithoutBasepath = pathname.slice(chrome.getBasePath().length);
|
||||
const match = pathnameWithoutBasepath.match(/^\/app\/([^\/]+)(?:\/|\?|#|$)/);
|
||||
if (match) return match[1];
|
||||
}
|
||||
|
||||
function decodeKibanaUrl(url) {
|
||||
const parsedUrl = parse(url, true);
|
||||
const appId = getAppId(parsedUrl);
|
||||
const hash = parsedUrl.hash || '';
|
||||
const parsedHash = parse(hash.slice(1), true);
|
||||
const globalState = parsedHash.query && parsedHash.query._g;
|
||||
return { appId, globalState, parsedUrl, parsedHash };
|
||||
}
|
||||
|
||||
function injectNewGlobalState(link, fromAppId, newGlobalState) {
|
||||
// parse the lastSubUrl of this link so we can manipulate its parts
|
||||
const { appId: toAppId, parsedHash: toHash, parsedUrl: toParsed } = decodeKibanaUrl(link.lastSubUrl);
|
||||
|
||||
// don't copy global state if links are for different apps
|
||||
if (fromAppId !== toAppId) return;
|
||||
|
||||
// add the new globalState to the hashUrl in the linkurl
|
||||
const toHashQuery = toHash.query || {};
|
||||
toHashQuery._g = newGlobalState;
|
||||
|
||||
// format the new subUrl and include the newHash
|
||||
link.lastSubUrl = format({
|
||||
protocol: toParsed.protocol,
|
||||
port: toParsed.port,
|
||||
hostname: toParsed.hostname,
|
||||
pathname: toParsed.pathname,
|
||||
query: toParsed.query,
|
||||
hash: format({
|
||||
pathname: toHash.pathname,
|
||||
query: toHashQuery,
|
||||
hash: toHash.hash,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
internals.trackPossibleSubUrl = function (url) {
|
||||
for (const link of internals.nav) {
|
||||
link.active = startsWith(url, link.url);
|
||||
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;
|
||||
}
|
||||
|
||||
const matchingTab = find(internals.tabs, { rootUrl: link.url });
|
||||
if (matchingTab) {
|
||||
setLastUrl(link, matchingTab.getLastUrl());
|
||||
continue;
|
||||
} else {
|
||||
refreshLastUrl(link);
|
||||
}
|
||||
|
||||
refreshLastUrl(link);
|
||||
if (newGlobalState) {
|
||||
injectNewGlobalState(link, appId, newGlobalState);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue