diff --git a/assets/static/silence.js b/assets/static/silence.js
index 34d5c50f6..3c465db77 100644
--- a/assets/static/silence.js
+++ b/assets/static/silence.js
@@ -1,330 +1,328 @@
-/* globals moment */ // moment.js
+const $ = require("jquery");
+const moment = require("moment");
-/* globals Alerts, Colors, Templates, Unsee, UI */
+const alerts = require("./alerts");
+const colors = require("./colors");
+const templates = require("./templates");
+const ui = require("./ui");
+const unsee = require("./unsee");
-/* exported Silence */
-var Silence = (function() {
+function alertmanagerSilencesAPIUrl(prefix) {
+ return prefix + "/api/v1/silences";
+}
- var alertmanagerSilencesAPIUrl = function(prefix) {
- return prefix + "/api/v1/silences";
+function silenceFormData() {
+ var values = $("#newSilenceForm").serializeArray();
+ var payload = {
+ matchers: [],
+ startsAt: "",
+ endsAt: "",
+ createdBy: "",
+ comment: ""
};
-
- var silenceFormData = function() {
- var values = $("#newSilenceForm").serializeArray();
- var payload = {
- matchers: [],
- startsAt: "",
- endsAt: "",
- createdBy: "",
- comment: ""
- };
- $.each(values, function(i, elem){
- switch (elem.name) {
- case "comment": case "createdBy":
- payload[elem.name] = elem.value;
- break;
- }
- });
- if ($("#startsAt").data("DateTimePicker")) {
- payload.startsAt = $("#startsAt").data("DateTimePicker").date();
- }
- if ($("#endsAt").data("DateTimePicker")) {
- payload.endsAt = $("#endsAt").data("DateTimePicker").date();
- }
- $.each($("#newSilenceForm select.silence-label-picker"), function(i, elem) {
- var labelKey = $(elem).data("label-key");
- var values = $(elem).selectpicker("val");
- if (values && values.length > 0) {
- var pval;
- var isRegex = false;
- if (values.length > 1) {
- pval = "^(?:" + values.join("|") + ")$";
- isRegex = true;
- } else {
- pval = values[0];
- }
- payload.matchers.push({
- name: labelKey,
- value: pval,
- isRegex: isRegex
- });
- }
- });
- return payload;
- };
-
- var silenceFormCalculateDuration = function() {
- // skip if datetimepicker isn't ready yet
- if (!$("#startsAt").data("DateTimePicker") || !$("#endsAt").data("DateTimePicker")) return false;
-
- var startsAt = $("#startsAt").data("DateTimePicker").date();
- var endsAt = $("#endsAt").data("DateTimePicker").date();
-
- var totalDays = (endsAt.diff(startsAt, "days"));
- var totalHours = (endsAt.diff(startsAt, "hours")) % 24;
- var totalMinutes = endsAt.diff(startsAt, "minutes") % 60;
- $("#silence-duration-days").html(totalDays);
- $("#silence-duration-hours").html(totalHours);
- $("#silence-duration-minutes").html(totalMinutes);
-
- var startsAtDesc = moment().to(startsAt);
- startsAtDesc = startsAtDesc.replace("in a few seconds", "now");
- startsAtDesc = startsAtDesc.replace("a few seconds ago", "now");
- $("#silence-start-description").html(startsAtDesc);
-
- var endsAtDesc = moment().to(endsAt);
- endsAtDesc = endsAtDesc.replace("in a few seconds", "now");
- endsAtDesc = endsAtDesc.replace("a few seconds ago", "now");
- $("#silence-end-description").html(endsAtDesc);
- };
-
- var silenceFormAlertmanagerURL = function() {
- return $("#newSilenceForm .silence-alertmanager-picker").selectpicker("val");
- };
-
- var silenceFormJSONRender = function() {
- var d = [];
- $.each(silenceFormAlertmanagerURL(), function(i, uri) {
- if (i > 0) {
- d.push("\n");
- }
- d.push("curl " + alertmanagerSilencesAPIUrl(uri));
- });
- d.push("\n -X POST --data ");
- d.push(JSON.stringify(silenceFormData(), undefined, 2));
- $("#silenceJSONBlob").html(d.join(""));
- };
-
- var silenceFormUpdateDuration = function(event) {
- // skip if datetimepicker isn't ready yet
- if (!$("#startsAt").data("DateTimePicker") || !$("#endsAt").data("DateTimePicker")) return false;
-
- var startsAt = $("#startsAt").data("DateTimePicker").date();
- var endsAt = $("#endsAt").data("DateTimePicker").date();
- var endsAtMinDate = $("#endsAt").data("DateTimePicker").minDate();
- var action = $(event.target).data("duration-action");
- var unit = $(event.target).data("duration-unit");
- var step = parseInt($(event.target).data("duration-step"));
-
- // re-calculate step for low values
- // if we have 5 minute step and current duration is 1 minute than clicking
- // on the increment should give us 5 minute, not 6 minute duration
- var totalValue = (endsAt.diff(startsAt, unit));
- switch (unit) {
- case "hours":
- totalValue = totalValue % 24;
- break;
- case "minutes":
- totalValue = totalValue % 60;
+ $.each(values, function(i, elem){
+ switch (elem.name) {
+ case "comment": case "createdBy":
+ payload[elem.name] = elem.value;
break;
}
-
- if (action == "increment") {
- // if step is 5 minute and current value is 3 than set 5 minutes, not 8
- if (step > 1 && totalValue < step) {
- step = step - totalValue;
- }
- endsAt.add(step, unit);
- } else {
- // if step is 5 minute and current value is 3 than set 0 minutes
- if (totalValue > 0 && step > 1 && totalValue < step) {
- step = totalValue;
- }
- endsAt.subtract(step, unit);
- if (endsAt < endsAtMinDate) {
- // if decrement would result in a timestamp lower than allowed minimum
- // then just reset it to the minimum
- endsAt = endsAtMinDate;
+ });
+ if ($("#startsAt").data("DateTimePicker")) {
+ payload.startsAt = $("#startsAt").data("DateTimePicker").date();
+ }
+ if ($("#endsAt").data("DateTimePicker")) {
+ payload.endsAt = $("#endsAt").data("DateTimePicker").date();
+ }
+ $.each($("#newSilenceForm select.silence-label-picker"), function(i, elem) {
+ var labelKey = $(elem).data("label-key");
+ var values = $(elem).selectpicker("val");
+ if (values && values.length > 0) {
+ var pval;
+ var isRegex = false;
+ if (values.length > 1) {
+ pval = "^(?:" + values.join("|") + ")$";
+ isRegex = true;
+ } else {
+ pval = values[0];
}
+ payload.matchers.push({
+ name: labelKey,
+ value: pval,
+ isRegex: isRegex
+ });
}
- $("#endsAt").data("DateTimePicker").date(endsAt);
- silenceFormCalculateDuration();
- };
+ });
+ return payload;
+}
- var sendSilencePOST = function(url, payload) {
- var elem = $(".silence-post-result[data-uri='" + url + "']");
- $.ajax({
- type: "POST",
- url: alertmanagerSilencesAPIUrl(url),
- data: JSON.stringify(payload),
- error: function(xhr, textStatus) {
- var err = Unsee.ParseAJAXError(xhr, textStatus);
- var errContent = Templates.Render("silenceFormError", {error: err});
+function silenceFormCalculateDuration() {
+ // skip if datetimepicker isn't ready yet
+ if (!$("#startsAt").data("DateTimePicker") || !$("#endsAt").data("DateTimePicker")) return false;
+
+ var startsAt = $("#startsAt").data("DateTimePicker").date();
+ var endsAt = $("#endsAt").data("DateTimePicker").date();
+
+ var totalDays = (endsAt.diff(startsAt, "days"));
+ var totalHours = (endsAt.diff(startsAt, "hours")) % 24;
+ var totalMinutes = endsAt.diff(startsAt, "minutes") % 60;
+ $("#silence-duration-days").html(totalDays);
+ $("#silence-duration-hours").html(totalHours);
+ $("#silence-duration-minutes").html(totalMinutes);
+
+ var startsAtDesc = moment().to(startsAt);
+ startsAtDesc = startsAtDesc.replace("in a few seconds", "now");
+ startsAtDesc = startsAtDesc.replace("a few seconds ago", "now");
+ $("#silence-start-description").html(startsAtDesc);
+
+ var endsAtDesc = moment().to(endsAt);
+ endsAtDesc = endsAtDesc.replace("in a few seconds", "now");
+ endsAtDesc = endsAtDesc.replace("a few seconds ago", "now");
+ $("#silence-end-description").html(endsAtDesc);
+}
+
+function silenceFormAlertmanagerURL() {
+ return $("#newSilenceForm .silence-alertmanager-picker").selectpicker("val");
+}
+
+function silenceFormJSONRender() {
+ var d = [];
+ $.each(silenceFormAlertmanagerURL(), function(i, uri) {
+ if (i > 0) {
+ d.push("\n");
+ }
+ d.push("curl " + alertmanagerSilencesAPIUrl(uri));
+ });
+ d.push("\n -X POST --data ");
+ d.push(JSON.stringify(silenceFormData(), undefined, 2));
+ $("#silenceJSONBlob").html(d.join(""));
+}
+
+function silenceFormUpdateDuration(event) {
+ // skip if datetimepicker isn't ready yet
+ if (!$("#startsAt").data("DateTimePicker") || !$("#endsAt").data("DateTimePicker")) return false;
+
+ var startsAt = $("#startsAt").data("DateTimePicker").date();
+ var endsAt = $("#endsAt").data("DateTimePicker").date();
+ var endsAtMinDate = $("#endsAt").data("DateTimePicker").minDate();
+ var action = $(event.target).data("duration-action");
+ var unit = $(event.target).data("duration-unit");
+ var step = parseInt($(event.target).data("duration-step"));
+
+ // re-calculate step for low values
+ // if we have 5 minute step and current duration is 1 minute than clicking
+ // on the increment should give us 5 minute, not 6 minute duration
+ var totalValue = (endsAt.diff(startsAt, unit));
+ switch (unit) {
+ case "hours":
+ totalValue = totalValue % 24;
+ break;
+ case "minutes":
+ totalValue = totalValue % 60;
+ break;
+ }
+
+ if (action == "increment") {
+ // if step is 5 minute and current value is 3 than set 5 minutes, not 8
+ if (step > 1 && totalValue < step) {
+ step = step - totalValue;
+ }
+ endsAt.add(step, unit);
+ } else {
+ // if step is 5 minute and current value is 3 than set 0 minutes
+ if (totalValue > 0 && step > 1 && totalValue < step) {
+ step = totalValue;
+ }
+ endsAt.subtract(step, unit);
+ if (endsAt < endsAtMinDate) {
+ // if decrement would result in a timestamp lower than allowed minimum
+ // then just reset it to the minimum
+ endsAt = endsAtMinDate;
+ }
+ }
+ $("#endsAt").data("DateTimePicker").date(endsAt);
+ silenceFormCalculateDuration();
+}
+
+function sendSilencePOST(url, payload) {
+ var elem = $(".silence-post-result[data-uri='" + url + "']");
+ $.ajax({
+ type: "POST",
+ url: alertmanagerSilencesAPIUrl(url),
+ data: JSON.stringify(payload),
+ error: function(xhr, textStatus) {
+ var err = unsee.parseAJAXError(xhr, textStatus);
+ var errContent = templates.renderTemplate("silenceFormError", {error: err});
+ $(elem).html(errContent);
+ },
+ success: function(data) {
+ if (data.status == "success") {
+ $(elem).html(templates.renderTemplate("silenceFormSuccess", {
+ silenceID: data.data.silenceId
+ }));
+ } else {
+ var err = "Invalid response from Alertmanager API: " + JSON.stringify(data);
+ var errContent = templates.renderTemplate("silenceFormError", {error: err});
$(elem).html(errContent);
+ }
+ },
+ dataType: "json"
+ });
+}
+
+// modal form for creating new silences
+function setupSilenceForm() {
+ var modal = $("#silenceModal");
+ modal.on("show.bs.modal", function(event) {
+ var elem = $(event.relatedTarget);
+ // hide tooltip for button that triggers this modal
+ elem.find("[data-toggle]").tooltip("hide");
+ unsee.pause();
+ modal.find(".modal-body").html(
+ templates.renderTemplate("silenceFormLoading", {})
+ );
+ var elemLabels = {};
+ $.each(elem.data("labels").split(","), function(i, l) {
+ elemLabels[l.split("=")[0]] = l.split("=")[1];
+ });
+ $.ajax({
+ url: "alerts.json?q=alertname=" + elem.data("alertname"),
+ error: function(xhr, textStatus) {
+ var err = unsee.parseAJAXError(xhr, textStatus);
+ modal.find(".modal-body").html(
+ templates.renderTemplate("silenceFormFatal", {error: err})
+ );
},
success: function(data) {
- if (data.status == "success") {
- $(elem).html(Templates.Render("silenceFormSuccess", {
- silenceID: data.data.silenceId
- }));
- } else {
- var err = "Invalid response from Alertmanager API: " + JSON.stringify(data);
- var errContent = Templates.Render("silenceFormError", {error: err});
- $(elem).html(errContent);
- }
- },
- dataType: "json"
- });
- };
-
- // modal form for creating new silences
- var setupSilenceForm = function() {
- var modal = $("#silenceModal");
- modal.on("show.bs.modal", function(event) {
- var elem = $(event.relatedTarget);
- // hide tooltip for button that triggers this modal
- elem.find("[data-toggle]").tooltip("hide");
- Unsee.Pause();
- modal.find(".modal-body").html(
- Templates.Render("silenceFormLoading", {})
- );
- var elemLabels = {};
- $.each(elem.data("labels").split(","), function(i, l) {
- elemLabels[l.split("=")[0]] = l.split("=")[1];
- });
- $.ajax({
- url: "alerts.json?q=alertname=" + elem.data("alertname"),
- error: function(xhr, textStatus) {
- var err = Unsee.ParseAJAXError(xhr, textStatus);
- modal.find(".modal-body").html(
- Templates.Render("silenceFormFatal", {error: err})
- );
- },
- success: function(data) {
- // add colors from the response to global color set
- Colors.Merge(data.colors);
- var modal = $("#silenceModal");
- var labels = {};
- var alertmanagers = {};
- $.each(data.groups, function(i, group) {
- $.each(group.alerts, function(j, alert) {
- $.each(alert.labels, function(labelKey, labelVal) {
- if (labels[labelKey] === undefined) {
- labels[labelKey] = {};
- }
- if (labels[labelKey][labelVal] === undefined) {
- labels[labelKey][labelVal] = {
- key: labelKey,
- value: labelVal,
- attrs: Alerts.GetLabelAttrs(labelKey, labelVal),
- selected: elemLabels[labelKey] == labelVal
- };
- }
- });
- $.each(alert.alertmanager, function(i, alertmanager){
- alertmanagers[alertmanager.name] = alertmanager;
- });
- });
- });
- modal.find(".modal-body").html(
- Templates.Render("silenceForm", {
- labels: labels,
- alertmanagers: alertmanagers,
- selectedAlertmanagers: elem.data("alertmanagers").split(",")
- })
- );
- $.each($(".silence-alertmanager-picker"), function(i, elem) {
- $(elem).selectpicker();
- });
- $.each($(".silence-label-picker"), function(i, elem) {
- $(elem).selectpicker({
- noneSelectedText: "" + $(this).data("label-key") + ": ",
- countSelectedText: function (numSelected) {
- return "" +
- $(elem).data("label-key") + ": " + numSelected + " values selected";
+ // add colors from the response to global color set
+ colors.merge(data.colors);
+ var modal = $("#silenceModal");
+ var labels = {};
+ var alertmanagers = {};
+ $.each(data.groups, function(i, group) {
+ $.each(group.alerts, function(j, alert) {
+ $.each(alert.labels, function(labelKey, labelVal) {
+ if (labels[labelKey] === undefined) {
+ labels[labelKey] = {};
+ }
+ if (labels[labelKey][labelVal] === undefined) {
+ labels[labelKey][labelVal] = {
+ key: labelKey,
+ value: labelVal,
+ attrs: alerts.getLabelAttrs(labelKey, labelVal),
+ selected: elemLabels[labelKey] == labelVal
+ };
}
});
+ $.each(alert.alertmanager, function(i, alertmanager){
+ alertmanagers[alertmanager.name] = alertmanager;
+ });
});
- $(".datetime-picker").datetimepicker({
- format: "YYYY-MM-DD HH:mm",
- icons: {
- time: "fa fa-clock-o",
- date: "fa fa-calendar",
- up: "fa fa-chevron-up",
- down: "fa fa-chevron-down",
- previous: "fa fa-chevron-left",
- next: "fa fa-chevron-right",
- today: "fa fa-asterisk",
- clear: "fa fa-undo",
- close: "fa fa-close"
- },
- minDate: moment(),
- sideBySide: true,
- inline: true
- });
- UI.SetupTooltips($("#newSilenceForm"));
- $(".select-label-badge").on("click", function() {
- var select = $(this).parent().parent().find("select");
- if (select.selectpicker("val").length) {
- // if there's anything selected deselect all
- select.selectpicker("deselectAll");
- } else {
- // else select all
- select.selectpicker("selectAll");
+ });
+ modal.find(".modal-body").html(
+ templates.renderTemplate("silenceForm", {
+ labels: labels,
+ alertmanagers: alertmanagers,
+ selectedAlertmanagers: elem.data("alertmanagers").split(",")
+ })
+ );
+ $.each($(".silence-alertmanager-picker"), function(i, elem) {
+ $(elem).selectpicker();
+ });
+ $.each($(".silence-label-picker"), function(i, elem) {
+ $(elem).selectpicker({
+ noneSelectedText: "" + $(this).data("label-key") + ": ",
+ countSelectedText: function (numSelected) {
+ return "" +
+ $(elem).data("label-key") + ": " + numSelected + " values selected";
}
});
- // set endsAt minDate to now + 1 minute
- $("#endsAt").data("DateTimePicker").minDate(moment().add(1, "minute"));
- // set endsAt time to +1 hour
- $("#endsAt").data("DateTimePicker").date(moment().add(1, "hours"));
- // whenever startsAt changes set it as the minDate for endsAt
- // we can't have endsAt < startsAt
- $("#newSilenceForm").on("dp.change", "#startsAt", function(){
- if (!$("#startsAt").data("DateTimePicker")) return false;
- var startsAt = $("#startsAt").data("DateTimePicker").date();
- // endsAt needs to be at least 1 minute after startsAt
- startsAt.add(1, "minute");
- $("#endsAt").data("DateTimePicker").minDate(startsAt);
- });
- $("#newSilenceForm").on("click", "a.silence-duration-btn", silenceFormUpdateDuration);
- $("#newSilenceForm").on("show.bs.collapse, dp.change", function () {
- silenceFormJSONRender();
- silenceFormCalculateDuration();
- });
- $("#newSilenceForm").on("change", function () {
- silenceFormJSONRender();
- });
- $("#newSilenceForm").submit(function(event) {
- var payload = silenceFormData();
- if (payload.matchers.length === 0) {
- var errContent = Templates.Render("silenceFormValidationError", {error: "Select at least on label"});
- $("#newSilenceAlert").html(errContent).removeClass("hidden");
- return false;
- }
- $("#newSilenceAlert").addClass("hidden");
-
- var selectedAMURIs = silenceFormAlertmanagerURL();
- var selectedAMs = [];
- $.each(alertmanagers, function(i, am) {
- if ($.inArray(am.uri, selectedAMURIs) >= 0) {
- selectedAMs.push(am);
- }
- });
- modal.find(".modal-body").html(
- Templates.Render("silenceFormResults", {alertmanagers: selectedAMs})
- );
-
- $.each(selectedAMURIs, function(i, uri){
- sendSilencePOST(uri, payload);
- });
-
- event.preventDefault();
- });
- silenceFormCalculateDuration();
+ });
+ $(".datetime-picker").datetimepicker({
+ format: "YYYY-MM-DD HH:mm",
+ icons: {
+ time: "fa fa-clock-o",
+ date: "fa fa-calendar",
+ up: "fa fa-chevron-up",
+ down: "fa fa-chevron-down",
+ previous: "fa fa-chevron-left",
+ next: "fa fa-chevron-right",
+ today: "fa fa-asterisk",
+ clear: "fa fa-undo",
+ close: "fa fa-close"
+ },
+ minDate: moment(),
+ sideBySide: true,
+ inline: true
+ });
+ ui.setupGroupTooltips($("#newSilenceForm"));
+ $(".select-label-badge").on("click", function() {
+ var select = $(this).parent().parent().find("select");
+ if (select.selectpicker("val").length) {
+ // if there's anything selected deselect all
+ select.selectpicker("deselectAll");
+ } else {
+ // else select all
+ select.selectpicker("selectAll");
+ }
+ });
+ // set endsAt minDate to now + 1 minute
+ $("#endsAt").data("DateTimePicker").minDate(moment().add(1, "minute"));
+ // set endsAt time to +1 hour
+ $("#endsAt").data("DateTimePicker").date(moment().add(1, "hours"));
+ // whenever startsAt changes set it as the minDate for endsAt
+ // we can't have endsAt < startsAt
+ $("#newSilenceForm").on("dp.change", "#startsAt", function(){
+ if (!$("#startsAt").data("DateTimePicker")) return false;
+ var startsAt = $("#startsAt").data("DateTimePicker").date();
+ // endsAt needs to be at least 1 minute after startsAt
+ startsAt.add(1, "minute");
+ $("#endsAt").data("DateTimePicker").minDate(startsAt);
+ });
+ $("#newSilenceForm").on("click", "a.silence-duration-btn", silenceFormUpdateDuration);
+ $("#newSilenceForm").on("show.bs.collapse, dp.change", function () {
silenceFormJSONRender();
- }
- });
+ silenceFormCalculateDuration();
+ });
+ $("#newSilenceForm").on("change", function () {
+ silenceFormJSONRender();
+ });
+ $("#newSilenceForm").submit(function(event) {
+ var payload = silenceFormData();
+ if (payload.matchers.length === 0) {
+ var errContent = templates.renderTemplate("silenceFormValidationError", {error: "Select at least on label"});
+ $("#newSilenceAlert").html(errContent).removeClass("hidden");
+ return false;
+ }
+ $("#newSilenceAlert").addClass("hidden");
+ var selectedAMURIs = silenceFormAlertmanagerURL();
+ var selectedAMs = [];
+ $.each(alertmanagers, function(i, am) {
+ if ($.inArray(am.uri, selectedAMURIs) >= 0) {
+ selectedAMs.push(am);
+ }
+ });
+ modal.find(".modal-body").html(
+ templates.renderTemplate("silenceFormResults", {alertmanagers: selectedAMs})
+ );
+
+ $.each(selectedAMURIs, function(i, uri){
+ sendSilencePOST(uri, payload);
+ });
+
+ event.preventDefault();
+ });
+ silenceFormCalculateDuration();
+ silenceFormJSONRender();
+ }
});
- modal.on("hidden.bs.modal", function() {
- var modal = $(this);
- modal.find(".modal-body").children().remove();
- Unsee.WaitForNextReload();
- });
- };
- return {
- Init: setupSilenceForm
- };
+ });
+ modal.on("hidden.bs.modal", function() {
+ var modal = $(this);
+ modal.find(".modal-body").children().remove();
+ unsee.resume();
+ });
+}
-})();
+exports.setupSilenceForm = setupSilenceForm;
diff --git a/assets/static/silence.test.js b/assets/static/silence.test.js
new file mode 100644
index 000000000..2ce6d91dd
--- /dev/null
+++ b/assets/static/silence.test.js
@@ -0,0 +1,5 @@
+test("silence setupSilenceForm()", () => {
+ window.jQuery = require("jquery");
+ const silence = require("./silence");
+ silence.setupSilenceForm();
+});