From 8161a0943d073c13dce6c8fa510b3b6f85324f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 17 Jan 2016 20:16:39 +0100 Subject: [PATCH 01/22] ux(password): minor fix for change password page --- public/app/core/components/navbar/navbar.html | 2 +- public/app/features/profile/partials/password.html | 10 +++++++--- public/app/features/profile/partials/profile.html | 6 +++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/public/app/core/components/navbar/navbar.html b/public/app/core/components/navbar/navbar.html index ab33b9ae2e9..5c1e08de1f6 100644 --- a/public/app/core/components/navbar/navbar.html +++ b/public/app/core/components/navbar/navbar.html @@ -13,7 +13,7 @@ - + {{ctrl.title}} diff --git a/public/app/features/profile/partials/password.html b/public/app/features/profile/partials/password.html index 24e828ee790..df940dd14a5 100644 --- a/public/app/features/profile/partials/password.html +++ b/public/app/features/profile/partials/password.html @@ -1,8 +1,8 @@ - + - +
@@ -47,7 +47,11 @@

- +
+ +   + Cancel +
diff --git a/public/app/features/profile/partials/profile.html b/public/app/features/profile/partials/profile.html index 425d2bac0fe..5f6f75f090f 100644 --- a/public/app/features/profile/partials/profile.html +++ b/public/app/features/profile/partials/profile.html @@ -1,10 +1,10 @@ - - + +
-

Account & Preferences

+

Profile & Preferences

Preferences

