github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/static/js/alert.js (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 'use strict'; 18 19 let alertData = {queryParams :{}}; 20 let alertEditFlag = 0; 21 let alertID; 22 let alertRule_name = "alertRule_name"; 23 let query_string = "query_string"; 24 let condition = "condition"; 25 let notification_channel_type = "notification_channel_type"; 26 let messageTemplateInfo = 27 '<i class="fa fa-info-circle position-absolute info-icon sendMsg" rel="tooltip" id="info-icon-msg" style="display: block;" title = "You can use following template variables:' + 28 '\n' + inDoubleBrackets("alert_rule_name") + 29 '\n' + inDoubleBrackets("query_string") + 30 '\n' + inDoubleBrackets('condition') + 31 '\n' + inDoubleBrackets('queryLanguage') + '"></i>'; 32 let messageInputBox = document.getElementById("message-info"); 33 if(messageInputBox) 34 messageInputBox.innerHTML += messageTemplateInfo; 35 36 // If there's double brackets next to each other, the templating system will 37 // try to replace what's inside the brackets with a value. We don't want that 38 // in this case. 39 function inDoubleBrackets(str) { 40 return "{" + "{" + str + "}" + "}"; 41 } 42 43 let mapConditionTypeToIndex =new Map([ 44 ["Is above",0], 45 ["Is below",1], 46 ["Equal to",2], 47 ["Not equal to",3] 48 ]); 49 50 let mapIndexToConditionType =new Map([ 51 [0,"Is above"], 52 [1,"Is below"], 53 [2,"Equal to"], 54 [3,"Not equal to"] 55 ]); 56 57 let mapIndexToAlertState=new Map([ 58 [0,"Normal"], 59 [1,"Pending"], 60 [2,"Firing"], 61 ]); 62 63 const alertForm =$('#alert-form'); 64 65 $(document).ready(function () { 66 if (Cookies.get('theme')) { 67 theme = Cookies.get('theme'); 68 $('body').attr('data-theme', theme); 69 70 } 71 $('.theme-btn').on('click', themePickerHandler); 72 $("#logs-language-btn").show(); 73 let startTime = "now-30m"; 74 let endTime = "now"; 75 datePickerHandler(startTime, endTime, startTime); 76 setupEventHandlers(); 77 78 $('.alert-condition-options li').on('click', setAlertConditionHandler); 79 $('#contact-points-dropdown').on('click', contactPointsDropdownHandler); 80 $('#logs-language-options li').on('click', setLogsLangHandler); 81 $('#data-source-options li').on('click', setDataSourceHandler); 82 $('#cancel-alert-btn').on('click',function(){ 83 window.location.href='../all-alerts.html'; 84 resetAddAlertForm(); 85 }); 86 87 alertForm.on('submit',(e)=>submitAddAlertForm(e)); 88 89 const tooltipIds = ["info-icon-spl", "info-icon-msg", "info-evaluate-every", "info-evaluate-for"]; 90 91 tooltipIds.forEach(id => { 92 $(`#${id}`).tooltip({ 93 delay: { show: 0, hide: 300 }, 94 trigger: "click" 95 }).on("click", function () { 96 $(`#${id}`).tooltip("show"); 97 }); 98 }); 99 100 $(document).mouseup(function (e) { 101 if ($(e.target).closest(".tooltip-inner").length === 0) { 102 tooltipIds.forEach(id => $(`#${id}`).tooltip("hide")); 103 } 104 }); 105 getAlertId(); 106 if(window.location.href.includes("alert-details.html")){ 107 alertDetailsFunctions(); 108 } 109 }); 110 111 function getAlertId() { 112 const urlParams = new URLSearchParams(window.location.search); 113 114 if (urlParams.has('id')) { 115 const id = urlParams.get('id'); 116 editAlert(id); 117 alertID = id; 118 } else if (urlParams.has('queryLanguage')) { 119 const queryLanguage = urlParams.get('queryLanguage'); 120 const searchText = urlParams.get('searchText'); 121 const startEpoch = urlParams.get('startEpoch'); 122 const endEpoch = urlParams.get('endEpoch'); 123 124 createAlertFromLogs(queryLanguage, searchText, startEpoch, endEpoch); 125 } 126 } 127 128 function editAlert(alertId){ 129 $.ajax({ 130 method: "get", 131 url: "api/alerts/" + alertId, 132 headers: { 133 'Content-Type': 'application/json; charset=utf-8', 134 'Accept': '*/*' 135 }, 136 dataType: 'json', 137 crossDomain: true, 138 }).then(function (res) { 139 if(window.location.href.includes("alert-details.html")){ 140 displayAlertProperties(res.alert) 141 }else{ 142 alertEditFlag = 1; 143 displayAlert(res.alert); 144 } 145 }) 146 } 147 148 function setAlertConditionHandler(e) { 149 $('.alert-condition-option').removeClass('active'); 150 $('#alert-condition span').html($(this).html()); 151 $(this).addClass('active'); 152 let optionId = $(this).attr('id'); 153 } 154 155 function contactPointsDropdownHandler() { 156 //get all contact points 157 $.ajax({ 158 method: "get", 159 url: "api/alerts/allContacts", 160 headers: { 161 'Content-Type': 'application/json; charset=utf-8', 162 'Accept': '*/*' 163 }, 164 dataType: 'json', 165 crossDomain: true, 166 }).then(function (res) { 167 if (res.contacts) { 168 let dropdown = $('.contact-points-options'); 169 170 res.contacts.forEach((cp) => { 171 if (!$(`.contact-points-option:contains(${cp.contact_name})`).length) { 172 dropdown.append(`<li class="contact-points-option" id="${cp.contact_id}">${cp.contact_name}</li>`); 173 } 174 }); 175 } 176 })} 177 178 179 $('.contact-points-options').on('click', 'li', function () { 180 $('.contact-points-option').removeClass('active'); 181 $('#contact-points-dropdown span').html($(this).html()); 182 $('#contact-points-dropdown span').attr('id', $(this).attr('id')); 183 $(this).addClass('active'); 184 185 if ($(this).html() === 'Add New') { 186 $('.popupOverlay, .popupContent').addClass('active'); 187 $('#contact-form-container').css("display", "block"); 188 } 189 }); 190 191 $(document).keyup(function(e) { 192 if (e.key === "Escape" || e.key === "Esc") { 193 $('.popupOverlay, .popupContent').removeClass('active'); 194 } 195 }); 196 197 198 199 //create new alert rule 200 function submitAddAlertForm(e){ 201 e.preventDefault(); 202 setAlertRule(); 203 alertEditFlag ? updateAlertRule(alertData) : createNewAlertRule(alertData); 204 } 205 206 function setAlertRule(){ 207 let dataSource = $('#alert-data-source span').text(); 208 alertData.alert_name = $('#alert-rule-name').val(), 209 alertData.queryParams.data_source = dataSource; 210 alertData.queryParams.queryLanguage = $('#logs-language-btn span').text(); 211 alertData.queryParams.queryText= $('#query').val(), 212 alertData.queryParams.startTime= filterStartDate, 213 alertData.queryParams.endTime= filterEndDate, 214 alertData.condition= mapConditionTypeToIndex.get($('#alert-condition span').text()), 215 alertData.eval_interval= parseInt($('#evaluate-every').val()), 216 alertData.eval_for= parseInt($('#evaluate-for').val()), 217 alertData.contact_name= $('#contact-points-dropdown span').text(), 218 alertData.contact_id= $('#contact-points-dropdown span').attr('id'), 219 alertData.message= $('.message').val() 220 alertData.value = parseFloat($('#threshold-value').val()); 221 alertData.message = $(".message").val(); 222 alertData.labels =[] 223 224 $('.label-container').each(function() { 225 let labelName = $(this).find('#label-key').val(); 226 let labelVal = $(this).find('#label-value').val(); 227 if (labelName && labelVal) { 228 let labelEntry = { 229 label_name: labelName, 230 label_value: labelVal 231 }; 232 alertData.labels.push(labelEntry); 233 } 234 }) 235 } 236 237 function createNewAlertRule(alertData){ 238 $.ajax({ 239 method: "post", 240 url: "api/alerts/create", 241 headers: { 242 'Content-Type': 'application/json; charset=utf-8', 243 'Accept': '*/*' 244 }, 245 data: JSON.stringify(alertData), 246 dataType: 'json', 247 crossDomain: true, 248 }).then((res)=>{ 249 resetAddAlertForm(); 250 window.location.href='../all-alerts.html'; 251 }).catch((err)=>{ 252 showToast(err.responseJSON.error) 253 }); 254 } 255 256 // update alert rule 257 function updateAlertRule(alertData){ 258 $.ajax({ 259 method: "post", 260 url: "api/alerts/update", 261 headers: { 262 'Content-Type': 'application/json; charset=utf-8', 263 'Accept': '*/*' 264 }, 265 data: JSON.stringify(alertData), 266 dataType: 'json', 267 crossDomain: true, 268 }).then((res)=>{ 269 resetAddAlertForm(); 270 window.location.href='../all-alerts.html'; 271 }).catch((err)=>{ 272 showToast(err.responseJSON.error) 273 }); 274 } 275 276 //reset alert form 277 function resetAddAlertForm(){ 278 alertForm[0].reset(); 279 } 280 281 function displayAlert(res){ 282 $('#alert-rule-name').val(res.alert_name); 283 $('#alert-data-source span').html(res.queryParams.data_source); 284 const queryLanguage = res.queryParams.queryLanguage; 285 $('#logs-language-btn span').text(queryLanguage); 286 $('.logs-language-option').removeClass('active'); 287 $(`.logs-language-option:contains(${queryLanguage})`).addClass('active'); 288 displayQueryToolTip(queryLanguage); 289 $('#query').val(res.queryParams.queryText); 290 $(`.ranges .inner-range #${res.queryParams.startTime}`).addClass('active'); 291 datePickerHandler(res.queryParams.startTime, res.queryParams.endTime, res.queryParams.startTime) 292 let conditionType = mapIndexToConditionType.get(res.condition) 293 $('.alert-condition-option').removeClass('active'); 294 $(`.alert-condition-options #option-${res.condition}`).addClass('active'); 295 $('#alert-condition span').text(conditionType); 296 $('#threshold-value').val(res.value); 297 $('#evaluate-every').val(res.eval_interval); 298 $('#evaluate-for').val(res.eval_for); 299 $('.message').val(res.message); 300 if(alertEditFlag){ 301 alertData.alert_id = res.alert_id; 302 } 303 $('#contact-points-dropdown span').html(res.contact_name); 304 $('#contact-points-dropdown span').attr('id', res.contact_id); 305 306 let isFirst = true; 307 (res.labels).forEach(function(label){ 308 let labelContainer; 309 if (isFirst) { 310 labelContainer = $('.label-container'); 311 isFirst = false; 312 } else { 313 labelContainer = $('.label-container').first().clone(); 314 labelContainer.append('<button class="btn-simple delete-icon" type="button" id="delete-alert-label"></button>'); 315 } 316 labelContainer.find("#label-key").val(label.label_name); 317 labelContainer.find("#label-value").val(label.label_value); 318 labelContainer.appendTo('.label-main-container'); 319 }) 320 321 } 322 323 function showToast(msg) { 324 let toast = 325 `<div class="div-toast" id="save-db-modal"> 326 ${msg} 327 <button type="button" aria-label="Close" class="toast-close">✖</button> 328 <div>` 329 $('body').prepend(toast); 330 $('.toast-close').on('click', removeToast) 331 setTimeout(removeToast, 2000); 332 } 333 334 function removeToast() { 335 $('.div-toast').remove(); 336 } 337 338 function setLogsLangHandler(e) { 339 $('.logs-language-option').removeClass('active'); 340 $('#logs-language-btn span').html($(this).html()); 341 $(this).addClass('active'); 342 displayQueryToolTip($(this).html()); 343 } 344 345 function setDataSourceHandler(e) { 346 $('.data-source-option').removeClass('active'); 347 $('#alert-data-source span').html($(this).html()); 348 $(this).addClass('active'); 349 } 350 351 function displayQueryToolTip(selectedQueryLang) { 352 $('#info-icon-pipeQL, #info-icon-spl').hide(); 353 if (selectedQueryLang === "Pipe QL") { 354 $('#info-icon-pipeQL').show(); 355 } else if (selectedQueryLang === "Splunk QL") { 356 $('#info-icon-spl').show(); 357 } 358 } 359 360 // Display Alert Details 361 function displayAlertProperties(res) { 362 const queryParams = res.queryParams; 363 $('.alert-name').text(res.alert_name); 364 $('.alert-status').text(mapIndexToAlertState.get(res.state)); 365 $('.alert-query').val(queryParams.queryText); 366 $('.alert-type').text(queryParams.data_source); 367 $('.alert-query-language').text(queryParams.queryLanguage); 368 $('.alert-condition').text(mapIndexToConditionType.get(res.condition)); 369 $('.alert-value').text(res.value); 370 $('.alert-every').text(res.eval_interval); 371 $('.alert-for').text(res.eval_for); 372 $('.alert-contact-point').text(res.contact_name); 373 const labelContainer = $('.alert-labels-container'); 374 const labels = res.labels; 375 labels.forEach(label => { 376 const labelElement = $('<div>').addClass('label-element').text(`${label.label_name}=${label.label_value}`); 377 labelContainer.append(labelElement); 378 }) 379 } 380 381 // Add Label 382 $(".add-label-container").on("click", function () { 383 var labelContainer = $(".label-container").first().clone(); 384 labelContainer.find("#label-key").val(""); 385 labelContainer.find("#label-value").val(""); 386 labelContainer.append('<button class="btn-simple delete-icon" type="button" id="delete-alert-label"></button>'); 387 labelContainer.appendTo(".label-main-container"); 388 }); 389 390 // Delete Label 391 $(".label-main-container").on("click", ".delete-icon", function () { 392 $(this).closest(".label-container").remove(); 393 }); 394 395 //On Alert Details Page 396 function alertDetailsFunctions(){ 397 function editAlert(event){ 398 var queryString = "?id=" + alertID; 399 window.location.href = "../alert.html" + queryString; 400 event.stopPropagation(); 401 } 402 403 function deleteAlert() { 404 $.ajax({ 405 method: 'delete', 406 url: 'api/alerts/delete', 407 headers: { 408 'Content-Type': 'application/json; charset=utf-8', 409 Accept: '*/*', 410 }, 411 data: JSON.stringify({ 412 alert_id: alertID 413 }), 414 crossDomain: true, 415 }).then(function (res) { 416 showToast(res.message) 417 window.location.href='../all-alerts.html'; 418 }); 419 } 420 421 function showPrompt(event) { 422 event.stopPropagation(); 423 $('.popupOverlay, .popupContent').addClass('active'); 424 425 $('#cancel-btn, .popupOverlay, #delete-btn').click(function () { 426 $('.popupOverlay, .popupContent').removeClass('active'); 427 }); 428 $('#delete-btn').click(deleteAlert) 429 } 430 431 $('#edit-alert-btn').on('click',editAlert) 432 $('#delete-alert').on('click',showPrompt) 433 $('#cancel-alert-details').on('click',function(){ 434 window.location.href='../all-alerts.html'; 435 }) 436 } 437 438 //Create alert from logs 439 function createAlertFromLogs(queryLanguage, query, startEpoch, endEpoch){ 440 $('#alert-rule-name').focus(); 441 $('#query').val(query); 442 $(`.ranges .inner-range #${startEpoch}`).addClass('active'); 443 datePickerHandler(startEpoch, endEpoch , startEpoch) 444 }