From fc9014f9204df635577c4bc0cb57a0bfdb21e25b Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Fri, 16 Mar 2018 12:36:36 +0100 Subject: [PATCH 01/31] added indent to dashboards inside folder in search dropdown, and added indent to dashboard icon in search item --- public/app/core/components/search/search_results.html | 2 +- public/sass/components/_search.scss | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/public/app/core/components/search/search_results.html b/public/app/core/components/search/search_results.html index 4e5bc88e0a9..7435f8d0b7e 100644 --- a/public/app/core/components/search/search_results.html +++ b/public/app/core/components/search/search_results.html @@ -20,7 +20,7 @@
- +
Date: Mon, 26 Mar 2018 14:14:57 +0200 Subject: [PATCH 02/31] styled login page for ie11 --- public/sass/pages/_login.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/public/sass/pages/_login.scss b/public/sass/pages/_login.scss index 8622eec4e99..de10808f122 100644 --- a/public/sass/pages/_login.scss +++ b/public/sass/pages/_login.scss @@ -3,6 +3,7 @@ $login-border: #8daac5; .login { background-position: center; min-height: 85vh; + height: 80vh; background-repeat: no-repeat; min-width: 100%; margin-left: 0; @@ -290,9 +291,14 @@ select:-webkit-autofill:focus { } @include media-breakpoint-up(md) { + .login-content { + flex: 1 0 100%; + } + .login-branding { width: 45%; padding: 2rem 4rem; + flex-grow: 1; .logo-icon { width: 130px; @@ -371,7 +377,7 @@ select:-webkit-autofill:focus { left: 0; right: 0; height: 100%; - content: ""; + content: ''; display: block; } From dbcba4a0094f9c360216182d0d326a0bca127d09 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 27 Mar 2018 10:41:47 +0200 Subject: [PATCH 03/31] sidemenu fix for internet explorer 11, changed icon width/height to pixels and added height to logo --- public/sass/base/_icons.scss | 6 ++++-- public/sass/components/_sidemenu.scss | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/sass/base/_icons.scss b/public/sass/base/_icons.scss index c701cc1249e..31e5ee62d6f 100644 --- a/public/sass/base/_icons.scss +++ b/public/sass/base/_icons.scss @@ -1,8 +1,10 @@ .gicon { line-height: 1; display: inline-block; - width: 1.1057142857em; - height: 1.1057142857em; + //width: 1.1057142857em; + //height: 1.1057142857em; + height: 22px; + width: 22px; text-align: center; background-repeat: no-repeat; background-position: center; diff --git a/public/sass/components/_sidemenu.scss b/public/sass/components/_sidemenu.scss index 8a5c3779714..e48ab0597a2 100644 --- a/public/sass/components/_sidemenu.scss +++ b/public/sass/components/_sidemenu.scss @@ -178,6 +178,7 @@ li.sidemenu-org-switcher { padding: 0.4rem 1rem 0.4rem 0.65rem; min-height: $navbarHeight; position: relative; + height: $navbarHeight - 1px; &:hover { background: $navbarButtonBackgroundHighlight; From d4be953d23a4dd15eb2c26a003c11cd0f40dc898 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 27 Mar 2018 12:36:13 +0200 Subject: [PATCH 04/31] fixed alignment in search + fixed issue ie popup --- public/app/features/dashboard/unsaved_changes_srv.ts | 4 ++-- public/sass/components/_search.scss | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/public/app/features/dashboard/unsaved_changes_srv.ts b/public/app/features/dashboard/unsaved_changes_srv.ts index ebf0101cee0..d4c12b8bcd6 100644 --- a/public/app/features/dashboard/unsaved_changes_srv.ts +++ b/public/app/features/dashboard/unsaved_changes_srv.ts @@ -35,12 +35,12 @@ export class Tracker { $window.onbeforeunload = () => { if (this.ignoreChanges()) { - return null; + return undefined; } if (this.hasChanges()) { return 'There are unsaved changes to this dashboard'; } - return null; + return undefined; }; scope.$on('$locationChangeStart', (event, next) => { diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index 47d4a926968..e69068b730a 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -31,7 +31,6 @@ //padding: 0.5rem 1.5rem 0.5rem 0; padding: 1rem 1rem 0.75rem 1rem; height: 51px; - line-height: 51px; box-sizing: border-box; outline: none; background: $side-menu-bg; From a3f15ced6805d3d949d02c5a8a1d5267a6dac3a7 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 28 Mar 2018 14:19:17 +0200 Subject: [PATCH 05/31] fixed graphpanel editmode and custom width for right side legend for IE11 --- public/app/plugins/panel/graph/legend.ts | 5 ++++- public/sass/pages/_dashboard.scss | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/panel/graph/legend.ts b/public/app/plugins/panel/graph/legend.ts index d1186ae0b1e..4dfeb75ff55 100644 --- a/public/app/plugins/panel/graph/legend.ts +++ b/public/app/plugins/panel/graph/legend.ts @@ -131,8 +131,11 @@ module.directive('graphLegend', function(popoverSrv, $timeout) { elem.empty(); // Set min-width if side style and there is a value, otherwise remove the CSS propery - var width = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth + 'px' : ''; + // Set width so it works with IE11 + var width: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth + 'px' : ''; + var ieWidth: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth - 1 + 'px' : ''; elem.css('min-width', width); + elem.css('width', ieWidth); elem.toggleClass('graph-legend-table', panel.legend.alignAsTable === true); diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index 871db4dfc2d..c957b6af790 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -33,7 +33,7 @@ div.flot-text { border: $panel-border; position: relative; border-radius: 3px; - height: 100%; + //height: 100%; &.panel-transparent { background-color: transparent; From d40b7433ead654eea5e942eb095b94ac1ea73c76 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 28 Mar 2018 15:06:20 +0200 Subject: [PATCH 06/31] removed padding for icons and added margin --- public/sass/pages/_alerting.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/sass/pages/_alerting.scss b/public/sass/pages/_alerting.scss index f44e26d5c20..5a481b55a8a 100644 --- a/public/sass/pages/_alerting.scss +++ b/public/sass/pages/_alerting.scss @@ -108,7 +108,7 @@ justify-content: center; align-items: center; width: 40px; - padding: 0 28px 0 16px; + margin-right: 8px; .icon-gf, .fa { font-size: 200%; From 2ccbf12d1c57cdbbf6c5ad59208faf6604e19075 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 28 Mar 2018 18:03:33 +0200 Subject: [PATCH 07/31] settings: return error instead of ignoring it closes #11281 --- pkg/setting/setting.go | 25 +++++++++++++++++++------ pkg/setting/setting_test.go | 7 +++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 5b79e866964..30a40602b1c 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -223,7 +223,7 @@ func shouldRedactURLKey(s string) bool { return strings.Contains(uppercased, "DATABASE_URL") } -func applyEnvVariableOverrides() { +func applyEnvVariableOverrides() error { appliedEnvOverrides = make([]string, 0) for _, section := range Cfg.Sections() { for _, key := range section.Keys() { @@ -238,7 +238,10 @@ func applyEnvVariableOverrides() { envValue = "*********" } if shouldRedactURLKey(envKey) { - u, _ := url.Parse(envValue) + u, err := url.Parse(envValue) + if err != nil { + return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err) + } ui := u.User if ui != nil { _, exists := ui.Password() @@ -252,6 +255,8 @@ func applyEnvVariableOverrides() { } } } + + return nil } func applyCommandLineDefaultProperties(props map[string]string) { @@ -377,7 +382,7 @@ func loadSpecifedConfigFile(configFile string) error { return nil } -func loadConfiguration(args *CommandLineArgs) { +func loadConfiguration(args *CommandLineArgs) error { var err error // load config defaults @@ -395,7 +400,7 @@ func loadConfiguration(args *CommandLineArgs) { if err != nil { fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err)) os.Exit(1) - return + return err } Cfg.BlockMode = false @@ -413,7 +418,10 @@ func loadConfiguration(args *CommandLineArgs) { } // apply environment overrides - applyEnvVariableOverrides() + err = applyEnvVariableOverrides() + if err != nil { + return err + } // apply command line overrides applyCommandLineProperties(commandLineProps) @@ -424,6 +432,8 @@ func loadConfiguration(args *CommandLineArgs) { // update data path and logging config DataPath = makeAbsolute(Cfg.Section("paths").Key("data").String(), HomePath) initLogging() + + return err } func pathExists(path string) bool { @@ -471,7 +481,10 @@ func validateStaticRootPath() error { func NewConfigContext(args *CommandLineArgs) error { setHomePath(args) - loadConfiguration(args) + err := loadConfiguration(args) + if err != nil { + return err + } Env = Cfg.Section("").Key("app_mode").MustString("development") InstanceName = Cfg.Section("").Key("instance_name").MustString("unknown_instance_name") diff --git a/pkg/setting/setting_test.go b/pkg/setting/setting_test.go index 640a1648340..87f9916075e 100644 --- a/pkg/setting/setting_test.go +++ b/pkg/setting/setting_test.go @@ -37,6 +37,13 @@ func TestLoadingSettings(t *testing.T) { So(appliedEnvOverrides, ShouldContain, "GF_SECURITY_ADMIN_PASSWORD=*********") }) + Convey("Should replace password when defined in environment2", func() { + os.Setenv("GF_DATABASE_URL", "postgres://grafana:sec{ret@postgres:5432/grafana") + err := NewConfigContext(&CommandLineArgs{HomePath: "../../"}) + + So(err, ShouldNotBeNil) + }) + Convey("Should replace password in URL when url environment is defined", func() { os.Setenv("GF_DATABASE_URL", "mysql://user:secret@localhost:3306/database") NewConfigContext(&CommandLineArgs{HomePath: "../../"}) From 45d9bfca97a3a3ab98889ad41d516667d575c735 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 28 Mar 2018 22:51:21 +0200 Subject: [PATCH 08/31] print to stderr since logger might not exist --- pkg/cmd/grafana-server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/grafana-server/server.go b/pkg/cmd/grafana-server/server.go index 5bbf43087ec..b8387403161 100644 --- a/pkg/cmd/grafana-server/server.go +++ b/pkg/cmd/grafana-server/server.go @@ -111,7 +111,7 @@ func (g *GrafanaServerImpl) initLogging() { }) if err != nil { - g.log.Error(err.Error()) + fmt.Fprintf(os.Stderr, "Failed to start grafana. error: %s\n", err.Error()) os.Exit(1) } From 8195c085fa2a095fe753f725663ff7217cc14365 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 29 Mar 2018 09:15:15 +0200 Subject: [PATCH 09/31] bounnd the esc key to exit timepicker --- public/app/core/services/keybindingSrv.ts | 7 +++++++ public/app/features/dashboard/timepicker/timepicker.ts | 3 +++ 2 files changed, 10 insertions(+) diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index 0d468b6980f..829a3415cc1 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -10,6 +10,7 @@ import 'mousetrap-global-bind'; export class KeybindingSrv { helpModal: boolean; modalOpen = false; + timepickerOpen = false; /** @ngInject */ constructor(private $rootScope, private $location) { @@ -22,6 +23,7 @@ export class KeybindingSrv { this.setupGlobal(); appEvents.on('show-modal', () => (this.modalOpen = true)); + $rootScope.onAppEvent('openTimepicker', () => (this.timepickerOpen = true)); } setupGlobal() { @@ -72,6 +74,11 @@ export class KeybindingSrv { appEvents.emit('hide-modal'); + if (this.timepickerOpen === true) { + this.$rootScope.appEvent('closeTimepicker'); + this.timepickerOpen = false; + } + if (!this.modalOpen) { this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false }); } else { diff --git a/public/app/features/dashboard/timepicker/timepicker.ts b/public/app/features/dashboard/timepicker/timepicker.ts index 2434e691515..19c3db7f6d3 100644 --- a/public/app/features/dashboard/timepicker/timepicker.ts +++ b/public/app/features/dashboard/timepicker/timepicker.ts @@ -32,6 +32,7 @@ export class TimePickerCtrl { $rootScope.onAppEvent('shift-time-forward', () => this.move(1), $scope); $rootScope.onAppEvent('shift-time-backward', () => this.move(-1), $scope); $rootScope.onAppEvent('refresh', this.onRefresh.bind(this), $scope); + $rootScope.onAppEvent('closeTimepicker', this.openDropdown.bind(this), $scope); // init options this.panel = this.dashboard.timepicker; @@ -100,6 +101,8 @@ export class TimePickerCtrl { return; } + this.$rootScope.appEvent('openTimepicker'); + this.onRefresh(); this.editTimeRaw = this.timeRaw; this.timeOptions = rangeUtil.getRelativeTimesList(this.panel, this.rangeString); From 65f7c5f08f891bab0cbb87e6cf18fbd8aa23d93b Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 29 Mar 2018 10:40:45 +0200 Subject: [PATCH 10/31] started migration to ts --- .../app/plugins/panel/graph/graph_tooltip.js | 292 ------------------ .../app/plugins/panel/graph/graph_tooltip.ts | 290 +++++++++++++++++ 2 files changed, 290 insertions(+), 292 deletions(-) delete mode 100644 public/app/plugins/panel/graph/graph_tooltip.js create mode 100644 public/app/plugins/panel/graph/graph_tooltip.ts diff --git a/public/app/plugins/panel/graph/graph_tooltip.js b/public/app/plugins/panel/graph/graph_tooltip.js deleted file mode 100644 index 89197717e42..00000000000 --- a/public/app/plugins/panel/graph/graph_tooltip.js +++ /dev/null @@ -1,292 +0,0 @@ -define([ - 'jquery', - 'app/core/core', -], -function ($, core) { - 'use strict'; - - var appEvents = core.appEvents; - - function GraphTooltip(elem, dashboard, scope, getSeriesFn) { - var self = this; - var ctrl = scope.ctrl; - var panel = ctrl.panel; - - var $tooltip = $('
'); - - this.destroy = function() { - $tooltip.remove(); - }; - - this.findHoverIndexFromDataPoints = function(posX, series, last) { - var ps = series.datapoints.pointsize; - var initial = last*ps; - var len = series.datapoints.points.length; - for (var j = initial; j < len; j += ps) { - // Special case of a non stepped line, highlight the very last point just before a null point - if ((!series.lines.steps && series.datapoints.points[initial] != null && series.datapoints.points[j] == null) - //normal case - || series.datapoints.points[j] > posX) { - return Math.max(j - ps, 0)/ps; - } - } - return j/ps - 1; - }; - - this.findHoverIndexFromData = function(posX, series) { - var lower = 0; - var upper = series.data.length - 1; - var middle; - while (true) { - if (lower > upper) { - return Math.max(upper, 0); - } - middle = Math.floor((lower + upper) / 2); - if (series.data[middle][0] === posX) { - return middle; - } else if (series.data[middle][0] < posX) { - lower = middle + 1; - } else { - upper = middle - 1; - } - } - }; - - this.renderAndShow = function(absoluteTime, innerHtml, pos, xMode) { - if (xMode === 'time') { - innerHtml = '
'+ absoluteTime + '
' + innerHtml; - } - $tooltip.html(innerHtml).place_tt(pos.pageX + 20, pos.pageY); - }; - - this.getMultiSeriesPlotHoverInfo = function(seriesList, pos) { - var value, i, series, hoverIndex, hoverDistance, pointTime, yaxis; - // 3 sub-arrays, 1st for hidden series, 2nd for left yaxis, 3rd for right yaxis. - var results = [[],[],[]]; - - //now we know the current X (j) position for X and Y values - var last_value = 0; //needed for stacked values - - var minDistance, minTime; - - for (i = 0; i < seriesList.length; i++) { - series = seriesList[i]; - - if (!series.data.length || (panel.legend.hideEmpty && series.allIsNull)) { - // Init value so that it does not brake series sorting - results[0].push({ hidden: true, value: 0 }); - continue; - } - - if (!series.data.length || (panel.legend.hideZero && series.allIsZero)) { - // Init value so that it does not brake series sorting - results[0].push({ hidden: true, value: 0 }); - continue; - } - - hoverIndex = this.findHoverIndexFromData(pos.x, series); - hoverDistance = pos.x - series.data[hoverIndex][0]; - pointTime = series.data[hoverIndex][0]; - - // Take the closest point before the cursor, or if it does not exist, the closest after - if (! minDistance - || (hoverDistance >=0 && (hoverDistance < minDistance || minDistance < 0)) - || (hoverDistance < 0 && hoverDistance > minDistance)) { - minDistance = hoverDistance; - minTime = pointTime; - } - - if (series.stack) { - if (panel.tooltip.value_type === 'individual') { - value = series.data[hoverIndex][1]; - } else if (!series.stack) { - value = series.data[hoverIndex][1]; - } else { - last_value += series.data[hoverIndex][1]; - value = last_value; - } - } else { - value = series.data[hoverIndex][1]; - } - - // Highlighting multiple Points depending on the plot type - if (series.lines.steps || series.stack) { - // stacked and steppedLine plots can have series with different length. - // Stacked series can increase its length on each new stacked serie if null points found, - // to speed the index search we begin always on the last found hoverIndex. - hoverIndex = this.findHoverIndexFromDataPoints(pos.x, series, hoverIndex); - } - - // Be sure we have a yaxis so that it does not brake series sorting - yaxis = 0; - if (series.yaxis) { - yaxis = series.yaxis.n; - } - - results[yaxis].push({ - value: value, - hoverIndex: hoverIndex, - color: series.color, - label: series.aliasEscaped, - time: pointTime, - distance: hoverDistance, - index: i - }); - } - - // Contat the 3 sub-arrays - results = results[0].concat(results[1],results[2]); - - // Time of the point closer to pointer - results.time = minTime; - - return results; - }; - - elem.mouseleave(function () { - if (panel.tooltip.shared) { - var plot = elem.data().plot; - if (plot) { - $tooltip.detach(); - plot.unhighlight(); - } - } - appEvents.emit('graph-hover-clear'); - }); - - elem.bind("plothover", function (event, pos, item) { - self.show(pos, item); - - // broadcast to other graph panels that we are hovering! - pos.panelRelY = (pos.pageY - elem.offset().top) / elem.height(); - appEvents.emit('graph-hover', {pos: pos, panel: panel}); - }); - - elem.bind("plotclick", function (event, pos, item) { - appEvents.emit('graph-click', {pos: pos, panel: panel, item: item}); - }); - - this.clear = function(plot) { - $tooltip.detach(); - plot.clearCrosshair(); - plot.unhighlight(); - }; - - this.show = function(pos, item) { - var plot = elem.data().plot; - var plotData = plot.getData(); - var xAxes = plot.getXAxes(); - var xMode = xAxes[0].options.mode; - var seriesList = getSeriesFn(); - var allSeriesMode = panel.tooltip.shared; - var group, value, absoluteTime, hoverInfo, i, series, seriesHtml, tooltipFormat; - - // if panelRelY is defined another panel wants us to show a tooltip - // get pageX from position on x axis and pageY from relative position in original panel - if (pos.panelRelY) { - var pointOffset = plot.pointOffset({x: pos.x}); - if (Number.isNaN(pointOffset.left) || pointOffset.left < 0 || pointOffset.left > elem.width()) { - self.clear(plot); - return; - } - pos.pageX = elem.offset().left + pointOffset.left; - pos.pageY = elem.offset().top + elem.height() * pos.panelRelY; - var isVisible = pos.pageY >= $(window).scrollTop() && pos.pageY <= $(window).innerHeight() + $(window).scrollTop(); - if (!isVisible) { - self.clear(plot); - return; - } - plot.setCrosshair(pos); - allSeriesMode = true; - - if (dashboard.sharedCrosshairModeOnly()) { - // if only crosshair mode we are done - return; - } - } - - if (seriesList.length === 0) { - return; - } - - if (seriesList[0].hasMsResolution) { - tooltipFormat = 'YYYY-MM-DD HH:mm:ss.SSS'; - } else { - tooltipFormat = 'YYYY-MM-DD HH:mm:ss'; - } - - if (allSeriesMode) { - plot.unhighlight(); - - var seriesHoverInfo = self.getMultiSeriesPlotHoverInfo(plotData, pos); - - seriesHtml = ''; - - absoluteTime = dashboard.formatDate(seriesHoverInfo.time, tooltipFormat); - - // Dynamically reorder the hovercard for the current time point if the - // option is enabled. - if (panel.tooltip.sort === 2) { - seriesHoverInfo.sort(function(a, b) { - return b.value - a.value; - }); - } else if (panel.tooltip.sort === 1) { - seriesHoverInfo.sort(function(a, b) { - return a.value - b.value; - }); - } - - for (i = 0; i < seriesHoverInfo.length; i++) { - hoverInfo = seriesHoverInfo[i]; - - if (hoverInfo.hidden) { - continue; - } - - var highlightClass = ''; - if (item && hoverInfo.index === item.seriesIndex) { - highlightClass = 'graph-tooltip-list-item--highlight'; - } - - series = seriesList[hoverInfo.index]; - - value = series.formatValue(hoverInfo.value); - - seriesHtml += '
'; - seriesHtml += ' ' + hoverInfo.label + ':
'; - seriesHtml += '
' + value + '
'; - plot.highlight(hoverInfo.index, hoverInfo.hoverIndex); - } - - self.renderAndShow(absoluteTime, seriesHtml, pos, xMode); - } - // single series tooltip - else if (item) { - series = seriesList[item.seriesIndex]; - group = '
'; - group += ' ' + series.aliasEscaped + ':
'; - - if (panel.stack && panel.tooltip.value_type === 'individual') { - value = item.datapoint[1] - item.datapoint[2]; - } - else { - value = item.datapoint[1]; - } - - value = series.formatValue(value); - - absoluteTime = dashboard.formatDate(item.datapoint[0], tooltipFormat); - - group += '
' + value + '
'; - - self.renderAndShow(absoluteTime, group, pos, xMode); - } - // no hit - else { - $tooltip.detach(); - } - }; - } - - return GraphTooltip; -}); diff --git a/public/app/plugins/panel/graph/graph_tooltip.ts b/public/app/plugins/panel/graph/graph_tooltip.ts new file mode 100644 index 00000000000..846a165bbaf --- /dev/null +++ b/public/app/plugins/panel/graph/graph_tooltip.ts @@ -0,0 +1,290 @@ +import $ from 'jquery'; +import { appEvents } from 'app/core/core'; + +//var appEvents = appEvents; + +export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { + let self = this; + let ctrl = scope.ctrl; + let panel = ctrl.panel; + + let $tooltip = $('
'); + + this.destroy = function() { + $tooltip.remove(); + }; + + this.findHoverIndexFromDataPoints = function(posX, series, last) { + var ps = series.datapoints.pointsize; + var initial = last * ps; + var len = series.datapoints.points.length; + for (var j = initial; j < len; j += ps) { + // Special case of a non stepped line, highlight the very last point just before a null point + if ( + (!series.lines.steps && series.datapoints.points[initial] != null && series.datapoints.points[j] == null) || + //normal case + series.datapoints.points[j] > posX + ) { + return Math.max(j - ps, 0) / ps; + } + } + return j / ps - 1; + }; + + this.findHoverIndexFromData = function(posX, series) { + var lower = 0; + var upper = series.data.length - 1; + var middle; + while (true) { + if (lower > upper) { + return Math.max(upper, 0); + } + middle = Math.floor((lower + upper) / 2); + if (series.data[middle][0] === posX) { + return middle; + } else if (series.data[middle][0] < posX) { + lower = middle + 1; + } else { + upper = middle - 1; + } + } + }; + + this.renderAndShow = function(absoluteTime, innerHtml, pos, xMode) { + if (xMode === 'time') { + innerHtml = '
' + absoluteTime + '
' + innerHtml; + } + $tooltip.html(innerHtml).place_tt(pos.pageX + 20, pos.pageY); + }; + + this.getMultiSeriesPlotHoverInfo = function(seriesList, pos) { + var value, i, series, hoverIndex, hoverDistance, pointTime, yaxis; + // 3 sub-arrays, 1st for hidden series, 2nd for left yaxis, 3rd for right yaxis. + var results: any = [[], [], []]; + + //now we know the current X (j) position for X and Y values + var last_value = 0; //needed for stacked values + + var minDistance, minTime; + + for (i = 0; i < seriesList.length; i++) { + series = seriesList[i]; + + if (!series.data.length || (panel.legend.hideEmpty && series.allIsNull)) { + // Init value so that it does not brake series sorting + results[0].push({ hidden: true, value: 0 }); + continue; + } + + if (!series.data.length || (panel.legend.hideZero && series.allIsZero)) { + // Init value so that it does not brake series sorting + results[0].push({ hidden: true, value: 0 }); + continue; + } + + hoverIndex = this.findHoverIndexFromData(pos.x, series); + hoverDistance = pos.x - series.data[hoverIndex][0]; + pointTime = series.data[hoverIndex][0]; + + // Take the closest point before the cursor, or if it does not exist, the closest after + if ( + !minDistance || + (hoverDistance >= 0 && (hoverDistance < minDistance || minDistance < 0)) || + (hoverDistance < 0 && hoverDistance > minDistance) + ) { + minDistance = hoverDistance; + minTime = pointTime; + } + + if (series.stack) { + if (panel.tooltip.value_type === 'individual') { + value = series.data[hoverIndex][1]; + } else if (!series.stack) { + value = series.data[hoverIndex][1]; + } else { + last_value += series.data[hoverIndex][1]; + value = last_value; + } + } else { + value = series.data[hoverIndex][1]; + } + + // Highlighting multiple Points depending on the plot type + if (series.lines.steps || series.stack) { + // stacked and steppedLine plots can have series with different length. + // Stacked series can increase its length on each new stacked serie if null points found, + // to speed the index search we begin always on the last found hoverIndex. + hoverIndex = this.findHoverIndexFromDataPoints(pos.x, series, hoverIndex); + } + + // Be sure we have a yaxis so that it does not brake series sorting + yaxis = 0; + if (series.yaxis) { + yaxis = series.yaxis.n; + } + + results[yaxis].push({ + value: value, + hoverIndex: hoverIndex, + color: series.color, + label: series.aliasEscaped, + time: pointTime, + distance: hoverDistance, + index: i, + }); + } + + // Contat the 3 sub-arrays + results = results[0].concat(results[1], results[2]); + + // Time of the point closer to pointer + results.time = minTime; + + return results; + }; + + elem.mouseleave(function() { + if (panel.tooltip.shared) { + var plot = elem.data().plot; + if (plot) { + $tooltip.detach(); + plot.unhighlight(); + } + } + appEvents.emit('graph-hover-clear'); + }); + + elem.bind('plothover', function(event, pos, item) { + self.show(pos, item); + + // broadcast to other graph panels that we are hovering! + pos.panelRelY = (pos.pageY - elem.offset().top) / elem.height(); + appEvents.emit('graph-hover', { pos: pos, panel: panel }); + }); + + elem.bind('plotclick', function(event, pos, item) { + appEvents.emit('graph-click', { pos: pos, panel: panel, item: item }); + }); + + this.clear = function(plot) { + $tooltip.detach(); + plot.clearCrosshair(); + plot.unhighlight(); + }; + + this.show = function(pos, item) { + var plot = elem.data().plot; + var plotData = plot.getData(); + var xAxes = plot.getXAxes(); + var xMode = xAxes[0].options.mode; + var seriesList = getSeriesFn(); + var allSeriesMode = panel.tooltip.shared; + var group, value, absoluteTime, hoverInfo, i, series, seriesHtml, tooltipFormat; + + // if panelRelY is defined another panel wants us to show a tooltip + // get pageX from position on x axis and pageY from relative position in original panel + if (pos.panelRelY) { + var pointOffset = plot.pointOffset({ x: pos.x }); + if (Number.isNaN(pointOffset.left) || pointOffset.left < 0 || pointOffset.left > elem.width()) { + self.clear(plot); + return; + } + pos.pageX = elem.offset().left + pointOffset.left; + pos.pageY = elem.offset().top + elem.height() * pos.panelRelY; + var isVisible = + pos.pageY >= $(window).scrollTop() && pos.pageY <= $(window).innerHeight() + $(window).scrollTop(); + if (!isVisible) { + self.clear(plot); + return; + } + plot.setCrosshair(pos); + allSeriesMode = true; + + if (dashboard.sharedCrosshairModeOnly()) { + // if only crosshair mode we are done + return; + } + } + + if (seriesList.length === 0) { + return; + } + + if (seriesList[0].hasMsResolution) { + tooltipFormat = 'YYYY-MM-DD HH:mm:ss.SSS'; + } else { + tooltipFormat = 'YYYY-MM-DD HH:mm:ss'; + } + + if (allSeriesMode) { + plot.unhighlight(); + + var seriesHoverInfo = self.getMultiSeriesPlotHoverInfo(plotData, pos); + + seriesHtml = ''; + + absoluteTime = dashboard.formatDate(seriesHoverInfo.time, tooltipFormat); + + // Dynamically reorder the hovercard for the current time point if the + // option is enabled. + if (panel.tooltip.sort === 2) { + seriesHoverInfo.sort(function(a, b) { + return b.value - a.value; + }); + } else if (panel.tooltip.sort === 1) { + seriesHoverInfo.sort(function(a, b) { + return a.value - b.value; + }); + } + + for (i = 0; i < seriesHoverInfo.length; i++) { + hoverInfo = seriesHoverInfo[i]; + + if (hoverInfo.hidden) { + continue; + } + + var highlightClass = ''; + if (item && hoverInfo.index === item.seriesIndex) { + highlightClass = 'graph-tooltip-list-item--highlight'; + } + + series = seriesList[hoverInfo.index]; + + value = series.formatValue(hoverInfo.value); + + seriesHtml += + '
'; + seriesHtml += + ' ' + hoverInfo.label + ':
'; + seriesHtml += '
' + value + '
'; + plot.highlight(hoverInfo.index, hoverInfo.hoverIndex); + } + + self.renderAndShow(absoluteTime, seriesHtml, pos, xMode); + } else if (item) { + // single series tooltip + series = seriesList[item.seriesIndex]; + group = '
'; + group += + ' ' + series.aliasEscaped + ':
'; + + if (panel.stack && panel.tooltip.value_type === 'individual') { + value = item.datapoint[1] - item.datapoint[2]; + } else { + value = item.datapoint[1]; + } + + value = series.formatValue(value); + + absoluteTime = dashboard.formatDate(item.datapoint[0], tooltipFormat); + + group += '
' + value + '
'; + + self.renderAndShow(absoluteTime, group, pos, xMode); + } else { + // no hit + $tooltip.detach(); + } + }; +} From 7b9b34c6e188344665948cca705c0e4d24389608 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 29 Mar 2018 11:51:34 +0200 Subject: [PATCH 11/31] migrated graph_tooltip to ts --- .../app/plugins/panel/graph/graph_tooltip.ts | 49 +++++++++---------- .../panel/graph/specs/tooltip_specs.ts | 5 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/public/app/plugins/panel/graph/graph_tooltip.ts b/public/app/plugins/panel/graph/graph_tooltip.ts index 846a165bbaf..509d15b8a25 100644 --- a/public/app/plugins/panel/graph/graph_tooltip.ts +++ b/public/app/plugins/panel/graph/graph_tooltip.ts @@ -1,8 +1,6 @@ import $ from 'jquery'; import { appEvents } from 'app/core/core'; -//var appEvents = appEvents; - export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { let self = this; let ctrl = scope.ctrl; @@ -15,10 +13,11 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { }; this.findHoverIndexFromDataPoints = function(posX, series, last) { - var ps = series.datapoints.pointsize; - var initial = last * ps; - var len = series.datapoints.points.length; - for (var j = initial; j < len; j += ps) { + let ps = series.datapoints.pointsize; + let initial = last * ps; + let len = series.datapoints.points.length; + let j; + for (j = initial; j < len; j += ps) { // Special case of a non stepped line, highlight the very last point just before a null point if ( (!series.lines.steps && series.datapoints.points[initial] != null && series.datapoints.points[j] == null) || @@ -32,9 +31,9 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { }; this.findHoverIndexFromData = function(posX, series) { - var lower = 0; - var upper = series.data.length - 1; - var middle; + let lower = 0; + let upper = series.data.length - 1; + let middle; while (true) { if (lower > upper) { return Math.max(upper, 0); @@ -58,14 +57,14 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { }; this.getMultiSeriesPlotHoverInfo = function(seriesList, pos) { - var value, i, series, hoverIndex, hoverDistance, pointTime, yaxis; + let value, i, series, hoverIndex, hoverDistance, pointTime, yaxis; // 3 sub-arrays, 1st for hidden series, 2nd for left yaxis, 3rd for right yaxis. - var results: any = [[], [], []]; + let results: any = [[], [], []]; //now we know the current X (j) position for X and Y values - var last_value = 0; //needed for stacked values + let last_value = 0; //needed for stacked values - var minDistance, minTime; + let minDistance, minTime; for (i = 0; i < seriesList.length; i++) { series = seriesList[i]; @@ -145,7 +144,7 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { elem.mouseleave(function() { if (panel.tooltip.shared) { - var plot = elem.data().plot; + let plot = elem.data().plot; if (plot) { $tooltip.detach(); plot.unhighlight(); @@ -173,25 +172,25 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { }; this.show = function(pos, item) { - var plot = elem.data().plot; - var plotData = plot.getData(); - var xAxes = plot.getXAxes(); - var xMode = xAxes[0].options.mode; - var seriesList = getSeriesFn(); - var allSeriesMode = panel.tooltip.shared; - var group, value, absoluteTime, hoverInfo, i, series, seriesHtml, tooltipFormat; + let plot = elem.data().plot; + let plotData = plot.getData(); + let xAxes = plot.getXAxes(); + let xMode = xAxes[0].options.mode; + let seriesList = getSeriesFn(); + let allSeriesMode = panel.tooltip.shared; + let group, value, absoluteTime, hoverInfo, i, series, seriesHtml, tooltipFormat; // if panelRelY is defined another panel wants us to show a tooltip // get pageX from position on x axis and pageY from relative position in original panel if (pos.panelRelY) { - var pointOffset = plot.pointOffset({ x: pos.x }); + let pointOffset = plot.pointOffset({ x: pos.x }); if (Number.isNaN(pointOffset.left) || pointOffset.left < 0 || pointOffset.left > elem.width()) { self.clear(plot); return; } pos.pageX = elem.offset().left + pointOffset.left; pos.pageY = elem.offset().top + elem.height() * pos.panelRelY; - var isVisible = + let isVisible = pos.pageY >= $(window).scrollTop() && pos.pageY <= $(window).innerHeight() + $(window).scrollTop(); if (!isVisible) { self.clear(plot); @@ -219,7 +218,7 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { if (allSeriesMode) { plot.unhighlight(); - var seriesHoverInfo = self.getMultiSeriesPlotHoverInfo(plotData, pos); + let seriesHoverInfo = self.getMultiSeriesPlotHoverInfo(plotData, pos); seriesHtml = ''; @@ -244,7 +243,7 @@ export default function GraphTooltip(elem, dashboard, scope, getSeriesFn) { continue; } - var highlightClass = ''; + let highlightClass = ''; if (item && hoverInfo.index === item.seriesIndex) { highlightClass = 'graph-tooltip-list-item--highlight'; } diff --git a/public/app/plugins/panel/graph/specs/tooltip_specs.ts b/public/app/plugins/panel/graph/specs/tooltip_specs.ts index c12697eadac..7dd5ed9b8a9 100644 --- a/public/app/plugins/panel/graph/specs/tooltip_specs.ts +++ b/public/app/plugins/panel/graph/specs/tooltip_specs.ts @@ -11,6 +11,7 @@ var scope = { var elem = $('
'); var dashboard = {}; +var getSeriesFn; function describeSharedTooltip(desc, fn) { var ctx: any = {}; @@ -30,7 +31,7 @@ function describeSharedTooltip(desc, fn) { describe(desc, function() { beforeEach(function() { ctx.setupFn(); - var tooltip = new GraphTooltip(elem, dashboard, scope); + var tooltip = new GraphTooltip(elem, dashboard, scope, getSeriesFn); ctx.results = tooltip.getMultiSeriesPlotHoverInfo(ctx.data, ctx.pos); }); @@ -39,7 +40,7 @@ function describeSharedTooltip(desc, fn) { } describe('findHoverIndexFromData', function() { - var tooltip = new GraphTooltip(elem, dashboard, scope); + var tooltip = new GraphTooltip(elem, dashboard, scope, getSeriesFn); var series = { data: [[100, 0], [101, 0], [102, 0], [103, 0], [104, 0], [105, 0], [106, 0], [107, 0]], }; From 9ef5f2700dd12fc7bfa1c6ac1c4f7cedcf2a52f3 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 29 Mar 2018 15:02:00 +0200 Subject: [PATCH 12/31] timepicker now closes without exiting edit/view mode, close order: modal, timepicker, view --- public/app/core/services/keybindingSrv.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index 829a3415cc1..e51c0477ffa 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -74,13 +74,13 @@ export class KeybindingSrv { appEvents.emit('hide-modal'); - if (this.timepickerOpen === true) { - this.$rootScope.appEvent('closeTimepicker'); - this.timepickerOpen = false; - } - if (!this.modalOpen) { - this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false }); + if (this.timepickerOpen) { + this.$rootScope.appEvent('closeTimepicker'); + this.timepickerOpen = false; + } else { + this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false }); + } } else { this.modalOpen = false; } From 98e1404fed0a1cab9cdc6f7404d805459f374f48 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 3 Apr 2018 09:39:46 +0200 Subject: [PATCH 13/31] added if to onAppevent, renamed appevent, add appevent to applyCustom and setRelativeFilter --- public/app/core/services/keybindingSrv.ts | 8 +++++++- public/app/features/dashboard/timepicker/timepicker.ts | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index e51c0477ffa..35cd7808d12 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -23,7 +23,13 @@ export class KeybindingSrv { this.setupGlobal(); appEvents.on('show-modal', () => (this.modalOpen = true)); - $rootScope.onAppEvent('openTimepicker', () => (this.timepickerOpen = true)); + $rootScope.onAppEvent('escTimepicker', () => { + if (!this.timepickerOpen) { + this.timepickerOpen = true; + } else { + this.timepickerOpen = false; + } + }); } setupGlobal() { diff --git a/public/app/features/dashboard/timepicker/timepicker.ts b/public/app/features/dashboard/timepicker/timepicker.ts index 19c3db7f6d3..32ce07e4468 100644 --- a/public/app/features/dashboard/timepicker/timepicker.ts +++ b/public/app/features/dashboard/timepicker/timepicker.ts @@ -96,13 +96,12 @@ export class TimePickerCtrl { } openDropdown() { + this.$rootScope.appEvent('escTimepicker'); if (this.isOpen) { this.isOpen = false; return; } - this.$rootScope.appEvent('openTimepicker'); - this.onRefresh(); this.editTimeRaw = this.timeRaw; this.timeOptions = rangeUtil.getRelativeTimesList(this.panel, this.rangeString); @@ -118,6 +117,7 @@ export class TimePickerCtrl { } applyCustom() { + this.$rootScope.appEvent('escTimepicker'); if (this.refresh.value !== this.dashboard.refresh) { this.timeSrv.setAutoRefresh(this.refresh.value); } @@ -139,6 +139,7 @@ export class TimePickerCtrl { } setRelativeFilter(timespan) { + this.$rootScope.appEvent('escTimepicker'); var range = { from: timespan.from, to: timespan.to }; if (this.panel.nowDelay && range.to === 'now') { From feb222f63327c8dbac43a2d44d4207f80bcead2c Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 3 Apr 2018 09:53:14 +0200 Subject: [PATCH 14/31] changed variable for tabbed close btn hover, and changed text-strong variable for lighttheme, removed commented out variable --- public/sass/_variables.light.scss | 3 +-- public/sass/components/_tabbed_view.scss | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/public/sass/_variables.light.scss b/public/sass/_variables.light.scss index a59350d2195..bb8f93dbe69 100644 --- a/public/sass/_variables.light.scss +++ b/public/sass/_variables.light.scss @@ -59,9 +59,8 @@ $critical: #ec2128; $body-bg: $gray-7; $page-bg: $gray-7; $body-color: $gray-1; -//$text-color: $dark-4; $text-color: $gray-1; -$text-color-strong: $white; +$text-color-strong: $dark-2; $text-color-weak: $gray-2; $text-color-faint: $gray-4; $text-color-emphasis: $dark-5; diff --git a/public/sass/components/_tabbed_view.scss b/public/sass/components/_tabbed_view.scss index dfd760753fe..bf95d453504 100644 --- a/public/sass/components/_tabbed_view.scss +++ b/public/sass/components/_tabbed_view.scss @@ -43,7 +43,7 @@ font-size: 120%; } &:hover { - color: $white; + color: $text-color-strong; } } From 658c6a8ff4b959b6cd394550ea7d9ecc7d2e301c Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 3 Apr 2018 15:43:25 +0200 Subject: [PATCH 15/31] changed from margin to padding --- public/sass/pages/_alerting.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/sass/pages/_alerting.scss b/public/sass/pages/_alerting.scss index 5a481b55a8a..fb6b6e78d1b 100644 --- a/public/sass/pages/_alerting.scss +++ b/public/sass/pages/_alerting.scss @@ -108,7 +108,8 @@ justify-content: center; align-items: center; width: 40px; - margin-right: 8px; + //margin-right: 8px; + padding: 0 4px 0 2px; .icon-gf, .fa { font-size: 200%; From 533f3a9e8c7df8dfd0f769c707c49aff55241bf8 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 3 Apr 2018 19:09:49 +0200 Subject: [PATCH 16/31] settings: fixes test For some reason, the url parse does not fail anymore for curly braces. Add a colon in the first segment to make sure the url parse fails. --- pkg/setting/setting_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/setting/setting_test.go b/pkg/setting/setting_test.go index 87f9916075e..2da728b7298 100644 --- a/pkg/setting/setting_test.go +++ b/pkg/setting/setting_test.go @@ -37,8 +37,8 @@ func TestLoadingSettings(t *testing.T) { So(appliedEnvOverrides, ShouldContain, "GF_SECURITY_ADMIN_PASSWORD=*********") }) - Convey("Should replace password when defined in environment2", func() { - os.Setenv("GF_DATABASE_URL", "postgres://grafana:sec{ret@postgres:5432/grafana") + Convey("Should return an error when url is invalid", func() { + os.Setenv("GF_DATABASE_URL", "postgres.%31://grafana:secret@postgres:5432/grafana") err := NewConfigContext(&CommandLineArgs{HomePath: "../../"}) So(err, ShouldNotBeNil) From a6c76355285aef2f477e288a9104293870ed8ac6 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 3 Apr 2018 19:39:50 +0200 Subject: [PATCH 17/31] graphite: fixes #11434 --- public/app/plugins/datasource/graphite/add_graphite_func.ts | 1 + public/app/plugins/datasource/graphite/func_editor.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/public/app/plugins/datasource/graphite/add_graphite_func.ts b/public/app/plugins/datasource/graphite/add_graphite_func.ts index f2a596c7071..6e64b5d12d0 100644 --- a/public/app/plugins/datasource/graphite/add_graphite_func.ts +++ b/public/app/plugins/datasource/graphite/add_graphite_func.ts @@ -4,6 +4,7 @@ import $ from 'jquery'; import rst2html from 'rst2html'; import Drop from 'tether-drop'; +/** @ngInject */ export function graphiteAddFunc($compile) { const inputTemplate = ''; diff --git a/public/app/plugins/datasource/graphite/func_editor.ts b/public/app/plugins/datasource/graphite/func_editor.ts index 86135aef343..82a838e7660 100644 --- a/public/app/plugins/datasource/graphite/func_editor.ts +++ b/public/app/plugins/datasource/graphite/func_editor.ts @@ -3,6 +3,7 @@ import _ from 'lodash'; import $ from 'jquery'; import rst2html from 'rst2html'; +/** @ngInject */ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) { const funcSpanTemplate = '
{{func.def.name}}('; const paramTemplate = From 4a93766143a73fe8af896c25cf102e1ca93a90f7 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 16 Mar 2018 12:56:39 -0400 Subject: [PATCH 18/31] Add case-insensitive sort for variables. --- public/app/features/templating/editor_ctrl.ts | 2 ++ public/app/features/templating/query_variable.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/public/app/features/templating/editor_ctrl.ts b/public/app/features/templating/editor_ctrl.ts index 428770a21e5..f20e93be42c 100644 --- a/public/app/features/templating/editor_ctrl.ts +++ b/public/app/features/templating/editor_ctrl.ts @@ -23,6 +23,8 @@ export class VariableEditorCtrl { { value: 2, text: 'Alphabetical (desc)' }, { value: 3, text: 'Numerical (asc)' }, { value: 4, text: 'Numerical (desc)' }, + { value: 5, text: 'Alphabetical (case-insensitive, asc)' }, + { value: 6, text: 'Alphabetical (case-insensitive, desc)' }, ]; $scope.hideOptions = [{ value: 0, text: '' }, { value: 1, text: 'Label' }, { value: 2, text: 'Variable' }]; diff --git a/public/app/features/templating/query_variable.ts b/public/app/features/templating/query_variable.ts index 58c7b692581..b87167ad646 100644 --- a/public/app/features/templating/query_variable.ts +++ b/public/app/features/templating/query_variable.ts @@ -197,6 +197,8 @@ export class QueryVariable implements Variable { return parseInt(matches[1], 10); } }); + } else if (sortType === 3) { + options = _.sortBy(options, opt => { return _.toLower(opt.text); }); } if (reverseSort) { From 70eb281840f9d7b786eb315356ed4f195b489506 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 3 Apr 2018 22:34:16 +0200 Subject: [PATCH 19/31] variables: adds test for variable sorting ref #11280 --- .../templating/specs/query_variable.jest.ts | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/public/app/features/templating/specs/query_variable.jest.ts b/public/app/features/templating/specs/query_variable.jest.ts index 7840d9e4242..ce753a4b205 100644 --- a/public/app/features/templating/specs/query_variable.jest.ts +++ b/public/app/features/templating/specs/query_variable.jest.ts @@ -40,11 +40,11 @@ describe('QueryVariable', () => { }); describe('can convert and sort metric names', () => { - var variable = new QueryVariable({}, null, null, null, null); - variable.sort = 3; // Numerical (asc) + const variable = new QueryVariable({}, null, null, null, null); + let input; - describe('can sort a mixed array of metric variables', () => { - var input = [ + beforeEach(() => { + input = [ { text: '0', value: '0' }, { text: '1', value: '1' }, { text: null, value: 3 }, @@ -58,11 +58,18 @@ describe('QueryVariable', () => { { text: '', value: undefined }, { text: undefined, value: '' }, ]; + }); + + describe('can sort a mixed array of metric variables in numeric order', () => { + let result; + + beforeEach(() => { + variable.sort = 3; // Numerical (asc) + result = variable.metricNamesToVariableValues(input); + }); - var result = variable.metricNamesToVariableValues(input); it('should return in same order', () => { var i = 0; - expect(result.length).toBe(11); expect(result[i++].text).toBe(''); expect(result[i++].text).toBe('0'); @@ -73,5 +80,27 @@ describe('QueryVariable', () => { expect(result[i++].text).toBe('6'); }); }); + + describe('can sort a mixed array of metric variables in alphabetical order', () => { + let result; + + beforeEach(() => { + variable.sort = 5; // Alphabetical CI (asc) + result = variable.metricNamesToVariableValues(input); + }); + + it('should return in same order', () => { + var i = 0; + console.log(result); + expect(result.length).toBe(11); + expect(result[i++].text).toBe(''); + expect(result[i++].text).toBe('0'); + expect(result[i++].text).toBe('1'); + expect(result[i++].text).toBe('10'); + expect(result[i++].text).toBe('3'); + expect(result[i++].text).toBe('4'); + expect(result[i++].text).toBe('5'); + }); + }); }); }); From 4b1c1acab42f06e317ddbf2e91ff59336f2a9306 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 3 Apr 2018 22:40:48 +0200 Subject: [PATCH 20/31] changelog: adds note for #11128 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b5ab29aa6..3f5b76486c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ * **AuthProxy**: Support IPv6 in Auth proxy white list [#11330](https://github.com/grafana/grafana/pull/11330), thx [@corny](https://github.com/corny) * **SMTP**: Don't connect to STMP server using TLS unless configured. [#7189](https://github.com/grafana/grafana/issues/7189) * **Prometheus**: Escape backslash in labels correctly. [#10555](https://github.com/grafana/grafana/issues/10555), thx [@roidelapluie](https://github.com/roidelapluie) +* **Variables** Case-insensitive sorting for template values [#11128](https://github.com/grafana/grafana/issues/11128) thx [@cross](https://github.com/cross) # 5.0.4 (2018-03-28) From 9841c81952de6eb13e433ffb6d820dc43ea55b96 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Wed, 4 Apr 2018 13:40:08 +0200 Subject: [PATCH 21/31] Notes for closing #7119 [skip ci] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f5b76486c4..4d221480de2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * **Prometheus**: Show template variable candidate in query editor [#9210](https://github.com/grafana/grafana/issues/9210), thx [@mtanda](https://github.com/mtanda) * **Prometheus**: Support POST for query and query_range [#9859](https://github.com/grafana/grafana/pull/9859), thx [@mtanda](https://github.com/mtanda) * **Alerting**: Add support for retries on alert queries [#5855](https://github.com/grafana/grafana/issues/5855), thx [@Thib17](https://github.com/Thib17) +* **Table**: Table plugin value mappings [#7119](https://github.com/grafana/grafana/issues/7119), thx [infernix](https://github.com/infernix) ### Minor * **OpsGenie**: Add triggered alerts as description [#11046](https://github.com/grafana/grafana/pull/11046), thx [@llamashoes](https://github.com/llamashoes) From 13f6d3be87a6c49a6b1f691324e5aca23aa94158 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 4 Apr 2018 14:16:39 +0200 Subject: [PATCH 22/31] migrated last all.js to ts --- public/app/core/services/all.js | 13 ------------- public/app/core/services/all.ts | 10 ++++++++++ public/app/features/all.js | 15 --------------- public/app/features/all.ts | 13 +++++++++++++ public/app/features/panel/all.js | 9 --------- public/app/features/panel/all.ts | 7 +++++++ public/app/features/playlist/all.js | 7 ------- public/app/features/playlist/all.ts | 5 +++++ 8 files changed, 35 insertions(+), 44 deletions(-) delete mode 100644 public/app/core/services/all.js create mode 100644 public/app/core/services/all.ts delete mode 100644 public/app/features/all.js create mode 100644 public/app/features/all.ts delete mode 100644 public/app/features/panel/all.js create mode 100644 public/app/features/panel/all.ts delete mode 100644 public/app/features/playlist/all.js create mode 100644 public/app/features/playlist/all.ts diff --git a/public/app/core/services/all.js b/public/app/core/services/all.js deleted file mode 100644 index 0a973440c5e..00000000000 --- a/public/app/core/services/all.js +++ /dev/null @@ -1,13 +0,0 @@ -define([ - './alert_srv', - './util_srv', - './context_srv', - './timer', - './analytics', - './popover_srv', - './segment_srv', - './backend_srv', - './dynamic_directive_srv', - './bridge_srv' -], -function () {}); diff --git a/public/app/core/services/all.ts b/public/app/core/services/all.ts new file mode 100644 index 00000000000..989015d2872 --- /dev/null +++ b/public/app/core/services/all.ts @@ -0,0 +1,10 @@ +import './alert_srv'; +import './util_srv'; +import './context_srv'; +import './timer'; +import './analytics'; +import './popover_srv'; +import './segment_srv'; +import './backend_srv'; +import './dynamic_directive_srv'; +import './bridge_srv'; diff --git a/public/app/features/all.js b/public/app/features/all.js deleted file mode 100644 index 759be6c11d2..00000000000 --- a/public/app/features/all.js +++ /dev/null @@ -1,15 +0,0 @@ -define([ - './panellinks/module', - './dashlinks/module', - './annotations/all', - './templating/all', - './plugins/all', - './dashboard/all', - './playlist/all', - './snapshot/all', - './panel/all', - './org/all', - './admin/admin', - './alerting/all', - './styleguide/styleguide', -], function () {}); diff --git a/public/app/features/all.ts b/public/app/features/all.ts new file mode 100644 index 00000000000..df987a8b59b --- /dev/null +++ b/public/app/features/all.ts @@ -0,0 +1,13 @@ +import './panellinks/module'; +import './dashlinks/module'; +import './annotations/all'; +import './templating/all'; +import './plugins/all'; +import './dashboard/all'; +import './playlist/all'; +import './snapshot/all'; +import './panel/all'; +import './org/all'; +import './admin/admin'; +import './alerting/all'; +import './styleguide/styleguide'; diff --git a/public/app/features/panel/all.js b/public/app/features/panel/all.js deleted file mode 100644 index aaa6d0d4ed0..00000000000 --- a/public/app/features/panel/all.js +++ /dev/null @@ -1,9 +0,0 @@ -define([ - './panel_header', - './panel_directive', - './solo_panel_ctrl', - './query_ctrl', - './panel_editor_tab', - './query_editor_row', - './query_troubleshooter', -], function () {}); diff --git a/public/app/features/panel/all.ts b/public/app/features/panel/all.ts new file mode 100644 index 00000000000..bdf1a097352 --- /dev/null +++ b/public/app/features/panel/all.ts @@ -0,0 +1,7 @@ +import './panel_header'; +import './panel_directive'; +import './solo_panel_ctrl'; +import './query_ctrl'; +import './panel_editor_tab'; +import './query_editor_row'; +import './query_troubleshooter'; diff --git a/public/app/features/playlist/all.js b/public/app/features/playlist/all.js deleted file mode 100644 index 3b07b0d74c5..00000000000 --- a/public/app/features/playlist/all.js +++ /dev/null @@ -1,7 +0,0 @@ -define([ - './playlists_ctrl', - './playlist_search', - './playlist_srv', - './playlist_edit_ctrl', - './playlist_routes' -], function () {}); diff --git a/public/app/features/playlist/all.ts b/public/app/features/playlist/all.ts new file mode 100644 index 00000000000..eb427b883ca --- /dev/null +++ b/public/app/features/playlist/all.ts @@ -0,0 +1,5 @@ +import './playlists_ctrl'; +import './playlist_search'; +import './playlist_srv'; +import './playlist_edit_ctrl'; +import './playlist_routes'; From 84dce3282aaac2a5d2b83de9af027619a880936c Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 4 Apr 2018 15:26:23 +0200 Subject: [PATCH 23/31] migrated playlist-routes to ts --- .../app/features/playlist/playlist_routes.js | 39 ------------------- .../app/features/playlist/playlist_routes.ts | 33 ++++++++++++++++ 2 files changed, 33 insertions(+), 39 deletions(-) delete mode 100644 public/app/features/playlist/playlist_routes.js create mode 100644 public/app/features/playlist/playlist_routes.ts diff --git a/public/app/features/playlist/playlist_routes.js b/public/app/features/playlist/playlist_routes.js deleted file mode 100644 index 193b0b52b20..00000000000 --- a/public/app/features/playlist/playlist_routes.js +++ /dev/null @@ -1,39 +0,0 @@ -define([ - 'angular', - 'lodash' -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.routes'); - - module.config(function($routeProvider) { - $routeProvider - .when('/playlists', { - templateUrl: 'public/app/features/playlist/partials/playlists.html', - controllerAs: 'ctrl', - controller : 'PlaylistsCtrl' - }) - .when('/playlists/create', { - templateUrl: 'public/app/features/playlist/partials/playlist.html', - controllerAs: 'ctrl', - controller : 'PlaylistEditCtrl' - }) - .when('/playlists/edit/:id', { - templateUrl: 'public/app/features/playlist/partials/playlist.html', - controllerAs: 'ctrl', - controller : 'PlaylistEditCtrl' - }) - .when('/playlists/play/:id', { - templateUrl: 'public/app/features/playlist/partials/playlists.html', - controllerAs: 'ctrl', - controller : 'PlaylistsCtrl', - resolve: { - init: function(playlistSrv, $route) { - var playlistId = $route.current.params.id; - playlistSrv.start(playlistId); - } - } - }); - }); -}); diff --git a/public/app/features/playlist/playlist_routes.ts b/public/app/features/playlist/playlist_routes.ts new file mode 100644 index 00000000000..c94446c2c1b --- /dev/null +++ b/public/app/features/playlist/playlist_routes.ts @@ -0,0 +1,33 @@ +import angular from 'angular'; + +function grafanaRoutes($routeProvider) { + $routeProvider + .when('/playlists', { + templateUrl: 'public/app/features/playlist/partials/playlists.html', + controllerAs: 'ctrl', + controller: 'PlaylistsCtrl', + }) + .when('/playlists/create', { + templateUrl: 'public/app/features/playlist/partials/playlist.html', + controllerAs: 'ctrl', + controller: 'PlaylistEditCtrl', + }) + .when('/playlists/edit/:id', { + templateUrl: 'public/app/features/playlist/partials/playlist.html', + controllerAs: 'ctrl', + controller: 'PlaylistEditCtrl', + }) + .when('/playlists/play/:id', { + templateUrl: 'public/app/features/playlist/partials/playlists.html', + controllerAs: 'ctrl', + controller: 'PlaylistsCtrl', + resolve: { + init: function(playlistSrv, $route) { + let playlistId = $route.current.params.id; + playlistSrv.start(playlistId); + }, + }, + }); +} + +angular.module('grafana.routes').config(grafanaRoutes); From 0273365df3dd25656330cd638b56617cd221d060 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 4 Apr 2018 16:20:01 +0200 Subject: [PATCH 24/31] created closeDropdown function, renamed appevent, added second appevent for open timepicker --- public/app/core/services/keybindingSrv.ts | 9 ++------- .../features/dashboard/timepicker/timepicker.ts | 16 +++++++++------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index 35cd7808d12..55d968fd981 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -23,13 +23,8 @@ export class KeybindingSrv { this.setupGlobal(); appEvents.on('show-modal', () => (this.modalOpen = true)); - $rootScope.onAppEvent('escTimepicker', () => { - if (!this.timepickerOpen) { - this.timepickerOpen = true; - } else { - this.timepickerOpen = false; - } - }); + $rootScope.onAppEvent('timepickerOpen', () => (this.timepickerOpen = true)); + $rootScope.onAppEvent('timepickerClosed', () => (this.timepickerOpen = false)); } setupGlobal() { diff --git a/public/app/features/dashboard/timepicker/timepicker.ts b/public/app/features/dashboard/timepicker/timepicker.ts index 32ce07e4468..33cfff92e7f 100644 --- a/public/app/features/dashboard/timepicker/timepicker.ts +++ b/public/app/features/dashboard/timepicker/timepicker.ts @@ -22,7 +22,6 @@ export class TimePickerCtrl { refresh: any; isUtc: boolean; firstDayOfWeek: number; - closeDropdown: any; isOpen: boolean; /** @ngInject */ @@ -96,9 +95,8 @@ export class TimePickerCtrl { } openDropdown() { - this.$rootScope.appEvent('escTimepicker'); if (this.isOpen) { - this.isOpen = false; + this.closeDropdown(); return; } @@ -114,16 +112,21 @@ export class TimePickerCtrl { this.refresh.options.unshift({ text: 'off' }); this.isOpen = true; + this.$rootScope.appEvent('timepickerOpen'); + } + + closeDropdown() { + this.isOpen = false; + this.$rootScope.appEvent('timepickerClosed'); } applyCustom() { - this.$rootScope.appEvent('escTimepicker'); if (this.refresh.value !== this.dashboard.refresh) { this.timeSrv.setAutoRefresh(this.refresh.value); } this.timeSrv.setTime(this.editTimeRaw); - this.isOpen = false; + this.closeDropdown(); } absoluteFromChanged() { @@ -139,7 +142,6 @@ export class TimePickerCtrl { } setRelativeFilter(timespan) { - this.$rootScope.appEvent('escTimepicker'); var range = { from: timespan.from, to: timespan.to }; if (this.panel.nowDelay && range.to === 'now') { @@ -147,7 +149,7 @@ export class TimePickerCtrl { } this.timeSrv.setTime(range); - this.isOpen = false; + this.closeDropdown(); } } From b69316752a4c27b1a9011d0a0e81b36b6cc76d7e Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 4 Apr 2018 19:51:12 +0300 Subject: [PATCH 25/31] scrollbar: fix dashboard width updating for different modes --- public/app/core/components/grafana_app.ts | 1 + public/app/core/components/scroll/scroll.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index 798a40cb1bf..1e3f0cb9119 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -167,6 +167,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop if (sidemenuHidden) { sidemenuHidden = false; body.addClass('sidemenu-open'); + appEvents.emit('toggle-inactive-mode'); $timeout(function() { $rootScope.$broadcast('render'); }, 100); diff --git a/public/app/core/components/scroll/scroll.ts b/public/app/core/components/scroll/scroll.ts index 0eb1c68ab71..ebe105a4fee 100644 --- a/public/app/core/components/scroll/scroll.ts +++ b/public/app/core/components/scroll/scroll.ts @@ -60,10 +60,16 @@ export function geminiScrollbar() { scope ); - appEvents.on('toggle-sidemenu', evt => { - // force updating dashboard width + // force updating dashboard width + appEvents.on('toggle-sidemenu', forceUpdate); + appEvents.on('toggle-sidemenu-hidden', forceUpdate); + appEvents.on('toggle-view-mode', forceUpdate); + appEvents.on('toggle-kiosk-mode', forceUpdate); + appEvents.on('toggle-inactive-mode', forceUpdate); + + function forceUpdate() { scrollbar.scroll(); - }); + } scope.$on('$routeChangeSuccess', () => { lastPos = 0; From 90aab445586b4a5ca00fba4d2f6de72d223d1235 Mon Sep 17 00:00:00 2001 From: Jarno Tuovinen Date: Wed, 4 Apr 2018 21:07:22 +0300 Subject: [PATCH 26/31] Use curly brackets around hyperlink help text #11478 (#11479) --- public/app/plugins/panel/table/column_options.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/panel/table/column_options.html b/public/app/plugins/panel/table/column_options.html index 9e8e4b404ae..4a4a6d0db9c 100644 --- a/public/app/plugins/panel/table/column_options.html +++ b/public/app/plugins/panel/table/column_options.html @@ -163,10 +163,10 @@ Use special variables to specify cell values:
- $__cell refers to current cell value + ${__cell} refers to current cell value
- $__cell_n refers to Nth column value in current row. Column indexes are started from 0. For instance, - $__cell_1 refers to second column's value. + ${__cell_n} refers to Nth column value in current row. Column indexes are started from 0. For instance, + ${__cell_1} refers to second column's value.
From b4ef55f5d027014a43404658581409b4c8d82f63 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 5 Apr 2018 11:51:32 +0300 Subject: [PATCH 27/31] scrollbar: fix potential memory leaks in event handlers --- public/app/core/components/scroll/scroll.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/public/app/core/components/scroll/scroll.ts b/public/app/core/components/scroll/scroll.ts index ebe105a4fee..12321bc4f5c 100644 --- a/public/app/core/components/scroll/scroll.ts +++ b/public/app/core/components/scroll/scroll.ts @@ -61,11 +61,11 @@ export function geminiScrollbar() { ); // force updating dashboard width - appEvents.on('toggle-sidemenu', forceUpdate); - appEvents.on('toggle-sidemenu-hidden', forceUpdate); - appEvents.on('toggle-view-mode', forceUpdate); - appEvents.on('toggle-kiosk-mode', forceUpdate); - appEvents.on('toggle-inactive-mode', forceUpdate); + appEvents.on('toggle-sidemenu', forceUpdate, scope); + appEvents.on('toggle-sidemenu-hidden', forceUpdate, scope); + appEvents.on('toggle-view-mode', forceUpdate, scope); + appEvents.on('toggle-kiosk-mode', forceUpdate, scope); + appEvents.on('toggle-inactive-mode', forceUpdate, scope); function forceUpdate() { scrollbar.scroll(); From b321a21cb569d1ac3c0dc88c53393aea2e48d2d5 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 5 Apr 2018 11:00:15 +0200 Subject: [PATCH 28/31] removed indent for manage dashboards --- public/sass/components/_search.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index e6b3795d752..ab63f96be50 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -206,7 +206,7 @@ padding: 5px; flex: 0 0 auto; font-size: 19px; - padding: 5px 2px 5px 16px; + padding: 5px 2px 5px 10px; } .search-item__tags { From fcfc33ee5795c5cd745248450212086394c7999e Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 5 Apr 2018 15:02:54 +0200 Subject: [PATCH 29/31] changelog: adds note for #11165 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d221480de2..2f763a15c82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * **Prometheus**: Support POST for query and query_range [#9859](https://github.com/grafana/grafana/pull/9859), thx [@mtanda](https://github.com/mtanda) * **Alerting**: Add support for retries on alert queries [#5855](https://github.com/grafana/grafana/issues/5855), thx [@Thib17](https://github.com/Thib17) * **Table**: Table plugin value mappings [#7119](https://github.com/grafana/grafana/issues/7119), thx [infernix](https://github.com/infernix) +* **IE11**: IE 11 compatibility [#11165](https://github.com/grafana/grafana/issues/11165) ### Minor * **OpsGenie**: Add triggered alerts as description [#11046](https://github.com/grafana/grafana/pull/11046), thx [@llamashoes](https://github.com/llamashoes) From fa43782299a6fde669d9ecd186eb1aa094db0067 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 5 Apr 2018 15:56:07 +0300 Subject: [PATCH 30/31] scrollbar: fix graph legend height --- public/app/plugins/panel/graph/legend.ts | 8 ++++---- public/app/plugins/panel/graph/template.ts | 4 +++- public/sass/components/_panel_graph.scss | 8 +++++++- public/sass/components/_scrollbar.scss | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/public/app/plugins/panel/graph/legend.ts b/public/app/plugins/panel/graph/legend.ts index c4ff5b31355..d3b548859de 100644 --- a/public/app/plugins/panel/graph/legend.ts +++ b/public/app/plugins/panel/graph/legend.ts @@ -238,10 +238,10 @@ module.directive('graphLegend', function(popoverSrv, $timeout) { tbodyElem.append(tableHeaderElem); tbodyElem.append(seriesElements); elem.append(tbodyElem); - tbodyElem.wrap('
'); + tbodyElem.wrap('
'); } else { - elem.append('
'); - elem.find('.graph-legend-content').append(seriesElements); + elem.append('
'); + elem.find('.graph-legend-scroll').append(seriesElements); } if (!panel.legend.rightSide || (panel.legend.rightSide && legendWidth !== legendRightDefaultWidth)) { @@ -261,7 +261,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) { `; let scrollRoot = elem; - let scroller = elem.find('.graph-legend-content'); + let scroller = elem.find('.graph-legend-scroll'); // clear existing scroll bar track to prevent duplication scrollRoot.find('.baron__track').remove(); diff --git a/public/app/plugins/panel/graph/template.ts b/public/app/plugins/panel/graph/template.ts index 0b9eb8227df..c897327fe1a 100644 --- a/public/app/plugins/panel/graph/template.ts +++ b/public/app/plugins/panel/graph/template.ts @@ -3,7 +3,9 @@ var template = `
-
+
+
+
`; diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index 83747d6caaf..cc5c601e0ea 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -49,6 +49,7 @@ } .graph-legend { + display: flex; flex: 0 1 auto; max-height: 30%; margin: 0; @@ -56,7 +57,8 @@ padding-top: 6px; position: relative; - height: 100%; + // fix for Firefox (white stripe on the right of scrollbar) + width: 99%; .popover-content { padding: 0; @@ -67,6 +69,10 @@ position: relative; } +.graph-legend-scroll { + position: relative; +} + .graph-legend-icon { position: relative; padding-right: 4px; diff --git a/public/sass/components/_scrollbar.scss b/public/sass/components/_scrollbar.scss index 7fb8ac6608c..93b81fc1b4b 100644 --- a/public/sass/components/_scrollbar.scss +++ b/public/sass/components/_scrollbar.scss @@ -192,12 +192,12 @@ // Width needs to be set to prevent content width issues // Set to 99% instead of 100% for fixing Firefox issue (white stripe on the right of scrollbar) - min-width: 99%; + width: 99%; } // Fix for side menu on mobile devices .main-view.baron { - min-width: unset; + width: unset; } .baron__clipper { From 9f07ae72ee4bebc41ec06bc85793529bf045aa66 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 5 Apr 2018 16:47:20 +0300 Subject: [PATCH 31/31] scrollbar: fix search scroller in mobile view --- public/sass/components/_search.scss | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index f54ac4b3d5c..8338a5d72ae 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -103,18 +103,20 @@ } .search-results-scroller { + display: flex; position: relative; - height: 100%; } .search-results-container { - height: 100%; display: block; padding: $spacer; position: relative; flex-grow: 10; margin-bottom: 1rem; + // Fix for search scroller in mobile view + height: unset; + .label-tag { margin-left: 6px; font-size: 11px;