diff --git a/api.go b/api.go index 4b628761..8627f6fb 100644 --- a/api.go +++ b/api.go @@ -38,7 +38,7 @@ type API struct { config string uptime time.Time - groups func() []*UIGroup + groups func() []*UIGroups // context is an indirection for testing. context func(r *http.Request) context.Context @@ -46,7 +46,7 @@ type API struct { } // NewAPI returns a new API. -func NewAPI(alerts provider.Alerts, silences provider.Silences, gf func() []*UIGroup) *API { +func NewAPI(alerts provider.Alerts, silences provider.Silences, gf func() []*UIGroups) *API { return &API{ context: route.Context, alerts: alerts, diff --git a/dispatch.go b/dispatch.go index 0575e0f7..e0edd547 100644 --- a/dispatch.go +++ b/dispatch.go @@ -59,14 +59,19 @@ func (d *Dispatcher) Run() { // UIGroup is the representation of a group of alerts as provided by // the API. type UIGroup struct { - Matchers types.Matchers `json:"matchers"` - RouteOpts *RouteOpts `json:"routeOpts"` - Labels model.LabelSet `json:"labels"` - Alerts model.Alerts `json:"alerts"` + RouteOpts *RouteOpts `json:"routeOpts"` + Alerts model.Alerts `json:"alerts"` } -func (d *Dispatcher) Groups() []*UIGroup { - var groups []*UIGroup +type UIGroups struct { + Labels model.LabelSet `json:"labels"` + Groups []*UIGroup `json:"groups"` +} + +func (d *Dispatcher) Groups() []*UIGroups { + var groups []*UIGroups + + seen := map[model.Fingerprint]*UIGroups{} for route, ags := range d.aggrGroups { for _, ag := range ags { @@ -75,14 +80,18 @@ func (d *Dispatcher) Groups() []*UIGroup { alerts = append(alerts, a) } - uig := &UIGroup{ - Matchers: route.SquashMatchers(), - Labels: ag.labels, - RouteOpts: &route.RouteOpts, - Alerts: types.Alerts(alerts...), + uig, ok := seen[ag.labels.Fingerprint()] + if !ok { + uig = &UIGroups{Labels: ag.labels} + + seen[ag.labels.Fingerprint()] = uig + groups = append(groups, uig) } - groups = append(groups, uig) + uig.Groups = append(uig.Groups, &UIGroup{ + RouteOpts: &route.RouteOpts, + Alerts: types.Alerts(alerts...), + }) } } diff --git a/main.go b/main.go index ac5ce6e6..2d97b4a7 100644 --- a/main.go +++ b/main.go @@ -66,7 +66,7 @@ func main() { ) defer disp.Stop() - api := NewAPI(alerts, silences, func() []*UIGroup { + api := NewAPI(alerts, silences, func() []*UIGroups { return disp.Groups() }) diff --git a/ui/app/js/app.js b/ui/app/js/app.js index f03167cf..2a56e231 100644 --- a/ui/app/js/app.js +++ b/ui/app/js/app.js @@ -24,7 +24,8 @@ angular.module('am.directives').directive('alert', return { restrict: 'E', scope: { - a: '=' + alert: '=', + hiddenLabels: '=' }, templateUrl: '/app/partials/alert.html' }; @@ -202,11 +203,11 @@ angular.module('am.controllers').controller('AlertCtrl', $scope.silence = { matchers: [] } - angular.forEach($scope.a.labels, function(value, key) { + angular.forEach($scope.alert.labels, function(value, key) { this.push({ name: key, value: value, - isRegex: false, + isRegex: false }); }, $scope.silence.matchers); @@ -219,11 +220,25 @@ angular.module('am.controllers').controller('AlertCtrl', angular.module('am.controllers').controller('AlertsCtrl', function($scope, AlertGroups) { $scope.groups = null; + $scope.allDestinations = []; $scope.refresh = function() { AlertGroups.query({}, function(data) { $scope.groups = data.data; + + $scope.allDestinations = []; + angular.forEach($scope.groups, function(group) { + angular.forEach(group.groups, function(g) { + if ($scope.allDestinations.indexOf(g.routeOpts.sendTo) < 0) { + $scope.allDestinations.push(g.routeOpts.sendTo); + } + }) + }); + + if (!$scope.destinations) { + $scope.destinations = angular.copy($scope.allDestinations); + } }, function(data) { $scope.error = data.data; diff --git a/ui/app/partials/alert.html b/ui/app/partials/alert.html index 15ee02b6..f5828724 100644 --- a/ui/app/partials/alert.html +++ b/ui/app/partials/alert.html @@ -1,8 +1,8 @@
{{ name }} | {{ val }} |