diff --git a/pkg/services/alerting/alert_rule.go b/pkg/services/alerting/alert_rule.go index 8678311a6a2..cfcf17f0a56 100644 --- a/pkg/services/alerting/alert_rule.go +++ b/pkg/services/alerting/alert_rule.go @@ -25,6 +25,10 @@ type AlertRule struct { Transformer Transformer } +func getTimeDurationStringToSeconds(str string) int64 { + return 60 +} + func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) { model := &AlertRule{} model.Id = ruleDef.Id @@ -39,13 +43,13 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) { Level: critical.Get("level").MustFloat64(), } - warning := ruleDef.Expression.Get("warning") + warning := ruleDef.Expression.Get("warn") model.Warning = Level{ Operator: warning.Get("op").MustString(), Level: warning.Get("level").MustFloat64(), } - model.Frequency = ruleDef.Expression.Get("frequency").MustInt64() + model.Frequency = getTimeDurationStringToSeconds(ruleDef.Expression.Get("frequency").MustString()) model.Transform = ruleDef.Expression.Get("transform").Get("type").MustString() model.TransformParams = *ruleDef.Expression.Get("transform") diff --git a/pkg/services/alerting/commands.go b/pkg/services/alerting/commands.go index 2d32396c7e1..4e269aca695 100644 --- a/pkg/services/alerting/commands.go +++ b/pkg/services/alerting/commands.go @@ -1,8 +1,6 @@ package alerting import ( - "fmt" - "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" ) @@ -38,57 +36,3 @@ func updateDashboardAlerts(cmd *UpdateDashboardAlertsCommand) error { return nil } - -func getTimeDurationStringToSeconds(str string) int64 { - return 60 -} - -func ConvetAlertModelToAlertRule(ruleDef *m.Alert) (*AlertRule, error) { - model := &AlertRule{} - model.Id = ruleDef.Id - model.OrgId = ruleDef.OrgId - model.Name = ruleDef.Name - model.Description = ruleDef.Description - model.State = ruleDef.State - - critical := ruleDef.Expression.Get("critical") - model.Critical = Level{ - Operator: critical.Get("op").MustString(), - Level: critical.Get("level").MustFloat64(), - } - - warning := ruleDef.Expression.Get("warning") - model.Warning = Level{ - Operator: warning.Get("op").MustString(), - Level: warning.Get("level").MustFloat64(), - } - - model.Frequency = getTimeDurationStringToSeconds(ruleDef.Expression.Get("frequency").MustString()) - model.Transform = ruleDef.Expression.Get("transform").Get("type").MustString() - model.TransformParams = *ruleDef.Expression.Get("transform") - - if model.Transform == "aggregation" { - model.Transformer = &AggregationTransformer{ - Method: ruleDef.Expression.Get("transform").Get("method").MustString(), - } - } - - query := ruleDef.Expression.Get("query") - model.Query = AlertQuery{ - Query: query.Get("query").MustString(), - DatasourceId: query.Get("datasourceId").MustInt64(), - From: query.Get("from").MustString(), - To: query.Get("to").MustString(), - Aggregator: query.Get("agg").MustString(), - } - - if model.Query.Query == "" { - return nil, fmt.Errorf("missing query.query") - } - - if model.Query.DatasourceId == 0 { - return nil, fmt.Errorf("missing query.datasourceId") - } - - return model, nil -} diff --git a/pkg/services/alerting/extractor_test.go b/pkg/services/alerting/extractor_test.go index 069489dfb23..6eda321f0dc 100644 --- a/pkg/services/alerting/extractor_test.go +++ b/pkg/services/alerting/extractor_test.go @@ -55,7 +55,7 @@ func TestAlertRuleExtraction(t *testing.T) { "method": "avg", "type": "aggregation" }, - "warning": { + "warn": { "level": 10, "op": ">" } @@ -90,7 +90,7 @@ func TestAlertRuleExtraction(t *testing.T) { "method": "avg", "name": "aggregation" }, - "warning": { + "warn": { "level": 10, "op": ">" } diff --git a/pkg/services/alerting/reader.go b/pkg/services/alerting/reader.go index 7f8f6b2c5de..db7da930746 100644 --- a/pkg/services/alerting/reader.go +++ b/pkg/services/alerting/reader.go @@ -49,7 +49,7 @@ func (arr *AlertRuleReader) Fetch() []*AlertRule { res := make([]*AlertRule, len(cmd.Result)) for i, ruleDef := range cmd.Result { - model, _ := ConvetAlertModelToAlertRule(ruleDef) + model, _ := NewAlertRuleFromDBModel(ruleDef) res[i] = model } diff --git a/pkg/services/sqlstore/alert_rule_parser_test.go b/pkg/services/sqlstore/alert_rule_parser_test.go deleted file mode 100644 index 8ec7c24429b..00000000000 --- a/pkg/services/sqlstore/alert_rule_parser_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package sqlstore - -import ( - "testing" - - "github.com/grafana/grafana/pkg/components/simplejson" - m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/alerting" - . "github.com/smartystreets/goconvey/convey" -) - -func TestAlertRuleModelParsing(t *testing.T) { - - Convey("Parsing alertRule from expression", t, func() { - alertRuleDAO := &m.Alert{} - json, _ := simplejson.NewJson([]byte(` - { - "frequency": 10, - "warning": { - "op": ">", - "level": 10 - }, - "critical": { - "op": ">", - "level": 20 - }, - "query": { - "refId": "A", - "from": "5m", - "to": "now", - "datasourceId": 1, - "query": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)" - }, - "transform": { - "type": "aggregation", - "method": "avg" - } - }`)) - - alertRuleDAO.Name = "Test" - alertRuleDAO.Expression = json - rule, _ := alerting.ConvetAlertModelToAlertRule(alertRuleDAO) - - Convey("Confirm that all properties are set", func() { - So(rule.Query.Query, ShouldEqual, "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)") - So(rule.Query.From, ShouldEqual, "5m") - So(rule.Query.To, ShouldEqual, "now") - So(rule.Query.DatasourceId, ShouldEqual, 1) - So(rule.Warning.Level, ShouldEqual, 10) - So(rule.Warning.Operator, ShouldEqual, ">") - So(rule.Critical.Level, ShouldEqual, 20) - So(rule.Critical.Operator, ShouldEqual, ">") - }) - }) -} diff --git a/public/app/features/dashboard/viewStateSrv.js b/public/app/features/dashboard/viewStateSrv.js index 035bfb6ae6e..fe1277c59c0 100644 --- a/public/app/features/dashboard/viewStateSrv.js +++ b/public/app/features/dashboard/viewStateSrv.js @@ -120,25 +120,28 @@ function (angular, _, $) { if (this.panelScopes.length === 0) { return; } if (this.dashboard.meta.fullscreen) { - if (this.fullscreenPanel) { - this.leaveFullscreen(false); - } var panelScope = this.getPanelScope(this.state.panelId); - // panel could be about to be created/added and scope does - // not exist yet if (!panelScope) { return; } + if (this.fullscreenPanel) { + // if already fullscreen + if (this.fullscreenPanel === panelScope) { + return; + } else { + this.leaveFullscreen(false); + } + } + if (!panelScope.ctrl.editModeInitiated) { panelScope.ctrl.initEditMode(); } - this.enterFullscreen(panelScope); - return; - } - - if (this.fullscreenPanel) { + if (!panelScope.ctrl.fullscreen) { + this.enterFullscreen(panelScope); + } + } else if (this.fullscreenPanel) { this.leaveFullscreen(true); } }; diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 0f253b5048a..bcb1980f854 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -152,8 +152,8 @@ export class PanelCtrl { calculatePanelHeight() { if (this.fullscreen) { var docHeight = $(window).height(); - var editHeight = Math.floor(docHeight * 0.3); - var fullscreenHeight = Math.floor(docHeight * 0.7); + var editHeight = Math.floor(docHeight * 0.4); + var fullscreenHeight = Math.floor(docHeight * 0.6); this.containerHeight = this.editMode ? editHeight : fullscreenHeight; } else { this.containerHeight = this.panel.height || this.row.height; diff --git a/public/app/plugins/panel/graph/alert_tab_ctrl.ts b/public/app/plugins/panel/graph/alert_tab_ctrl.ts index 3f83e6db38e..d16274efb56 100644 --- a/public/app/plugins/panel/graph/alert_tab_ctrl.ts +++ b/public/app/plugins/panel/graph/alert_tab_ctrl.ts @@ -50,7 +50,7 @@ export class AlertTabCtrl { notify: [], enabled: false, scheduler: 1, - warning: { op: '>', level: undefined }, + warn: { op: '>', level: undefined }, critical: { op: '>', level: undefined }, query: { refId: 'A', @@ -70,8 +70,16 @@ export class AlertTabCtrl { $scope.ctrl = this; this.metricTargets = this.panel.targets.map(val => val); - this.initAlertModel(); + + // set panel alert edit mode + this.panelCtrl.editingAlert = true; + this.panelCtrl.render(); + + $scope.$on("$destroy", () => { + this.panelCtrl.editingAlert = false; + this.panelCtrl.render(); + }); } initAlertModel() { @@ -125,21 +133,21 @@ export class AlertTabCtrl { } convertThresholdsToAlertThresholds() { - if (this.panel.grid - && this.panel.grid.threshold1 - && this.alert.warnLevel === undefined - ) { - this.alert.warning.op = '>'; - this.alert.warning.level = this.panel.grid.threshold1; - } - - if (this.panel.grid - && this.panel.grid.threshold2 - && this.alert.critical.level === undefined - ) { - this.alert.critical.op = '>'; - this.alert.critical.level = this.panel.grid.threshold2; - } + // if (this.panel.grid + // && this.panel.grid.threshold1 + // && this.alert.warnLevel === undefined + // ) { + // this.alert.warning.op = '>'; + // this.alert.warning.level = this.panel.grid.threshold1; + // } + // + // if (this.panel.grid + // && this.panel.grid.threshold2 + // && this.alert.critical.level === undefined + // ) { + // this.alert.critical.op = '>'; + // this.alert.critical.level = this.panel.grid.threshold2; + // } } delete() { @@ -156,6 +164,10 @@ export class AlertTabCtrl { disable() { this.alert.enabled = false; } + + levelsUpdated() { + this.panelCtrl.render(); + } } /** @ngInject */ diff --git a/public/app/plugins/panel/graph/graph.js b/public/app/plugins/panel/graph/graph.js index 621229d9d88..23c9cd65a9f 100755 --- a/public/app/plugins/panel/graph/graph.js +++ b/public/app/plugins/panel/graph/graph.js @@ -169,6 +169,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) { var right = panel.yaxes[1]; if (left.show && left.label) { gridMargin.left = 20; } if (right.show && right.label) { gridMargin.right = 20; } + } // Function for rendering panel @@ -178,6 +179,12 @@ function (angular, $, moment, _, kbn, GraphTooltip) { panelWidth = panelWidthCache[panel.span] = elem.width(); } + if (ctrl.editingAlert) { + elem.css('margin-right', '220px'); + } else { + elem.css('margin-right', ''); + } + if (shouldAbortRender()) { return; } @@ -186,6 +193,10 @@ function (angular, $, moment, _, kbn, GraphTooltip) { // Populate element var options = { + alerting: { + editing: ctrl.editingAlert, + alert: panel.alert, + }, hooks: { draw: [drawHook], processOffset: [processOffsetHook], @@ -260,6 +271,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) { function callPlot(incrementRenderCounter) { try { + console.log('rendering'); $.plot(elem, sortedSeries, options); } catch (e) { console.log('flotcharts error', e); @@ -312,6 +324,50 @@ function (angular, $, moment, _, kbn, GraphTooltip) { } function addGridThresholds(options, panel) { + if (panel.alert && panel.alert.enabled) { + var crit = panel.alert.critical; + var warn = panel.alert.warn; + var critEdge = Infinity; + var warnEdge = crit.level; + + if (_.isNumber(crit.level)) { + if (crit.op === '<') { + critEdge = -Infinity; + } + + // fill + options.grid.markings.push({ + yaxis: {from: crit.level, to: critEdge}, + color: 'rgba(234, 112, 112, 0.10)', + }); + + // line + options.grid.markings.push({ + yaxis: {from: crit.level, to: crit.level}, + color: '#ed2e18' + }); + } + + if (_.isNumber(warn.level)) { + // if (warn.op === '<') { + // } + + // fill + options.grid.markings.push({ + yaxis: {from: warn.level, to: warnEdge}, + color: 'rgba(216, 200, 27, 0.10)', + }); + + // line + options.grid.markings.push({ + yaxis: {from: warn.level, to: warn.level}, + color: '#F79520' + }); + } + + return; + } + if (_.isNumber(panel.grid.threshold1)) { var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null); options.grid.markings.push({ diff --git a/public/app/plugins/panel/graph/jquery.flot.alerts.ts b/public/app/plugins/panel/graph/jquery.flot.alerts.ts index e95e0871d92..65229b31065 100644 --- a/public/app/plugins/panel/graph/jquery.flot.alerts.ts +++ b/public/app/plugins/panel/graph/jquery.flot.alerts.ts @@ -2,24 +2,63 @@ import 'jquery.flot'; import $ from 'jquery'; +import _ from 'lodash'; var options = {}; -function getHandleTemplate(type) { +function getHandleTemplate(type, op, value) { + if (op === '>') { op = '>'; } + if (op === '<') { op = '<'; } + return ` -