From a6fa01f89b6b21dfedc73b84da2995b3e5da0067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 6 Sep 2014 14:02:18 +0200 Subject: [PATCH 01/45] POC of panel edit menu --- src/app/directives/grafanaPanel.js | 81 +++++++++++++++++++----------- src/css/less/panel.less | 31 ++++++------ 2 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/app/directives/grafanaPanel.js b/src/app/directives/grafanaPanel.js index 5f56fd67b35..ec6048609ea 100644 --- a/src/app/directives/grafanaPanel.js +++ b/src/app/directives/grafanaPanel.js @@ -6,6 +6,49 @@ define([ function (angular, $) { 'use strict'; + angular + .module('grafana.directives') + .directive('panelTitle', function($compile) { + var linkTemplate = '{{panel.title || interpolateTemplateVars}}'; + var menuTemplate = '
' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + ' ' + + '
'; + + return { + restrict: 'A', + link: function($scope, elem) { + var $link = $(linkTemplate); + elem.append($link); + + $link.click(function() { + var $menu = $(menuTemplate); + var menuScope = $scope.$new(); + + elem.append($menu); + $compile($menu.contents())(menuScope); + + setTimeout(function() { + $menu.remove(); + menuScope.$destroy(); + $link.show(); + }, 8000); + + $link.hide(); + }); + + $compile(elem.contents())($scope); + } + }; + + }); + angular .module('grafana.directives') .directive('grafanaPanel', function($compile, $parse) { @@ -15,37 +58,19 @@ function (angular, $) { var panelHeader = '
'+ - '
' + - '
' + - '' + - '' + - '' + - '' + + '' + + '' + + '' + '' + + '' + - '' + - '' + - '' + + '' + + '' + + '' + - '' + - '' + - '{{panel.title | interpolateTemplateVars}}' + - '' + - ''+ - - '
'+ - '
\n'+ + '
' + + '
'+ ''; return { diff --git a/src/css/less/panel.less b/src/css/less/panel.less index 19e5a077872..85f65cd5f16 100644 --- a/src/css/less/panel.less +++ b/src/css/less/panel.less @@ -28,23 +28,10 @@ z-index: 800; } -.panel div.panel-extra div.panel-extra-container { - margin-right: -10px; - margin-top: 3px; +.panel-header { text-align: center; - ul { - text-align: left; - } } -.panel div.panel-extra { - font-size: 0.9em; - margin-bottom: 0px; -} - -.panel div.panel-extra .extra { - float:right !important; -} .panel-error { color: @white; @@ -69,3 +56,19 @@ bottom: 0; } +.panel-menu { + display: inline-block; + vertical-align: top; + a { + font-size: 1.2em; + float: left; + padding: 2px 10px; + border-top: 1px solid black; + border-right: 1px solid black; + border-bottom: 1px solid black; + background: @grayDark; + } + a:first-child { + border-left: 1px solid black; + } +} From e78c48620fc4a9e0f6d63fae05205afd1fc50a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 19 Sep 2014 13:24:15 +0200 Subject: [PATCH 02/45] Trying to improve yaxis precision --- src/app/components/kbn.js | 76 ++++-------------------------- src/app/components/timeSeries.js | 16 +++---- src/app/directives/grafanaGraph.js | 22 ++++++--- 3 files changed, 33 insertions(+), 81 deletions(-) diff --git a/src/app/components/kbn.js b/src/app/components/kbn.js index 7c61b22c83b..e41722747fb 100644 --- a/src/app/components/kbn.js +++ b/src/app/components/kbn.js @@ -7,6 +7,7 @@ function($, _, moment) { 'use strict'; var kbn = {}; + kbn.formatFunctions = {}; kbn.round_interval = function(interval) { switch (true) { @@ -497,52 +498,7 @@ function($, _, moment) { return (size.toFixed(decimals) + ext); }; - kbn.getFormatFunction = function(formatName, decimals) { - switch(formatName) { - case 'short': - return function(val) { - return kbn.shortFormat(val, decimals); - }; - case 'bytes': - return function(val) { - return kbn.byteFormat(val, decimals); - }; - case 'bits': - return function(val) { - return kbn.bitFormat(val, decimals); - }; - case 'bps': - return function(val) { - return kbn.bpsFormat(val, decimals); - }; - case 's': - return function(val) { - return kbn.sFormat(val, decimals); - }; - case 'ms': - return function(val) { - return kbn.msFormat(val, decimals); - }; - case 'µs': - return function(val) { - return kbn.microsFormat(val, decimals); - }; - case 'ns': - return function(val) { - return kbn.nanosFormat(val, decimals); - }; - case 'percent': - return function(val, axis) { - return kbn.noneFormat(val, axis ? axis.tickDecimals : null) + ' %'; - }; - default: - return function(val, axis) { - return kbn.noneFormat(val, axis ? axis.tickDecimals : null); - }; - } - }; - - kbn.noneFormat = function(value, decimals) { + kbn.toFixed = function(value, decimals) { var factor = decimals ? Math.pow(10, decimals) : 1; var formatted = String(Math.round(value * factor) / factor); @@ -553,7 +509,6 @@ function($, _, moment) { // If tickDecimals was specified, ensure that we have exactly that // much precision; otherwise default to the value's own precision. - if (decimals != null) { var decimalPos = formatted.indexOf("."); var precision = decimalPos === -1 ? 0 : formatted.length - decimalPos - 1; @@ -565,17 +520,13 @@ function($, _, moment) { return formatted; }; - kbn.msFormat = function(size, decimals) { - // Less than 1 milli, downscale to micro - if (size !== 0 && Math.abs(size) < 1) { - return kbn.microsFormat(size * 1000, decimals); - } - else if (Math.abs(size) < 1000) { - return size.toFixed(decimals) + " ms"; + kbn.formatFunctions.ms = function(size, decimals) { + if (Math.abs(size) < 1000) { + return kbn.toFixed(size, decimals) + " ms"; } // Less than 1 min else if (Math.abs(size) < 60000) { - return (size / 1000).toFixed(decimals) + " s"; + return kbn.toFixed(size / 1000, decimals) + " s"; } // Less than 1 hour, devide in minutes else if (Math.abs(size) < 3600000) { @@ -594,12 +545,7 @@ function($, _, moment) { }; kbn.sFormat = function(size, decimals) { - // Less than 1 sec, downscale to milli - if (size !== 0 && Math.abs(size) < 1) { - return kbn.msFormat(size * 1000, decimals); - } - // Less than 10 min, use seconds - else if (Math.abs(size) < 600) { + if (Math.abs(size) < 600) { return size.toFixed(decimals) + " s"; } // Less than 1 hour, devide in minutes @@ -623,12 +569,8 @@ function($, _, moment) { }; kbn.microsFormat = function(size, decimals) { - // Less than 1 micro, downscale to nano - if (size !== 0 && Math.abs(size) < 1) { - return kbn.nanosFormat(size * 1000, decimals); - } - else if (Math.abs(size) < 1000) { - return size.toFixed(decimals) + " µs"; + if (Math.abs(size) < 1000) { + return kbn.toFixed(size, decimals) + " µs"; } else if (Math.abs(size) < 1000000) { return (size / 1000).toFixed(decimals) + " ms"; diff --git a/src/app/components/timeSeries.js b/src/app/components/timeSeries.js index 4c58c211cc3..576e8be8e8a 100644 --- a/src/app/components/timeSeries.js +++ b/src/app/components/timeSeries.js @@ -100,21 +100,21 @@ function (_, kbn) { } if (result.length) { - this.info.avg = (this.info.total / result.length); this.info.current = result[result.length-1][1]; - - var formater = kbn.getFormatFunction(yFormats[this.yaxis - 1], 2); - this.info.avg = this.info.avg != null ? formater(this.info.avg) : null; - this.info.current = this.info.current != null ? formater(this.info.current) : null; - this.info.min = this.info.min != null ? formater(this.info.min) : null; - this.info.max = this.info.max != null ? formater(this.info.max) : null; - this.info.total = this.info.total != null ? formater(this.info.total) : null; } return result; }; + TimeSeries.prototype.updateLegendValues = function(formater, decimals) { + this.info.avg = this.info.avg != null ? formater(this.info.avg, decimals) : null; + this.info.current = this.info.current != null ? formater(this.info.current, decimals) : null; + this.info.min = this.info.min != null ? formater(this.info.min, decimals) : null; + this.info.max = this.info.max != null ? formater(this.info.max, decimals) : null; + this.info.total = this.info.total != null ? formater(this.info.total, decimals) : null; + }; + return TimeSeries; }); diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index ee6b0fb7dd7..53edcf1bc13 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -88,6 +88,18 @@ function (angular, $, kbn, moment, _) { } } + function updateLegendValues(plot) { + var yaxis = plot.getYAxes(); + console.log('drawSeries', yaxis); + + for (var i = 0; i < data.length; i++) { + var series = data[i]; + var formater = kbn.formatFunctions[scope.panel.y_formats[series.yaxis - 1]]; + series.updateLegendValues(formater, yaxis[series.yaxis - 1].tickDecimals); + } + + } + // Function for rendering panel function render_panel() { if (shouldAbortRender()) { @@ -110,11 +122,7 @@ function (angular, $, kbn, moment, _) { // Populate element var options = { - hooks: { - drawSeries: [function() { - console.log('drawSeries', arguments); - }] - }, + hooks: { draw: [updateLegendValues] }, legend: { show: false }, series: { stackpercent: panel.stack ? panel.percentage : false, @@ -318,7 +326,9 @@ function (angular, $, kbn, moment, _) { } function configureAxisMode(axis, format) { - axis.tickFormatter = kbn.getFormatFunction(format, 1); + axis.tickFormatter = function(val, axis) { + return kbn.formatFunctions[format](val, axis.tickDecimals); + }; } function time_format(interval, ticks, min, max) { From 010baad5327afb67909be3aee81400ac12416fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 22 Sep 2014 12:54:02 +0200 Subject: [PATCH 03/45] Dashboard: fixed init of editable setting, #837 --- src/app/services/dashboard/dashboardSrv.js | 2 +- src/test/specs/dashboardSrv-specs.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/app/services/dashboard/dashboardSrv.js b/src/app/services/dashboard/dashboardSrv.js index c6b386917ba..17313a207d5 100644 --- a/src/app/services/dashboard/dashboardSrv.js +++ b/src/app/services/dashboard/dashboardSrv.js @@ -25,7 +25,7 @@ function (angular, $, kbn, _, moment) { this.tags = data.tags || []; this.style = data.style || "dark"; this.timezone = data.timezone || 'browser'; - this.editable = data.editable || true; + this.editable = data.editable === false ? false : true; this.hideControls = data.hideControls || false; this.rows = data.rows || []; this.nav = data.nav || []; diff --git a/src/test/specs/dashboardSrv-specs.js b/src/test/specs/dashboardSrv-specs.js index f916279db98..862c2a6fc41 100644 --- a/src/test/specs/dashboardSrv-specs.js +++ b/src/test/specs/dashboardSrv-specs.js @@ -82,6 +82,22 @@ define([ }); + describe('when creating dashboard with editable false', function() { + var model; + + beforeEach(module('grafana.services')); + beforeEach(inject(function(dashboardSrv) { + model = dashboardSrv.create({ + editable: false + }); + })); + + it('should set editable false', function() { + expect(model.editable).to.be(false); + }); + + }); + describe('when creating dashboard with old schema', function() { var model; var graph; From 352ad3385a2f9686df8bba674cf2595a00181b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 22 Sep 2014 12:59:21 +0200 Subject: [PATCH 04/45] Updated changelog and package.json to new version 1.8.0 --- CHANGELOG.md | 4 +++- package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69835953dc1..8d28e9223f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -# 1.8.0 (unreleased) +# 1.8.0 (2014-09-22) + +Read this [blog post](http://grafana.org/blog/2014/09/11/grafana-1-8-0-rc1-released.html) for an overview of all improvements. **Fixes** - [Issue #802](https://github.com/grafana/grafana/issues/802). Annotations: Fix when using InfluxDB datasource diff --git a/package.json b/package.json index f84ca9cf8c6..8de8f05cf8a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Coding Instinct AB" }, "name": "grafana", - "version": "1.8.0-rc1", + "version": "1.8.0", "repository": { "type": "git", "url": "http://github.com/torkelo/grafana.git" From 7fe76d32d075a62189e3b4c3529699f1003e341a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 22 Sep 2014 13:05:44 +0200 Subject: [PATCH 05/45] updated latest.json --- latest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/latest.json b/latest.json index c66de1bc179..6e7dc07bae2 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "version": "1.8.0-rc1", - "url": "http://grafanarel.s3.amazonaws.com/grafana-1.8.0-rc1" + "version": "1.8.0", + "url": "http://grafanarel.s3.amazonaws.com/grafana-1.8.0.tar.gz" } From af8fec941c372f637ed2a5ed435698b95566254d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 23 Sep 2014 08:18:59 +0200 Subject: [PATCH 06/45] Graph: Fix for series draw order not being the same after hiding/unhiding series, Fixes #847 --- CHANGELOG.md | 5 +++++ src/app/directives/grafanaGraph.js | 26 ++++++-------------------- src/test/specs/grafanaGraph-specs.js | 13 +++++++++++++ 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d28e9223f0..79bc9c23752 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.9.0 (unreleased) + +**Fixes** +- [Issue #847](https://github.com/grafana/grafana/issues/847). Graph: Fix for series draw order not being the same after hiding/unhiding series + # 1.8.0 (2014-09-22) Read this [blog post](http://grafana.org/blog/2014/09/11/grafana-1-8-0-rc1-released.html) for an overview of all improvements. diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index 15f1556aa62..a2987213cb4 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -16,7 +16,6 @@ function (angular, $, kbn, moment, _) { template: '
', link: function(scope, elem) { var data, annotations; - var hiddenData = {}; var dashboard = scope.dashboard; var legendSideLastValue = null; @@ -24,14 +23,7 @@ function (angular, $, kbn, moment, _) { scope.get_data(); }); - scope.$on('toggleLegend', function(e, series) { - _.each(series, function(serie) { - if (hiddenData[serie.alias]) { - data.push(hiddenData[serie.alias]); - delete hiddenData[serie.alias]; - } - }); - + scope.$on('toggleLegend', function() { render_panel(); }); @@ -95,17 +87,6 @@ function (angular, $, kbn, moment, _) { } var panel = scope.panel; - - _.each(_.keys(scope.hiddenSeries), function(seriesAlias) { - var dataSeries = _.find(data, function(series) { - return series.info.alias === seriesAlias; - }); - if (dataSeries) { - hiddenData[dataSeries.info.alias] = dataSeries; - data = _.without(data, dataSeries); - } - }); - var stack = panel.stack ? true : null; // Populate element @@ -156,6 +137,11 @@ function (angular, $, kbn, moment, _) { var series = data[i]; series.applySeriesOverrides(panel.seriesOverrides); series.data = series.getFlotPairs(panel.nullPointMode, panel.y_formats); + // if hidden remove points and disable stack + if (scope.hiddenSeries[series.info.alias]) { + series.data = []; + series.stack = false; + } } if (data.length && data[0].info.timeStep) { diff --git a/src/test/specs/grafanaGraph-specs.js b/src/test/specs/grafanaGraph-specs.js index 1b86ee9073d..faf19119d27 100644 --- a/src/test/specs/grafanaGraph-specs.js +++ b/src/test/specs/grafanaGraph-specs.js @@ -29,6 +29,7 @@ define([ y_formats: [], seriesOverrides: [] }; + scope.hiddenSeries = {}; scope.dashboard = { timezone: 'browser' }; scope.range = { from: new Date('2014-08-09 10:00:00'), @@ -145,6 +146,18 @@ define([ }); }); + graphScenario('when series is hidden', function(ctx) { + ctx.setup(function(scope) { + scope.hiddenSeries = {'series2': true}; + }); + + it('should remove datapoints and disable stack', function() { + expect(ctx.plotData[0].info.alias).to.be('series1'); + expect(ctx.plotData[1].data.length).to.be(0); + expect(ctx.plotData[1].stack).to.be(false); + }); + }); + }); }); From 0fbace72856e5854ce7483c945a007e5f3591e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 23 Sep 2014 08:32:04 +0200 Subject: [PATCH 07/45] Row: fix for row editor and scroll pos, Fixes #846 --- src/app/directives/dashEditLink.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/directives/dashEditLink.js b/src/app/directives/dashEditLink.js index 599cf341fe5..d0babd967e4 100644 --- a/src/app/directives/dashEditLink.js +++ b/src/app/directives/dashEditLink.js @@ -34,6 +34,7 @@ function (angular, $) { function hideScrollbars(value) { if (value) { + window.scrollTo(0,0); document.documentElement.style.overflow = 'hidden'; // firefox, chrome document.body.scroll = "no"; // ie only } else { From bd3bae3af0ef5e40b997e004cfdc1f1791fa982f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 23 Sep 2014 10:52:31 +0200 Subject: [PATCH 08/45] another attempt at improving panel edit menu --- ' | 79 ++++++++++++++++++++++++++++++ src/app/controllers/row.js | 5 ++ src/app/directives/grafanaPanel.js | 33 ++++++++----- src/app/partials/dashboard.html | 9 ++++ src/css/less/panel.less | 6 ++- 5 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 ' diff --git a/' b/' new file mode 100644 index 00000000000..b22d59592f8 --- /dev/null +++ b/' @@ -0,0 +1,79 @@ +.panel { + display: inline-block; + float: left; + vertical-align: top; +} + +.panel-container { + padding: 0px 0px 0px 0px; + background: @grafanaPanelBackground; + margin: 5px; + position: relative; +} + +.panel-content { + padding: 0px 10px 5px 10px; +} + +.panel-title { + border: 0px; + font-weight: bold; + position: relative; +} + +.panel-loading { + position:absolute; + top: 0px; + right: 4px; + z-index: 800; +} + +.panel-header { + text-align: center; +} + + +.panel-error { + color: @white; + position: absolute; + left: 0; + padding: 0px 17px 6px 5px; + top: 0; + i { + position: relative; + top: -2px; + } +} + +.panel-error-arrow { + width: 0; + height: 0; + position: absolute; + border-left: 31px solid transparent; + border-right: 30px solid transparent; + border-bottom: 27px solid @grafanaPanelBackground; + left: 0; + bottom: 0; +} + +.panel-menu { + display: inline-block; + vertical-align: top; + a { + font-size: 1.2em; + float: left; + padding: 7px 10px; + border-top: 1px solid black; + border-right: 1px solid black; + border-bottom: 1px solid black; + background: @grayDark; + } + a:first-child { + border-left: 1px solid black; + } +} + +.panel-highlight { + border: 1px solid @blue; + .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)"); +} diff --git a/src/app/controllers/row.js b/src/app/controllers/row.js index 621c3eddda5..45287d85e48 100644 --- a/src/app/controllers/row.js +++ b/src/app/controllers/row.js @@ -22,6 +22,11 @@ function (angular, app, _) { $scope.reset_panel(); }; + $scope.togglePanelMenu = function(posX) { + $scope.showPanelMenu = !$scope.showPanelMenu; + $scope.panelMenuPos = posX; + }; + $scope.toggle_row = function(row) { row.collapse = row.collapse ? false : true; if (!row.collapse) { diff --git a/src/app/directives/grafanaPanel.js b/src/app/directives/grafanaPanel.js index ec6048609ea..22c5f539664 100644 --- a/src/app/directives/grafanaPanel.js +++ b/src/app/directives/grafanaPanel.js @@ -27,20 +27,31 @@ function (angular, $) { var $link = $(linkTemplate); elem.append($link); - $link.click(function() { - var $menu = $(menuTemplate); - var menuScope = $scope.$new(); + $link.click(function(e) { + var menuWidth = 452; + var windowWidth = $(window).width(); + var maxPos = windowWidth - menuWidth - 20; + var leftPos = e.screenX - (menuWidth / 2); + leftPos = Math.min(leftPos, maxPos); - elem.append($menu); - $compile($menu.contents())(menuScope); + $scope.$apply(function() { + $scope.togglePanelMenu(leftPos); + }); + elem.parents(".panel-container").toggleClass('panel-highlight'); + console.log(e); +// var $menu = $(menuTemplate); +// var menuScope = $scope.$new(); +// +// elem.append($menu); +// $compile($menu.contents())(menuScope); - setTimeout(function() { - $menu.remove(); - menuScope.$destroy(); - $link.show(); - }, 8000); + // setTimeout(function() { + // $menu.remove(); + // menuScope.$destroy(); + // $link.show(); + // }, 8000); - $link.hide(); + //$link.hide(); }); $compile(elem.contents())($scope); diff --git a/src/app/partials/dashboard.html b/src/app/partials/dashboard.html index 8afe5d40824..2c2ed566c66 100644 --- a/src/app/partials/dashboard.html +++ b/src/app/partials/dashboard.html @@ -74,6 +74,15 @@ + +
diff --git a/src/css/less/panel.less b/src/css/less/panel.less index 85f65cd5f16..4dbfb321224 100644 --- a/src/css/less/panel.less +++ b/src/css/less/panel.less @@ -62,7 +62,7 @@ a { font-size: 1.2em; float: left; - padding: 2px 10px; + padding: 7px 10px; border-top: 1px solid black; border-right: 1px solid black; border-bottom: 1px solid black; @@ -72,3 +72,7 @@ border-left: 1px solid black; } } + +.panel-highlight { + .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236, 0.9)"); +} From f59bb6461aad6afe757d0400f264ba8e685fc928 Mon Sep 17 00:00:00 2001 From: toni-moreno Date: Tue, 23 Sep 2014 13:51:59 +0200 Subject: [PATCH 09/45] added shared tooltips to graphs --- src/app/components/require.config.js | 2 + src/app/directives/grafanaGraph.js | 73 ++++++++- src/app/panels/graph/module.js | 3 +- src/app/panels/graph/styleEditor.html | 8 + src/test/specs/grafanaGraph-specs.js | 5 +- src/test/test-main.js | 2 + src/vendor/jquery/jquery.flot.crosshair.js | 176 +++++++++++++++++++++ 7 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 src/vendor/jquery/jquery.flot.crosshair.js diff --git a/src/app/components/require.config.js b/src/app/components/require.config.js index 6a17f9635a2..61689fedc3c 100644 --- a/src/app/components/require.config.js +++ b/src/app/components/require.config.js @@ -40,6 +40,7 @@ require.config({ 'jquery.flot.stack': '../vendor/jquery/jquery.flot.stack', 'jquery.flot.stackpercent':'../vendor/jquery/jquery.flot.stackpercent', 'jquery.flot.time': '../vendor/jquery/jquery.flot.time', + 'jquery.flot.crosshair': '../vendor/jquery/jquery.flot.crosshair', modernizr: '../vendor/modernizr-2.6.1', @@ -83,6 +84,7 @@ require.config({ 'jquery.flot.stack': ['jquery', 'jquery.flot'], 'jquery.flot.stackpercent':['jquery', 'jquery.flot'], 'jquery.flot.time': ['jquery', 'jquery.flot'], + 'jquery.flot.crosshair':['jquery', 'jquery.flot'], 'angular-cookies': ['angular'], 'angular-dragdrop': ['jquery','jquery-ui','angular'], 'angular-loader': ['angular'], diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index a2987213cb4..0942f4c80ef 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -130,6 +130,9 @@ function (angular, $, kbn, moment, _) { selection: { mode: "x", color: '#666' + }, + crosshair: { + mode: panel.tooltip.shared ? "x" : null } }; @@ -157,7 +160,7 @@ function (angular, $, kbn, moment, _) { function callPlot() { try { - $.plot(elem, sortedSeries, options); + elem.flot=$.plot(elem, sortedSeries, options); } catch (e) { console.log('flotcharts error', e); } @@ -326,9 +329,73 @@ function (angular, $, kbn, moment, _) { var $tooltip = $('
'); - elem.bind("plothover", function (event, pos, item) { - var group, value, timestamp, seriesInfo, format; + //this event will erase tooltip and crosshair once leaved the graph + elem.mouseleave(function () { + console.log('onmouse out:'); + if(scope.panel.tooltip.shared) { + $tooltip.detach(); + elem.flot.clearCrosshair(); + } + }); + elem.bind("plothover", function (event, pos, item) { + var group, value, timestamp, seriesInfo, format, i, j, s, s_final; + + //if tooltip shared we'll show a crosshair and will look for X and all Y series values + //else we will take from item. + if(scope.panel.tooltip.shared){ + //check if all series has same length if so, only one x index will + //be checked and only for exact timestamp values + var l = []; + var series; + for (i = 0; i < data.length; ++i) { + series = data[i]; + l.push(series.data.length); + } + //if all series has the same length it is because of they share time axis + if(_.uniq(l).length === 1) { + s=''; + series = data[0]; + j=0; + do { + ++j; + } while (series.data[j][0] < pos.x); + j--; //we take previous value in time. + //now we know the current X (j) position for X and Y values + timestamp = dashboard.formatDate(series.data[j][0]); + var last_value=0; //needed for stacked values + for (i = data.length-1; i >= 0; --i) { + //stacked values should be added in reverse order + series = data[i]; + seriesInfo = series.info; + format = scope.panel.y_formats[seriesInfo.yaxis - 1]; + if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') { + value = series.data[j][1]; + } else { + last_value+=series.data[j][1]; + value = last_value; + } + value = kbn.getFormatFunction(format, 2)(value,series.yaxis); + if (seriesInfo.alias) { + group = '' + + ' ' + seriesInfo.alias; + } else { + group = kbn.query_color_dot(series.color, 15) + ' '; + } + //pre-pending new values + s_final= group+ ": "+value +'
'+ s; + s=s_final; + } + + $tooltip.html('Time@ '+ + timestamp + '
' + s + '
').place_tt(pos.pageX, pos.pageY); + return; + }else { + console.log('WARNING: tootltip shared can not be shown becouse of from ' + +data.length+' series has different length '+_.uniq(l)); + $tooltip.detach(); + } + } if (item) { seriesInfo = item.series.info; format = scope.panel.y_formats[seriesInfo.yaxis - 1]; diff --git a/src/app/panels/graph/module.js b/src/app/panels/graph/module.js index aa6667ee154..bbe64d10c37 100644 --- a/src/app/panels/graph/module.js +++ b/src/app/panels/graph/module.js @@ -15,7 +15,8 @@ define([ 'jquery.flot.selection', 'jquery.flot.time', 'jquery.flot.stack', - 'jquery.flot.stackpercent' + 'jquery.flot.stackpercent', + 'jquery.flot.crosshair' ], function (angular, app, $, _, kbn, moment, TimeSeries) { 'use strict'; diff --git a/src/app/panels/graph/styleEditor.html b/src/app/panels/graph/styleEditor.html index cd83f23f197..d2ff50f77ea 100644 --- a/src/app/panels/graph/styleEditor.html +++ b/src/app/panels/graph/styleEditor.html @@ -61,8 +61,16 @@
+ +
+
Tooltip
+
+ +
+
+
Series specific overrides Regex match example: /server[0-3]/i
diff --git a/src/test/specs/grafanaGraph-specs.js b/src/test/specs/grafanaGraph-specs.js index faf19119d27..159a923cc7c 100644 --- a/src/test/specs/grafanaGraph-specs.js +++ b/src/test/specs/grafanaGraph-specs.js @@ -27,7 +27,10 @@ define([ legend: {}, grid: {}, y_formats: [], - seriesOverrides: [] + seriesOverrides: [], + tooltip: { + shared: true + } }; scope.hiddenSeries = {}; scope.dashboard = { timezone: 'browser' }; diff --git a/src/test/test-main.js b/src/test/test-main.js index 342f3143a9e..f60cdb87da4 100644 --- a/src/test/test-main.js +++ b/src/test/test-main.js @@ -43,6 +43,7 @@ require.config({ 'jquery.flot.stack': '../vendor/jquery/jquery.flot.stack', 'jquery.flot.stackpercent':'../vendor/jquery/jquery.flot.stackpercent', 'jquery.flot.time': '../vendor/jquery/jquery.flot.time', + 'jquery.flot.crosshair': '../vendor/jquery/jquery.flot.crosshair', modernizr: '../vendor/modernizr-2.6.1', }, @@ -77,6 +78,7 @@ require.config({ 'jquery.flot.stack': ['jquery', 'jquery.flot'], 'jquery.flot.stackpercent':['jquery', 'jquery.flot'], 'jquery.flot.time': ['jquery', 'jquery.flot'], + 'jquery.flot.crosshair':['jquery', 'jquery.flot'], 'angular-route': ['angular'], 'angular-cookies': ['angular'], diff --git a/src/vendor/jquery/jquery.flot.crosshair.js b/src/vendor/jquery/jquery.flot.crosshair.js new file mode 100644 index 00000000000..5111695e3d1 --- /dev/null +++ b/src/vendor/jquery/jquery.flot.crosshair.js @@ -0,0 +1,176 @@ +/* Flot plugin for showing crosshairs when the mouse hovers over the plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + crosshair: { + mode: null or "x" or "y" or "xy" + color: color + lineWidth: number + } + +Set the mode to one of "x", "y" or "xy". The "x" mode enables a vertical +crosshair that lets you trace the values on the x axis, "y" enables a +horizontal crosshair and "xy" enables them both. "color" is the color of the +crosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of +the drawn lines (default is 1). + +The plugin also adds four public methods: + + - setCrosshair( pos ) + + Set the position of the crosshair. Note that this is cleared if the user + moves the mouse. "pos" is in coordinates of the plot and should be on the + form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple + axes), which is coincidentally the same format as what you get from a + "plothover" event. If "pos" is null, the crosshair is cleared. + + - clearCrosshair() + + Clear the crosshair. + + - lockCrosshair(pos) + + Cause the crosshair to lock to the current location, no longer updating if + the user moves the mouse. Optionally supply a position (passed on to + setCrosshair()) to move it to. + + Example usage: + + var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; + $("#graph").bind( "plothover", function ( evt, position, item ) { + if ( item ) { + // Lock the crosshair to the data point being hovered + myFlot.lockCrosshair({ + x: item.datapoint[ 0 ], + y: item.datapoint[ 1 ] + }); + } else { + // Return normal crosshair operation + myFlot.unlockCrosshair(); + } + }); + + - unlockCrosshair() + + Free the crosshair to move again after locking it. +*/ + +(function ($) { + var options = { + crosshair: { + mode: null, // one of null, "x", "y" or "xy", + color: "rgba(170, 0, 0, 0.80)", + lineWidth: 1 + } + }; + + function init(plot) { + // position of crosshair in pixels + var crosshair = { x: -1, y: -1, locked: false }; + + plot.setCrosshair = function setCrosshair(pos) { + if (!pos) + crosshair.x = -1; + else { + var o = plot.p2c(pos); + crosshair.x = Math.max(0, Math.min(o.left, plot.width())); + crosshair.y = Math.max(0, Math.min(o.top, plot.height())); + } + + plot.triggerRedrawOverlay(); + }; + + plot.clearCrosshair = plot.setCrosshair; // passes null for pos + + plot.lockCrosshair = function lockCrosshair(pos) { + if (pos) + plot.setCrosshair(pos); + crosshair.locked = true; + }; + + plot.unlockCrosshair = function unlockCrosshair() { + crosshair.locked = false; + }; + + function onMouseOut(e) { + if (crosshair.locked) + return; + + if (crosshair.x != -1) { + crosshair.x = -1; + plot.triggerRedrawOverlay(); + } + } + + function onMouseMove(e) { + if (crosshair.locked) + return; + + if (plot.getSelection && plot.getSelection()) { + crosshair.x = -1; // hide the crosshair while selecting + return; + } + + var offset = plot.offset(); + crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); + crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); + plot.triggerRedrawOverlay(); + } + + plot.hooks.bindEvents.push(function (plot, eventHolder) { + if (!plot.getOptions().crosshair.mode) + return; + + eventHolder.mouseout(onMouseOut); + eventHolder.mousemove(onMouseMove); + }); + + plot.hooks.drawOverlay.push(function (plot, ctx) { + var c = plot.getOptions().crosshair; + if (!c.mode) + return; + + var plotOffset = plot.getPlotOffset(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + if (crosshair.x != -1) { + var adj = plot.getOptions().crosshair.lineWidth % 2 ? 0.5 : 0; + + ctx.strokeStyle = c.color; + ctx.lineWidth = c.lineWidth; + ctx.lineJoin = "round"; + + ctx.beginPath(); + if (c.mode.indexOf("x") != -1) { + var drawX = Math.floor(crosshair.x) + adj; + ctx.moveTo(drawX, 0); + ctx.lineTo(drawX, plot.height()); + } + if (c.mode.indexOf("y") != -1) { + var drawY = Math.floor(crosshair.y) + adj; + ctx.moveTo(0, drawY); + ctx.lineTo(plot.width(), drawY); + } + ctx.stroke(); + } + ctx.restore(); + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mouseout", onMouseOut); + eventHolder.unbind("mousemove", onMouseMove); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'crosshair', + version: '1.0' + }); +})(jQuery); From 1be840f19ddb98a0312f465600b2e9c850ffffd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 23 Sep 2014 16:11:31 +0200 Subject: [PATCH 10/45] More wort on panel edit menu --- src/app/directives/grafanaPanel.js | 122 +++++++++++++++++++++-------- src/app/partials/dashboard.html | 19 +++-- src/app/services/panelSrv.js | 74 ++++++++--------- src/css/less/panel.less | 35 ++++++--- 4 files changed, 159 insertions(+), 91 deletions(-) diff --git a/src/app/directives/grafanaPanel.js b/src/app/directives/grafanaPanel.js index 22c5f539664..b4365bf4174 100644 --- a/src/app/directives/grafanaPanel.js +++ b/src/app/directives/grafanaPanel.js @@ -3,55 +3,113 @@ define([ 'jquery', 'lodash', ], -function (angular, $) { +function (angular, $, _) { 'use strict'; angular .module('grafana.directives') .directive('panelTitle', function($compile) { - var linkTemplate = '{{panel.title || interpolateTemplateVars}}
'; - var menuTemplate = '
' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - '' + - ' ' + - '
'; + var linkTemplate = '{{panel.title || interpolateTemplateVars}}'; + var moveAttributes = ' data-drag=true data-jqyoui-options="kbnJqUiDraggableOptions"'+ + ' jqyoui-draggable="'+ + '{'+ + 'animate:false,'+ + 'mutate:false,'+ + 'index:{{$index}},'+ + 'onStart:\'panelMoveStart\','+ + 'onStop:\'panelMoveStop\''+ + '}" ng-model="panel" '; + + function createMenuTemplate($scope) { + var template = '
'; + template += '
'; + template += '
'; + template += ''; + template += ''; + template += ''; + template += ''; + template += '
'; + template += '
'; + + template += '
'; + + _.each($scope.panelMeta.menu, function(item) { + template += ''; + }); + + template += 'share'; + + template += '
'; + template += '
'; + template += '
'; + return template; + } return { restrict: 'A', link: function($scope, elem) { var $link = $(linkTemplate); + var $panelContainer = elem.parents(".panel-container"); + var menuTemplate = createMenuTemplate($scope); + var menuWidth = 277; + var menuScope = null; + var timeout = null; + elem.append($link); - $link.click(function(e) { - var menuWidth = 452; + var dismiss = function() { + $('.panel-menu').remove(); + + if (menuScope) { + menuScope.$destroy(); + menuScope = null; + $panelContainer.removeClass('panel-highlight'); + } + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + return; + }; + + $link.click(function() { + if (menuScope) { + dismiss(); + return; + } + + dismiss(); + var windowWidth = $(window).width(); - var maxPos = windowWidth - menuWidth - 20; - var leftPos = e.screenX - (menuWidth / 2); - leftPos = Math.min(leftPos, maxPos); + var panelLeftPos = $(elem).offset().left; + var panelWidth = $(elem).width(); + var menuLeftPos = (panelWidth / 2) - (menuWidth/2); + var stickingOut = panelLeftPos + menuLeftPos + menuWidth - windowWidth; + if (stickingOut > 0) { + menuLeftPos -= stickingOut + 10; + } + if (panelLeftPos + menuLeftPos < 0) { + menuLeftPos = 0; + } + var $menu = $(menuTemplate); + $menu.css('left', menuLeftPos); + + menuScope = $scope.$new(); + + elem.append($menu); $scope.$apply(function() { - $scope.togglePanelMenu(leftPos); + $compile($menu.contents())(menuScope); }); - elem.parents(".panel-container").toggleClass('panel-highlight'); - console.log(e); -// var $menu = $(menuTemplate); -// var menuScope = $scope.$new(); -// -// elem.append($menu); -// $compile($menu.contents())(menuScope); - // setTimeout(function() { - // $menu.remove(); - // menuScope.$destroy(); - // $link.show(); - // }, 8000); - //$link.hide(); + $(".panel-container").removeClass('panel-highlight'); + $panelContainer.toggleClass('panel-highlight'); + + //timeout = setTimeout(dismiss, 8000); }); $compile(elem.contents())($scope); @@ -80,7 +138,7 @@ function (angular, $) { '' + '' + - '
' + + '
' + '
'+ ''; diff --git a/src/app/partials/dashboard.html b/src/app/partials/dashboard.html index 2c2ed566c66..e05fd2ae8e9 100644 --- a/src/app/partials/dashboard.html +++ b/src/app/partials/dashboard.html @@ -74,18 +74,17 @@ - - -
+
+
+ + + + + + +
Date: Tue, 23 Sep 2014 22:10:10 +0200 Subject: [PATCH 11/45] Lots of progress on new panel edit menu, very tricky to get this right but think I am getting close to something that is good and will work long term --- ' | 79 ----------------- src/app/directives/grafanaPanel.js | 118 +------------------------ src/app/directives/panelMenu.js | 134 +++++++++++++++++++++++++++++ src/app/services/panelSrv.js | 6 +- src/css/less/panel.less | 3 +- 5 files changed, 141 insertions(+), 199 deletions(-) delete mode 100644 ' create mode 100644 src/app/directives/panelMenu.js diff --git a/' b/' deleted file mode 100644 index b22d59592f8..00000000000 --- a/' +++ /dev/null @@ -1,79 +0,0 @@ -.panel { - display: inline-block; - float: left; - vertical-align: top; -} - -.panel-container { - padding: 0px 0px 0px 0px; - background: @grafanaPanelBackground; - margin: 5px; - position: relative; -} - -.panel-content { - padding: 0px 10px 5px 10px; -} - -.panel-title { - border: 0px; - font-weight: bold; - position: relative; -} - -.panel-loading { - position:absolute; - top: 0px; - right: 4px; - z-index: 800; -} - -.panel-header { - text-align: center; -} - - -.panel-error { - color: @white; - position: absolute; - left: 0; - padding: 0px 17px 6px 5px; - top: 0; - i { - position: relative; - top: -2px; - } -} - -.panel-error-arrow { - width: 0; - height: 0; - position: absolute; - border-left: 31px solid transparent; - border-right: 30px solid transparent; - border-bottom: 27px solid @grafanaPanelBackground; - left: 0; - bottom: 0; -} - -.panel-menu { - display: inline-block; - vertical-align: top; - a { - font-size: 1.2em; - float: left; - padding: 7px 10px; - border-top: 1px solid black; - border-right: 1px solid black; - border-bottom: 1px solid black; - background: @grayDark; - } - a:first-child { - border-left: 1px solid black; - } -} - -.panel-highlight { - border: 1px solid @blue; - .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)"); -} diff --git a/src/app/directives/grafanaPanel.js b/src/app/directives/grafanaPanel.js index b4365bf4174..d0ec252559a 100644 --- a/src/app/directives/grafanaPanel.js +++ b/src/app/directives/grafanaPanel.js @@ -1,123 +1,11 @@ define([ 'angular', 'jquery', - 'lodash', + './panelMenu', ], -function (angular, $, _) { +function (angular, $) { 'use strict'; - angular - .module('grafana.directives') - .directive('panelTitle', function($compile) { - var linkTemplate = '{{panel.title || interpolateTemplateVars}}'; - var moveAttributes = ' data-drag=true data-jqyoui-options="kbnJqUiDraggableOptions"'+ - ' jqyoui-draggable="'+ - '{'+ - 'animate:false,'+ - 'mutate:false,'+ - 'index:{{$index}},'+ - 'onStart:\'panelMoveStart\','+ - 'onStop:\'panelMoveStop\''+ - '}" ng-model="panel" '; - - function createMenuTemplate($scope) { - var template = '
'; - template += '
'; - template += '
'; - template += ''; - template += ''; - template += ''; - template += ''; - template += '
'; - template += '
'; - - template += '
'; - - _.each($scope.panelMeta.menu, function(item) { - template += ''; - }); - - template += 'share'; - - template += '
'; - template += '
'; - template += '
'; - return template; - } - - return { - restrict: 'A', - link: function($scope, elem) { - var $link = $(linkTemplate); - var $panelContainer = elem.parents(".panel-container"); - var menuTemplate = createMenuTemplate($scope); - var menuWidth = 277; - var menuScope = null; - var timeout = null; - - elem.append($link); - - var dismiss = function() { - $('.panel-menu').remove(); - - if (menuScope) { - menuScope.$destroy(); - menuScope = null; - $panelContainer.removeClass('panel-highlight'); - } - if (timeout) { - clearTimeout(timeout); - timeout = null; - } - return; - }; - - $link.click(function() { - if (menuScope) { - dismiss(); - return; - } - - dismiss(); - - var windowWidth = $(window).width(); - var panelLeftPos = $(elem).offset().left; - var panelWidth = $(elem).width(); - var menuLeftPos = (panelWidth / 2) - (menuWidth/2); - var stickingOut = panelLeftPos + menuLeftPos + menuWidth - windowWidth; - if (stickingOut > 0) { - menuLeftPos -= stickingOut + 10; - } - if (panelLeftPos + menuLeftPos < 0) { - menuLeftPos = 0; - } - - var $menu = $(menuTemplate); - $menu.css('left', menuLeftPos); - - menuScope = $scope.$new(); - - elem.append($menu); - $scope.$apply(function() { - $compile($menu.contents())(menuScope); - }); - - - $(".panel-container").removeClass('panel-highlight'); - $panelContainer.toggleClass('panel-highlight'); - - //timeout = setTimeout(dismiss, 8000); - }); - - $compile(elem.contents())($scope); - } - }; - - }); - angular .module('grafana.directives') .directive('grafanaPanel', function($compile, $parse) { @@ -138,7 +26,7 @@ function (angular, $, _) { '' + '' + - '
' + + '
' + '
'+ '
'; diff --git a/src/app/directives/panelMenu.js b/src/app/directives/panelMenu.js new file mode 100644 index 00000000000..6f8411c7965 --- /dev/null +++ b/src/app/directives/panelMenu.js @@ -0,0 +1,134 @@ +define([ + 'angular', + 'jquery', + 'lodash', +], +function (angular, $, _) { + 'use strict'; + + angular + .module('grafana.directives') + .directive('panelMenu', function($compile) { + var linkTemplate = '{{panel.title || interpolateTemplateVars}}'; + var moveAttributes = ' data-drag=true data-jqyoui-options="kbnJqUiDraggableOptions"'+ + ' jqyoui-draggable="{'+ + 'animate:false,'+ + 'mutate:false,'+ + 'index:{{$index}},'+ + 'onStart:\'panelMoveStart\','+ + 'onStop:\'panelMoveStop\''+ + '}" ng-model="panel" '; + + function createMenuTemplate($scope) { + var template = '
'; + template += '
'; + template += '
'; + template += ''; + template += ''; + template += ''; + template += ''; + template += '
'; + template += '
'; + + template += '
'; + + _.each($scope.panelMeta.menu, function(item) { + template += ''; + }); + + template += 'share'; + + template += '
'; + template += '
'; + template += '
'; + return template; + } + + return { + restrict: 'A', + link: function($scope, elem) { + var $link = $(linkTemplate); + var $panelContainer = elem.parents(".panel-container"); + var menuTemplate = createMenuTemplate($scope); + var menuWidth = 246; + var menuScope = null; + var timeout = null; + var $menu = null; + + elem.append($link); + + function dismiss(time) { + clearTimeout(timeout); + timeout = null; + + console.log('dismiss', time); + + if (time) { + timeout = setTimeout(dismiss, time); + return; + } + + // if hovering or draging pospone close + if ($menu.is(':hover') || $scope.dashboard.$$panelDragging) { + dismiss(2500); + return; + } + + if (menuScope) { + $menu.unbind(); + $menu.remove(); + menuScope.$destroy(); + menuScope = null; + $menu = null; + $panelContainer.removeClass('panel-highlight'); + } + } + + var showMenu = function() { + if ($menu) { + dismiss(); + return; + } + + var windowWidth = $(window).width(); + var panelLeftPos = $(elem).offset().left; + var panelWidth = $(elem).width(); + var menuLeftPos = (panelWidth / 2) - (menuWidth/2); + var stickingOut = panelLeftPos + menuLeftPos + menuWidth - windowWidth; + if (stickingOut > 0) { + menuLeftPos -= stickingOut + 10; + } + if (panelLeftPos + menuLeftPos < 0) { + menuLeftPos = 0; + } + + $menu = $(menuTemplate); + $menu.css('left', menuLeftPos); + $menu.mouseleave(function() { + dismiss(1000); + }); + + menuScope = $scope.$new(); + + $('.panel-menu').remove(); + elem.append($menu); + $scope.$apply(function() { + $compile($menu.contents())(menuScope); + }); + + $(".panel-container").removeClass('panel-highlight'); + $panelContainer.toggleClass('panel-highlight'); + + dismiss(2000); + }; + + $link.click(showMenu); + $compile(elem.contents())($scope); + } + }; + }); +}); diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index e71e56c8a53..fed5073e38f 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -52,10 +52,8 @@ function (angular, _) { // condition: true // }, { - text: 'advanced', - submenu: [ - { text: 'Panel JSON', click: 'editPanelJson()' }, - ], + text: 'json', + click: 'editPanelJson()', condition: true }, // { diff --git a/src/css/less/panel.less b/src/css/less/panel.less index fa48d361616..902d245298e 100644 --- a/src/css/less/panel.less +++ b/src/css/less/panel.less @@ -59,13 +59,13 @@ .panel-menu { z-index: 10000; - width: 277px; position: absolute; background: @grafanaTargetFuncBackground; border: 1px solid black; top: -62px; .panel-menu-row { + white-space: nowrap; border-bottom: 1px solid black; &:last-child { border-bottom: none; @@ -77,6 +77,7 @@ } .panel-menu-link { + display: inline-block; border-right: 1px solid black; &:last-child { border: none; From d6f1c379c0a2ccfd9032041b01a73b13911dbd14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 23 Sep 2014 22:30:01 +0200 Subject: [PATCH 12/45] fixed text editor & scope issue --- src/app/directives/panelMenu.js | 2 +- src/app/services/panelSrv.js | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/app/directives/panelMenu.js b/src/app/directives/panelMenu.js index 6f8411c7965..d0ee044c571 100644 --- a/src/app/directives/panelMenu.js +++ b/src/app/directives/panelMenu.js @@ -53,7 +53,6 @@ function (angular, $, _) { link: function($scope, elem) { var $link = $(linkTemplate); var $panelContainer = elem.parents(".panel-container"); - var menuTemplate = createMenuTemplate($scope); var menuWidth = 246; var menuScope = null; var timeout = null; @@ -106,6 +105,7 @@ function (angular, $, _) { menuLeftPos = 0; } + var menuTemplate = createMenuTemplate($scope); $menu = $(menuTemplate); $menu.css('left', menuLeftPos); $menu.mouseleave(function() { diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index fed5073e38f..e526b937336 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -20,13 +20,8 @@ function (angular, _) { }, { text: 'edit', - editorLink: "app/partials/paneleditor.html", - condition: !$scope.panelMeta.fullscreenEdit - }, - { - text: 'edit', - click: "toggleFullscreen(true)", - condition: $scope.panelMeta.fullscreenEdit + click: 'editPanel()', + condition: true, }, { text: 'duplicate', @@ -66,6 +61,15 @@ function (angular, _) { $scope.inspector = {}; $scope.panelMeta.menu = _.where(menu, { condition: true }); + $scope.editPanel = function() { + if ($scope.panelMeta.fullscreenEdit) { + $scope.toggleFullscreen(true); + } + else { + $scope.emitAppEvent('show-dash-editor', { src: 'app/partials/paneleditor.html', scope: $scope }); + } + }; + $scope.editPanelJson = function() { $scope.emitAppEvent('show-json-editor', { object: $scope.panel, updateHandler: $scope.replacePanel }); }; From 81747e162326d3381a7f0b0a88e372e76f11ed07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 09:03:04 +0200 Subject: [PATCH 13/45] Annotations: Fix for annotations not reloaded when switching between 2 dashboards with annotations, Fixes #851 --- CHANGELOG.md | 3 +++ src/app/services/annotationsSrv.js | 3 ++- src/app/services/elasticsearch/es-datasource.js | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79bc9c23752..c70461859dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # 1.9.0 (unreleased) +# 1.8.1 (unreleased) + **Fixes** - [Issue #847](https://github.com/grafana/grafana/issues/847). Graph: Fix for series draw order not being the same after hiding/unhiding series +- [Issue #851](https://github.com/grafana/grafana/issues/851). Annotations: Fix for annotations not reloaded when switching between 2 dashboards with annotations # 1.8.0 (2014-09-22) diff --git a/src/app/services/annotationsSrv.js b/src/app/services/annotationsSrv.js index 04fb4224cc6..25c76caeb77 100644 --- a/src/app/services/annotationsSrv.js +++ b/src/app/services/annotationsSrv.js @@ -13,7 +13,8 @@ define([ var timezone; this.init = function() { - $rootScope.$on('refresh', this.clearCache); + $rootScope.onAppEvent('refresh', this.clearCache); + $rootScope.onAppEvent('setup-dashboard', this.clearCache); }; this.clearCache = function() { diff --git a/src/app/services/elasticsearch/es-datasource.js b/src/app/services/elasticsearch/es-datasource.js index 04d1e62ce04..f9ec01dbd4c 100644 --- a/src/app/services/elasticsearch/es-datasource.js +++ b/src/app/services/elasticsearch/es-datasource.js @@ -94,6 +94,10 @@ function (angular, _, config, kbn, moment) { for (var i = 0; i < fieldNames.length; i++) { fieldValue = fieldValue[fieldNames[i]]; + if (!fieldValue) { + console.log('could not find field in annotatation: ', fieldName); + return ''; + } } if (_.isArray(fieldValue)) { From f4e24038feebf6c52d144c1634fa6c4c0a354210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 10:51:20 +0200 Subject: [PATCH 14/45] Import: Fixes to import from json file and import from graphite. Issues was lingering state from previous dashboard. Closes #840, Closes #853 --- CHANGELOG.md | 2 ++ src/app/controllers/dashboardCtrl.js | 10 ++++----- src/app/controllers/grafanaCtrl.js | 6 ++++- src/app/controllers/graphiteImport.js | 13 ++++++----- src/app/controllers/row.js | 1 + src/app/directives/dashUpload.js | 12 +++++----- src/app/partials/dashboard.html | 2 +- src/app/partials/import.html | 12 ++++++---- src/app/routes/dashboard-from-db.js | 29 ++++++++++++++++++++----- src/app/routes/dashboard-from-file.js | 2 +- src/app/routes/dashboard-from-script.js | 2 +- 11 files changed, 61 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c70461859dd..dce1108a1c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ **Fixes** - [Issue #847](https://github.com/grafana/grafana/issues/847). Graph: Fix for series draw order not being the same after hiding/unhiding series - [Issue #851](https://github.com/grafana/grafana/issues/851). Annotations: Fix for annotations not reloaded when switching between 2 dashboards with annotations +- [Issue #846](https://github.com/grafana/grafana/issues/846). Edit panes: Issue when open row or json editor when scrolled down the page, unable to scroll and you did not see editor +- [Issue #840](https://github.com/grafana/grafana/issues/840). Import: Fixes to import from json file and import from graphite. Issues was lingering state from previous dashboard. # 1.8.0 (2014-09-22) diff --git a/src/app/controllers/dashboardCtrl.js b/src/app/controllers/dashboardCtrl.js index 424f0e225e8..709e33ae7d3 100644 --- a/src/app/controllers/dashboardCtrl.js +++ b/src/app/controllers/dashboardCtrl.js @@ -19,19 +19,18 @@ function (angular, $, config, _) { dashboardSrv, dashboardViewStateSrv, panelMoveSrv, - timer, $timeout) { $scope.editor = { index: 0 }; $scope.panelNames = config.panels; var resizeEventTimeout; - $scope.init = function() { + this.init = function(dashboardData) { $scope.availablePanels = config.panels; - $scope.onAppEvent('setup-dashboard', $scope.setupDashboard); - $scope.onAppEvent('show-json-editor', $scope.showJsonEditor); $scope.reset_row(); $scope.registerWindowResizeEvent(); + $scope.onAppEvent('show-json-editor', $scope.showJsonEditor); + $scope.setupDashboard(dashboardData); }; $scope.registerWindowResizeEvent = function() { @@ -41,7 +40,7 @@ function (angular, $, config, _) { }); }; - $scope.setupDashboard = function(event, dashboardData) { + $scope.setupDashboard = function(dashboardData) { $rootScope.performance.dashboardLoadStart = new Date().getTime(); $rootScope.performance.panelsInitialized = 0; $rootScope.performance.panelsRendered = 0; @@ -129,6 +128,5 @@ function (angular, $, config, _) { return $scope.editorTabs; }; - $scope.init(); }); }); diff --git a/src/app/controllers/grafanaCtrl.js b/src/app/controllers/grafanaCtrl.js index 060c0bc0803..5d406dee1b6 100644 --- a/src/app/controllers/grafanaCtrl.js +++ b/src/app/controllers/grafanaCtrl.js @@ -10,7 +10,7 @@ function (angular, config, _, $, store) { var module = angular.module('grafana.controllers'); - module.controller('GrafanaCtrl', function($scope, alertSrv, grafanaVersion, $rootScope) { + module.controller('GrafanaCtrl', function($scope, alertSrv, grafanaVersion, $rootScope, $controller) { $scope.grafanaVersion = grafanaVersion[0] === '@' ? 'master' : grafanaVersion; $scope.consoleEnabled = store.getBool('grafanaConsole'); @@ -32,6 +32,10 @@ function (angular, config, _, $, store) { store.set('grafanaConsole', $scope.consoleEnabled); }; + $scope.initDashboard = function(dashboardData, viewScope) { + $controller('DashboardCtrl', { $scope: viewScope }).init(dashboardData); + }; + $rootScope.onAppEvent = function(name, callback) { var unbind = $rootScope.$on(name, callback); this.$on('$destroy', unbind); diff --git a/src/app/controllers/graphiteImport.js b/src/app/controllers/graphiteImport.js index d60c8ada3be..a552cd73560 100644 --- a/src/app/controllers/graphiteImport.js +++ b/src/app/controllers/graphiteImport.js @@ -1,14 +1,15 @@ define([ 'angular', 'app', - 'lodash' + 'lodash', + 'kbn' ], -function (angular, app, _) { +function (angular, app, _, kbn) { 'use strict'; var module = angular.module('grafana.controllers'); - module.controller('GraphiteImportCtrl', function($scope, $rootScope, $timeout, datasourceSrv) { + module.controller('GraphiteImportCtrl', function($scope, $rootScope, $timeout, datasourceSrv, $location) { $scope.init = function() { $scope.datasources = datasourceSrv.getMetricSources(); @@ -79,7 +80,7 @@ function (angular, app, _) { } panel = { - type: 'graphite', + type: 'graph', span: 12 / graphsPerRow, title: graph[1].title, targets: [], @@ -95,7 +96,9 @@ function (angular, app, _) { currentRow.panels.push(panel); }); - $scope.emitAppEvent('setup-dashboard', newDashboard); + window.grafanaImportDashboard = newDashboard; + $location.path('/dashboard/import/' + kbn.slugifyForUrl(newDashboard.title)); + $scope.dismiss(); } diff --git a/src/app/controllers/row.js b/src/app/controllers/row.js index 621c3eddda5..b877f7d10fb 100644 --- a/src/app/controllers/row.js +++ b/src/app/controllers/row.js @@ -13,6 +13,7 @@ function (angular, app, _) { title: "Row", height: "150px", collapse: false, + editable: true, panels: [], }; diff --git a/src/app/directives/dashUpload.js b/src/app/directives/dashUpload.js index 1d7c4ec405e..ba214cf19a4 100644 --- a/src/app/directives/dashUpload.js +++ b/src/app/directives/dashUpload.js @@ -1,12 +1,13 @@ define([ - 'angular' + 'angular', + 'kbn' ], -function (angular) { +function (angular, kbn) { 'use strict'; var module = angular.module('grafana.directives'); - module.directive('dashUpload', function(timer, alertSrv) { + module.directive('dashUpload', function(timer, alertSrv, $location) { return { restrict: 'A', link: function(scope) { @@ -14,9 +15,10 @@ function (angular) { var files = evt.target.files; // FileList object var readerOnload = function() { return function(e) { - var dashboard = JSON.parse(e.target.result); scope.$apply(function() { - scope.emitAppEvent('setup-dashboard', dashboard); + window.grafanaImportDashboard = JSON.parse(e.target.result); + var title = kbn.slugifyForUrl(window.grafanaImportDashboard.title); + $location.path('/dashboard/import/' + title); }); }; }; diff --git a/src/app/partials/dashboard.html b/src/app/partials/dashboard.html index 8afe5d40824..2fa9bbcf2eb 100644 --- a/src/app/partials/dashboard.html +++ b/src/app/partials/dashboard.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/partials/import.html b/src/app/partials/import.html index f81468465d4..e89aff41342 100644 --- a/src/app/partials/import.html +++ b/src/app/partials/import.html @@ -16,11 +16,15 @@
-
- +
+
- + +
- {{dash.name}}{{dash.name}} + + import + +
diff --git a/src/app/routes/dashboard-from-db.js b/src/app/routes/dashboard-from-db.js index a5a37ece12d..67c25ab4946 100644 --- a/src/app/routes/dashboard-from-db.js +++ b/src/app/routes/dashboard-from-db.js @@ -22,7 +22,13 @@ function (angular) { templateUrl: 'app/partials/dashboard.html', controller : 'DashFromDBProvider', reloadOnSearch: false, + }) + .when('/dashboard/import/:id', { + templateUrl: 'app/partials/dashboard.html', + controller : 'DashFromImportCtrl', + reloadOnSearch: false, }); + }); module.controller('DashFromDBProvider', function($scope, $rootScope, datasourceSrv, $routeParams, alertSrv) { @@ -31,12 +37,23 @@ function (angular) { var isTemp = window.location.href.indexOf('dashboard/temp') !== -1; db.getDashboard($routeParams.id, isTemp) - .then(function(dashboard) { - $scope.emitAppEvent('setup-dashboard', dashboard); - }).then(null, function(error) { - $scope.emitAppEvent('setup-dashboard', { title: 'Grafana'}); - alertSrv.set('Error', error, 'error'); - }); + .then(function(dashboard) { + $scope.initDashboard(dashboard, $scope); + }).then(null, function(error) { + $scope.initDashboard({ title: 'Grafana'}, $scope); + alertSrv.set('Error', error, 'error'); + }); + }); + + module.controller('DashFromImportCtrl', function($scope, $location, alertSrv) { + + if (!window.grafanaImportDashboard) { + alertSrv.set('Not found', 'Cannot reload page with unsaved imported dashboard', 'warning', 7000); + $location.path(''); + return; + } + + $scope.initDashboard(window.grafanaImportDashboard, $scope); }); }); diff --git a/src/app/routes/dashboard-from-file.js b/src/app/routes/dashboard-from-file.js index dc54eaddaf6..82db05480b4 100644 --- a/src/app/routes/dashboard-from-file.js +++ b/src/app/routes/dashboard-from-file.js @@ -52,7 +52,7 @@ function (angular, $, config, _) { }; file_load($routeParams.jsonFile).then(function(result) { - $scope.emitAppEvent('setup-dashboard', result); + $scope.initDashboard(result, $scope); }); }); diff --git a/src/app/routes/dashboard-from-script.js b/src/app/routes/dashboard-from-script.js index cacdf9939b6..fa3abd36e81 100644 --- a/src/app/routes/dashboard-from-script.js +++ b/src/app/routes/dashboard-from-script.js @@ -53,7 +53,7 @@ function (angular, $, config, _, kbn, moment) { }; script_load($routeParams.jsFile).then(function(result) { - $scope.emitAppEvent('setup-dashboard', result.data); + $scope.initDashboard(result.data, $scope); }); }); From 34f36fff5c296e9f22a697f213bf7ca926288f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 11:17:34 +0200 Subject: [PATCH 15/45] small fix for graphite-web import --- src/app/controllers/graphiteImport.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/controllers/graphiteImport.js b/src/app/controllers/graphiteImport.js index a552cd73560..091f4b8fe5f 100644 --- a/src/app/controllers/graphiteImport.js +++ b/src/app/controllers/graphiteImport.js @@ -73,7 +73,7 @@ function (angular, app, _, kbn) { newDashboard.title = state.name; newDashboard.rows.push(currentRow); - _.each(state.graphs, function(graph) { + _.each(state.graphs, function(graph, index) { if (currentRow.panels.length === graphsPerRow) { currentRow = angular.copy(rowTemplate); newDashboard.rows.push(currentRow); @@ -84,7 +84,8 @@ function (angular, app, _, kbn) { span: 12 / graphsPerRow, title: graph[1].title, targets: [], - datasource: datasource + datasource: datasource, + id: index + 1 }; _.each(graph[1].target, function(target) { From bce6e75cfaf336767b778a3d7a46912c5f35734b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 11:35:08 +0200 Subject: [PATCH 16/45] InfluxDB: Fix for bug when saving dashboard where title is the same as slugified url id, Fixes #859 --- CHANGELOG.md | 1 + src/app/services/influxdb/influxdbDatasource.js | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dce1108a1c7..92bdd66eca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [Issue #851](https://github.com/grafana/grafana/issues/851). Annotations: Fix for annotations not reloaded when switching between 2 dashboards with annotations - [Issue #846](https://github.com/grafana/grafana/issues/846). Edit panes: Issue when open row or json editor when scrolled down the page, unable to scroll and you did not see editor - [Issue #840](https://github.com/grafana/grafana/issues/840). Import: Fixes to import from json file and import from graphite. Issues was lingering state from previous dashboard. +- [Issue #859](https://github.com/grafana/grafana/issues/859). InfluxDB: Fix for bug when saving dashboard where title is the same as slugified url id # 1.8.0 (2014-09-22) diff --git a/src/app/services/influxdb/influxdbDatasource.js b/src/app/services/influxdb/influxdbDatasource.js index c076fb2c5e1..8ad003cc632 100644 --- a/src/app/services/influxdb/influxdbDatasource.js +++ b/src/app/services/influxdb/influxdbDatasource.js @@ -203,7 +203,7 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) { else { var self = this; return this._influxRequest('POST', '/series', data).then(function() { - self._removeUnslugifiedDashboard(title, false); + self._removeUnslugifiedDashboard(id, title, false); return { title: title, url: '/dashboard/db/' + id }; }, function(err) { throw 'Failed to save dashboard to InfluxDB: ' + err.data; @@ -211,7 +211,9 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) { } }; - InfluxDatasource.prototype._removeUnslugifiedDashboard = function(id, isTemp) { + InfluxDatasource.prototype._removeUnslugifiedDashboard = function(id, title, isTemp) { + if (id === title) { return; } + var self = this; self._getDashboardInternal(id, isTemp).then(function(dashboard) { if (dashboard !== null) { From 622c1a1dada5d6e931962ca191b2d7dfd5149704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 11:58:02 +0200 Subject: [PATCH 17/45] small tweak to new panel edit menu --- src/app/directives/panelMenu.js | 4 +--- src/app/services/panelSrv.js | 33 ++++++++++----------------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/app/directives/panelMenu.js b/src/app/directives/panelMenu.js index d0ee044c571..4ffb5c5cb81 100644 --- a/src/app/directives/panelMenu.js +++ b/src/app/directives/panelMenu.js @@ -40,8 +40,6 @@ function (angular, $, _) { template += item.text + ''; }); - template += 'share'; - template += '
'; template += ''; template += ''; @@ -123,7 +121,7 @@ function (angular, $, _) { $(".panel-container").removeClass('panel-highlight'); $panelContainer.toggleClass('panel-highlight'); - dismiss(2000); + dismiss(2500); }; $link.click(showMenu); diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index e526b937336..7ee45027b2b 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -15,47 +15,34 @@ function (angular, _) { var menu = [ { text: "view", + icon: "icon-eye-open", click: 'toggleFullscreen(false)', condition: $scope.panelMeta.fullscreenView }, { text: 'edit', + icon: 'icon-cogs', click: 'editPanel()', condition: true, }, { text: 'duplicate', + icon: 'icon-copy', click: 'duplicatePanel(panel)', condition: true }, - // { - // text: 'span', - // submenu: [ - // { text: '1', click: 'updateColumnSpan(1)' }, - // { text: '2', click: 'updateColumnSpan(2)' }, - // { text: '3', click: 'updateColumnSpan(3)' }, - // { text: '4', click: 'updateColumnSpan(4)' }, - // { text: '5', click: 'updateColumnSpan(5)' }, - // { text: '6', click: 'updateColumnSpan(6)' }, - // { text: '7', click: 'updateColumnSpan(7)' }, - // { text: '8', click: 'updateColumnSpan(8)' }, - // { text: '9', click: 'updateColumnSpan(9)' }, - // { text: '10', click: 'updateColumnSpan(10)' }, - // { text: '11', click: 'updateColumnSpan(11)' }, - // { text: '12', click: 'updateColumnSpan(12)' }, - // ], - // condition: true - // }, { text: 'json', + icon: 'icon-code', click: 'editPanelJson()', condition: true }, - // { - // text: 'remove', - // click: 'remove_panel_from_row(row, panel)', - // condition: true - // } + { + text: 'share', + icon: 'icon-share', + click: 'sharePanel()', + condition: true + }, ]; $scope.inspector = {}; From d5ffe6acef74b2c9bb34e5ff7b9eef2c830668ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 12:14:20 +0200 Subject: [PATCH 18/45] White theme: Fixes for hidden series legend text and disabled annotations color, Closes #852 --- CHANGELOG.md | 1 + src/app/partials/graphite/editor.html | 2 ++ src/app/partials/submenu.html | 7 ------- src/css/less/graph.less | 2 +- src/css/less/submenu.less | 2 +- src/css/less/variables.dark.less | 1 + src/css/less/variables.light.less | 3 ++- 7 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92bdd66eca0..82390a8e88c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [Issue #846](https://github.com/grafana/grafana/issues/846). Edit panes: Issue when open row or json editor when scrolled down the page, unable to scroll and you did not see editor - [Issue #840](https://github.com/grafana/grafana/issues/840). Import: Fixes to import from json file and import from graphite. Issues was lingering state from previous dashboard. - [Issue #859](https://github.com/grafana/grafana/issues/859). InfluxDB: Fix for bug when saving dashboard where title is the same as slugified url id +- [Issue #852](https://github.com/grafana/grafana/issues/852). White theme: Fixes for hidden series legend text and disabled annotations color # 1.8.0 (2014-09-22) diff --git a/src/app/partials/graphite/editor.html b/src/app/partials/graphite/editor.html index dcbc4306e0f..f54c830d46b 100755 --- a/src/app/partials/graphite/editor.html +++ b/src/app/partials/graphite/editor.html @@ -76,6 +76,7 @@
+
  • @@ -125,6 +126,7 @@
+
diff --git a/src/app/partials/submenu.html b/src/app/partials/submenu.html index 42884a84058..e82e2505afb 100644 --- a/src/app/partials/submenu.html +++ b/src/app/partials/submenu.html @@ -17,9 +17,6 @@
    -
  • - VARIABLES -
  • ${{variable.name}}: @@ -31,10 +28,6 @@
'+ ''; diff --git a/src/app/directives/panelMenu.js b/src/app/directives/panelMenu.js index 4ffb5c5cb81..c3ed0cea458 100644 --- a/src/app/directives/panelMenu.js +++ b/src/app/directives/panelMenu.js @@ -9,7 +9,7 @@ function (angular, $, _) { angular .module('grafana.directives') .directive('panelMenu', function($compile) { - var linkTemplate = '{{panel.title || interpolateTemplateVars}}'; + var linkTemplate = '{{panel.title || interpolateTemplateVars}}'; var moveAttributes = ' data-drag=true data-jqyoui-options="kbnJqUiDraggableOptions"'+ ' jqyoui-draggable="{'+ 'animate:false,'+ @@ -62,8 +62,6 @@ function (angular, $, _) { clearTimeout(timeout); timeout = null; - console.log('dismiss', time); - if (time) { timeout = setTimeout(dismiss, time); return; @@ -124,7 +122,7 @@ function (angular, $, _) { dismiss(2500); }; - $link.click(showMenu); + elem.click(showMenu); $compile(elem.contents())($scope); } }; diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index 7ee45027b2b..8840a78695f 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -10,7 +10,6 @@ function (angular, _) { this.init = function($scope) { if (!$scope.panel.span) { $scope.panel.span = 12; } - if (!$scope.panel.title) { $scope.panel.title = 'No title'; } var menu = [ { diff --git a/src/css/less/panel.less b/src/css/less/panel.less index 902d245298e..7e103fc463a 100644 --- a/src/css/less/panel.less +++ b/src/css/less/panel.less @@ -15,6 +15,11 @@ padding: 0px 10px 5px 10px; } +.panel-title-container { + min-height: 5px; + cursor: pointer; +} + .panel-title { border: 0px; font-weight: bold; From 743c95d0f939455516f196ec8e8a8d4ed5b9fccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 12:45:03 +0200 Subject: [PATCH 21/45] small fix to panel menu positioning --- src/app/directives/panelMenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/directives/panelMenu.js b/src/app/directives/panelMenu.js index c3ed0cea458..d9932cd7bb2 100644 --- a/src/app/directives/panelMenu.js +++ b/src/app/directives/panelMenu.js @@ -51,7 +51,7 @@ function (angular, $, _) { link: function($scope, elem) { var $link = $(linkTemplate); var $panelContainer = elem.parents(".panel-container"); - var menuWidth = 246; + var menuWidth = $scope.panelMeta.menu.length === 5 ? 246 : 201; var menuScope = null; var timeout = null; var $menu = null; From eaa899e9cf00582ca2a6c25328e327567d82b67e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 14:00:44 +0200 Subject: [PATCH 22/45] Small fix to fullscreen mode where scrolling would scroll the background dashboard & page header --- src/css/less/grafana.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/css/less/grafana.less b/src/css/less/grafana.less index b291b548219..9f55faf3ba7 100644 --- a/src/css/less/grafana.less +++ b/src/css/less/grafana.less @@ -117,8 +117,9 @@ } .dashboard-fullscreen { - .row-control-inner { - display: none; + .main-view-container { + height: 0; + overflow: hidden; } } From 69e80fd11c7aa2de128f7b2f8612ec8936c04416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 16:20:55 +0200 Subject: [PATCH 23/45] working on share feature, and refactorings --- src/app/controllers/dashboardNavCtrl.js | 4 ++-- src/app/controllers/grafanaCtrl.js | 10 ++++---- src/app/partials/share-panel.html | 26 +++++++++++++++++++++ src/app/partials/unsaved-changes.html | 7 +++--- src/app/services/alertSrv.js | 14 ++++++++++- src/app/services/all.js | 1 + src/app/services/panelSrv.js | 7 ++++++ src/app/services/utilSrv.js | 31 +++++++++++++++++++++++++ src/css/less/bootswatch.dark.less | 2 +- src/css/less/grafana.less | 8 +++++-- src/css/less/overrides.less | 5 ---- src/css/less/panel.less | 2 +- src/css/less/variables.dark.less | 2 +- src/vendor/angular/angular-strap.js | 3 ++- src/vendor/bootstrap/less/modals.less | 2 +- 15 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 src/app/partials/share-panel.html create mode 100644 src/app/services/utilSrv.js diff --git a/src/app/controllers/dashboardNavCtrl.js b/src/app/controllers/dashboardNavCtrl.js index d16139e2e09..71a9f756a9c 100644 --- a/src/app/controllers/dashboardNavCtrl.js +++ b/src/app/controllers/dashboardNavCtrl.js @@ -78,7 +78,7 @@ function (angular, _, moment, config, store) { var clone = angular.copy($scope.dashboard); $scope.db.saveDashboard(clone) .then(function(result) { - alertSrv.set('Dashboard Saved', 'Saved as "' + result.title + '"','success', 3000); + $scope.appEvent('alert-success', ['Dashboard saved', 'Saved as ' + result.title]); if (result.url !== $location.path()) { $location.search({}); @@ -88,7 +88,7 @@ function (angular, _, moment, config, store) { $rootScope.$emit('dashboard-saved', $scope.dashboard); }, function(err) { - alertSrv.set('Save failed', err, 'error', 5000); + $scope.emitAppEvent('alert-error', ['Save failed', err]); }); }; diff --git a/src/app/controllers/grafanaCtrl.js b/src/app/controllers/grafanaCtrl.js index 5d406dee1b6..98f2115680f 100644 --- a/src/app/controllers/grafanaCtrl.js +++ b/src/app/controllers/grafanaCtrl.js @@ -10,19 +10,19 @@ function (angular, config, _, $, store) { var module = angular.module('grafana.controllers'); - module.controller('GrafanaCtrl', function($scope, alertSrv, grafanaVersion, $rootScope, $controller) { + module.controller('GrafanaCtrl', function($scope, alertSrv, utilSrv, grafanaVersion, $rootScope, $controller) { $scope.grafanaVersion = grafanaVersion[0] === '@' ? 'master' : grafanaVersion; - $scope.consoleEnabled = store.getBool('grafanaConsole'); - + $scope._ = _; $rootScope.profilingEnabled = store.getBool('profilingEnabled'); $rootScope.performance = { loadStart: new Date().getTime() }; $scope.init = function() { - $scope._ = _; - if ($rootScope.profilingEnabled) { $scope.initProfiling(); } + alertSrv.init(); + utilSrv.init(); + $scope.dashAlerts = alertSrv; $scope.grafana = { style: 'dark' }; }; diff --git a/src/app/partials/share-panel.html b/src/app/partials/share-panel.html new file mode 100644 index 00000000000..34b8b424683 --- /dev/null +++ b/src/app/partials/share-panel.html @@ -0,0 +1,26 @@ +
+ + + + + +
diff --git a/src/app/partials/unsaved-changes.html b/src/app/partials/unsaved-changes.html index b025575e7e7..846a30bbc3b 100644 --- a/src/app/partials/unsaved-changes.html +++ b/src/app/partials/unsaved-changes.html @@ -1,19 +1,18 @@ -
-
+
@@ -16,7 +16,18 @@ diff --git a/src/css/less/grafana.less b/src/css/less/grafana.less index 0bc2d6058c4..2e943f98e3e 100644 --- a/src/css/less/grafana.less +++ b/src/css/less/grafana.less @@ -53,8 +53,9 @@ } .modal { - max-width: 1024px; + max-width: 800px; left: 0; + right: 0; margin-left: auto; margin-right: auto; @@ -528,3 +529,10 @@ select.grafana-target-segment-input { .grafana-tip { padding-left: 5px; } + +input[type=text].input-fluid { + width: 100%; + box-sizing: border-box; + padding: 14px; +} + diff --git a/src/css/less/overrides.less b/src/css/less/overrides.less index b8fc8e640c1..6c8f6c0224f 100644 --- a/src/css/less/overrides.less +++ b/src/css/less/overrides.less @@ -562,12 +562,6 @@ div.flot-text { background-color: darken(@purple, 10%); } -.annotation-editor-table { - td { - white-space: nowrap; - } -} - // Top menu .save-dashboard-dropdown { padding: 10px; From 4c59ec815e443134b21e515193ed47692a1915a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 24 Sep 2014 18:55:55 +0200 Subject: [PATCH 26/45] work on share panel view, and better look for checkbox --- src/app/controllers/sharePanelCtrl.js | 3 +++ src/app/directives/tip.js | 14 +++++++++++++ src/app/panels/graph/styleEditor.html | 18 +++++++++++------ src/app/panels/timepicker/module.html | 5 +---- src/app/partials/dasheditor.html | 27 +++++++++++++++----------- src/app/partials/share-panel.html | 14 +++++++------ src/css/less/forms.less | 26 +++++++++++++++++++++++++ src/css/less/grafana.less | 9 +-------- src/img/check_radio_sheet.png | Bin 0 -> 4343 bytes src/img/checkbox.png | Bin 0 -> 870 bytes 10 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 src/css/less/forms.less create mode 100644 src/img/check_radio_sheet.png create mode 100644 src/img/checkbox.png diff --git a/src/app/controllers/sharePanelCtrl.js b/src/app/controllers/sharePanelCtrl.js index 891f2b73317..87903378416 100644 --- a/src/app/controllers/sharePanelCtrl.js +++ b/src/app/controllers/sharePanelCtrl.js @@ -28,6 +28,9 @@ function (angular, _) { $scope.shareUrl += "&from=" + from; $scope.shareUrl += "&to=" + to; + $scope.forCurrent = true; + $scope.toPanel = true; + $timeout(function() { var input = $element.find('[data-share-panel-url]'); input.focus(); diff --git a/src/app/directives/tip.js b/src/app/directives/tip.js index 974ed98a637..ff364b35569 100644 --- a/src/app/directives/tip.js +++ b/src/app/directives/tip.js @@ -17,4 +17,18 @@ function (angular, kbn) { } }; }); + + angular + .module('grafana.directives') + .directive('tip', function($compile) { + return { + restrict: 'E', + link: function(scope, elem, attrs) { + var _t = ''; + elem.replaceWith($compile(angular.element(_t))(scope)); + } + }; + }); + }); diff --git a/src/app/panels/graph/styleEditor.html b/src/app/panels/graph/styleEditor.html index cd83f23f197..24a05549268 100644 --- a/src/app/panels/graph/styleEditor.html +++ b/src/app/panels/graph/styleEditor.html @@ -1,14 +1,20 @@
Chart Options
-
- +
+ + +
-
- +
+ + +
-
- +
+ + +
diff --git a/src/app/panels/timepicker/module.html b/src/app/panels/timepicker/module.html index 8357f66a7a3..9371eb16f2e 100644 --- a/src/app/panels/timepicker/module.html +++ b/src/app/panels/timepicker/module.html @@ -9,9 +9,7 @@ border: 0px !important; } - -
+ -
diff --git a/src/app/partials/dasheditor.html b/src/app/partials/dasheditor.html index 30c43704f8b..bcb8a9402de 100644 --- a/src/app/partials/dasheditor.html +++ b/src/app/partials/dasheditor.html @@ -28,9 +28,10 @@
-
- - +
+ + +
@@ -71,16 +72,20 @@
-
- - +
+ + +
-
- - +
+ + +
-
- +
+ + +
diff --git a/src/app/partials/share-panel.html b/src/app/partials/share-panel.html index f6d2f598fdc..3eb7c4daec8 100644 --- a/src/app/partials/share-panel.html +++ b/src/app/partials/share-panel.html @@ -16,13 +16,15 @@