From 30c19d525e302e942942deeaaa875159351ad7f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 17 Jan 2016 20:32:37 +0100 Subject: [PATCH 02/22] ux(): minor page rename --- public/app/core/components/sidemenu/sidemenu.ts | 2 +- public/app/features/profile/partials/profile.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/core/components/sidemenu/sidemenu.ts b/public/app/core/components/sidemenu/sidemenu.ts index 83a1c520089..d2a640c1345 100644 --- a/public/app/core/components/sidemenu/sidemenu.ts +++ b/public/app/core/components/sidemenu/sidemenu.ts @@ -41,7 +41,7 @@ export class SideMenuCtrl { this.orgMenu = [ {section: 'You', cssClass: 'dropdown-menu-title'}, {text: 'Preferences', url: this.getUrl('/profile')}, - {text: 'Account', url: this.getUrl('/profile')}, + {text: 'Profile', url: this.getUrl('/profile')}, ]; if (this.isSignedIn) { diff --git a/public/app/features/profile/partials/profile.html b/public/app/features/profile/partials/profile.html index 5f6f75f090f..4e8c15044c2 100644 --- a/public/app/features/profile/partials/profile.html +++ b/public/app/features/profile/partials/profile.html @@ -4,7 +4,7 @@
-

Profile & Preferences

+

Profile

Preferences

From 053868f5931d21e80f48a47b6078f452a920c013 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 08:38:32 +0100 Subject: [PATCH 03/22] fix(login): fix vulnerbility for timing attacks closes #3760 --- pkg/login/auth.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/login/auth.go b/pkg/login/auth.go index 38d87444e23..f2034476f81 100644 --- a/pkg/login/auth.go +++ b/pkg/login/auth.go @@ -3,6 +3,7 @@ package login import ( "errors" + "crypto/subtle" "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" @@ -56,7 +57,7 @@ func loginUsingGrafanaDB(query *LoginUserQuery) error { user := userQuery.Result passwordHashed := util.EncodePassword(query.Password, user.Salt) - if passwordHashed != user.Password { + if subtle.ConstantTimeCompare([]byte(passwordHashed), []byte(user.Password)) != 1 { return ErrInvalidCredentials } From a35bf497bed5553bbce75461ea235c359927e2f4 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 09:26:24 +0100 Subject: [PATCH 04/22] feat(units): add more data rate units closes #3759 --- public/app/core/utils/kbn.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js index cc296324eb5..e8084361916 100644 --- a/public/app/core/utils/kbn.js +++ b/public/app/core/utils/kbn.js @@ -595,6 +595,10 @@ function($, _) { {text: 'packets/sec', value: 'pps'}, {text: 'bits/sec', value: 'bps'}, {text: 'bytes/sec', value: 'Bps'}, + {text: 'megabytes/sec', value: 'MBs'}, + {text: 'megabites/sec', value: 'Mbits'}, + {text: 'gigabytes/sec', value: 'GBs'}, + {text: 'gigabites/sec', value: 'Gbits'}, ] }, { From 6a95963c898b64f181480904c65aeea011e56590 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 09:47:01 +0100 Subject: [PATCH 05/22] Revert "feat(units): add more data rate units" This reverts commit a35bf497bed5553bbce75461ea235c359927e2f4. --- public/app/core/utils/kbn.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js index e8084361916..cc296324eb5 100644 --- a/public/app/core/utils/kbn.js +++ b/public/app/core/utils/kbn.js @@ -595,10 +595,6 @@ function($, _) { {text: 'packets/sec', value: 'pps'}, {text: 'bits/sec', value: 'bps'}, {text: 'bytes/sec', value: 'Bps'}, - {text: 'megabytes/sec', value: 'MBs'}, - {text: 'megabites/sec', value: 'Mbits'}, - {text: 'gigabytes/sec', value: 'GBs'}, - {text: 'gigabites/sec', value: 'Gbits'}, ] }, { From 899a44a73534dae6998ebbf68ce9141611f1e773 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 10:02:46 +0100 Subject: [PATCH 06/22] feat(units): add more data rate options --- public/app/core/utils/kbn.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js index cc296324eb5..e323a9223e3 100644 --- a/public/app/core/utils/kbn.js +++ b/public/app/core/utils/kbn.js @@ -352,9 +352,15 @@ function($, _) { kbn.valueFormats.gbytes = kbn.formatBuilders.binarySIPrefix('B', 3); // Data Rate - kbn.valueFormats.pps = kbn.formatBuilders.decimalSIPrefix('pps'); - kbn.valueFormats.bps = kbn.formatBuilders.decimalSIPrefix('bps'); - kbn.valueFormats.Bps = kbn.formatBuilders.decimalSIPrefix('Bps'); + kbn.valueFormats.pps = kbn.formatBuilders.decimalSIPrefix('pps'); + kbn.valueFormats.bps = kbn.formatBuilders.decimalSIPrefix('bps'); + kbn.valueFormats.Bps = kbn.formatBuilders.decimalSIPrefix('Bps'); + kbn.valueFormats.KBs = kbn.formatBuilders.decimalSIPrefix('Bs', 1); + kbn.valueFormats.Kbits = kbn.formatBuilders.decimalSIPrefix('bits', 1); + kbn.valueFormats.MBs = kbn.formatBuilders.decimalSIPrefix('Bs', 2); + kbn.valueFormats.Mbits = kbn.formatBuilders.decimalSIPrefix('bits', 2); + kbn.valueFormats.GBs = kbn.formatBuilders.decimalSIPrefix('Bs', 3); + kbn.valueFormats.Gbits = kbn.formatBuilders.decimalSIPrefix('bits', 3); // Throughput kbn.valueFormats.ops = kbn.formatBuilders.simpleCountUnit('ops'); @@ -595,6 +601,12 @@ function($, _) { {text: 'packets/sec', value: 'pps'}, {text: 'bits/sec', value: 'bps'}, {text: 'bytes/sec', value: 'Bps'}, + {text: 'kilobites/sec', value: 'Kbits'}, + {text: 'kilobytes/sec', value: 'KBs'}, + {text: 'megabites/sec', value: 'Mbits'}, + {text: 'megabytes/sec', value: 'MBs'}, + {text: 'gigabytes/sec', value: 'GBs'}, + {text: 'gigabites/sec', value: 'Gbits'}, ] }, { From edcef7d078524774131cd3f0135b0d71bfbdb14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 18 Jan 2016 12:12:05 +0100 Subject: [PATCH 07/22] fix(graph): fixed for graph series color selector popover, broken in recent 3.0-pre1 build, fixes #3774 --- public/app/core/components/grafana_app.ts | 14 +++++++++++--- public/app/plugins/panel/graph/legend.js | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index 35ea141d03c..07799de518b 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -165,22 +165,30 @@ export function grafanaAppDirective() { // handle document clicks that should hide things elem.click(function(evt) { - if ($(evt.target).parents().length === 0) { + var target = $(evt.target); + if (target.parents().length === 0) { return; } // hide search if (elem.find('.search-container').length > 0) { - if ($(evt.target).parents('.search-container').length === 0) { + if (target.parents('.search-container').length === 0) { scope.appEvent('hide-dash-search'); } } // hide sidemenu if (!ignoreSideMenuHide && elem.find('.sidemenu').length > 0) { - if ($(evt.target).parents('.sidemenu').length === 0) { + if (target.parents('.sidemenu').length === 0) { scope.$apply(() => scope.contextSrv.toggleSideMenu()); } } + + // hide popovers + var popover = elem.find('.popover'); + console.log(target.parents('.graph-legend').length); + if (popover.length > 0 && target.parents('.graph-legend').length === 0) { + popover.hide(); + } }); } }; diff --git a/public/app/plugins/panel/graph/legend.js b/public/app/plugins/panel/graph/legend.js index 2d3f8ac3b90..cf64d90414b 100644 --- a/public/app/plugins/panel/graph/legend.js +++ b/public/app/plugins/panel/graph/legend.js @@ -45,7 +45,7 @@ function (angular, _, $) { popoverScope.series = seriesInfo; popoverSrv.show({ element: el, - templateUrl: 'app/plugins/panels/graph/legend.popover.html', + templateUrl: 'app/plugins/panel/graph/legend.popover.html', scope: popoverScope }); } From 00802d035ac21c700a245ac4dfcf9c358ee28fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 18 Jan 2016 12:19:46 +0100 Subject: [PATCH 08/22] refactor(): refactoring submenu to directive --- public/app/features/apps/partials/edit.html | 7 ++- public/app/features/dashboard/all.js | 2 +- .../features/dashboard/submenu/submenu.html | 30 ++++++++++++ .../app/features/dashboard/submenu/submenu.ts | 46 +++++++++++++++++++ public/app/features/dashboard/submenuCtrl.js | 39 ---------------- public/app/partials/dashboard.html | 3 +- public/app/partials/submenu.html | 30 ------------ public/views/index.html | 1 + 8 files changed, 82 insertions(+), 76 deletions(-) create mode 100644 public/app/features/dashboard/submenu/submenu.html create mode 100644 public/app/features/dashboard/submenu/submenu.ts delete mode 100644 public/app/features/dashboard/submenuCtrl.js delete mode 100644 public/app/partials/submenu.html diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html index cb3adece43c..fc09dc4754c 100644 --- a/public/app/features/apps/partials/edit.html +++ b/public/app/features/apps/partials/edit.html @@ -1,9 +1,8 @@ - + - +
diff --git a/public/app/features/dashboard/all.js b/public/app/features/dashboard/all.js index f2716979903..9d7cd06019b 100644 --- a/public/app/features/dashboard/all.js +++ b/public/app/features/dashboard/all.js @@ -2,11 +2,11 @@ define([ './dashboardCtrl', './dashboardLoaderSrv', './dashnav/dashnav', + './submenu/submenu', './saveDashboardAsCtrl', './rowCtrl', './shareModalCtrl', './shareSnapshotCtrl', - './submenuCtrl', './dashboardSrv', './keybindings', './viewStateSrv', diff --git a/public/app/features/dashboard/submenu/submenu.html b/public/app/features/dashboard/submenu/submenu.html new file mode 100644 index 00000000000..b7bf0e89232 --- /dev/null +++ b/public/app/features/dashboard/submenu/submenu.html @@ -0,0 +1,30 @@ + diff --git a/public/app/features/dashboard/submenu/submenu.ts b/public/app/features/dashboard/submenu/submenu.ts new file mode 100644 index 00000000000..7e304d88464 --- /dev/null +++ b/public/app/features/dashboard/submenu/submenu.ts @@ -0,0 +1,46 @@ +/// + +import angular from 'angular'; + +export class SubmenuCtrl { + annotations: any; + variables: any; + dashboard: any; + + constructor(private $rootScope, private templateValuesSrv, private dynamicDashboardSrv) { + this.annotations = this.dashboard.templating.list; + this.variables = this.dashboard.templating.list; + } + + disableAnnotation(annotation) { + annotation.enable = !annotation.enable; + this.$rootScope.$broadcast('refresh'); + } + + getValuesForTag(variable, tagKey) { + return this.templateValuesSrv.getValuesForTag(variable, tagKey); + } + + variableUpdated(variable) { + this.templateValuesSrv.variableUpdated(variable).then(() => { + this.dynamicDashboardSrv.update(this.dashboard); + this.$rootScope.$emit('template-variable-value-updated'); + this.$rootScope.$broadcast('refresh'); + }); + } +} + +export function submenuDirective() { + return { + restrict: 'E', + templateUrl: 'app/features/dashboard/submenu/submenu.html', + controller: SubmenuCtrl, + bindToController: true, + controllerAs: 'ctrl', + scope: { + dashboard: "=", + } + }; +} + +angular.module('grafana.directives').directive('dashboardSubmenu', submenuDirective); diff --git a/public/app/features/dashboard/submenuCtrl.js b/public/app/features/dashboard/submenuCtrl.js deleted file mode 100644 index b1d0dc3ae32..00000000000 --- a/public/app/features/dashboard/submenuCtrl.js +++ /dev/null @@ -1,39 +0,0 @@ -define([ - 'angular', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.controllers'); - - module.controller('SubmenuCtrl', function($scope, $q, $rootScope, templateValuesSrv, dynamicDashboardSrv) { - - $scope.init = function() { - $scope.panel = $scope.pulldown; - $scope.row = $scope.pulldown; - $scope.annotations = $scope.dashboard.templating.list; - $scope.variables = $scope.dashboard.templating.list; - }; - - $scope.disableAnnotation = function (annotation) { - annotation.enable = !annotation.enable; - $rootScope.$broadcast('refresh'); - }; - - $scope.getValuesForTag = function(variable, tagKey) { - return templateValuesSrv.getValuesForTag(variable, tagKey); - }; - - $scope.variableUpdated = function(variable) { - templateValuesSrv.variableUpdated(variable).then(function() { - dynamicDashboardSrv.update($scope.dashboard); - $rootScope.$emit('template-variable-value-updated'); - $rootScope.$broadcast('refresh'); - }); - }; - - $scope.init(); - - }); - -}); diff --git a/public/app/partials/dashboard.html b/public/app/partials/dashboard.html index 4c5336b88f6..9d20da3d7b4 100644 --- a/public/app/partials/dashboard.html +++ b/public/app/partials/dashboard.html @@ -6,8 +6,7 @@
-
-
+
diff --git a/public/app/partials/submenu.html b/public/app/partials/submenu.html deleted file mode 100644 index 485186696c3..00000000000 --- a/public/app/partials/submenu.html +++ /dev/null @@ -1,30 +0,0 @@ - diff --git a/public/views/index.html b/public/views/index.html index a3e21da4a04..2d05f414658 100644 --- a/public/views/index.html +++ b/public/views/index.html @@ -27,6 +27,7 @@ + From bc21862661c25e025ee9b5cfc1399e8d82f16120 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 13:21:48 +0100 Subject: [PATCH 09/22] tech(playlist): refactor playlistSrv to typescript --- public/app/features/playlist/playlistSrv.js | 56 -------------------- public/app/features/playlist/playlistSrv.ts | 58 +++++++++++++++++++++ 2 files changed, 58 insertions(+), 56 deletions(-) delete mode 100644 public/app/features/playlist/playlistSrv.js create mode 100644 public/app/features/playlist/playlistSrv.ts diff --git a/public/app/features/playlist/playlistSrv.js b/public/app/features/playlist/playlistSrv.js deleted file mode 100644 index f7ea59b6c98..00000000000 --- a/public/app/features/playlist/playlistSrv.js +++ /dev/null @@ -1,56 +0,0 @@ -define([ - 'angular', - 'lodash', - 'app/core/utils/kbn', -], -function (angular, _, kbn) { - 'use strict'; - - var module = angular.module('grafana.services'); - - module.service('playlistSrv', function($location, $rootScope, $timeout) { - var self = this; - - this.next = function() { - $timeout.cancel(self.cancelPromise); - - angular.element(window).unbind('resize'); - var dash = self.dashboards[self.index % self.dashboards.length]; - - $location.url('dashboard/' + dash.uri); - - self.index++; - self.cancelPromise = $timeout(self.next, self.interval); - }; - - this.prev = function() { - self.index = Math.max(self.index - 2, 0); - self.next(); - }; - - this.start = function(dashboards, interval) { - self.stop(); - - self.index = 0; - self.interval = kbn.interval_to_ms(interval); - - self.dashboards = dashboards; - $rootScope.playlistSrv = this; - - self.cancelPromise = $timeout(self.next, self.interval); - self.next(); - }; - - this.stop = function() { - self.index = 0; - - if (self.cancelPromise) { - $timeout.cancel(self.cancelPromise); - } - - $rootScope.playlistSrv = null; - }; - - }); - -}); diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlistSrv.ts new file mode 100644 index 00000000000..2377aae8db2 --- /dev/null +++ b/public/app/features/playlist/playlistSrv.ts @@ -0,0 +1,58 @@ +/// + +import angular from 'angular'; +import coreModule from '../../core/core_module'; +import kbn from 'app/core/utils/kbn'; + +class PlaylistSrv { + private cancelPromise: any + private dashboards: any + private index: number + private interval: any + + /** @ngInject */ + constructor(private $rootScope:any, private $location:any, private $timeout:any) { + } + + next() { + this.$timeout.cancel(this.cancelPromise); + + angular.element(window).unbind('resize'); + var dash = this.dashboards[this.index % this.dashboards.length]; + + this.$location.url('dashboard/' + dash.uri); + + this.index++; + this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); + } + + prevfunction() { + this.index = Math.max(this.index - 2, 0); + this.next(); + } + + start(dashboards, interval) { + this.stop(); + + this.index = 0; + this.interval = kbn.interval_to_ms(interval); + + this.dashboards = dashboards; + this.$rootScope.playlistSrv = this; + + this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); + this.next(); + } + + stop() { + this.index = 0; + + if (this.cancelPromise) { + this.$timeout.cancel(this.cancelPromise); + } + + this.$rootScope.playlistSrv = null; + } +} + +coreModule.service('playlistSrv', PlaylistSrv) From dca503bcbd61a468a2c6ee80bc7af58bc1f051b4 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 13:40:51 +0100 Subject: [PATCH 10/22] feat(playlist): playlistsrv is now started by id --- public/app/features/playlist/playlistSrv.ts | 23 ++++++++++++++----- .../app/features/playlist/playlist_routes.js | 3 +++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlistSrv.ts index 2377aae8db2..efb45d81182 100644 --- a/public/app/features/playlist/playlistSrv.ts +++ b/public/app/features/playlist/playlistSrv.ts @@ -11,7 +11,11 @@ class PlaylistSrv { private interval: any /** @ngInject */ - constructor(private $rootScope:any, private $location:any, private $timeout:any) { + constructor( + private $rootScope:any, + private $location:any, + private $timeout:any, + private backendSrv:any) { } next() { @@ -31,17 +35,24 @@ class PlaylistSrv { this.next(); } - start(dashboards, interval) { + start(playlistId) { this.stop(); this.index = 0; - this.interval = kbn.interval_to_ms(interval); - this.dashboards = dashboards; this.$rootScope.playlistSrv = this; - this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); - this.next(); + this.backendSrv.get('/api/playlists/' + playlistId) + .then((playlist) => { + this.backendSrv.get('/api/playlists/' + playlistId + '/dashboards') + .then((dashboards) => { + this.dashboards = dashboards; + this.interval = kbn.interval_to_ms(playlist.interval); + this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); + + this.next(); + }); + }); } stop() { diff --git a/public/app/features/playlist/playlist_routes.js b/public/app/features/playlist/playlist_routes.js index b9358148f8a..a7737dd4e10 100644 --- a/public/app/features/playlist/playlist_routes.js +++ b/public/app/features/playlist/playlist_routes.js @@ -29,6 +29,8 @@ function (angular) { init: function(backendSrv, playlistSrv, $route) { var playlistId = $route.current.params.id; + playlistSrv.start(playlistId) + /* return backendSrv.get('/api/playlists/' + playlistId) .then(function(playlist) { return backendSrv.get('/api/playlists/' + playlistId + '/dashboards') @@ -36,6 +38,7 @@ function (angular) { playlistSrv.start(dashboards, playlist.interval); }); }); + */ } } }); From 62ae02bdd1c7bd1226a426127e6ad4721b2cd221 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 13:54:32 +0100 Subject: [PATCH 11/22] feat(playlist): reload all dashboards every cycle closes #3706 --- public/app/features/playlist/playlistSrv.ts | 16 ++++++++++++---- public/app/features/playlist/playlist_routes.js | 13 ++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlistSrv.ts index efb45d81182..327055fa66d 100644 --- a/public/app/features/playlist/playlistSrv.ts +++ b/public/app/features/playlist/playlistSrv.ts @@ -9,6 +9,7 @@ class PlaylistSrv { private dashboards: any private index: number private interval: any + private playlistId: number /** @ngInject */ constructor( @@ -22,12 +23,17 @@ class PlaylistSrv { this.$timeout.cancel(this.cancelPromise); angular.element(window).unbind('resize'); - var dash = this.dashboards[this.index % this.dashboards.length]; - this.$location.url('dashboard/' + dash.uri); + if (this.index > this.dashboards.length -1) { + this.start(this.playlistId); + } else { + var dash = this.dashboards[this.index]; - this.index++; - this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); + this.$location.url('dashboard/' + dash.uri); + + this.index++; + this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); + } } prevfunction() { @@ -39,6 +45,7 @@ class PlaylistSrv { this.stop(); this.index = 0; + this.playlistId = playlistId; this.$rootScope.playlistSrv = this; @@ -57,6 +64,7 @@ class PlaylistSrv { stop() { this.index = 0; + this.playlistId = 0; if (this.cancelPromise) { this.$timeout.cancel(this.cancelPromise); diff --git a/public/app/features/playlist/playlist_routes.js b/public/app/features/playlist/playlist_routes.js index a7737dd4e10..0cb618dea5d 100644 --- a/public/app/features/playlist/playlist_routes.js +++ b/public/app/features/playlist/playlist_routes.js @@ -26,19 +26,10 @@ function (angular) { templateUrl: 'app/partials/dashboard.html', controller : 'LoadDashboardCtrl', resolve: { - init: function(backendSrv, playlistSrv, $route) { + init: function(playlistSrv, $route) { var playlistId = $route.current.params.id; - playlistSrv.start(playlistId) - /* - return backendSrv.get('/api/playlists/' + playlistId) - .then(function(playlist) { - return backendSrv.get('/api/playlists/' + playlistId + '/dashboards') - .then(function(dashboards) { - playlistSrv.start(dashboards, playlist.interval); - }); - }); - */ + playlistSrv.start(playlistId); } } }); From 10adc57b3f25ae8270e73106675b354a943cc902 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 14:05:48 +0100 Subject: [PATCH 12/22] style(playlist): fixes some TS hint errors --- public/app/features/playlist/playlistSrv.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlistSrv.ts index 327055fa66d..d2ddf25896f 100644 --- a/public/app/features/playlist/playlistSrv.ts +++ b/public/app/features/playlist/playlistSrv.ts @@ -5,19 +5,14 @@ import coreModule from '../../core/core_module'; import kbn from 'app/core/utils/kbn'; class PlaylistSrv { - private cancelPromise: any - private dashboards: any - private index: number - private interval: any - private playlistId: number + private cancelPromise: any; + private dashboards: any; + private index: number; + private interval: any; + private playlistId: number; /** @ngInject */ - constructor( - private $rootScope:any, - private $location:any, - private $timeout:any, - private backendSrv:any) { - } + constructor(private $rootScope:any, private $location:any, private $timeout:any, private backendSrv:any) { } next() { this.$timeout.cancel(this.cancelPromise); @@ -74,4 +69,4 @@ class PlaylistSrv { } } -coreModule.service('playlistSrv', PlaylistSrv) +coreModule.service('playlistSrv', PlaylistSrv); From 88e9161e576bdf2674d9651f68a52b836eff3b28 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 14:13:11 +0100 Subject: [PATCH 13/22] style(playlist): fixes some TS hint errors --- public/app/features/playlist/playlistSrv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlistSrv.ts index d2ddf25896f..bae60804643 100644 --- a/public/app/features/playlist/playlistSrv.ts +++ b/public/app/features/playlist/playlistSrv.ts @@ -12,7 +12,7 @@ class PlaylistSrv { private playlistId: number; /** @ngInject */ - constructor(private $rootScope:any, private $location:any, private $timeout:any, private backendSrv:any) { } + constructor(private $rootScope: any, private $location: any, private $timeout: any, private backendSrv: any) { } next() { this.$timeout.cancel(this.cancelPromise); From 61a655f1995801d2d35e32fc7fa7c2c002628c71 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 14:37:53 +0100 Subject: [PATCH 14/22] feat(hooks): add grunt test to pre commit --- .hooks/pre-commit | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.hooks/pre-commit b/.hooks/pre-commit index 83ec0adba1a..2519d4c44f4 100755 --- a/.hooks/pre-commit +++ b/.hooks/pre-commit @@ -5,3 +5,6 @@ if [ $? -gt 0 ]; then echo "Some files aren't formatted, please run 'go fmt ./pkg/...' to format your source code before committing" exit 1 fi + + +grunt test From c12aa0e8ce73ba5af3aa05089b77c6aea61f70c3 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 14:41:17 +0100 Subject: [PATCH 15/22] feat(hooks): add scripts for symlinking git hooks --- symlink_git_hooks.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 symlink_git_hooks.sh diff --git a/symlink_git_hooks.sh b/symlink_git_hooks.sh new file mode 100644 index 00000000000..7c3b58feaca --- /dev/null +++ b/symlink_git_hooks.sh @@ -0,0 +1,3 @@ +#/bin/bash + +ln -s .hooks/* .git/hooks/ From 568832c5af767ba9f15179fade4aa8e2f308b741 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 14:58:46 +0100 Subject: [PATCH 16/22] style(playlist): improves variable name --- public/app/features/playlist/playlistSrv.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlistSrv.ts index bae60804643..d5d386a88ca 100644 --- a/public/app/features/playlist/playlistSrv.ts +++ b/public/app/features/playlist/playlistSrv.ts @@ -19,7 +19,9 @@ class PlaylistSrv { angular.element(window).unbind('resize'); - if (this.index > this.dashboards.length -1) { + var playedAllDashboards = this.index > this.dashboards.length - 1; + + if (playedAllDashboards) { this.start(this.playlistId); } else { var dash = this.dashboards[this.index]; From 66eebd1ac3326ed75d36257701f0da27c3979233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 18 Jan 2016 16:00:11 +0100 Subject: [PATCH 17/22] refactor(playlist): refactor of playlist feature, and PR #3776 --- pkg/api/api.go | 4 +- pkg/api/playlist.go | 40 ++++++------- pkg/models/playlist.go | 60 +++++++++++-------- .../sqlstore/migrations/playlist_mig.go | 13 ++-- pkg/services/sqlstore/playlist.go | 51 ++++++++-------- public/app/core/components/grafana_app.ts | 1 - public/app/features/playlist/all.js | 2 +- .../features/playlist/partials/playlist.html | 4 +- .../features/playlist/partials/playlists.html | 8 +-- .../features/playlist/playlist_edit_ctrl.js | 5 +- .../app/features/playlist/playlist_routes.js | 3 - .../{playlistSrv.ts => playlist_srv.ts} | 27 ++++----- .../app/features/playlist/playlists_ctrl.js | 42 ++++++------- 13 files changed, 131 insertions(+), 129 deletions(-) rename public/app/features/playlist/{playlistSrv.ts => playlist_srv.ts} (61%) diff --git a/pkg/api/api.go b/pkg/api/api.go index 1770b210439..ea434ed71da 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -189,8 +189,8 @@ func Register(r *macaron.Macaron) { r.Get("/:id/items", ValidateOrgPlaylist, wrap(GetPlaylistItems)) r.Get("/:id/dashboards", ValidateOrgPlaylist, wrap(GetPlaylistDashboards)) r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist)) - r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistQuery{}), ValidateOrgPlaylist, wrap(UpdatePlaylist)) - r.Post("/", reqEditorRole, bind(m.CreatePlaylistQuery{}), wrap(CreatePlaylist)) + r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistCommand{}), ValidateOrgPlaylist, wrap(UpdatePlaylist)) + r.Post("/", reqEditorRole, bind(m.CreatePlaylistCommand{}), wrap(CreatePlaylist)) }) // Search diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index d9503114ff3..c053b4cb8d1 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -2,11 +2,12 @@ package api import ( "errors" + "strconv" + "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" - "strconv" ) func ValidateOrgPlaylist(c *middleware.Context) { @@ -33,8 +34,8 @@ func SearchPlaylists(c *middleware.Context) Response { limit = 1000 } - searchQuery := m.PlaylistQuery{ - Title: query, + searchQuery := m.GetPlaylistsQuery{ + Name: query, Limit: limit, OrgId: c.OrgId, } @@ -59,7 +60,7 @@ func GetPlaylist(c *middleware.Context) Response { dto := &m.PlaylistDTO{ Id: cmd.Result.Id, - Title: cmd.Result.Title, + Name: cmd.Result.Name, Interval: cmd.Result.Interval, OrgId: cmd.Result.OrgId, Items: playlistDTOs, @@ -159,7 +160,7 @@ func GetPlaylistDashboards(c *middleware.Context) Response { func DeletePlaylist(c *middleware.Context) Response { id := c.ParamsInt64(":id") - cmd := m.DeletePlaylistQuery{Id: id} + cmd := m.DeletePlaylistCommand{Id: id, OrgId: c.OrgId} if err := bus.Dispatch(&cmd); err != nil { return ApiError(500, "Failed to delete playlist", err) } @@ -167,28 +168,27 @@ func DeletePlaylist(c *middleware.Context) Response { return Json(200, "") } -func CreatePlaylist(c *middleware.Context, query m.CreatePlaylistQuery) Response { - query.OrgId = c.OrgId - err := bus.Dispatch(&query) - if err != nil { +func CreatePlaylist(c *middleware.Context, cmd m.CreatePlaylistCommand) Response { + cmd.OrgId = c.OrgId + + if err := bus.Dispatch(&cmd); err != nil { return ApiError(500, "Failed to create playlist", err) } - return Json(200, query.Result) + return Json(200, cmd.Result) } -func UpdatePlaylist(c *middleware.Context, query m.UpdatePlaylistQuery) Response { - err := bus.Dispatch(&query) +func UpdatePlaylist(c *middleware.Context, cmd m.UpdatePlaylistCommand) Response { + cmd.OrgId = c.OrgId + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "Failed to save playlist", err) + } + + playlistDTOs, err := LoadPlaylistItemDTOs(cmd.Id) if err != nil { return ApiError(500, "Failed to save playlist", err) } - playlistDTOs, err := LoadPlaylistItemDTOs(query.Id) - if err != nil { - return ApiError(500, "Failed to save playlist", err) - } - - query.Result.Items = playlistDTOs - - return Json(200, query.Result) + cmd.Result.Items = playlistDTOs + return Json(200, cmd.Result) } diff --git a/pkg/models/playlist.go b/pkg/models/playlist.go index 5d861dc11b0..4c37c369b3e 100644 --- a/pkg/models/playlist.go +++ b/pkg/models/playlist.go @@ -13,14 +13,14 @@ var ( // Playlist model type Playlist struct { Id int64 `json:"id"` - Title string `json:"title"` + Name string `json:"name"` Interval string `json:"interval"` OrgId int64 `json:"-"` } type PlaylistDTO struct { Id int64 `json:"id"` - Title string `json:"title"` + Name string `json:"name"` Interval string `json:"interval"` OrgId int64 `json:"-"` Items []PlaylistItemDTO `json:"items"` @@ -71,35 +71,47 @@ type PlaylistDashboardDto struct { // // COMMANDS // -type PlaylistQuery struct { - Title string - Limit int - OrgId int64 - Result Playlists -} - -type UpdatePlaylistQuery struct { - Id int64 - Title string - Type string - Interval string - Items []PlaylistItemDTO +type UpdatePlaylistCommand struct { + OrgId int64 `json:"-"` + Id int64 `json:"id" binding:"Required"` + Name string `json:"name" binding:"Required"` + Type string `json:"type"` + Interval string `json:"interval"` + Data []int64 `json:"data"` + Items []PlaylistItemDTO `json:"items"` Result *PlaylistDTO } -type CreatePlaylistQuery struct { - Title string - Type string - Interval string - Data []int64 - OrgId int64 - Items []PlaylistItemDTO +type CreatePlaylistCommand struct { + Name string `json:"name" binding:"Required"` + Type string `json:"type"` + Interval string `json:"interval"` + Data []int64 `json:"data"` + Items []PlaylistItemDTO `json:"items"` + OrgId int64 `json:"-"` Result *Playlist } +type DeletePlaylistCommand struct { + Id int64 + OrgId int64 +} + +// +// QUERIES +// + +type GetPlaylistsQuery struct { + Name string + Limit int + OrgId int64 + + Result Playlists +} + type GetPlaylistByIdQuery struct { Id int64 Result *Playlist @@ -114,7 +126,3 @@ type GetPlaylistDashboardsQuery struct { DashboardIds []int64 Result *PlaylistDashboards } - -type DeletePlaylistQuery struct { - Id int64 -} diff --git a/pkg/services/sqlstore/migrations/playlist_mig.go b/pkg/services/sqlstore/migrations/playlist_mig.go index b972994e45b..636fc091006 100644 --- a/pkg/services/sqlstore/migrations/playlist_mig.go +++ b/pkg/services/sqlstore/migrations/playlist_mig.go @@ -3,20 +3,23 @@ package migrations import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" func addPlaylistMigrations(mg *Migrator) { - playlistV1 := Table{ + mg.AddMigration("Drop old table playlist table", NewDropTableMigration("playlist")) + mg.AddMigration("Drop old table playlist_item table", NewDropTableMigration("playlist_item")) + + playlistV2 := Table{ Name: "playlist", Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, - {Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "interval", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "org_id", Type: DB_BigInt, Nullable: false}, }, } // create table - mg.AddMigration("create playlist table v1", NewAddTableMigration(playlistV1)) + mg.AddMigration("create playlist table v2", NewAddTableMigration(playlistV2)) - playlistItemV1 := Table{ + playlistItemV2 := Table{ Name: "playlist_item", Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, @@ -28,5 +31,5 @@ func addPlaylistMigrations(mg *Migrator) { }, } - mg.AddMigration("create playlist item table v1", NewAddTableMigration(playlistItemV1)) + mg.AddMigration("create playlist item table v2", NewAddTableMigration(playlistItemV2)) } diff --git a/pkg/services/sqlstore/playlist.go b/pkg/services/sqlstore/playlist.go index fd3a49b2b2a..ee0b3b950c7 100644 --- a/pkg/services/sqlstore/playlist.go +++ b/pkg/services/sqlstore/playlist.go @@ -2,6 +2,7 @@ package sqlstore import ( "fmt" + "github.com/go-xorm/xorm" "github.com/grafana/grafana/pkg/bus" @@ -18,13 +19,13 @@ func init() { bus.AddHandler("sql", GetPlaylistItem) } -func CreatePlaylist(query *m.CreatePlaylistQuery) error { +func CreatePlaylist(cmd *m.CreatePlaylistCommand) error { var err error playlist := m.Playlist{ - Title: query.Title, - Interval: query.Interval, - OrgId: query.OrgId, + Name: cmd.Name, + Interval: cmd.Interval, + OrgId: cmd.OrgId, } _, err = x.Insert(&playlist) @@ -32,7 +33,7 @@ func CreatePlaylist(query *m.CreatePlaylistQuery) error { fmt.Printf("%v", playlist.Id) playlistItems := make([]m.PlaylistItem, 0) - for _, item := range query.Items { + for _, item := range cmd.Items { playlistItems = append(playlistItems, m.PlaylistItem{ PlaylistId: playlist.Id, Type: item.Type, @@ -44,40 +45,40 @@ func CreatePlaylist(query *m.CreatePlaylistQuery) error { _, err = x.Insert(&playlistItems) - query.Result = &playlist + cmd.Result = &playlist return err } -func UpdatePlaylist(query *m.UpdatePlaylistQuery) error { +func UpdatePlaylist(cmd *m.UpdatePlaylistCommand) error { var err error - x.Logger.SetLevel(5) playlist := m.Playlist{ - Id: query.Id, - Title: query.Title, - Interval: query.Interval, + Id: cmd.Id, + OrgId: cmd.OrgId, + Name: cmd.Name, + Interval: cmd.Interval, } - existingPlaylist := x.Where("id = ?", query.Id).Find(m.Playlist{}) + existingPlaylist := x.Where("id = ? AND org_id = ?", cmd.Id, cmd.OrgId).Find(m.Playlist{}) if existingPlaylist == nil { return m.ErrPlaylistNotFound } - query.Result = &m.PlaylistDTO{ + cmd.Result = &m.PlaylistDTO{ Id: playlist.Id, OrgId: playlist.OrgId, - Title: playlist.Title, + Name: playlist.Name, Interval: playlist.Interval, } - _, err = x.Id(query.Id).Cols("id", "title", "timespan").Update(&playlist) + _, err = x.Id(cmd.Id).Cols("id", "name", "interval").Update(&playlist) if err != nil { return err } rawSql := "DELETE FROM playlist_item WHERE playlist_id = ?" - _, err = x.Exec(rawSql, query.Id) + _, err = x.Exec(rawSql, cmd.Id) if err != nil { return err @@ -85,7 +86,7 @@ func UpdatePlaylist(query *m.UpdatePlaylistQuery) error { playlistItems := make([]m.PlaylistItem, 0) - for _, item := range query.Items { + for _, item := range cmd.Items { playlistItems = append(playlistItems, m.PlaylistItem{ PlaylistId: playlist.Id, Type: item.Type, @@ -113,33 +114,33 @@ func GetPlaylist(query *m.GetPlaylistByIdQuery) error { return err } -func DeletePlaylist(query *m.DeletePlaylistQuery) error { - if query.Id == 0 { +func DeletePlaylist(cmd *m.DeletePlaylistCommand) error { + if cmd.Id == 0 { return m.ErrCommandValidationFailed } return inTransaction(func(sess *xorm.Session) error { - var rawPlaylistSql = "DELETE FROM playlist WHERE id = ?" - _, err := sess.Exec(rawPlaylistSql, query.Id) + var rawPlaylistSql = "DELETE FROM playlist WHERE id = ? and org_id = ?" + _, err := sess.Exec(rawPlaylistSql, cmd.Id, cmd.OrgId) if err != nil { return err } var rawItemSql = "DELETE FROM playlist_item WHERE playlist_id = ?" - _, err2 := sess.Exec(rawItemSql, query.Id) + _, err2 := sess.Exec(rawItemSql, cmd.Id) return err2 }) } -func SearchPlaylists(query *m.PlaylistQuery) error { +func SearchPlaylists(query *m.GetPlaylistsQuery) error { var playlists = make(m.Playlists, 0) sess := x.Limit(query.Limit) - if query.Title != "" { - sess.Where("title LIKE ?", query.Title) + if query.Name != "" { + sess.Where("name LIKE ?", query.Name) } sess.Where("org_id = ?", query.OrgId) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index 07799de518b..c93599f7f3a 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -185,7 +185,6 @@ export function grafanaAppDirective() { // hide popovers var popover = elem.find('.popover'); - console.log(target.parents('.graph-legend').length); if (popover.length > 0 && target.parents('.graph-legend').length === 0) { popover.hide(); } diff --git a/public/app/features/playlist/all.js b/public/app/features/playlist/all.js index df0d6983c06..a37de0f4612 100644 --- a/public/app/features/playlist/all.js +++ b/public/app/features/playlist/all.js @@ -1,6 +1,6 @@ define([ './playlists_ctrl', - './playlistSrv', + './playlist_srv', './playlist_edit_ctrl', './playlist_routes' ], function () {}); diff --git a/public/app/features/playlist/partials/playlist.html b/public/app/features/playlist/partials/playlist.html index bf5fe4fd485..6f47c65568f 100644 --- a/public/app/features/playlist/partials/playlist.html +++ b/public/app/features/playlist/partials/playlist.html @@ -1,7 +1,7 @@ @@ -20,7 +20,7 @@ Name
  • - +
  • diff --git a/public/app/features/playlist/partials/playlists.html b/public/app/features/playlist/partials/playlists.html index 9f95c64a566..a8a4724b34c 100644 --- a/public/app/features/playlist/partials/playlists.html +++ b/public/app/features/playlist/partials/playlists.html @@ -1,12 +1,12 @@ - +
    - +

    Saved playlists

    @@ -21,7 +21,7 @@ - {{playlist.title}} + {{playlist.name}} playlists/play/{{playlist.id}} diff --git a/public/app/features/playlist/playlist_edit_ctrl.js b/public/app/features/playlist/playlist_edit_ctrl.js index 4efda3695eb..3817ec12634 100644 --- a/public/app/features/playlist/playlist_edit_ctrl.js +++ b/public/app/features/playlist/playlist_edit_ctrl.js @@ -13,7 +13,9 @@ function (angular, config, _) { $scope.foundPlaylistItems = []; $scope.searchQuery = ''; $scope.loading = false; - $scope.playlist = {}; + $scope.playlist = { + interval: '10m', + }; $scope.playlistItems = []; $scope.init = function() { @@ -68,7 +70,6 @@ function (angular, config, _) { $scope.playlistItems.push(playlistItem); $scope.filterFoundPlaylistItems(); - }; $scope.removePlaylistItem = function(playlistItem) { diff --git a/public/app/features/playlist/playlist_routes.js b/public/app/features/playlist/playlist_routes.js index 0cb618dea5d..2de1f7b30c8 100644 --- a/public/app/features/playlist/playlist_routes.js +++ b/public/app/features/playlist/playlist_routes.js @@ -23,12 +23,9 @@ function (angular) { controller : 'PlaylistEditCtrl' }) .when('/playlists/play/:id', { - templateUrl: 'app/partials/dashboard.html', - controller : 'LoadDashboardCtrl', resolve: { init: function(playlistSrv, $route) { var playlistId = $route.current.params.id; - playlistSrv.start(playlistId); } } diff --git a/public/app/features/playlist/playlistSrv.ts b/public/app/features/playlist/playlist_srv.ts similarity index 61% rename from public/app/features/playlist/playlistSrv.ts rename to public/app/features/playlist/playlist_srv.ts index bae60804643..c2106878b0f 100644 --- a/public/app/features/playlist/playlistSrv.ts +++ b/public/app/features/playlist/playlist_srv.ts @@ -17,9 +17,7 @@ class PlaylistSrv { next() { this.$timeout.cancel(this.cancelPromise); - angular.element(window).unbind('resize'); - - if (this.index > this.dashboards.length -1) { + if (this.index > this.dashboards.length - 1) { this.start(this.playlistId); } else { var dash = this.dashboards[this.index]; @@ -27,11 +25,11 @@ class PlaylistSrv { this.$location.url('dashboard/' + dash.uri); this.index++; - this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); + this.cancelPromise = this.$timeout(() => this.next(), this.interval); } } - prevfunction() { + prev() { this.index = Math.max(this.index - 2, 0); this.next(); } @@ -41,20 +39,15 @@ class PlaylistSrv { this.index = 0; this.playlistId = playlistId; - this.$rootScope.playlistSrv = this; - this.backendSrv.get('/api/playlists/' + playlistId) - .then((playlist) => { - this.backendSrv.get('/api/playlists/' + playlistId + '/dashboards') - .then((dashboards) => { - this.dashboards = dashboards; - this.interval = kbn.interval_to_ms(playlist.interval); - this.cancelPromise = this.$timeout(() => { this.next(); }, this.interval); - - this.next(); - }); + this.backendSrv.get(`/api/playlists/${playlistId}`).then(playlist => { + this.backendSrv.get(`/api/playlists/${playlistId}/dashboards`).then(dashboards => { + this.dashboards = dashboards; + this.interval = kbn.interval_to_ms(playlist.interval); + this.next(); }); + }); } stop() { @@ -62,7 +55,7 @@ class PlaylistSrv { this.playlistId = 0; if (this.cancelPromise) { - this.$timeout.cancel(this.cancelPromise); + this.$timeout.cancel(this.cancelPromise); } this.$rootScope.playlistSrv = null; diff --git a/public/app/features/playlist/playlists_ctrl.js b/public/app/features/playlist/playlists_ctrl.js index b4bc464825c..375492e6772 100644 --- a/public/app/features/playlist/playlists_ctrl.js +++ b/public/app/features/playlist/playlists_ctrl.js @@ -13,31 +13,31 @@ function (angular, _) { $scope.playlists = result; }); - $scope.removePlaylist = function(playlist) { - var modalScope = $scope.$new(true); + $scope.removePlaylistConfirmed = function(playlist) { + _.remove($scope.playlists, {id: playlist.id}); - modalScope.playlist = playlist; - modalScope.removePlaylist = function() { - modalScope.dismiss(); - _.remove($scope.playlists, {id: playlist.id}); - - backendSrv.delete('/api/playlists/' + playlist.id) - .then(function() { - $scope.appEvent('alert-success', ['Playlist deleted', '']); - }, function() { - $scope.appEvent('alert-error', ['Unable to delete playlist', '']); - $scope.playlists.push(playlist); - }); - }; - - $scope.appEvent('show-modal', { - src: './app/features/playlist/partials/playlist-remove.html', - scope: modalScope + backendSrv.delete('/api/playlists/' + playlist.id) + .then(function() { + $scope.appEvent('alert-success', ['Playlist deleted', '']); + }, function() { + $scope.appEvent('alert-error', ['Unable to delete playlist', '']); + $scope.playlists.push(playlist); }); }; - $scope.createPlaylist = function() { - $location.path('/playlists/create'); + $scope.removePlaylist = function(playlist) { + + $scope.appEvent('confirm-modal', { + title: 'Confirm delete playlist', + text: 'Are you sure you want to delete playlist ' + playlist.name + '?', + yesText: "Delete", + icon: "fa-warning", + onConfirm: function() { + $scope.removePlaylistConfirmed(playlist); + } + }); + }; + }); }); From 1d4803cff03d07af6a91a127034f4ee02c123bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 18 Jan 2016 16:18:04 +0100 Subject: [PATCH 18/22] fix(singlestat): fixed issue with singlestat and drilldown link introduced in recent commit, fixes #3777 --- public/app/plugins/panel/singlestat/module.js | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/public/app/plugins/panel/singlestat/module.js b/public/app/plugins/panel/singlestat/module.js index 2ed8221150a..8ce441818e6 100644 --- a/public/app/plugins/panel/singlestat/module.js +++ b/public/app/plugins/panel/singlestat/module.js @@ -23,6 +23,7 @@ function (SingleStatCtrl, _, $) { elem = inner; $panelContainer = elem.parents('.panel-container'); firstRender = false; + hookupDrilldownLinkTooltip(); } } @@ -186,41 +187,44 @@ function (SingleStatCtrl, _, $) { } } - // drilldown link tooltip - var drilldownTooltip = $('
    hello
    "'); + function hookupDrilldownLinkTooltip() { + // drilldown link tooltip + var drilldownTooltip = $('
    hello
    "'); - elem.mouseleave(function() { - if (panel.links.length === 0) { return;} - drilldownTooltip.detach(); - }); + elem.mouseleave(function() { + if (panel.links.length === 0) { return;} + drilldownTooltip.detach(); + }); - elem.click(function() { - if (!linkInfo) { return; } + elem.click(function(evt) { + if (!linkInfo) { return; } + // ignore title clicks in title + if ($(evt).parents('.panel-header').length > 0) { return; } - if (linkInfo.target === '_blank') { - var redirectWindow = window.open(linkInfo.href, '_blank'); - redirectWindow.location; - return; - } + if (linkInfo.target === '_blank') { + var redirectWindow = window.open(linkInfo.href, '_blank'); + redirectWindow.location; + return; + } - if (linkInfo.href.indexOf('http') === 0) { - window.location.href = linkInfo.href; - } else { - $timeout(function() { - $location.url(linkInfo.href); - }); - } + if (linkInfo.href.indexOf('http') === 0) { + window.location.href = linkInfo.href; + } else { + $timeout(function() { + $location.url(linkInfo.href); + }); + } - drilldownTooltip.detach(); - }); + drilldownTooltip.detach(); + }); - elem.mousemove(function(e) { - if (!linkInfo) { return;} + elem.mousemove(function(e) { + if (!linkInfo) { return;} - drilldownTooltip.text('click to go to: ' + linkInfo.title); - - drilldownTooltip.place_tt(e.pageX+20, e.pageY-15); - }); + drilldownTooltip.text('click to go to: ' + linkInfo.title); + drilldownTooltip.place_tt(e.pageX+20, e.pageY-15); + }); + } } }; } From 4a54edd8bb0a3412753bc3b2634179e398c1f924 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 17:12:24 +0100 Subject: [PATCH 19/22] feat(playlist): clicks outside control stops playlist fixes #3711 --- public/app/core/components/grafana_app.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index c93599f7f3a..77583536a4f 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -139,7 +139,7 @@ export class GrafanaCtrl { } } -export function grafanaAppDirective() { +export function grafanaAppDirective(playlistSrv) { return { restrict: 'E', controller: GrafanaCtrl, @@ -170,6 +170,10 @@ export function grafanaAppDirective() { return; } + if (target.parents('.dash-playlist-actions').length === 0) { + playlistSrv.stop(); + } + // hide search if (elem.find('.search-container').length > 0) { if (target.parents('.search-container').length === 0) { From eb8871a4bd39e2ae2e1b00bce6de78b34f304c54 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 17:31:33 +0100 Subject: [PATCH 20/22] fix(playlist): add nginject for prod build --- public/app/core/components/grafana_app.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index 77583536a4f..15c7f7fdb3b 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -139,6 +139,7 @@ export class GrafanaCtrl { } } +/** @ngInject */ export function grafanaAppDirective(playlistSrv) { return { restrict: 'E', From d94896cf10a1d8fe6bb6e5fa4e06c7df4d39e9b1 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 18 Jan 2016 17:31:53 +0100 Subject: [PATCH 21/22] feat(build): make symlink script executible --- symlink_git_hooks.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 symlink_git_hooks.sh diff --git a/symlink_git_hooks.sh b/symlink_git_hooks.sh old mode 100644 new mode 100755 From 3418db1dcd1d048081a764dbd125cfafa05556e3 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Mon, 18 Jan 2016 10:41:14 -0600 Subject: [PATCH 22/22] Fix grammatical error in graphite datasource doc Replace "you" with "your". --- docs/sources/datasources/graphite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/datasources/graphite.md b/docs/sources/datasources/graphite.md index c4cae0b0c65..af53d0bf60c 100644 --- a/docs/sources/datasources/graphite.md +++ b/docs/sources/datasources/graphite.md @@ -25,7 +25,7 @@ Name | Description ------------ | ------------- Name | The data source name, important that this is the same as in Grafana v1.x if you plan to import old dashboards. Default | Default data source means that it will be pre-selected for new panels. -Url | The http protocol, ip and port of you graphite-web or graphite-api install. +Url | The http protocol, ip and port of your graphite-web or graphite-api install. Access | Proxy = access via Grafana backend, Direct = access directory from browser.