mirror of
https://github.com/prometheus/alertmanager
synced 2025-01-12 01:00:08 +00:00
Merge pull request #5 from prometheus/refactor/editable-silences
Implement silence create/read/update/delete API and UI workflow.
This commit is contained in:
commit
3f9cc9e3e3
7
main.go
7
main.go
@ -34,12 +34,19 @@ func main() {
|
||||
defer aggregator.Close()
|
||||
|
||||
webService := &web.WebService{
|
||||
// REST API Service.
|
||||
AlertManagerService: &api.AlertManagerService{
|
||||
Aggregator: aggregator,
|
||||
Suppressor: suppressor,
|
||||
},
|
||||
|
||||
// Template-based page handlers.
|
||||
AlertsHandler: &web.AlertsHandler{
|
||||
Aggregator: aggregator,
|
||||
},
|
||||
SilencesHandler: &web.SilencesHandler{
|
||||
Suppressor: suppressor,
|
||||
},
|
||||
}
|
||||
go webService.ServeForever()
|
||||
|
||||
|
@ -19,15 +19,25 @@ import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
const eventNameLabel = "name"
|
||||
|
||||
type EventFingerprint uint64
|
||||
|
||||
type EventLabels map[string]string
|
||||
type EventPayload map[string]string
|
||||
|
||||
// Event models an action triggered by Prometheus.
|
||||
type Event struct {
|
||||
// Label value pairs for purpose of aggregation, matching, and disposition
|
||||
// dispatching. This must minimally include a "name" label.
|
||||
Labels map[string]string
|
||||
Labels EventLabels
|
||||
// Extra key/value information which is not used for aggregation.
|
||||
Payload map[string]string
|
||||
Payload EventPayload
|
||||
}
|
||||
|
||||
func (e Event) Name() string {
|
||||
// BUG: ensure in a proper place that all events have a name?
|
||||
return e.Labels[eventNameLabel]
|
||||
}
|
||||
|
||||
func (e Event) Fingerprint() EventFingerprint {
|
||||
|
@ -14,6 +14,7 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
@ -21,6 +22,7 @@ import (
|
||||
)
|
||||
|
||||
type SuppressionId uint
|
||||
type Suppressions []*Suppression
|
||||
|
||||
type Suppression struct {
|
||||
// The numeric ID of the suppression.
|
||||
@ -40,7 +42,53 @@ type Suppression struct {
|
||||
expiryTimer *time.Timer
|
||||
}
|
||||
|
||||
type Suppressions []*Suppression
|
||||
type ApiSilence struct {
|
||||
CreatedBy string
|
||||
CreatedAtSeconds int64
|
||||
EndsAtSeconds int64
|
||||
Comment string
|
||||
Filters map[string]string
|
||||
}
|
||||
|
||||
func (s *Suppression) MarshalJSON() ([]byte, error) {
|
||||
filters := map[string]string{}
|
||||
for _, f := range s.Filters {
|
||||
name := f.Name.String()[1 : len(f.Name.String())-1]
|
||||
value := f.Value.String()[1 : len(f.Value.String())-1]
|
||||
filters[name] = value
|
||||
}
|
||||
|
||||
return json.Marshal(&ApiSilence{
|
||||
CreatedBy: s.CreatedBy,
|
||||
CreatedAtSeconds: s.CreatedAt.Unix(),
|
||||
EndsAtSeconds: s.EndsAt.Unix(),
|
||||
Comment: s.Comment,
|
||||
Filters: filters,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Suppression) UnmarshalJSON(data []byte) error {
|
||||
sc := &ApiSilence{}
|
||||
json.Unmarshal(data, sc)
|
||||
|
||||
filters := make(Filters, 0, len(sc.Filters))
|
||||
for label, value := range sc.Filters {
|
||||
filters = append(filters, NewFilter(label, value))
|
||||
}
|
||||
|
||||
if sc.EndsAtSeconds == 0 {
|
||||
sc.EndsAtSeconds = time.Now().Add(time.Hour).Unix()
|
||||
}
|
||||
|
||||
*s = Suppression{
|
||||
CreatedBy: sc.CreatedBy,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
EndsAt: time.Unix(sc.EndsAtSeconds, 0).UTC(),
|
||||
Comment: sc.Comment,
|
||||
Filters: filters,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Suppressor struct {
|
||||
// Suppressions managed by this Suppressor.
|
||||
|
@ -14,8 +14,9 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/prometheus/alert_manager/manager"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/alert_manager/manager"
|
||||
)
|
||||
|
||||
type AlertStatus struct {
|
||||
|
@ -22,7 +22,13 @@ import (
|
||||
type AlertManagerService struct {
|
||||
gorest.RestService `root:"/api/" consumes:"application/json" produces:"application/json"`
|
||||
|
||||
addEvents gorest.EndPoint `method:"POST" path:"/event" postdata:"Events"`
|
||||
addEvents gorest.EndPoint `method:"POST" path:"/events" postdata:"Events"`
|
||||
addSilence gorest.EndPoint `method:"POST" path:"/silences" postdata:"Suppression"`
|
||||
getSilence gorest.EndPoint `method:"GET" path:"/silences/{id:int}" output:"string"`
|
||||
updateSilence gorest.EndPoint `method:"POST" path:"/silences/{id:int}" postdata:"Suppression"`
|
||||
delSilence gorest.EndPoint `method:"DELETE" path:"/silences/{id:int}"`
|
||||
silenceSummary gorest.EndPoint `method:"GET" path:"/silences" output:"string"`
|
||||
|
||||
Aggregator *manager.Aggregator
|
||||
Suppressor *manager.Suppressor
|
||||
}
|
||||
|
93
web/api/silence.go
Normal file
93
web/api/silence.go
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2013 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"code.google.com/p/gorest"
|
||||
|
||||
"github.com/prometheus/alert_manager/manager"
|
||||
)
|
||||
|
||||
type Silence struct {
|
||||
CreatedBy string
|
||||
CreatedAtSeconds int64
|
||||
EndsAtSeconds int64
|
||||
Comment string
|
||||
Filters map[string]string
|
||||
}
|
||||
|
||||
func (s AlertManagerService) AddSilence(sc manager.Suppression) {
|
||||
// BUG: add server-side form validation.
|
||||
id := s.Suppressor.AddSuppression(&sc)
|
||||
|
||||
rb := s.ResponseBuilder()
|
||||
rb.SetResponseCode(http.StatusCreated)
|
||||
rb.Location(fmt.Sprintf("/api/silences/%d", id))
|
||||
}
|
||||
|
||||
func (s AlertManagerService) GetSilence(id int) string {
|
||||
rb := s.ResponseBuilder()
|
||||
rb.SetContentType(gorest.Application_Json)
|
||||
silence, err := s.Suppressor.GetSuppression(manager.SuppressionId(id))
|
||||
if err != nil {
|
||||
log.Printf("Error getting silence: %s", err)
|
||||
rb.SetResponseCode(http.StatusNotFound)
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
resultBytes, err := json.Marshal(&silence)
|
||||
if err != nil {
|
||||
log.Printf("Error marshalling silence: %s", err)
|
||||
rb.SetResponseCode(http.StatusInternalServerError)
|
||||
return err.Error()
|
||||
}
|
||||
return string(resultBytes)
|
||||
}
|
||||
|
||||
func (s AlertManagerService) UpdateSilence(sc manager.Suppression, id int) {
|
||||
// BUG: add server-side form validation.
|
||||
sc.Id = manager.SuppressionId(id)
|
||||
if err := s.Suppressor.UpdateSuppression(&sc); err != nil {
|
||||
log.Printf("Error updating silence: %s", err)
|
||||
rb := s.ResponseBuilder()
|
||||
rb.SetResponseCode(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (s AlertManagerService) DelSilence(id int) {
|
||||
if err := s.Suppressor.DelSuppression(manager.SuppressionId(id)); err != nil {
|
||||
log.Printf("Error deleting silence: %s", err)
|
||||
rb := s.ResponseBuilder()
|
||||
rb.SetResponseCode(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (s AlertManagerService) SilenceSummary() string {
|
||||
rb := s.ResponseBuilder()
|
||||
rb.SetContentType(gorest.Application_Json)
|
||||
silenceSummary := s.Suppressor.SuppressionSummary()
|
||||
|
||||
resultBytes, err := json.Marshal(silenceSummary)
|
||||
if err != nil {
|
||||
log.Printf("Error marshalling silences: %s", err)
|
||||
rb.SetResponseCode(http.StatusInternalServerError)
|
||||
return err.Error()
|
||||
}
|
||||
return string(resultBytes)
|
||||
}
|
@ -15,10 +15,21 @@ package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/alert_manager/manager"
|
||||
)
|
||||
|
||||
type SilencesHandler struct{}
|
||||
type SilenceStatus struct {
|
||||
Silences manager.Suppressions
|
||||
}
|
||||
|
||||
type SilencesHandler struct {
|
||||
Suppressor *manager.Suppressor
|
||||
}
|
||||
|
||||
func (h *SilencesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
executeTemplate(w, "silences", nil)
|
||||
silenceStatus := &SilenceStatus{
|
||||
Silences: h.Suppressor.SuppressionSummary(),
|
||||
}
|
||||
executeTemplate(w, "silences", silenceStatus)
|
||||
}
|
||||
|
@ -2,14 +2,10 @@ body {
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
#create_silence_modal th {
|
||||
#edit_silence_modal th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.add_silence_form {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.del_label_button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
var silenceRow = null;
|
||||
var silenceId = null;
|
||||
|
||||
function clearSilenceLabels() {
|
||||
$("#silence_label_table").empty();
|
||||
$("#silence_filters_table").empty();
|
||||
}
|
||||
|
||||
function addSilenceLabel(label, value) {
|
||||
@ -9,11 +12,11 @@ function addSilenceLabel(label, value) {
|
||||
if (!value) {
|
||||
value = "";
|
||||
}
|
||||
$("#silence_label_table").append(
|
||||
$("#silence_filters_table").append(
|
||||
'<tr>' +
|
||||
' <td><input class="input-large" type="text" placeholder="label regex" value="' + label + '"></td>' +
|
||||
' <td><input class="input-large" type="text" placeholder="value regex" value="' + value + '"></td>' +
|
||||
' <td><button class="btn del_label_button"><i class="icon-minus"></i></button></td>' +
|
||||
' <td><input class="input-large" name="silence_filter_label[]" type="text" placeholder="label regex" value="' + label + '" required></td>' +
|
||||
' <td><input class="input-large" name="silence_filter_value[]" type="text" placeholder="value regex" value="' + value + '" required></td>' +
|
||||
' <td><button type="button" class="btn del_label_button"><i class="icon-minus"></i></button></td>' +
|
||||
'</tr>');
|
||||
bindDelLabel();
|
||||
}
|
||||
@ -25,25 +28,173 @@ function bindDelLabel() {
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
$("#new_silence_btn").click(function() {
|
||||
clearSilenceLabels();
|
||||
function silenceJsonFromForm() {
|
||||
var filters = {};
|
||||
var labels = $('input[name="silence_filter_label[]"]');
|
||||
var values = $('input[name="silence_filter_value[]"]');
|
||||
for (var i = 0; i < labels.length; i++) {
|
||||
filters[labels.get(i).value] = values.get(i).value;
|
||||
}
|
||||
|
||||
var endsAt = 0;
|
||||
if ($("#silence_ends_at").val() != "") {
|
||||
var picker = $("#ends_at_datetimepicker").data("datetimepicker");
|
||||
endsAt = Math.round(picker.getLocalDate().getTime() / 1000);
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
CreatedBy: $("#silence_created_by").val(),
|
||||
EndsAtSeconds: endsAt,
|
||||
Comment: $("#silence_comment").val(),
|
||||
Filters: filters
|
||||
});
|
||||
}
|
||||
|
||||
$(".add_silence_btn").click(function() {
|
||||
clearSilenceLabels();
|
||||
|
||||
var form = $(this).parents("form");
|
||||
var labels = form.children('input[name="label[]"]');
|
||||
var values = form.children('input[name="value[]"]');
|
||||
for (var i = 0; i < labels.length; i++) {
|
||||
addSilenceLabel(labels.get(i).value, values.get(i).value);
|
||||
function createSilence() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/api/silences",
|
||||
data: silenceJsonFromForm(),
|
||||
dataType: "text",
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
location.reload();
|
||||
},
|
||||
error: function(data, textStatus, jqXHR) {
|
||||
alert("Creating silence failed: " + textStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$("#add_label_button").click(function() {
|
||||
function updateSilence() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/api/silences/" + silenceId,
|
||||
data: silenceJsonFromForm(),
|
||||
dataType: "text",
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
location.reload();
|
||||
},
|
||||
error: function(data, textStatus, jqXHR) {
|
||||
alert("Updating silence failed: " + textStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getSilence(silenceId, successFn) {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/api/silences/" + silenceId,
|
||||
async: false,
|
||||
success: successFn,
|
||||
error: function(data, textStatus, jqXHR) {
|
||||
alert("Creating silence failed: " + textStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteSilence(silenceId, silenceRow) {
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url: "/api/silences/" + silenceId,
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
silenceRow.remove();
|
||||
$("#del_silence_modal").modal("hide");
|
||||
},
|
||||
error: function(data, textStatus, jqXHR) {
|
||||
alert("Removing silence failed: " + textStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initNewSilence() {
|
||||
silenceId = null;
|
||||
$("#edit_silence_header, #edit_silence_btn").html("Create Silence");
|
||||
$("#edit_silence_form")[0].reset();
|
||||
}
|
||||
|
||||
function populateSilenceLabels(form) {
|
||||
var labels = form.children('input[name="label[]"]');
|
||||
var values = form.children('input[name="value[]"]');
|
||||
for (var i = 0; i < labels.length; i++) {
|
||||
addSilenceLabel(labels.get(i).value, values.get(i).value);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
$.ajaxSetup({
|
||||
cache: false
|
||||
});
|
||||
|
||||
$("#ends_at_datetimepicker").datetimepicker({
|
||||
language: "en",
|
||||
pickSeconds: false
|
||||
});
|
||||
|
||||
$("#edit_silence_modal").on("shown", function(e) {
|
||||
$("#silence_created_by").focus();
|
||||
});
|
||||
|
||||
$("#edit_silence_modal").on("hidden", function(e) {
|
||||
clearSilenceLabels();
|
||||
});
|
||||
|
||||
// This is the "Silences" page button to open the dialog for creating a new
|
||||
// silence.
|
||||
$("#new_silence_btn").click(function() {
|
||||
initNewSilence();
|
||||
});
|
||||
|
||||
// These are the "Alerts" page buttons to open the dialog for creating a new
|
||||
// silence for the alert / alert instance.
|
||||
$(".add_silence_btn").click(function() {
|
||||
initNewSilence();
|
||||
populateSilenceLabels($(this).parents("form"));
|
||||
});
|
||||
|
||||
$("#add_filter_button").click(function() {
|
||||
addSilenceLabel("", "");
|
||||
});
|
||||
|
||||
$("#edit_silence_form").submit(function() {
|
||||
if (silenceId != null) {
|
||||
updateSilence();
|
||||
} else {
|
||||
createSilence();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$(".edit_silence_btn").click(function() {
|
||||
$("#edit_silence_header, #edit_silence_btn").html("Update Silence");
|
||||
|
||||
silenceRow = $(this).parents("tr");
|
||||
silenceId = silenceRow.find("input[name='silence_id']").val();
|
||||
$("#edit_silence_form input[name='silence_id']").val(silenceId);
|
||||
getSilence(silenceId, function(silence) {
|
||||
var picker = $("#ends_at_datetimepicker").data('datetimepicker');
|
||||
var endsAt = new Date(silence.EndsAtSeconds * 1000);
|
||||
picker.setLocalDate(endsAt);
|
||||
|
||||
$("#silence_created_by").val(silence.CreatedBy);
|
||||
$("#silence_comment").val(silence.Comment);
|
||||
for (var f in silence.Filters) {
|
||||
addSilenceLabel(f, silence.Filters[f]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// When clicking the "Remove Silence" button in the Silences table, save the
|
||||
// table row and silence ID to global variables (ugh) so they can be used
|
||||
// from the modal dialog to remove that silence.
|
||||
$(".del_silence_modal_btn").click(function() {
|
||||
silenceRow = $(this).parents("tr");
|
||||
silenceId = silenceRow.find("input[name='silence_id']").val();
|
||||
});
|
||||
|
||||
// Deletion confirmation button action.
|
||||
$(".del_silence_btn").click(function() {
|
||||
deleteSilence(silenceId, silenceRow);
|
||||
});
|
||||
}
|
||||
|
||||
$(init);
|
||||
|
8
web/static/vendor/tarruda_bootstrap_datetimepicker/css/bootstrap-datetimepicker.min.css
vendored
Normal file
8
web/static/vendor/tarruda_bootstrap_datetimepicker/css/bootstrap-datetimepicker.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
26
web/static/vendor/tarruda_bootstrap_datetimepicker/js/bootstrap-datetimepicker.min.js
vendored
Normal file
26
web/static/vendor/tarruda_bootstrap_datetimepicker/js/bootstrap-datetimepicker.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -10,6 +10,9 @@
|
||||
<link href="/static/vendor/bootstrap/css/bootstrap.min.css" media="all" rel="stylesheet" type="text/css" />
|
||||
<script src="/static/vendor/bootstrap/js/bootstrap.js" type="text/javascript"></script>
|
||||
|
||||
<link href="/static/vendor/tarruda_bootstrap_datetimepicker/css/bootstrap-datetimepicker.min.css" media="all" rel="stylesheet" type="text/css" />
|
||||
<script src="/static/vendor/tarruda_bootstrap_datetimepicker/js/bootstrap-datetimepicker.min.js" type="text/javascript"></script>
|
||||
|
||||
<link href="/static/css/default.css" media="all" rel="stylesheet" type="text/css" />
|
||||
|
||||
{{template "head" .}}
|
||||
@ -45,43 +48,49 @@
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{define "createSilenceModal"}}
|
||||
{{define "editSilenceModal"}}
|
||||
<!-- Modal -->
|
||||
<div id="create_silence_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="create_silence_header" aria-hidden="true">
|
||||
<div id="edit_silence_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="edit_silence_header" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="create_silence_header">Create Silence</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="edit_silence_header">Create Silence</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal">
|
||||
<form class="form-horizontal" id="edit_silence_form">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="silence_creator">Creator</label>
|
||||
<label class="control-label" for="silence_created_by">Creator</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="silence_creator" placeholder="Creator">
|
||||
<input type="text" id="silence_created_by" placeholder="Creator" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="silence_expiry">Expiry</label>
|
||||
<label class="control-label" for="silence_ends_at">Ends At</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="silence_expiry" placeholder="Expiry">
|
||||
<div id="ends_at_datetimepicker" class="input-append date">
|
||||
<input type="text" id="silence_ends_at" placeholder="Ends At (default 1h from now)" data-format="dd/MM/yyyy hh:mm:ss">
|
||||
<span class="add-on">
|
||||
<i data-time-icon="icon-time" data-date-icon="icon-calendar"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="silence_creator">Comment</label>
|
||||
<label class="control-label" for="silence_created_by">Comment</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="silence_comment" placeholder="Comment">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<label>Labels:</label>
|
||||
<table id="silence_label_table">
|
||||
</table>
|
||||
<button class="btn" id="add_label_button"><i class="icon-plus"></i> Add Label Filter</button>
|
||||
<button class="btn">Preview Silence</button>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
|
||||
<button class="btn btn-primary">Create Silence</button>
|
||||
</div>
|
||||
<label>Label filters:</label>
|
||||
<table id="silence_filters_table">
|
||||
</table>
|
||||
<br/>
|
||||
<button type="button" class="btn" id="add_filter_button"><i class="icon-plus"></i> Add Label Filter</button>
|
||||
<button type="button" class="btn">Preview Silence</button>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary" id="edit_silence_btn">Create Silence</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
|
@ -24,23 +24,23 @@
|
||||
{{range .AlertAggregates}}
|
||||
<tr>
|
||||
<td>
|
||||
{{index .Event.Name}}
|
||||
<span class="label label-important">{{index .Event.Name}}</span>
|
||||
<form class="add_silence_form">
|
||||
<input type="hidden" name="label[]" value="name">
|
||||
<input type="hidden" name="value[]" value="{{.Event.Labels.name}}">
|
||||
<a href="#create_silence_modal" role="button" class="btn btn-mini add_silence_btn" data-toggle="modal">Silence Alert</a>
|
||||
<a href="#edit_silence_modal" role="button" class="btn btn-mini add_silence_btn" data-toggle="modal">Silence Alert</a>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
{{range $label, $value := .Event.Labels}}
|
||||
<b>{{$label}}</b>="{{$value}}",
|
||||
<span class="label label-info"><b>{{$label}}</b>="{{$value}}"</span>
|
||||
{{end}}
|
||||
<form class="add_silence_form">
|
||||
{{range $label, $value := .Event.Labels}}
|
||||
<input type="hidden" name="label[]" value="{{$label}}">
|
||||
<input type="hidden" name="value[]" value="{{$value}}">
|
||||
{{end}}
|
||||
<a href="#create_silence_modal" role="button" class="btn btn-mini add_silence_btn" data-toggle="modal">Silence Instance</a>
|
||||
<a href="#edit_silence_modal" role="button" class="btn btn-mini add_silence_btn" data-toggle="modal">Silence Instance</a>
|
||||
</form>
|
||||
</td>
|
||||
<td>{{timeSince .Created}} ago</td>
|
||||
@ -50,5 +50,5 @@
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "createSilenceModal" .}}
|
||||
{{template "editSilenceModal" .}}
|
||||
{{end}}
|
||||
|
@ -6,89 +6,54 @@
|
||||
|
||||
{{define "content"}}
|
||||
<h2>Silences</h2>
|
||||
<p><a href="#create_silence_modal" role="button" class="btn btn-primary" id="new_silence_btn" data-toggle="modal">New Silence</a></p>
|
||||
<p><a href="#edit_silence_modal" role="button" class="btn btn-primary" id="new_silence_btn" data-toggle="modal">New Silence</a></p>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Labels</th>
|
||||
<th>Creator</th>
|
||||
<th>Expires At</th>
|
||||
<th>Created At</th>
|
||||
<th>Ends At</th>
|
||||
<th>Notes</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{service="Taxes",country="*"}</td>
|
||||
<td>your government</td>
|
||||
<td>2050-01-01 10:23:00</td>
|
||||
<td>Taxes are here to stay. Sorry.</td>
|
||||
<td>
|
||||
<button class="btn btn-mini btn-primary">Edit Silence</button>
|
||||
<button class="btn btn-mini btn-danger">Remove Silence</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{range .Silences}}
|
||||
<tr>
|
||||
<td>{{.Id}}</td>
|
||||
<td>
|
||||
{{range .Filters}}
|
||||
<b>{{.Name}}</b>="{{.Value}}",
|
||||
{{end}}
|
||||
</td>
|
||||
<td>{{.CreatedBy}}</td>
|
||||
<td>{{.CreatedAt}}</td>
|
||||
<td>{{.EndsAt}}</td>
|
||||
<td>{{.Comment}}</td>
|
||||
<td>
|
||||
<input type="hidden" name="silence_id" value="{{.Id}}">
|
||||
|
||||
<a href="#edit_silence_modal" role="button" class="btn btn-mini btn-primary edit_silence_btn" id="new_silence_btn" data-toggle="modal">Edit Silence</a>
|
||||
<a href="#del_silence_modal" role="button" class="btn btn-mini btn-danger del_silence_modal_btn" data-toggle="modal">Remove Silence</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "createSilenceModal" .}}
|
||||
{{template "editSilenceModal" .}}
|
||||
<div id="del_silence_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="del_silence_header">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="del_silence_header">Deletion Confirmation</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you really want to delete this silence?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</a>
|
||||
<button class="btn btn-primary btn-danger del_silence_btn">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
Loading…
Reference in New Issue
Block a user