Просмотр исходного кода

feat(alerting): add support for alert page filter

bergquist 9 лет назад
Родитель
Сommit
1be513fabd

+ 6 - 3
pkg/api/alerting.go

@@ -47,6 +47,7 @@ func GetAlertChanges(c *middleware.Context) Response {
 func GetAlerts(c *middleware.Context) Response {
 	query := models.GetAlertsQuery{
 		OrgId: c.OrgId,
+		State: c.QueryStrings("state"),
 	}
 
 	if err := bus.Dispatch(&query); err != nil {
@@ -78,8 +79,10 @@ func GetAlerts(c *middleware.Context) Response {
 		DashboardIds: dashboardIds,
 	}
 
-	if err := bus.Dispatch(&dashboardsQuery); err != nil {
-		return ApiError(500, "List alerts failed", err)
+	if len(alertDTOs) > 0 {
+		if err := bus.Dispatch(&dashboardsQuery); err != nil {
+			return ApiError(500, "List alerts failed", err)
+		}
 	}
 
 	//TODO: should be possible to speed this up with lookup table
@@ -128,7 +131,7 @@ func DelAlert(c *middleware.Context) Response {
 func GetAlertStates(c *middleware.Context) Response {
 	alertId := c.ParamsInt64(":alertId")
 
-	query := models.GetAlertsStateCommand{
+	query := models.GetAlertsStateQuery{
 		AlertId: alertId,
 	}
 

+ 1 - 0
pkg/models/alerts.go

@@ -96,6 +96,7 @@ type DeleteAlertCommand struct {
 //Queries
 type GetAlertsQuery struct {
 	OrgId int64
+	State []string
 
 	Result []AlertRule
 }

+ 1 - 1
pkg/models/alerts_state.go

@@ -38,7 +38,7 @@ type UpdateAlertStateCommand struct {
 
 // Queries
 
-type GetAlertsStateCommand struct {
+type GetAlertsStateQuery struct {
 	OrgId   int64 `json:"orgId" binding:"Required"`
 	AlertId int64 `json:"alertId" binding:"Required"`
 

+ 30 - 3
pkg/services/sqlstore/alert_rule.go

@@ -1,15 +1,17 @@
 package sqlstore
 
 import (
+	"bytes"
 	"fmt"
 	"github.com/go-xorm/xorm"
 	"github.com/grafana/grafana/pkg/bus"
 	m "github.com/grafana/grafana/pkg/models"
+	"strings"
 )
 
 func init() {
 	bus.AddHandler("sql", SaveAlerts)
-	bus.AddHandler("sql", GetAllAlertsForOrg)
+	bus.AddHandler("sql", HandleAlertsQuery)
 	bus.AddHandler("sql", GetAlertById)
 	bus.AddHandler("sql", GetAlertsByDashboardId)
 	bus.AddHandler("sql", GetAlertsByDashboardAndPanelId)
@@ -41,9 +43,33 @@ func DeleteAlertById(cmd *m.DeleteAlertCommand) error {
 	})
 }
 
-func GetAllAlertsForOrg(query *m.GetAlertsQuery) error {
+func HandleAlertsQuery(query *m.GetAlertsQuery) error {
+	var sql bytes.Buffer
+	params := make([]interface{}, 0)
+
+	sql.WriteString(`SELECT *
+						from alert_rule
+						`)
+
+	sql.WriteString(`WHERE org_id = ?`)
+	params = append(params, query.OrgId)
+
+	if len(query.State) > 0 {
+
+		sql.WriteString(` AND (`)
+		for i, v := range query.State {
+			if i > 0 {
+				sql.WriteString(" OR ")
+			}
+			sql.WriteString("state = ? ")
+			params = append(params, strings.ToUpper(v))
+		}
+		sql.WriteString(")")
+
+	}
+
 	alerts := make([]m.AlertRule, 0)
-	if err := x.Where("org_id = ?", query.OrgId).Find(&alerts); err != nil {
+	if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil {
 		return err
 	}
 
@@ -127,6 +153,7 @@ func upsertAlerts(alerts []m.AlertRule, posted *[]m.AlertRule, sess *xorm.Sessio
 			}
 
 		} else {
+			alert.State = "OK"
 			_, err := sess.Insert(&alert)
 			if err != nil {
 				return err

+ 0 - 1
pkg/services/sqlstore/alert_rule_test.go

@@ -30,7 +30,6 @@ func TestAlertingDataAccess(t *testing.T) {
 				Description:  "Alerting description",
 				QueryRange:   "5m",
 				Aggregator:   "avg",
-				State:        "OK",
 			},
 		}
 

+ 1 - 1
pkg/services/sqlstore/alert_state.go

@@ -47,7 +47,7 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error {
 	})
 }
 
-func GetAlertStateLogByAlertId(cmd *m.GetAlertsStateCommand) error {
+func GetAlertStateLogByAlertId(cmd *m.GetAlertsStateQuery) error {
 	alertLogs := make([]m.AlertState, 0)
 
 	if err := x.Where("alert_id = ?", cmd.AlertId).Desc("created").Find(&alertLogs); err != nil {

+ 12 - 1
pkg/services/sqlstore/alert_state_test.go

@@ -82,7 +82,7 @@ func TestAlertingStateAccess(t *testing.T) {
 				})
 
 				Convey("should have two event state logs", func() {
-					query := &m.GetAlertsStateCommand{
+					query := &m.GetAlertsStateQuery{
 						AlertId: 1,
 						OrgId:   1,
 					}
@@ -92,6 +92,17 @@ func TestAlertingStateAccess(t *testing.T) {
 
 					So(len(*query.Result), ShouldEqual, 2)
 				})
+
+				Convey("should not get any alerts with critical state", func() {
+					query := &m.GetAlertsQuery{
+						OrgId: 1,
+						State: []string{"Critical"},
+					}
+
+					err := HandleAlertsQuery(query)
+					So(err, ShouldBeNil)
+					So(len(query.Result), ShouldEqual, 0)
+				})
 			})
 		})
 	})

+ 7 - 1
public/app/features/alerts/alerts_ctrl.ts

@@ -9,6 +9,8 @@ import alertDef from './alert_def';
 export class AlertPageCtrl {
 
   alerts: any;
+  stateFilters = [ 'Ok', 'Warn', 'Critical', 'Acknowledged' ];
+  stateFilter = 'Warn';
 
   /** @ngInject */
   constructor(private backendSrv) {
@@ -16,7 +18,11 @@ export class AlertPageCtrl {
   }
 
   loadAlerts() {
-    this.backendSrv.get('/api/alerts/rules').then(result => {
+    var params = {
+      state: this.stateFilter
+    };
+
+    this.backendSrv.get('/api/alerts/rules', params).then(result => {
       this.alerts = _.map(result, alert => {
         alert.iconCss = alertDef.getCssForState(alert.state);
         return alert;

+ 27 - 24
public/app/features/alerts/partials/alerts_page.html

@@ -3,34 +3,37 @@
 
 <div class="page-container" >
 	<div class="page-header">
-    <h1>Alerts</h1>
-  </div>
+		<h1>Alerts</h1>
+		<div class="gf-form-select-wrapper max-width-10">
+			<select class="gf-form-input" ng-model="ctrl.stateFilter" ng-change="ctrl.loadAlerts()" ng-options="filter as filter for filter in ctrl.stateFilters"></select>
+		</div>
+	</div>
 
-  <table class="grafana-options-table">
-    <thead>
-      <th style="min-width: 200px"><strong>Name</strong></th>
-      <th style="width: 1%">State</th>
-      <th style="width: 1%"></th>
-    </thead>
-    <tr ng-repeat="alert in ctrl.alerts">
-      <td>
+	<table class="grafana-options-table">
+		<thead>
+			<th style="min-width: 200px"><strong>Name</strong></th>
+			<th style="width: 1%">State</th>
+			<th style="width: 1%"></th>
+		</thead>
+		<tr ng-repeat="alert in ctrl.alerts">
+			<td>
 				<a href="/alerts/events/{{alert.id}}">
-          {{alert.title}}
-        </a>
-      </td>
-      <td class="text-center">
+					{{alert.title}}
+				</a>
+			</td>
+			<td class="text-center">
 				<a href="/alerts/events/{{alert.id}}">
-          <i class="icon-gf {{alert.iconCss}}"></i>
-        </a>
-      </td>
-      <td class="text-center">
+					<i class="icon-gf {{alert.iconCss}}"></i>
+				</a>
+			</td>
+			<td class="text-center">
 				<a href="/dashboard/{{alert.dashboardUri}}?panelId={{alert.panelId}}&fullscreen&edit" class="btn btn-inverse btn-small">
-          <i class="fa fa-edit"></i>
-          edit
-        </a>
-      </td>
-    </tr>
-  </table>
+					<i class="fa fa-edit"></i>
+					edit
+				</a>
+			</td>
+		</tr>
+	</table>
 </div>