diff --git a/CHANGELOG.md b/CHANGELOG.md index 0331dfd5d95..6c82ce61a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ # 2.0.0 (unreleased) +**New features** +- [Issue #1331](https://github.com/grafana/grafana/issues/1331). Graph & Singlestat: New axis/unit format selector and more units (kbytes, Joule, Watt, eV), and new design for graph axis & grid tab and single stat options tab views + **Enhancements** - [Issue #1297](https://github.com/grafana/grafana/issues/1297). Graphite: Added cumulative and minimumBelow graphite functions - [Issue #1296](https://github.com/grafana/grafana/issues/1296). InfluxDB: Auto escape column names with special characters. Thanks @steven-aerts +- [Issue #1321](https://github.com/grafana/grafana/issues/1321). SingleStatPanel: You can now use template variables in pre & postfix +- [Issue #599](https://github.com/grafana/grafana/issues/599). Graph: Added right y axis label setting and graph support **Fixes** - [Issue #1298](https://github.com/grafana/grafana/issues/1298). InfluxDB: Fix handling of empty array in templating variable query diff --git a/src/app/components/kbn.js b/src/app/components/kbn.js index aedfbb90f17..80a2b976f6e 100644 --- a/src/app/components/kbn.js +++ b/src/app/components/kbn.js @@ -362,8 +362,14 @@ function($, _, moment) { kbn.valueFormats.bits = kbn.formatFuncCreator(1024, [' b', ' Kib', ' Mib', ' Gib', ' Tib', ' Pib', ' Eib', ' Zib', ' Yib']); kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); + kbn.valueFormats.kbytes = kbn.formatFuncCreator(1024, [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); + kbn.valueFormats.mbytes = kbn.formatFuncCreator(1024, [' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']); + kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']); kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Qaudr', ' Quint', ' Sext', ' Sept']); + kbn.valueFormats.joule = kbn.formatFuncCreator(1000, [' J', ' kJ', ' MJ', 'GJ', 'TJ', 'PJ', 'EJ', 'ZJ', 'YJ']); + kbn.valueFormats.watt = kbn.formatFuncCreator(1000, [' W', ' kW', ' MW', 'GW', 'TW', 'PW', 'EW', 'ZW', 'YW']); + kbn.valueFormats.ev = kbn.formatFuncCreator(1000, [' eV', ' keV', ' MeV', 'GeV', 'TeV', 'PeV', 'EeV', 'ZeV', 'YeV']); kbn.valueFormats.none = kbn.toFixed; kbn.valueFormats.ms = function(size, decimals, scaledDecimals) { @@ -479,5 +485,50 @@ function($, _, moment) { return new RegExp(match[1], match[2]); }; + kbn.getUnitFormats = function() { + return [ + { + text: 'none', + submenu: [ + {text: 'none' , value: 'none'}, + {text: 'short', value: 'short'}, + {text: 'percent', value: 'percent'}, + ] + }, + { + text: 'duration', + submenu: [ + {text: 'nanoseconds (ns)' , value: 'ns'}, + {text: 'microseconds (µs)', value: 'µs'}, + {text: 'milliseconds (ms)', value: 'ms'}, + {text: 'seconds (s)', value: 's'}, + ] + }, + { + text: 'data', + submenu: [ + {text: 'bits', value: 'bits'}, + {text: 'bytes', value: 'bytes'}, + {text: 'kilobytes', value: 'kbytes'}, + ] + }, + { + text: 'data rate', + submenu: [ + {text: 'bits/sec', value: 'bps'}, + {text: 'bytes/sec', value: 'Bps'}, + ] + }, + { + text: 'energy', + submenu: [ + {text: 'watt', value: 'watt'}, + {text: 'joule', value: 'joule'}, + {text: 'eV', value: 'ev'}, + ] + }, + ]; + }; + return kbn; }); diff --git a/src/app/directives/arrayJoin.js b/src/app/directives/arrayJoin.js index 9f0900d880d..a2b5fbe59dd 100644 --- a/src/app/directives/arrayJoin.js +++ b/src/app/directives/arrayJoin.js @@ -31,4 +31,5 @@ function (angular, app, _) { } }; }); + }); diff --git a/src/app/directives/dropdown.typeahead.js b/src/app/directives/dropdown.typeahead.js index f46de052c06..56203ee3c6f 100644 --- a/src/app/directives/dropdown.typeahead.js +++ b/src/app/directives/dropdown.typeahead.js @@ -17,35 +17,47 @@ function (angular, app, _, $) { var buttonTemplate = ''; + ' data-placement="top">'; return { scope: { - "menuItems": "=dropdownTypeahead", - "dropdownTypeaheadOnSelect": "&dropdownTypeaheadOnSelect" + menuItems: "=dropdownTypeahead", + dropdownTypeaheadOnSelect: "&dropdownTypeaheadOnSelect", + model: '=ngModel' }, - link: function($scope, elem) { + link: function($scope, elem, attrs) { var $input = $(inputTemplate); var $button = $(buttonTemplate); $input.appendTo(elem); $button.appendTo(elem); - var typeaheadValues = _.reduce($scope.menuItems, function(memo, value) { - _.each(value.submenu, function(item) { + if (attrs.linkText) { + $button.html(attrs.linkText); + } + + if (attrs.ngModel) { + $scope.$watch('model', function(newValue) { + _.each($scope.menuItems, function(item) { + _.each(item.submenu, function(subItem) { + if (subItem.value === newValue) { + $button.html(subItem.text); + } + }); + }); + }); + } + + var typeaheadValues = _.reduce($scope.menuItems, function(memo, value, index) { + _.each(value.submenu, function(item, subIndex) { + item.click = 'menuItemSelected(' + index + ',' + subIndex + ')'; memo.push(value.text + ' ' + item.text); }); return memo; }, []); - $scope.menuItemSelected = function(optionIndex, valueIndex) { - var option = $scope.menuItems[optionIndex]; - var result = { - $item: option.submenu[valueIndex], - $optionIndex: optionIndex, - $valueIndex: valueIndex - }; - - $scope.dropdownTypeaheadOnSelect(result); + $scope.menuItemSelected = function(index, subIndex) { + var item = $scope.menuItems[index]; + $scope.dropdownTypeaheadOnSelect({$item: item, $subItem: item.submenu[subIndex]}); }; $input.attr('data-provide', 'typeahead'); @@ -55,12 +67,11 @@ function (angular, app, _, $) { items: 10, updater: function (value) { var result = {}; - _.each($scope.menuItems, function(menuItem, optionIndex) { - _.each(menuItem.submenu, function(submenuItem, valueIndex) { + _.each($scope.menuItems, function(menuItem) { + _.each(menuItem.submenu, function(submenuItem) { if (value === (menuItem.text + ' ' + submenuItem.text)) { - result.$item = submenuItem; - result.$optionIndex = optionIndex; - result.$valueIndex = valueIndex; + result.$item = menuItem; + result.$subItem = submenuItem; } }); }); diff --git a/src/app/directives/ngModelOnBlur.js b/src/app/directives/ngModelOnBlur.js index 0e9d94a282e..1aea09f9dc8 100644 --- a/src/app/directives/ngModelOnBlur.js +++ b/src/app/directives/ngModelOnBlur.js @@ -22,5 +22,17 @@ function (angular) { }); } }; + }) + .directive('emptyToNull', function () { + return { + restrict: 'A', + require: 'ngModel', + link: function (scope, elm, attrs, ctrl) { + ctrl.$parsers.push(function (viewValue) { + if(viewValue === "") { return null; } + return viewValue; + }); + } + }; }); }); diff --git a/src/app/features/annotations/partials/editor.html b/src/app/features/annotations/partials/editor.html index b6118f15d63..14208dc2ab2 100644 --- a/src/app/features/annotations/partials/editor.html +++ b/src/app/features/annotations/partials/editor.html @@ -53,7 +53,7 @@ -