mirror of https://github.com/grafana/grafana
parent
b3f3b70b90
commit
1f9922a5aa
@ -1,22 +1,22 @@ |
||||
#! /usr/bin/env bash |
||||
|
||||
deb_ver=3.0.0-beta41460581169 |
||||
rpm_ver=3.0.0-beta41460581169 |
||||
deb_ver=3.0.0-beta51460658374 |
||||
rpm_ver=3.0.0-beta51460658374 |
||||
|
||||
#rpm_ver=3.0.0-1 |
||||
|
||||
wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb |
||||
#wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb |
||||
|
||||
#package_cloud push grafana/stable/debian/jessie grafana_${deb_ver}_amd64.deb |
||||
#package_cloud push grafana/stable/debian/wheezy grafana_${deb_ver}_amd64.deb |
||||
|
||||
package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb |
||||
package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb |
||||
#package_cloud push grafana/testing/debian/jessie grafana_${deb_ver}_amd64.deb |
||||
#package_cloud push grafana/testing/debian/wheezy grafana_${deb_ver}_amd64.deb |
||||
|
||||
wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm |
||||
#wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm |
||||
|
||||
package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm |
||||
ackage_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm |
||||
#package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm |
||||
package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm |
||||
|
||||
# package_cloud push grafana/stable/el/7 grafana-${version}-1.x86_64.rpm |
||||
# package_cloud push grafana/stable/el/6 grafana-${version}-1.x86_64.rpm |
||||
|
@ -1,147 +0,0 @@ |
||||
define([ |
||||
'angular', |
||||
'jquery', |
||||
'app/core/config', |
||||
'moment', |
||||
], |
||||
function (angular, $, config, moment) { |
||||
"use strict"; |
||||
|
||||
var module = angular.module('grafana.controllers'); |
||||
|
||||
module.controller('DashboardCtrl', function( |
||||
$scope, |
||||
$rootScope, |
||||
dashboardKeybindings, |
||||
timeSrv, |
||||
templateValuesSrv, |
||||
dynamicDashboardSrv, |
||||
dashboardSrv, |
||||
unsavedChangesSrv, |
||||
dashboardViewStateSrv, |
||||
contextSrv, |
||||
$timeout) { |
||||
|
||||
$scope.editor = { index: 0 }; |
||||
$scope.panels = config.panels; |
||||
|
||||
var resizeEventTimeout; |
||||
|
||||
this.init = function(dashboard) { |
||||
$scope.resetRow(); |
||||
$scope.registerWindowResizeEvent(); |
||||
$scope.onAppEvent('show-json-editor', $scope.showJsonEditor); |
||||
$scope.setupDashboard(dashboard); |
||||
}; |
||||
|
||||
$scope.setupDashboard = function(data) { |
||||
$rootScope.performance.dashboardLoadStart = new Date().getTime(); |
||||
$rootScope.performance.panelsInitialized = 0; |
||||
$rootScope.performance.panelsRendered = 0; |
||||
|
||||
var dashboard = dashboardSrv.create(data.dashboard, data.meta); |
||||
dashboardSrv.setCurrent(dashboard); |
||||
|
||||
// init services
|
||||
timeSrv.init(dashboard); |
||||
|
||||
// template values service needs to initialize completely before
|
||||
// the rest of the dashboard can load
|
||||
templateValuesSrv.init(dashboard).finally(function() { |
||||
dynamicDashboardSrv.init(dashboard); |
||||
unsavedChangesSrv.init(dashboard, $scope); |
||||
|
||||
$scope.dashboard = dashboard; |
||||
$scope.dashboardMeta = dashboard.meta; |
||||
$scope.dashboardViewState = dashboardViewStateSrv.create($scope); |
||||
|
||||
dashboardKeybindings.shortcuts($scope); |
||||
|
||||
$scope.updateSubmenuVisibility(); |
||||
$scope.setWindowTitleAndTheme(); |
||||
|
||||
$scope.appEvent("dashboard-loaded", $scope.dashboard); |
||||
}).catch(function(err) { |
||||
if (err.data && err.data.message) { err.message = err.data.message; } |
||||
$scope.appEvent("alert-error", ['Dashboard init failed', 'Template variables could not be initialized: ' + err.message]); |
||||
}); |
||||
}; |
||||
|
||||
$scope.updateSubmenuVisibility = function() { |
||||
$scope.submenuEnabled = $scope.dashboard.isSubmenuFeaturesEnabled(); |
||||
}; |
||||
|
||||
$scope.setWindowTitleAndTheme = function() { |
||||
window.document.title = config.window_title_prefix + $scope.dashboard.title; |
||||
}; |
||||
|
||||
$scope.broadcastRefresh = function() { |
||||
$rootScope.performance.panelsRendered = 0; |
||||
$rootScope.$broadcast('refresh'); |
||||
}; |
||||
|
||||
$scope.addRow = function(dash, row) { |
||||
dash.rows.push(row); |
||||
}; |
||||
|
||||
$scope.addRowDefault = function() { |
||||
$scope.resetRow(); |
||||
$scope.row.title = 'New row'; |
||||
$scope.addRow($scope.dashboard, $scope.row); |
||||
}; |
||||
|
||||
$scope.resetRow = function() { |
||||
$scope.row = { |
||||
title: '', |
||||
height: '250px', |
||||
editable: true, |
||||
}; |
||||
}; |
||||
|
||||
$scope.showJsonEditor = function(evt, options) { |
||||
var editScope = $rootScope.$new(); |
||||
editScope.object = options.object; |
||||
editScope.updateHandler = options.updateHandler; |
||||
$scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope }); |
||||
}; |
||||
|
||||
$scope.onDrop = function(panelId, row, dropTarget) { |
||||
var info = $scope.dashboard.getPanelInfoById(panelId); |
||||
if (dropTarget) { |
||||
var dropInfo = $scope.dashboard.getPanelInfoById(dropTarget.id); |
||||
dropInfo.row.panels[dropInfo.index] = info.panel; |
||||
info.row.panels[info.index] = dropTarget; |
||||
var dragSpan = info.panel.span; |
||||
info.panel.span = dropTarget.span; |
||||
dropTarget.span = dragSpan; |
||||
} |
||||
else { |
||||
info.row.panels.splice(info.index, 1); |
||||
info.panel.span = 12 - $scope.dashboard.rowSpan(row); |
||||
row.panels.push(info.panel); |
||||
} |
||||
|
||||
$rootScope.$broadcast('render'); |
||||
}; |
||||
|
||||
$scope.registerWindowResizeEvent = function() { |
||||
angular.element(window).bind('resize', function() { |
||||
$timeout.cancel(resizeEventTimeout); |
||||
resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200); |
||||
}); |
||||
$scope.$on('$destroy', function() { |
||||
angular.element(window).unbind('resize'); |
||||
}); |
||||
}; |
||||
|
||||
$scope.timezoneChanged = function() { |
||||
$rootScope.$broadcast("refresh"); |
||||
}; |
||||
|
||||
$scope.formatDate = function(date) { |
||||
return moment(date).format('MMM Do YYYY, h:mm:ss a'); |
||||
}; |
||||
|
||||
}); |
||||
|
||||
}); |
@ -0,0 +1,154 @@ |
||||
///<reference path="../../headers/common.d.ts" />
|
||||
|
||||
import config from 'app/core/config'; |
||||
import angular from 'angular'; |
||||
import moment from 'moment'; |
||||
import _ from 'lodash'; |
||||
|
||||
import coreModule from 'app/core/core_module'; |
||||
import {DynamicDashboardSrv} from './dynamic_dashboard_srv'; |
||||
|
||||
export class DashboardCtrl { |
||||
|
||||
/** @ngInject */ |
||||
constructor( |
||||
private $scope, |
||||
private $rootScope, |
||||
dashboardKeybindings, |
||||
timeSrv, |
||||
templateValuesSrv, |
||||
dashboardSrv, |
||||
unsavedChangesSrv, |
||||
dashboardViewStateSrv, |
||||
contextSrv, |
||||
$timeout) { |
||||
|
||||
$scope.editor = { index: 0 }; |
||||
$scope.panels = config.panels; |
||||
$scope.dynamicDashboardSrv = new DynamicDashboardSrv(); |
||||
|
||||
var resizeEventTimeout; |
||||
|
||||
$scope.setupDashboard = function(data) { |
||||
$rootScope.performance.dashboardLoadStart = new Date().getTime(); |
||||
$rootScope.performance.panelsInitialized = 0; |
||||
$rootScope.performance.panelsRendered = 0; |
||||
|
||||
var dashboard = dashboardSrv.create(data.dashboard, data.meta); |
||||
dashboardSrv.setCurrent(dashboard); |
||||
|
||||
// init services
|
||||
timeSrv.init(dashboard); |
||||
|
||||
// template values service needs to initialize completely before
|
||||
// the rest of the dashboard can load
|
||||
templateValuesSrv.init(dashboard).finally(function() { |
||||
$scope.dynamicDashboardSrv.init(dashboard); |
||||
|
||||
unsavedChangesSrv.init(dashboard, $scope); |
||||
|
||||
$scope.dashboard = dashboard; |
||||
$scope.dashboardMeta = dashboard.meta; |
||||
$scope.dashboardViewState = dashboardViewStateSrv.create($scope); |
||||
|
||||
dashboardKeybindings.shortcuts($scope); |
||||
|
||||
$scope.updateSubmenuVisibility(); |
||||
$scope.setWindowTitleAndTheme(); |
||||
|
||||
$scope.appEvent("dashboard-loaded", $scope.dashboard); |
||||
}).catch(function(err) { |
||||
if (err.data && err.data.message) { err.message = err.data.message; } |
||||
$scope.appEvent("alert-error", ['Dashboard init failed', 'Template variables could not be initialized: ' + err.message]); |
||||
}); |
||||
}; |
||||
|
||||
$scope.templateVariableUpdated = function() { |
||||
$scope.dynamicDashboardSrv.update($scope.dashboard); |
||||
}; |
||||
|
||||
$scope.updateSubmenuVisibility = function() { |
||||
$scope.submenuEnabled = $scope.dashboard.isSubmenuFeaturesEnabled(); |
||||
}; |
||||
|
||||
$scope.setWindowTitleAndTheme = function() { |
||||
window.document.title = config.window_title_prefix + $scope.dashboard.title; |
||||
}; |
||||
|
||||
$scope.broadcastRefresh = function() { |
||||
$rootScope.performance.panelsRendered = 0; |
||||
$rootScope.$broadcast('refresh'); |
||||
}; |
||||
|
||||
$scope.addRow = function(dash, row) { |
||||
dash.rows.push(row); |
||||
}; |
||||
|
||||
$scope.addRowDefault = function() { |
||||
$scope.resetRow(); |
||||
$scope.row.title = 'New row'; |
||||
$scope.addRow($scope.dashboard, $scope.row); |
||||
}; |
||||
|
||||
$scope.resetRow = function() { |
||||
$scope.row = { |
||||
title: '', |
||||
height: '250px', |
||||
editable: true, |
||||
}; |
||||
}; |
||||
|
||||
$scope.showJsonEditor = function(evt, options) { |
||||
var editScope = $rootScope.$new(); |
||||
editScope.object = options.object; |
||||
editScope.updateHandler = options.updateHandler; |
||||
$scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope }); |
||||
}; |
||||
|
||||
$scope.onDrop = function(panelId, row, dropTarget) { |
||||
var info = $scope.dashboard.getPanelInfoById(panelId); |
||||
if (dropTarget) { |
||||
var dropInfo = $scope.dashboard.getPanelInfoById(dropTarget.id); |
||||
dropInfo.row.panels[dropInfo.index] = info.panel; |
||||
info.row.panels[info.index] = dropTarget; |
||||
var dragSpan = info.panel.span; |
||||
info.panel.span = dropTarget.span; |
||||
dropTarget.span = dragSpan; |
||||
} else { |
||||
info.row.panels.splice(info.index, 1); |
||||
info.panel.span = 12 - $scope.dashboard.rowSpan(row); |
||||
row.panels.push(info.panel); |
||||
} |
||||
|
||||
$rootScope.$broadcast('render'); |
||||
}; |
||||
|
||||
$scope.registerWindowResizeEvent = function() { |
||||
angular.element(window).bind('resize', function() { |
||||
$timeout.cancel(resizeEventTimeout); |
||||
resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200); |
||||
}); |
||||
$scope.$on('$destroy', function() { |
||||
angular.element(window).unbind('resize'); |
||||
}); |
||||
}; |
||||
|
||||
$scope.timezoneChanged = function() { |
||||
$rootScope.$broadcast("refresh"); |
||||
}; |
||||
|
||||
$scope.formatDate = function(date) { |
||||
return moment(date).format('MMM Do YYYY, h:mm:ss a'); |
||||
}; |
||||
} |
||||
|
||||
init(dashboard) { |
||||
this.$scope.resetRow(); |
||||
this.$scope.registerWindowResizeEvent(); |
||||
this.$scope.onAppEvent('show-json-editor', this.$scope.showJsonEditor); |
||||
this.$scope.onAppEvent('template-variable-value-updated', this.$scope.templateVariableUpdated); |
||||
this.$scope.setupDashboard(dashboard); |
||||
} |
||||
} |
||||
|
||||
coreModule.controller('DashboardCtrl', DashboardCtrl); |
@ -1,181 +0,0 @@ |
||||
define([ |
||||
'angular', |
||||
'lodash', |
||||
], |
||||
function (angular, _) { |
||||
'use strict'; |
||||
|
||||
var module = angular.module('grafana.services'); |
||||
|
||||
module.service('dynamicDashboardSrv', function() { |
||||
var self = this; |
||||
|
||||
this.init = function(dashboard) { |
||||
if (dashboard.snapshot) { return; } |
||||
|
||||
this.iteration = new Date().getTime(); |
||||
this.process(dashboard); |
||||
}; |
||||
|
||||
this.update = function(dashboard) { |
||||
if (dashboard.snapshot) { return; } |
||||
|
||||
this.iteration = this.iteration + 1; |
||||
this.process(dashboard); |
||||
}; |
||||
|
||||
this.process = function(dashboard) { |
||||
if (dashboard.templating.list.length === 0) { return; } |
||||
this.dashboard = dashboard; |
||||
|
||||
var i, j, row, panel; |
||||
for (i = 0; i < this.dashboard.rows.length; i++) { |
||||
row = this.dashboard.rows[i]; |
||||
// handle row repeats
|
||||
if (row.repeat) { |
||||
this.repeatRow(row, i); |
||||
} |
||||
// clean up old left overs
|
||||
else if (row.repeatRowId && row.repeatIteration !== this.iteration) { |
||||
this.dashboard.rows.splice(i, 1); |
||||
i = i - 1; |
||||
continue; |
||||
} |
||||
|
||||
// repeat panels
|
||||
for (j = 0; j < row.panels.length; j++) { |
||||
panel = row.panels[j]; |
||||
if (panel.repeat) { |
||||
this.repeatPanel(panel, row); |
||||
} |
||||
// clean up old left overs
|
||||
else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) { |
||||
row.panels = _.without(row.panels, panel); |
||||
j = j - 1; |
||||
} else if (!_.isEmpty(panel.scopedVars) && panel.repeatIteration !== this.iteration) { |
||||
panel.scopedVars = {}; |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
// returns a new row clone or reuses a clone from previous iteration
|
||||
this.getRowClone = function(sourceRow, repeatIndex, sourceRowIndex) { |
||||
if (repeatIndex === 0) { |
||||
return sourceRow; |
||||
} |
||||
|
||||
var i, panel, row, copy; |
||||
var sourceRowId = sourceRowIndex + 1; |
||||
|
||||
// look for row to reuse
|
||||
for (i = 0; i < this.dashboard.rows.length; i++) { |
||||
row = this.dashboard.rows[i]; |
||||
if (row.repeatRowId === sourceRowId && row.repeatIteration !== this.iteration) { |
||||
copy = row; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!copy) { |
||||
copy = angular.copy(sourceRow); |
||||
this.dashboard.rows.splice(sourceRowIndex + repeatIndex, 0, copy); |
||||
|
||||
// set new panel ids
|
||||
for (i = 0; i < copy.panels.length; i++) { |
||||
panel = copy.panels[i]; |
||||
panel.id = this.dashboard.getNextPanelId(); |
||||
} |
||||
} |
||||
|
||||
copy.repeat = null; |
||||
copy.repeatRowId = sourceRowId; |
||||
copy.repeatIteration = this.iteration; |
||||
return copy; |
||||
}; |
||||
|
||||
// returns a new row clone or reuses a clone from previous iteration
|
||||
this.repeatRow = function(row, rowIndex) { |
||||
var variables = this.dashboard.templating.list; |
||||
var variable = _.findWhere(variables, {name: row.repeat}); |
||||
if (!variable) { |
||||
return; |
||||
} |
||||
|
||||
var selected, copy, i, panel; |
||||
if (variable.current.text === 'All') { |
||||
selected = variable.options.slice(1, variable.options.length); |
||||
} else { |
||||
selected = _.filter(variable.options, {selected: true}); |
||||
} |
||||
|
||||
_.each(selected, function(option, index) { |
||||
copy = self.getRowClone(row, index, rowIndex); |
||||
copy.scopedVars = {}; |
||||
copy.scopedVars[variable.name] = option; |
||||
|
||||
for (i = 0; i < copy.panels.length; i++) { |
||||
panel = copy.panels[i]; |
||||
panel.scopedVars = {}; |
||||
panel.scopedVars[variable.name] = option; |
||||
panel.repeatIteration = this.iteration; |
||||
} |
||||
}, this); |
||||
}; |
||||
|
||||
this.getPanelClone = function(sourcePanel, row, index) { |
||||
// if first clone return source
|
||||
if (index === 0) { |
||||
return sourcePanel; |
||||
} |
||||
|
||||
var i, tmpId, panel, clone; |
||||
|
||||
// first try finding an existing clone to use
|
||||
for (i = 0; i < row.panels.length; i++) { |
||||
panel = row.panels[i]; |
||||
if (panel.repeatIteration !== this.iteration && panel.repeatPanelId === sourcePanel.id) { |
||||
clone = panel; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!clone) { |
||||
clone = { id: this.dashboard.getNextPanelId() }; |
||||
row.panels.push(clone); |
||||
} |
||||
|
||||
// save id
|
||||
tmpId = clone.id; |
||||
// copy properties from source
|
||||
angular.copy(sourcePanel, clone); |
||||
// restore id
|
||||
clone.id = tmpId; |
||||
clone.repeatIteration = this.iteration; |
||||
clone.repeatPanelId = sourcePanel.id; |
||||
clone.repeat = null; |
||||
return clone; |
||||
}; |
||||
|
||||
this.repeatPanel = function(panel, row) { |
||||
var variables = this.dashboard.templating.list; |
||||
var variable = _.findWhere(variables, {name: panel.repeat}); |
||||
if (!variable) { return; } |
||||
|
||||
var selected; |
||||
if (variable.current.text === 'All') { |
||||
selected = variable.options.slice(1, variable.options.length); |
||||
} else { |
||||
selected = _.filter(variable.options, {selected: true}); |
||||
} |
||||
|
||||
_.each(selected, function(option, index) { |
||||
var copy = self.getPanelClone(panel, row, index); |
||||
copy.span = Math.max(12 / selected.length, panel.minSpan); |
||||
copy.scopedVars = copy.scopedVars || {}; |
||||
copy.scopedVars[variable.name] = option; |
||||
}); |
||||
}; |
||||
|
||||
}); |
||||
}); |
@ -0,0 +1,175 @@ |
||||
///<reference path="../../headers/common.d.ts" />
|
||||
|
||||
import config from 'app/core/config'; |
||||
import angular from 'angular'; |
||||
import _ from 'lodash'; |
||||
|
||||
export class DynamicDashboardSrv { |
||||
iteration: number; |
||||
dashboard: any; |
||||
|
||||
init(dashboard) { |
||||
if (dashboard.snapshot) { return; } |
||||
|
||||
this.iteration = new Date().getTime(); |
||||
this.process(dashboard); |
||||
} |
||||
|
||||
update(dashboard) { |
||||
if (dashboard.snapshot) { return; } |
||||
|
||||
this.iteration = this.iteration + 1; |
||||
this.process(dashboard); |
||||
} |
||||
|
||||
process(dashboard) { |
||||
if (dashboard.templating.list.length === 0) { return; } |
||||
this.dashboard = dashboard; |
||||
|
||||
var i, j, row, panel; |
||||
for (i = 0; i < this.dashboard.rows.length; i++) { |
||||
row = this.dashboard.rows[i]; |
||||
// handle row repeats
|
||||
if (row.repeat) { |
||||
this.repeatRow(row, i); |
||||
} else if (row.repeatRowId && row.repeatIteration !== this.iteration) { |
||||
// clean up old left overs
|
||||
this.dashboard.rows.splice(i, 1); |
||||
i = i - 1; |
||||
continue; |
||||
} |
||||
|
||||
// repeat panels
|
||||
for (j = 0; j < row.panels.length; j++) { |
||||
panel = row.panels[j]; |
||||
if (panel.repeat) { |
||||
this.repeatPanel(panel, row); |
||||
} else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) { |
||||
// clean up old left overs
|
||||
row.panels = _.without(row.panels, panel); |
||||
j = j - 1; |
||||
} else if (!_.isEmpty(panel.scopedVars) && panel.repeatIteration !== this.iteration) { |
||||
panel.scopedVars = {}; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// returns a new row clone or reuses a clone from previous iteration
|
||||
getRowClone(sourceRow, repeatIndex, sourceRowIndex) { |
||||
if (repeatIndex === 0) { |
||||
return sourceRow; |
||||
} |
||||
|
||||
var i, panel, row, copy; |
||||
var sourceRowId = sourceRowIndex + 1; |
||||
|
||||
// look for row to reuse
|
||||
for (i = 0; i < this.dashboard.rows.length; i++) { |
||||
row = this.dashboard.rows[i]; |
||||
if (row.repeatRowId === sourceRowId && row.repeatIteration !== this.iteration) { |
||||
copy = row; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!copy) { |
||||
copy = angular.copy(sourceRow); |
||||
this.dashboard.rows.splice(sourceRowIndex + repeatIndex, 0, copy); |
||||
|
||||
// set new panel ids
|
||||
for (i = 0; i < copy.panels.length; i++) { |
||||
panel = copy.panels[i]; |
||||
panel.id = this.dashboard.getNextPanelId(); |
||||
} |
||||
} |
||||
|
||||
copy.repeat = null; |
||||
copy.repeatRowId = sourceRowId; |
||||
copy.repeatIteration = this.iteration; |
||||
return copy; |
||||
} |
||||
|
||||
// returns a new row clone or reuses a clone from previous iteration
|
||||
repeatRow(row, rowIndex) { |
||||
var variables = this.dashboard.templating.list; |
||||
var variable = _.findWhere(variables, {name: row.repeat}); |
||||
if (!variable) { |
||||
return; |
||||
} |
||||
|
||||
var selected, copy, i, panel; |
||||
if (variable.current.text === 'All') { |
||||
selected = variable.options.slice(1, variable.options.length); |
||||
} else { |
||||
selected = _.filter(variable.options, {selected: true}); |
||||
} |
||||
|
||||
_.each(selected, (option, index) => { |
||||
copy = this.getRowClone(row, index, rowIndex); |
||||
copy.scopedVars = {}; |
||||
copy.scopedVars[variable.name] = option; |
||||
|
||||
for (i = 0; i < copy.panels.length; i++) { |
||||
panel = copy.panels[i]; |
||||
panel.scopedVars = {}; |
||||
panel.scopedVars[variable.name] = option; |
||||
panel.repeatIteration = this.iteration; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
getPanelClone(sourcePanel, row, index) { |
||||
// if first clone return source
|
||||
if (index === 0) { |
||||
return sourcePanel; |
||||
} |
||||
|
||||
var i, tmpId, panel, clone; |
||||
|
||||
// first try finding an existing clone to use
|
||||
for (i = 0; i < row.panels.length; i++) { |
||||
panel = row.panels[i]; |
||||
if (panel.repeatIteration !== this.iteration && panel.repeatPanelId === sourcePanel.id) { |
||||
clone = panel; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!clone) { |
||||
clone = { id: this.dashboard.getNextPanelId() }; |
||||
row.panels.push(clone); |
||||
} |
||||
|
||||
// save id
|
||||
tmpId = clone.id; |
||||
// copy properties from source
|
||||
angular.copy(sourcePanel, clone); |
||||
// restore id
|
||||
clone.id = tmpId; |
||||
clone.repeatIteration = this.iteration; |
||||
clone.repeatPanelId = sourcePanel.id; |
||||
clone.repeat = null; |
||||
return clone; |
||||
} |
||||
|
||||
repeatPanel(panel, row) { |
||||
var variables = this.dashboard.templating.list; |
||||
var variable = _.findWhere(variables, {name: panel.repeat}); |
||||
if (!variable) { return; } |
||||
|
||||
var selected; |
||||
if (variable.current.text === 'All') { |
||||
selected = variable.options.slice(1, variable.options.length); |
||||
} else { |
||||
selected = _.filter(variable.options, {selected: true}); |
||||
} |
||||
|
||||
_.each(selected, (option, index) => { |
||||
var copy = this.getPanelClone(panel, row, index); |
||||
copy.span = Math.max(12 / selected.length, panel.minSpan); |
||||
copy.scopedVars = copy.scopedVars || {}; |
||||
copy.scopedVars[variable.name] = option; |
||||
}); |
||||
} |
||||
} |
@ -1,267 +0,0 @@ |
||||
define([ |
||||
'app/features/dashboard/dynamicDashboardSrv', |
||||
'app/features/dashboard/dashboardSrv' |
||||
], function() { |
||||
'use strict'; |
||||
|
||||
function dynamicDashScenario(desc, func) { |
||||
|
||||
describe(desc, function() { |
||||
var ctx = {}; |
||||
|
||||
ctx.setup = function (setupFunc) { |
||||
|
||||
beforeEach(module('grafana.services')); |
||||
beforeEach(module(function($provide) { |
||||
$provide.value('contextSrv', { |
||||
user: { timezone: 'utc'} |
||||
}); |
||||
})); |
||||
|
||||
beforeEach(inject(function(dynamicDashboardSrv, dashboardSrv) { |
||||
ctx.dynamicDashboardSrv = dynamicDashboardSrv; |
||||
ctx.dashboardSrv = dashboardSrv; |
||||
|
||||
var model = { |
||||
rows: [], |
||||
templating: { list: [] } |
||||
}; |
||||
|
||||
setupFunc(model); |
||||
ctx.dash = ctx.dashboardSrv.create(model); |
||||
ctx.dynamicDashboardSrv.init(ctx.dash); |
||||
ctx.rows = ctx.dash.rows; |
||||
})); |
||||
}; |
||||
|
||||
func(ctx); |
||||
}); |
||||
} |
||||
|
||||
dynamicDashScenario('given dashboard with panel repeat', function(ctx) { |
||||
ctx.setup(function(dash) { |
||||
dash.rows.push({ |
||||
panels: [{id: 2, repeat: 'apps'}] |
||||
}); |
||||
dash.templating.list.push({ |
||||
name: 'apps', |
||||
current: { |
||||
text: 'se1, se2, se3', |
||||
value: ['se1', 'se2', 'se3'] |
||||
}, |
||||
options: [ |
||||
{text: 'se1', value: 'se1', selected: true}, |
||||
{text: 'se2', value: 'se2', selected: true}, |
||||
{text: 'se3', value: 'se3', selected: true}, |
||||
{text: 'se4', value: 'se4', selected: false} |
||||
] |
||||
}); |
||||
}); |
||||
|
||||
it('should repeat panel one time', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(3); |
||||
}); |
||||
|
||||
it('should mark panel repeated', function() { |
||||
expect(ctx.rows[0].panels[0].repeat).to.be('apps'); |
||||
expect(ctx.rows[0].panels[1].repeatPanelId).to.be(2); |
||||
}); |
||||
|
||||
it('should set scopedVars on panels', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars.apps.value).to.be('se1'); |
||||
expect(ctx.rows[0].panels[1].scopedVars.apps.value).to.be('se2'); |
||||
expect(ctx.rows[0].panels[2].scopedVars.apps.value).to.be('se3'); |
||||
}); |
||||
|
||||
describe('After a second iteration', function() { |
||||
var repeatedPanelAfterIteration1; |
||||
|
||||
beforeEach(function() { |
||||
repeatedPanelAfterIteration1 = ctx.rows[0].panels[1]; |
||||
ctx.rows[0].panels[0].fill = 10; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should have reused same panel instances', function() { |
||||
expect(ctx.rows[0].panels[1]).to.be(repeatedPanelAfterIteration1); |
||||
}); |
||||
|
||||
it('reused panel should copy properties from source', function() { |
||||
expect(ctx.rows[0].panels[1].fill).to.be(10); |
||||
}); |
||||
|
||||
it('should have same panel count', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(3); |
||||
}); |
||||
}); |
||||
|
||||
describe('After a second iteration and selected values reduced', function() { |
||||
beforeEach(function() { |
||||
ctx.dash.templating.list[0].options[1].selected = false; |
||||
|
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should clean up repeated panel', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(2); |
||||
}); |
||||
}); |
||||
|
||||
describe('After a second iteration and panel repeat is turned off', function() { |
||||
beforeEach(function() { |
||||
ctx.rows[0].panels[0].repeat = null; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should clean up repeated panel', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(1); |
||||
}); |
||||
|
||||
it('should remove scoped vars from reused panel', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars).to.be.empty(); |
||||
}); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
dynamicDashScenario('given dashboard with row repeat', function(ctx) { |
||||
ctx.setup(function(dash) { |
||||
dash.rows.push({ |
||||
repeat: 'servers', |
||||
panels: [{id: 2}] |
||||
}); |
||||
dash.rows.push({panels: []}); |
||||
dash.templating.list.push({ |
||||
name: 'servers', |
||||
current: { |
||||
text: 'se1, se2', |
||||
value: ['se1', 'se2'] |
||||
}, |
||||
options: [ |
||||
{text: 'se1', value: 'se1', selected: true}, |
||||
{text: 'se2', value: 'se2', selected: true}, |
||||
] |
||||
}); |
||||
}); |
||||
|
||||
it('should repeat row one time', function() { |
||||
expect(ctx.rows.length).to.be(3); |
||||
}); |
||||
|
||||
it('should keep panel ids on first row', function() { |
||||
expect(ctx.rows[0].panels[0].id).to.be(2); |
||||
}); |
||||
|
||||
it('should keep first row as repeat', function() { |
||||
expect(ctx.rows[0].repeat).to.be('servers'); |
||||
}); |
||||
|
||||
it('should clear repeat field on repeated row', function() { |
||||
expect(ctx.rows[1].repeat).to.be(null); |
||||
}); |
||||
|
||||
it('should add scopedVars to rows', function() { |
||||
expect(ctx.rows[0].scopedVars.servers.value).to.be('se1'); |
||||
expect(ctx.rows[1].scopedVars.servers.value).to.be('se2'); |
||||
}); |
||||
|
||||
it('should generate a repeartRowId based on repeat row index', function() { |
||||
expect(ctx.rows[1].repeatRowId).to.be(1); |
||||
}); |
||||
|
||||
it('should set scopedVars on row panels', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); |
||||
expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); |
||||
}); |
||||
|
||||
describe('After a second iteration', function() { |
||||
var repeatedRowAfterFirstIteration; |
||||
|
||||
beforeEach(function() { |
||||
repeatedRowAfterFirstIteration = ctx.rows[1]; |
||||
ctx.rows[0].height = 500; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should still only have 2 rows', function() { |
||||
expect(ctx.rows.length).to.be(3); |
||||
}); |
||||
|
||||
it.skip('should have updated props from source', function() { |
||||
expect(ctx.rows[1].height).to.be(500); |
||||
}); |
||||
|
||||
it('should reuse row instance', function() { |
||||
expect(ctx.rows[1]).to.be(repeatedRowAfterFirstIteration); |
||||
}); |
||||
}); |
||||
|
||||
describe('After a second iteration and selected values reduced', function() { |
||||
beforeEach(function() { |
||||
ctx.dash.templating.list[0].options[1].selected = false; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should remove repeated second row', function() { |
||||
expect(ctx.rows.length).to.be(2); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
dynamicDashScenario('given dashboard with row repeat and panel repeat', function(ctx) { |
||||
ctx.setup(function(dash) { |
||||
dash.rows.push({ |
||||
repeat: 'servers', |
||||
panels: [{id: 2, repeat: 'metric'}] |
||||
}); |
||||
dash.templating.list.push({ |
||||
name: 'servers', |
||||
current: { text: 'se1, se2', value: ['se1', 'se2'] }, |
||||
options: [ |
||||
{text: 'se1', value: 'se1', selected: true}, |
||||
{text: 'se2', value: 'se2', selected: true}, |
||||
] |
||||
}); |
||||
dash.templating.list.push({ |
||||
name: 'metric', |
||||
current: { text: 'm1, m2', value: ['m1', 'm2'] }, |
||||
options: [ |
||||
{text: 'm1', value: 'm1', selected: true}, |
||||
{text: 'm2', value: 'm2', selected: true}, |
||||
] |
||||
}); |
||||
}); |
||||
|
||||
it('should repeat row one time', function() { |
||||
expect(ctx.rows.length).to.be(2); |
||||
}); |
||||
|
||||
it('should repeat panel on both rows', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(2); |
||||
expect(ctx.rows[1].panels.length).to.be(2); |
||||
}); |
||||
|
||||
it('should keep panel ids on first row', function() { |
||||
expect(ctx.rows[0].panels[0].id).to.be(2); |
||||
}); |
||||
|
||||
it('should mark second row as repeated', function() { |
||||
expect(ctx.rows[0].repeat).to.be('servers'); |
||||
}); |
||||
|
||||
it('should clear repeat field on repeated row', function() { |
||||
expect(ctx.rows[1].repeat).to.be(null); |
||||
}); |
||||
|
||||
it('should generate a repeartRowId based on repeat row index', function() { |
||||
expect(ctx.rows[1].repeatRowId).to.be(1); |
||||
}); |
||||
|
||||
it('should set scopedVars on row panels', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); |
||||
expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
}); |
@ -0,0 +1,264 @@ |
||||
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; |
||||
|
||||
import 'app/features/dashboard/dashboardSrv'; |
||||
import {DynamicDashboardSrv} from '../../app/features/dashboard/dynamic_dashboard_srv'; |
||||
|
||||
function dynamicDashScenario(desc, func) { |
||||
|
||||
describe(desc, function() { |
||||
var ctx: any = {}; |
||||
|
||||
ctx.setup = function (setupFunc) { |
||||
|
||||
beforeEach(angularMocks.module('grafana.services')); |
||||
beforeEach(angularMocks.module(function($provide) { |
||||
$provide.value('contextSrv', { |
||||
user: { timezone: 'utc'} |
||||
}); |
||||
})); |
||||
|
||||
beforeEach(angularMocks.inject(function(dashboardSrv) { |
||||
ctx.dashboardSrv = dashboardSrv; |
||||
var model = { |
||||
rows: [], |
||||
templating: { list: [] } |
||||
}; |
||||
|
||||
setupFunc(model); |
||||
ctx.dash = ctx.dashboardSrv.create(model); |
||||
ctx.dynamicDashboardSrv = new DynamicDashboardSrv(); |
||||
ctx.dynamicDashboardSrv.init(ctx.dash); |
||||
ctx.rows = ctx.dash.rows; |
||||
})); |
||||
}; |
||||
|
||||
func(ctx); |
||||
}); |
||||
} |
||||
|
||||
dynamicDashScenario('given dashboard with panel repeat', function(ctx) { |
||||
ctx.setup(function(dash) { |
||||
dash.rows.push({ |
||||
panels: [{id: 2, repeat: 'apps'}] |
||||
}); |
||||
dash.templating.list.push({ |
||||
name: 'apps', |
||||
current: { |
||||
text: 'se1, se2, se3', |
||||
value: ['se1', 'se2', 'se3'] |
||||
}, |
||||
options: [ |
||||
{text: 'se1', value: 'se1', selected: true}, |
||||
{text: 'se2', value: 'se2', selected: true}, |
||||
{text: 'se3', value: 'se3', selected: true}, |
||||
{text: 'se4', value: 'se4', selected: false} |
||||
] |
||||
}); |
||||
}); |
||||
|
||||
it('should repeat panel one time', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(3); |
||||
}); |
||||
|
||||
it('should mark panel repeated', function() { |
||||
expect(ctx.rows[0].panels[0].repeat).to.be('apps'); |
||||
expect(ctx.rows[0].panels[1].repeatPanelId).to.be(2); |
||||
}); |
||||
|
||||
it('should set scopedVars on panels', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars.apps.value).to.be('se1'); |
||||
expect(ctx.rows[0].panels[1].scopedVars.apps.value).to.be('se2'); |
||||
expect(ctx.rows[0].panels[2].scopedVars.apps.value).to.be('se3'); |
||||
}); |
||||
|
||||
describe('After a second iteration', function() { |
||||
var repeatedPanelAfterIteration1; |
||||
|
||||
beforeEach(function() { |
||||
repeatedPanelAfterIteration1 = ctx.rows[0].panels[1]; |
||||
ctx.rows[0].panels[0].fill = 10; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should have reused same panel instances', function() { |
||||
expect(ctx.rows[0].panels[1]).to.be(repeatedPanelAfterIteration1); |
||||
}); |
||||
|
||||
it('reused panel should copy properties from source', function() { |
||||
expect(ctx.rows[0].panels[1].fill).to.be(10); |
||||
}); |
||||
|
||||
it('should have same panel count', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(3); |
||||
}); |
||||
}); |
||||
|
||||
describe('After a second iteration and selected values reduced', function() { |
||||
beforeEach(function() { |
||||
ctx.dash.templating.list[0].options[1].selected = false; |
||||
|
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should clean up repeated panel', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(2); |
||||
}); |
||||
}); |
||||
|
||||
describe('After a second iteration and panel repeat is turned off', function() { |
||||
beforeEach(function() { |
||||
ctx.rows[0].panels[0].repeat = null; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should clean up repeated panel', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(1); |
||||
}); |
||||
|
||||
it('should remove scoped vars from reused panel', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars).to.be.empty(); |
||||
}); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
dynamicDashScenario('given dashboard with row repeat', function(ctx) { |
||||
ctx.setup(function(dash) { |
||||
dash.rows.push({ |
||||
repeat: 'servers', |
||||
panels: [{id: 2}] |
||||
}); |
||||
dash.rows.push({panels: []}); |
||||
dash.templating.list.push({ |
||||
name: 'servers', |
||||
current: { |
||||
text: 'se1, se2', |
||||
value: ['se1', 'se2'] |
||||
}, |
||||
options: [ |
||||
{text: 'se1', value: 'se1', selected: true}, |
||||
{text: 'se2', value: 'se2', selected: true}, |
||||
] |
||||
}); |
||||
}); |
||||
|
||||
it('should repeat row one time', function() { |
||||
expect(ctx.rows.length).to.be(3); |
||||
}); |
||||
|
||||
it('should keep panel ids on first row', function() { |
||||
expect(ctx.rows[0].panels[0].id).to.be(2); |
||||
}); |
||||
|
||||
it('should keep first row as repeat', function() { |
||||
expect(ctx.rows[0].repeat).to.be('servers'); |
||||
}); |
||||
|
||||
it('should clear repeat field on repeated row', function() { |
||||
expect(ctx.rows[1].repeat).to.be(null); |
||||
}); |
||||
|
||||
it('should add scopedVars to rows', function() { |
||||
expect(ctx.rows[0].scopedVars.servers.value).to.be('se1'); |
||||
expect(ctx.rows[1].scopedVars.servers.value).to.be('se2'); |
||||
}); |
||||
|
||||
it('should generate a repeartRowId based on repeat row index', function() { |
||||
expect(ctx.rows[1].repeatRowId).to.be(1); |
||||
}); |
||||
|
||||
it('should set scopedVars on row panels', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); |
||||
expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); |
||||
}); |
||||
|
||||
describe('After a second iteration', function() { |
||||
var repeatedRowAfterFirstIteration; |
||||
|
||||
beforeEach(function() { |
||||
repeatedRowAfterFirstIteration = ctx.rows[1]; |
||||
ctx.rows[0].height = 500; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should still only have 2 rows', function() { |
||||
expect(ctx.rows.length).to.be(3); |
||||
}); |
||||
|
||||
it.skip('should have updated props from source', function() { |
||||
expect(ctx.rows[1].height).to.be(500); |
||||
}); |
||||
|
||||
it('should reuse row instance', function() { |
||||
expect(ctx.rows[1]).to.be(repeatedRowAfterFirstIteration); |
||||
}); |
||||
}); |
||||
|
||||
describe('After a second iteration and selected values reduced', function() { |
||||
beforeEach(function() { |
||||
ctx.dash.templating.list[0].options[1].selected = false; |
||||
ctx.dynamicDashboardSrv.update(ctx.dash); |
||||
}); |
||||
|
||||
it('should remove repeated second row', function() { |
||||
expect(ctx.rows.length).to.be(2); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
dynamicDashScenario('given dashboard with row repeat and panel repeat', function(ctx) { |
||||
ctx.setup(function(dash) { |
||||
dash.rows.push({ |
||||
repeat: 'servers', |
||||
panels: [{id: 2, repeat: 'metric'}] |
||||
}); |
||||
dash.templating.list.push({ |
||||
name: 'servers', |
||||
current: { text: 'se1, se2', value: ['se1', 'se2'] }, |
||||
options: [ |
||||
{text: 'se1', value: 'se1', selected: true}, |
||||
{text: 'se2', value: 'se2', selected: true}, |
||||
] |
||||
}); |
||||
dash.templating.list.push({ |
||||
name: 'metric', |
||||
current: { text: 'm1, m2', value: ['m1', 'm2'] }, |
||||
options: [ |
||||
{text: 'm1', value: 'm1', selected: true}, |
||||
{text: 'm2', value: 'm2', selected: true}, |
||||
] |
||||
}); |
||||
}); |
||||
|
||||
it('should repeat row one time', function() { |
||||
expect(ctx.rows.length).to.be(2); |
||||
}); |
||||
|
||||
it('should repeat panel on both rows', function() { |
||||
expect(ctx.rows[0].panels.length).to.be(2); |
||||
expect(ctx.rows[1].panels.length).to.be(2); |
||||
}); |
||||
|
||||
it('should keep panel ids on first row', function() { |
||||
expect(ctx.rows[0].panels[0].id).to.be(2); |
||||
}); |
||||
|
||||
it('should mark second row as repeated', function() { |
||||
expect(ctx.rows[0].repeat).to.be('servers'); |
||||
}); |
||||
|
||||
it('should clear repeat field on repeated row', function() { |
||||
expect(ctx.rows[1].repeat).to.be(null); |
||||
}); |
||||
|
||||
it('should generate a repeartRowId based on repeat row index', function() { |
||||
expect(ctx.rows[1].repeatRowId).to.be(1); |
||||
}); |
||||
|
||||
it('should set scopedVars on row panels', function() { |
||||
expect(ctx.rows[0].panels[0].scopedVars.servers.value).to.be('se1'); |
||||
expect(ctx.rows[1].panels[0].scopedVars.servers.value).to.be('se2'); |
||||
}); |
||||
|
||||
}); |
||||
|
Loading…
Reference in new issue