@@ -84,17 +92,6 @@
- -
- - - - - - {{(hits || 0) | number:0}} - -
-
@@ -153,7 +150,6 @@

Examples:

Searching

-
{{fetchStatus.complete}}/{{fetchStatus.total}}
diff --git a/src/plugins/kibana/public/discover/styles/main.less b/src/plugins/kibana/public/discover/styles/main.less index 13b53fc815b18..f9c6a466e61b6 100644 --- a/src/plugins/kibana/public/discover/styles/main.less +++ b/src/plugins/kibana/public/discover/styles/main.less @@ -29,6 +29,10 @@ height: 200px; max-height: 600px; + .loading { + opacity: 1 !important; + } + &.only-spy { height: auto; @@ -71,12 +75,10 @@ } &-info { - background-color: @discover-info-bg; - float: right; - padding: 5px 10px; + line-height: 30px; + padding: 0px 10px; border-bottom-left-radius: @border-radius-base; - text-align: right; &-title { font-weight: bold; @@ -245,6 +247,10 @@ disc-field-chooser { } } + .sidebar-item.active .sidebar-item-title { + background-color: @sidebar-active-bg; + color: @sidebar-active-color; + } .sidebar-item-title { position: relative; } diff --git a/src/plugins/kibana/public/kibana.js b/src/plugins/kibana/public/kibana.js index d3704cba58be1..12540a8a943ad 100644 --- a/src/plugins/kibana/public/kibana.js +++ b/src/plugins/kibana/public/kibana.js @@ -28,36 +28,14 @@ routes chrome .setBrand({ - 'logo': 'url(' + kibanaLogoUrl + ') left no-repeat', - 'smallLogo': 'url(' + kibanaLogoUrl + ') left no-repeat' + 'logo': 'url(' + kibanaLogoUrl + ') 6px 10px / 140px 50px no-repeat #e8488b', + 'smallLogo': 'url(' + kibanaLogoUrl + ') 6px 10px / 140px 50px no-repeat #e8488b' }) -.setNavBackground('#222222') .setTabDefaults({ resetWhenActive: true, - lastUrlStore: window.sessionStore, + lastUrlStore: window.sessionStorage, activeIndicatorColor: '#656a76' }) -.setTabs([ - { - id: 'discover', - title: 'Discover' - }, - { - id: 'visualize', - title: 'Visualize', - activeIndicatorColor: function () { - return (String(this.lastUrl).indexOf('/visualize/step/') === 0) ? 'white' : '#656a76'; - } - }, - { - id: 'dashboard', - title: 'Dashboard' - }, - { - id: 'settings', - title: 'Settings' - } -]) .setRootController('kibana', function ($scope, $rootScope, courier, config) { function setDefaultTimezone() { moment.tz.setDefault(config.get('dateFormat:tz')); diff --git a/src/plugins/kibana/public/settings/app.html b/src/plugins/kibana/public/settings/app.html index 6bb1ecd5a167c..f78a64d809790 100644 --- a/src/plugins/kibana/public/settings/app.html +++ b/src/plugins/kibana/public/settings/app.html @@ -1,6 +1,7 @@
diff --git a/src/plugins/kibana/public/visualize/wizard/wizard.js b/src/plugins/kibana/public/visualize/wizard/wizard.js index 77f13971597ce..e59a1bef78484 100644 --- a/src/plugins/kibana/public/visualize/wizard/wizard.js +++ b/src/plugins/kibana/public/visualize/wizard/wizard.js @@ -8,7 +8,7 @@ import uiModules from 'ui/modules'; const templateStep = function (num, txt) { - return '
' + txt + '
'; + return '
' + txt + '
'; }; const module = uiModules.get('app/visualize', ['kibana/courier']); @@ -56,16 +56,8 @@ module.controller('VisualizeWizardStep2', function ($route, $scope, $location, t list: $route.current.locals.indexPatternIds }; - $scope.$watch('stepTwoMode', function (mode) { - if (mode === 'new') { - if ($scope.indexPattern.list && $scope.indexPattern.list.length === 1) { - $scope.indexPattern.selection = $scope.indexPattern.list[0]; - } - } - }); - - $scope.$watch('indexPattern.selection', function (pattern) { + $scope.makeUrl = function (pattern) { if (!pattern) return; - kbnUrl.change('/visualize/create?type={{type}}&indexPattern={{pattern}}', {type: type, pattern: pattern}); - }); + return `#/visualize/create?type=${type}&indexPattern=${pattern}`; + }; }); diff --git a/src/plugins/metric_vis/public/metric_vis.less b/src/plugins/metric_vis/public/metric_vis.less index bc0b7244a5e34..88abea610948d 100644 --- a/src/plugins/metric_vis/public/metric_vis.less +++ b/src/plugins/metric_vis/public/metric_vis.less @@ -16,6 +16,5 @@ .metric-container { text-align: center; - padding: 1em; } } diff --git a/src/plugins/status_page/public/status_page.js b/src/plugins/status_page/public/status_page.js index 8938e33e62bf7..52e39042bb874 100644 --- a/src/plugins/status_page/public/status_page.js +++ b/src/plugins/status_page/public/status_page.js @@ -7,13 +7,6 @@ import 'plugins/status_page/status_page.less'; const chrome = require('ui/chrome') -.setTabs([ - { - id: '', - title: 'Server Status', - activeIndicatorColor: '#EFF0F2' - } -]) .setRootTemplate(require('plugins/status_page/status_page.html')) .setRootController('ui', function ($http, $scope) { const ui = this; @@ -54,3 +47,8 @@ const chrome = require('ui/chrome') ui.refresh(); }); + +require('ui/modules').get('kibana') +.config(function (appSwitcherEnsureNavigationProvider) { + appSwitcherEnsureNavigationProvider.forceNavigation(true); +}); diff --git a/src/ui/index.js b/src/ui/index.js index b6a8350f54323..1231704ac5316 100644 --- a/src/ui/index.js +++ b/src/ui/index.js @@ -62,7 +62,7 @@ module.exports = async (kbnServer, server, config) => { server.decorate('reply', 'renderApp', function (app) { const payload = { app: app, - nav: uiExports.apps, + nav: uiExports.navLinks.inOrder, version: kbnServer.version, buildNum: config.get('pkg.buildNum'), buildSha: config.get('pkg.buildSha'), diff --git a/src/ui/public/agg_response/geo_json/_tooltip.html b/src/ui/public/agg_response/geo_json/_tooltip.html index 31540085da0b3..b0d07cb80e4b3 100644 --- a/src/ui/public/agg_response/geo_json/_tooltip.html +++ b/src/ui/public/agg_response/geo_json/_tooltip.html @@ -1,8 +1,8 @@ - - + +
{{detail.label}}{{detail.value}}{{detail.label}}{{detail.value}}
diff --git a/src/ui/public/agg_response/hierarchical/_tooltip.html b/src/ui/public/agg_response/hierarchical/_tooltip.html index 44527343e728b..e714441492663 100644 --- a/src/ui/public/agg_response/hierarchical/_tooltip.html +++ b/src/ui/public/agg_response/hierarchical/_tooltip.html @@ -1,16 +1,16 @@ - + - + -
field value {{metricCol.label}}
{{row.field}} {{row.bucket}} {{row.metric}}
\ No newline at end of file + diff --git a/src/ui/public/agg_response/point_series/_tooltip.html b/src/ui/public/agg_response/point_series/_tooltip.html index 9e1a52df59fb8..322d5a0bc3798 100644 --- a/src/ui/public/agg_response/point_series/_tooltip.html +++ b/src/ui/public/agg_response/point_series/_tooltip.html @@ -1,11 +1,11 @@ - - + -
{{detail.label}} + {{detail.label}} {{detail.value}} ({{detail.percent}})
\ No newline at end of file + diff --git a/src/ui/public/chrome/__tests__/_tab_fake_store.js b/src/ui/public/chrome/__tests__/_tab_fake_store.js index 1b8ab81602259..a678440d14b78 100644 --- a/src/ui/public/chrome/__tests__/_tab_fake_store.js +++ b/src/ui/public/chrome/__tests__/_tab_fake_store.js @@ -4,6 +4,7 @@ export default class TabFakeStore { constructor() { this[store] = new Map(); } getItem(k) { return this[store].get(k); } setItem(k, v) { return this[store].set(k, v); } + removeItem(k) { return this[store].delete(k); } getKeys() { return [ ...this[store].keys() ]; } getValues() { return [ ...this[store].values() ]; } } diff --git a/src/ui/public/chrome/__tests__/tab.js b/src/ui/public/chrome/__tests__/tab.js index dcba69a356f94..add635bf7e2c1 100644 --- a/src/ui/public/chrome/__tests__/tab.js +++ b/src/ui/public/chrome/__tests__/tab.js @@ -1,3 +1,4 @@ +import sinon from 'auto-release-sinon'; import Tab from '../tab'; import expect from 'expect.js'; import TabFakeStore from './_tab_fake_store'; @@ -89,13 +90,24 @@ describe('Chrome Tab', function () { it('discovers the lastUrl', function () { const lastUrlStore = new TabFakeStore(); const tab = new Tab({ id: 'foo', lastUrlStore }); - expect(tab.lastUrl).to.not.equal('bar'); + expect(tab.lastUrl).to.not.equal('/foo/bar'); - tab.setLastUrl('bar'); - expect(tab.lastUrl).to.equal('bar'); + tab.setLastUrl('/foo/bar'); + expect(tab.lastUrl).to.equal('/foo/bar'); const tab2 = new Tab({ id: 'foo', lastUrlStore }); - expect(tab2.lastUrl).to.equal('bar'); + expect(tab2.lastUrl).to.equal('/foo/bar'); + }); + + it('logs a warning about last urls that do not match the rootUrl', function () { + const lastUrlStore = new TabFakeStore(); + 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); }); }); @@ -167,14 +179,14 @@ describe('Chrome Tab', function () { expect(tab.getLastPath()).to.equal('/index'); }); - it('throws an error if the lastUrl does not extend the root url', function () { - expect(function () { - const baseUrl = 'http://local:5601/app/visualize#'; - const tab = new Tab({ baseUrl }); + 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(); - }).to.throwError(/invalid.*root/); + tab.setLastUrl('http://local:5601/'); + tab.getLastPath(); + sinon.assert.calledOnce(console.log);// eslint-disable-line no-console }); }); diff --git a/src/ui/public/chrome/api/__tests__/angular.js b/src/ui/public/chrome/api/__tests__/angular.js new file mode 100644 index 0000000000000..51b77b57df0a6 --- /dev/null +++ b/src/ui/public/chrome/api/__tests__/angular.js @@ -0,0 +1,19 @@ +import expect from 'expect.js'; + +import kbnAngular from '../angular'; +import TabFakeStore from '../../__tests__/_tab_fake_store'; +import { noop } from 'lodash'; + +describe('Chrome API :: Angular', () => { + describe('location helper methods', () => { + it('should return the sub app based on the url', () => { + const chrome = { + getInjected: noop, + addBasePath: noop + }; + kbnAngular(chrome, {}); + }); + it('should return breadcrumbs based on the url', () => { + }); + }); +}); diff --git a/src/ui/public/chrome/api/__tests__/apps.js b/src/ui/public/chrome/api/__tests__/apps.js index f0269e79c46d4..e50fe59e57ef1 100644 --- a/src/ui/public/chrome/api/__tests__/apps.js +++ b/src/ui/public/chrome/api/__tests__/apps.js @@ -86,11 +86,11 @@ describe('Chrome API :: apps', function () { describe('#getAppUrl()', function () { it('returns the resolved url of the current app', function () { const chrome = {}; - const app = { url: '/foo' }; + const app = { navLink: { url: '/foo' } }; setup(chrome, { app }); const a = document.createElement('a'); - a.setAttribute('href', app.url); + a.setAttribute('href', app.navLink.url); expect(chrome.getAppUrl()).to.equal(a.href); }); diff --git a/src/ui/public/chrome/api/angular.js b/src/ui/public/chrome/api/angular.js index 77d8ea77ec3fb..e9b12626d36ab 100644 --- a/src/ui/public/chrome/api/angular.js +++ b/src/ui/public/chrome/api/angular.js @@ -3,6 +3,9 @@ import modules from 'ui/modules'; module.exports = function (chrome, internals) { + chrome.getFirstPathSegment = _.noop; + chrome.getBreadcrumbs = _.noop; + chrome.setupAngular = function () { var kibana = modules.get('kibana'); @@ -15,12 +18,22 @@ module.exports = function (chrome, internals) { .value('buildNum', internals.buildNum) .value('buildSha', internals.buildSha) .value('sessionId', Date.now()) + .value('chrome', chrome) .value('esUrl', (function () { var a = document.createElement('a'); a.href = chrome.addBasePath('/elasticsearch'); return a.href; }())) - .config(chrome.$setupXsrfRequestInterceptor); + .config(chrome.$setupXsrfRequestInterceptor) + .run(($location) => { + chrome.getFirstPathSegment = () => { + return $location.path().split('/')[1]; + }; + + chrome.getBreadcrumbs = () => { + return $location.path().split('/').slice(1); + }; + }); require('../directives')(chrome, internals); diff --git a/src/ui/public/chrome/api/apps.js b/src/ui/public/chrome/api/apps.js index ee6b7b1b86aff..c94dd537c28c7 100644 --- a/src/ui/public/chrome/api/apps.js +++ b/src/ui/public/chrome/api/apps.js @@ -3,8 +3,8 @@ import { resolve } from 'url'; module.exports = function (chrome, internals) { - if (internals.app) { - internals.app.url = resolve(window.location.href, internals.app.url); + if (get(internals, 'app.navLink.url')) { + internals.app.navLink.url = resolve(window.location.href, internals.app.navLink.url); } internals.appUrlStore = internals.appUrlStore || window.sessionStorage; @@ -35,7 +35,7 @@ module.exports = function (chrome, internals) { }; chrome.getAppUrl = function () { - return get(internals, ['app', 'url']); + return get(internals, ['app', 'navLink', 'url']); }; chrome.getInjected = function (name, def) { diff --git a/src/ui/public/chrome/api/nav.js b/src/ui/public/chrome/api/nav.js index 0b630a2eccd14..d993baa216ef9 100644 --- a/src/ui/public/chrome/api/nav.js +++ b/src/ui/public/chrome/api/nav.js @@ -1,15 +1,11 @@ import { parse, format } from 'url'; -import { startsWith, isString } from 'lodash'; +import { startsWith, isString, find } from 'lodash'; export default function (chrome, internals) { chrome.getNavLinks = function () { return internals.nav; }; - chrome.getLastSubUrlFor = function (url) { - return internals.appUrlStore.getItem(`lastSubUrl:${url}`); - }; - chrome.getBasePath = function () { return internals.basePath || ''; }; @@ -34,26 +30,46 @@ export default function (chrome, internals) { }); }; + function lastSubUrlKey(link) { + return `lastSubUrl:${link.url}`; + } + + function setLastUrl(link, url) { + link.lastSubUrl = url; + internals.appUrlStore.setItem(lastSubUrlKey(link), url); + } + + function refreshLastUrl(link) { + link.lastSubUrl = internals.appUrlStore.getItem(lastSubUrlKey(link)); + } + internals.trackPossibleSubUrl = function (url) { for (const link of internals.nav) { - if (startsWith(url, link.url)) { - link.lastSubUrl = url; - internals.appUrlStore.setItem(`lastSubUrl:${link.url}`, 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; + } + + refreshLastUrl(link); } }; internals.nav.forEach(link => { // convert all link urls to absolute urls - var a = document.createElement('a'); a.setAttribute('href', link.url); link.url = a.href; - link.lastSubUrl = chrome.getLastSubUrlFor(link.url); - - if (link.url === chrome.getAppUrl()) { - link.active = true; - } }); + // simulate a possible change in url to initialize the + // link.active and link.lastUrl properties + internals.trackPossibleSubUrl(document.location.href); }; diff --git a/src/ui/public/chrome/api/tabs.js b/src/ui/public/chrome/api/tabs.js index 97205ed597484..c7ac25e14ce24 100644 --- a/src/ui/public/chrome/api/tabs.js +++ b/src/ui/public/chrome/api/tabs.js @@ -76,12 +76,6 @@ module.exports = function (chrome, internals) { return internals.tabs.getActive(); }; - /** - * @param {any} def - the default value if there isn't any active tab - * @return {any} - */ - chrome.getActiveTabId = activeGetter('id'); - /** * @param {any} def - the default value if there isn't any active tab * @return {any} diff --git a/src/ui/public/chrome/chrome.html b/src/ui/public/chrome/chrome.html index 6e5cccbfdd497..465b9525c5fdd 100644 --- a/src/ui/public/chrome/chrome.html +++ b/src/ui/public/chrome/chrome.html @@ -1,74 +1,86 @@ -
- +
- - - - - - - - - - -
+
diff --git a/src/ui/public/chrome/chrome.js b/src/ui/public/chrome/chrome.js index bb51cd12c1fa0..cb0e2bd6c3e4a 100644 --- a/src/ui/public/chrome/chrome.js +++ b/src/ui/public/chrome/chrome.js @@ -9,6 +9,7 @@ import $ from 'jquery'; import 'ui/timefilter'; import 'ui/private'; import 'ui/promises'; +import 'ui/directives/kbn_src'; var chrome = {}; var internals = _.defaults( diff --git a/src/ui/public/chrome/config/filter.html b/src/ui/public/chrome/config/filter.html index 71a3dd32645ef..1930ee75d01ab 100644 --- a/src/ui/public/chrome/config/filter.html +++ b/src/ui/public/chrome/config/filter.html @@ -1,7 +1,7 @@ + interval="opts.timefilter.refreshInterval"> diff --git a/src/ui/public/chrome/config/interval.html b/src/ui/public/chrome/config/interval.html index d41a601709709..44d86b4140925 100644 --- a/src/ui/public/chrome/config/interval.html +++ b/src/ui/public/chrome/config/interval.html @@ -1,7 +1,7 @@ + interval="opts.timefilter.refreshInterval"> diff --git a/src/ui/public/chrome/context.js b/src/ui/public/chrome/context.js index 092ea422dcdff..4328d85243ce6 100644 --- a/src/ui/public/chrome/context.js +++ b/src/ui/public/chrome/context.js @@ -21,11 +21,6 @@ uiModules // chrome is responsible for timepicker ui and state transfer... $scope.timefilter = timefilter; - $scope.pickerTemplate = new ConfigTemplate({ - filter: require('ui/chrome/config/filter.html'), - interval: require('ui/chrome/config/interval.html') - }); - $scope.toggleRefresh = function () { timefilter.refreshInterval.pause = !timefilter.refreshInterval.pause; }; diff --git a/src/ui/public/chrome/directives/active_http_spinner.html b/src/ui/public/chrome/directives/active_http_spinner.html index d7c9b64fbe3c6..eac432ce1ee6a 100644 --- a/src/ui/public/chrome/directives/active_http_spinner.html +++ b/src/ui/public/chrome/directives/active_http_spinner.html @@ -1,5 +1 @@ - +
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 7613cb03142b4..1e0a0d0e665da 100644 --- a/src/ui/public/chrome/directives/app_switcher/app_switcher.html +++ b/src/ui/public/chrome/directives/app_switcher/app_switcher.html @@ -1,7 +1,7 @@