diff --git a/src/ui/public/autoload/modules.js b/src/ui/public/autoload/modules.js index 5919a14605474..32aef92c482e3 100644 --- a/src/ui/public/autoload/modules.js +++ b/src/ui/public/autoload/modules.js @@ -1,6 +1,5 @@ import 'angular'; import 'ui/chrome'; -import 'ui/chrome/context'; import 'ui/bind'; import 'ui/bound_to_config_obj'; import 'ui/config'; diff --git a/src/ui/public/chrome/__tests__/config_controls.js b/src/ui/public/chrome/__tests__/config_controls.js new file mode 100644 index 0000000000000..d9d2c29af1c94 --- /dev/null +++ b/src/ui/public/chrome/__tests__/config_controls.js @@ -0,0 +1,54 @@ +import ngMock from 'ngMock'; +import $ from 'jquery'; +import expect from 'expect.js'; + +import uiModules from 'ui/modules'; +import chromeConfigControlsRegistry from 'ui/registry/chrome_config_controls'; +import Registry from 'ui/registry/_registry'; +import 'ui/chrome/directives/config_controls'; +import 'ui/directives/config'; + +describe('chrome config controls', function () { + let compile; + let stubRegistry; + + beforeEach(ngMock.module('kibana', function (PrivateProvider) { + stubRegistry = new Registry({ + order: ['order'] + }); + + PrivateProvider.swap(chromeConfigControlsRegistry, stubRegistry); + })); + + beforeEach(ngMock.inject(function ($compile, $rootScope) { + compile = function () { + const $el = $(''); + let $scope = $rootScope.$new(); + $compile($el)($scope); + $scope.$digest(); + return $el; + }; + })); + + it('injects configs from the ui/registry/chrome_config_controls registry', function () { + stubRegistry.register(function () { + return { + name: 'control1', + order: 1, + config: { + } + }; + }); + stubRegistry.register(function () { + return { + name: 'control2', + order: 2, + config: { + } + }; + }); + + var $el = compile(); + expect($el.find('config')).to.have.length(2); + }); +}); diff --git a/src/ui/public/chrome/__tests__/nav_controls.js b/src/ui/public/chrome/__tests__/nav_controls.js index 64b3d54ef9d88..2194f6168f94b 100644 --- a/src/ui/public/chrome/__tests__/nav_controls.js +++ b/src/ui/public/chrome/__tests__/nav_controls.js @@ -4,18 +4,26 @@ import expect from 'expect.js'; import uiModules from 'ui/modules'; import chromeNavControlsRegistry from 'ui/registry/chrome_nav_controls'; +import chromeConfigControlsRegistry from 'ui/registry/chrome_config_controls'; import Registry from 'ui/registry/_registry'; describe('chrome nav controls', function () { let compile; - let stubRegistry; + let stubNavRegistry; + let stubConfigRegistry; beforeEach(ngMock.module('kibana', function (PrivateProvider) { - stubRegistry = new Registry({ + stubNavRegistry = new Registry({ order: ['order'] }); - PrivateProvider.swap(chromeNavControlsRegistry, stubRegistry); + PrivateProvider.swap(chromeNavControlsRegistry, stubNavRegistry); + + stubConfigRegistry = new Registry({ + order: ['order'] + }); + + PrivateProvider.swap(chromeConfigControlsRegistry, stubConfigRegistry); })); beforeEach(ngMock.inject(function ($compile, $rootScope) { @@ -28,7 +36,7 @@ describe('chrome nav controls', function () { })); it('injects templates from the ui/registry/chrome_nav_controls registry', function () { - stubRegistry.register(function () { + stubNavRegistry.register(function () { return { name: 'control', order: 100, @@ -40,22 +48,39 @@ describe('chrome nav controls', function () { expect($el.find('#testTemplateEl')).to.have.length(1); }); + it('injects templates from the ui/registry/chrome_config_controls registry', function () { + stubConfigRegistry.register(function () { + return { + name: 'control', + order: 100, + navbar: { + template: `` + } + }; + }); + + var $el = compile(); + expect($el.find('#testTemplateEl')).to.have.length(1); + }); + it('renders controls in reverse order, assuming that each control will float:right', function () { - stubRegistry.register(function () { + stubConfigRegistry.register(function () { return { name: 'control2', order: 2, - template: `` + navbar: { + template: `` + } }; }); - stubRegistry.register(function () { + stubNavRegistry.register(function () { return { name: 'control1', order: 1, template: `` }; }); - stubRegistry.register(function () { + stubNavRegistry.register(function () { return { name: 'control3', order: 3, diff --git a/src/ui/public/chrome/chrome.html b/src/ui/public/chrome/chrome.html index 6e5cccbfdd497..65a67b2008fea 100644 --- a/src/ui/public/chrome/chrome.html +++ b/src/ui/public/chrome/chrome.html @@ -1,5 +1,5 @@ -
+
+ - - -
diff --git a/src/ui/public/chrome/config/filter.html b/src/ui/public/chrome/config/filter.html deleted file mode 100644 index 71a3dd32645ef..0000000000000 --- a/src/ui/public/chrome/config/filter.html +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/src/ui/public/chrome/config/interval.html b/src/ui/public/chrome/config/interval.html deleted file mode 100644 index d41a601709709..0000000000000 --- a/src/ui/public/chrome/config/interval.html +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/src/ui/public/chrome/context.js b/src/ui/public/chrome/context.js deleted file mode 100644 index 092ea422dcdff..0000000000000 --- a/src/ui/public/chrome/context.js +++ /dev/null @@ -1,35 +0,0 @@ -import _ from 'lodash'; -import ConfigTemplate from 'ui/config_template'; -import uiModules from 'ui/modules'; - -uiModules -.get('kibana') -// TODO: all of this really belongs in the timepicker -.directive('chromeContext', function (timefilter, globalState) { - - var listenForUpdates = _.once(function ($scope) { - $scope.$listen(timefilter, 'update', function (newVal, oldVal) { - globalState.time = _.clone(timefilter.time); - globalState.refreshInterval = _.clone(timefilter.refreshInterval); - globalState.save(); - }); - }); - - return { - link: function ($scope) { - listenForUpdates($scope); - - // 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/append_nav_controls.js b/src/ui/public/chrome/directives/append_nav_controls.js index d37b9c6fe0a74..2fd90a7a2d247 100644 --- a/src/ui/public/chrome/directives/append_nav_controls.js +++ b/src/ui/public/chrome/directives/append_nav_controls.js @@ -1,14 +1,11 @@ +import _ from 'lodash'; import $ from 'jquery'; import chromeNavControlsRegistry from 'ui/registry/chrome_nav_controls'; +import chromeConfigControlsRegistry from 'ui/registry/chrome_config_controls'; import UiModules from 'ui/modules'; import spinnerHtml from './active_http_spinner.html'; -const spinner = { - name: 'active http requests', - template: spinnerHtml -}; - export default function (chrome, internals) { UiModules @@ -17,16 +14,43 @@ export default function (chrome, internals) { return { template: function ($element) { const parts = [$element.html()]; - const controls = Private(chromeNavControlsRegistry); + const navs = Private(chromeNavControlsRegistry); + const configs = Private(chromeConfigControlsRegistry); + + const controls = [ + { + name: 'active http requests', + order: -100, + template: spinnerHtml + }, + + ...navs.map(function (nav) { + return { + template: `${nav.template}`, + order: nav.order + }; + }), + + ...configs.map(function (config) { + let $wrapper = $('
'); + let $directive = $(``); + $directive.html(config.navbar.template); + $wrapper.append($directive); + return { + template: `${$wrapper.html()}`, + order: config.order + }; + }), + ]; - for (const control of [spinner, ...controls.inOrder]) { - parts.unshift( - ``, - control.template - ); - } + _.sortBy(controls, 'order').forEach(function (control) { + parts.unshift(control.template); + }); return parts.join('\n'); + }, + controller: function ($scope) { + $scope.configs = Private(chromeConfigControlsRegistry).byName; } }; }); diff --git a/src/ui/public/chrome/directives/config_controls.html b/src/ui/public/chrome/directives/config_controls.html new file mode 100644 index 0000000000000..115346011c154 --- /dev/null +++ b/src/ui/public/chrome/directives/config_controls.html @@ -0,0 +1,8 @@ +
+ + +
diff --git a/src/ui/public/chrome/directives/config_controls.js b/src/ui/public/chrome/directives/config_controls.js new file mode 100644 index 0000000000000..fbe4676747ee6 --- /dev/null +++ b/src/ui/public/chrome/directives/config_controls.js @@ -0,0 +1,22 @@ +import $ from 'jquery'; + +import chromeConfigControlsRegistry from 'ui/registry/chrome_config_controls'; +import UiModules from 'ui/modules'; +import configControlsHtml from './config_controls.html'; + +export default function (chrome, internals) { + + UiModules + .get('kibana') + .directive('kbnChromeConfigControls', function (Private) { + const controls = Private(chromeConfigControlsRegistry); + return { + restrict: 'E', + template: configControlsHtml, + controller: function ($scope) { + $scope.controls = controls.inOrder; + } + }; + }); + +} diff --git a/src/ui/public/chrome/directives/index.js b/src/ui/public/chrome/directives/index.js index 530646292d388..1d38db2acb222 100644 --- a/src/ui/public/chrome/directives/index.js +++ b/src/ui/public/chrome/directives/index.js @@ -3,8 +3,10 @@ import 'ui/directives/config'; import './app_switcher'; import kbnChromeProv from './kbn_chrome'; import kbnChromeNavControlsProv from './append_nav_controls'; +import kbnChromeConfigControlsProv from './config_controls'; export default function (chrome, internals) { kbnChromeProv(chrome, internals); kbnChromeNavControlsProv(chrome, internals); + kbnChromeConfigControlsProv(chrome, internals); } diff --git a/src/ui/public/courier/courier.js b/src/ui/public/courier/courier.js index 486d5bcb20e88..b48b7f9d5b2b6 100644 --- a/src/ui/public/courier/courier.js +++ b/src/ui/public/courier/courier.js @@ -22,7 +22,7 @@ import RedirectWhenMissingProvider from './_redirect_when_missing'; uiModules.get('kibana/courier') -.service('courier', function ($rootScope, Private, Promise, indexPatterns) { +.service('courier', function ($rootScope, Private, Promise, indexPatterns, timefilter) { function Courier() { var self = this; @@ -134,9 +134,11 @@ uiModules.get('kibana/courier') }; // Listen for refreshInterval changes - $rootScope.$watchCollection('timefilter.refreshInterval', function () { - var refreshValue = _.get($rootScope, 'timefilter.refreshInterval.value'); - var refreshPause = _.get($rootScope, 'timefilter.refreshInterval.pause'); + $rootScope.$watchCollection(function () { + return timefilter.refreshInterval; + }, function (interval) { + var refreshValue = _.get(interval, 'value'); + var refreshPause = _.get(interval, 'pause'); if (_.isNumber(refreshValue) && !refreshPause) { self.fetchInterval(refreshValue); } else { diff --git a/src/ui/public/directives/__tests__/timepicker.js b/src/ui/public/directives/__tests__/timepicker.js index bd8f9f6fe7be6..53b63f6996a19 100644 --- a/src/ui/public/directives/__tests__/timepicker.js +++ b/src/ui/public/directives/__tests__/timepicker.js @@ -28,23 +28,18 @@ var init = function () { clock = sinon.useFakeTimers(moment(anchor).valueOf()); // Create the scope - ngMock.inject(function ($rootScope, $compile) { + ngMock.inject(function ($rootScope, $compile, timefilter) { // Give us a scope $parentScope = $rootScope; // Add some parameters to it - var timefilter = { - time : { - from: moment().subtract(15, 'minutes'), - to: moment(), - mode: undefined - }, - refreshInterval : { - value : 0, - display : 'Off' - } - }; + timefilter.time.from = moment().subtract(15, 'minutes'); + timefilter.time.to = moment(); + timefilter.time.mode = undefined; + timefilter.refreshInterval.value = 0; + timefilter.refreshInterval.display = 'Off'; + $parentScope.timefilter = timefilter; // Create the element diff --git a/src/ui/public/registry/chrome_config_controls.js b/src/ui/public/registry/chrome_config_controls.js new file mode 100644 index 0000000000000..3e0b32c4dc0ac --- /dev/null +++ b/src/ui/public/registry/chrome_config_controls.js @@ -0,0 +1,12 @@ +import _ from 'lodash'; +import uiRegistry from 'ui/registry/_registry'; +export default uiRegistry({ + name: 'chromeConfigControls', + order: ['order'], + index: ['name'], + constructor() { + this.forEach(configControl => { + configControl.name = configControl.name.replace(/[^a-zA-Z0-9]/g, '_'); + }); + } +}); diff --git a/src/ui/public/timepicker/config/filter.html b/src/ui/public/timepicker/config/filter.html new file mode 100644 index 0000000000000..7dcf535fcc5b1 --- /dev/null +++ b/src/ui/public/timepicker/config/filter.html @@ -0,0 +1,7 @@ + + diff --git a/src/ui/public/timepicker/config/interval.html b/src/ui/public/timepicker/config/interval.html new file mode 100644 index 0000000000000..529af7868b639 --- /dev/null +++ b/src/ui/public/timepicker/config/interval.html @@ -0,0 +1,7 @@ + + diff --git a/src/ui/public/timepicker/toggle.js b/src/ui/public/timepicker/toggle.js index 2b9bf03fdc6be..76eb8f9594d65 100644 --- a/src/ui/public/timepicker/toggle.js +++ b/src/ui/public/timepicker/toggle.js @@ -1,16 +1,45 @@ +import _ from 'lodash'; import UiModules from 'ui/modules'; -import chromeNavControlsRegistry from 'ui/registry/chrome_nav_controls'; +import chromeConfigControlsRegistry from 'ui/registry/chrome_config_controls'; +import ConfigTemplate from 'ui/ConfigTemplate'; import toggleHtml from './toggle.html'; +import filterConfig from './config/filter.html'; +import intervalConfig from './config/interval.html'; -// TODO: the chrome-context directive is currently responsible for several variables -// on scope used by this template. We need to get rid of that directive and move that -// logic here +chromeConfigControlsRegistry.register(function (timefilter, globalState) { + let pickerTemplate = new ConfigTemplate({ + filter: filterConfig, + interval: intervalConfig + }); + + var listenForUpdates = _.once(function ($scope) { + $scope.$listen(timefilter, 'update', function (newVal, oldVal) { + globalState.time = _.clone(timefilter.time); + globalState.refreshInterval = _.clone(timefilter.refreshInterval); + globalState.save(); + }); + }); -chromeNavControlsRegistry.register(function () { return { name: 'timepicker toggle', order: 100, - template: toggleHtml + navbar: { + template: toggleHtml, + controller: function ($scope) { + listenForUpdates($scope); + $scope.pickerTemplate = pickerTemplate; + $scope.timefilter = timefilter; + + $scope.toggleRefresh = function () { + timefilter.refreshInterval.pause = !timefilter.refreshInterval.pause; + }; + } + }, + config: { + template: pickerTemplate, + close: pickerTemplate.close, + object: timefilter + } }; }); diff --git a/src/ui/ui_app.js b/src/ui/ui_app.js index a14d01e5d9846..4b15f8d771a5b 100644 --- a/src/ui/ui_app.js +++ b/src/ui/ui_app.js @@ -36,7 +36,7 @@ class UiApp { getModules() { return _.chain([ this.uiExports.find(_.get(this, 'spec.uses', [])), - this.uiExports.find(['chromeNavControls', 'hacks']), + this.uiExports.find(['chromeNavControls', 'hacks', 'chromeConfigControls']), ]) .flatten() .uniq() diff --git a/src/ui/ui_exports.js b/src/ui/ui_exports.js index da5edef1a8f03..b35467849384f 100644 --- a/src/ui/ui_exports.js +++ b/src/ui/ui_exports.js @@ -65,6 +65,7 @@ class UiExports { case 'settingsSections': case 'docViews': case 'hacks': + case 'chromeConfigControls': return (plugin, spec) => { this.aliases[type] = _.union(this.aliases[type] || [], spec); };