| /** |
| * @module /silence-sk |
| * @description <h2><code>silence-sk</code></h2> |
| * |
| * @evt add-silence-note Sent when the user adds a note to an silence. |
| * The detail includes the text of the note and the key of the silence. |
| * |
| * <pre> |
| * detail { |
| * key: "12312123123", |
| * text: "blah blah blah", |
| * } |
| * </pre> |
| * |
| * @evt del-silence-note Sent when the user deletes a note on an silence. |
| * The detail includes the index of the note and the key of the silence. |
| * |
| * <pre> |
| * detail { |
| * key: "12312123123", |
| * index: 0, |
| * } |
| * </pre> |
| * |
| * @evt save-silence Sent when the user saves a silence. |
| * The detail is the silence. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| * @evt archive-silence Sent when the user archives a silence. |
| * The detail is the silence. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| * @evt reactivate-silence Sent when the user reactivates a silence. |
| * The detail is the silence. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| * @evt delete-silence Sent when the user deletes a silence. |
| * The detail is the silence. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| * @evt delete-silence-param Sent when the user deletes a param from a silence. |
| * The detail is a copy of the silence with the parameter deleted. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| * @evt modify-silence-param Sent when the user modifies a param from a silence. |
| * The detail is a copy of the silence with the parameter modified. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| * @evt add-silence-param Sent when the user add a param to a silence. |
| * The detail is a copy of the silence with the new parameter added. |
| * |
| * <pre> |
| * detail { |
| * silence: {...}, |
| * } |
| * </pre> |
| * |
| */ |
| import { define } from 'elements-sk/define'; |
| import 'elements-sk/icon/add-box-icon-sk'; |
| import 'elements-sk/icon/delete-icon-sk'; |
| |
| import { $$ } from 'common-sk/modules/dom'; |
| import { diffDate } from 'common-sk/modules/human'; |
| import { errorMessage } from 'elements-sk/errorMessage'; |
| import { html, render } from 'lit-html'; |
| import { upgradeProperty } from 'elements-sk/upgradeProperty'; |
| import { |
| abbr, displaySilence, expiresIn, getDurationTillNextDay, notes, |
| } from '../am'; |
| import * as paramset from '../paramset'; |
| |
| const BOT_CENTRIC_PARAMS = ['alertname', 'bot']; |
| |
| function table(ele, o) { |
| const keys = Object.keys(o); |
| keys.sort(); |
| const botCentricParams = JSON.stringify(keys) === JSON.stringify(BOT_CENTRIC_PARAMS); |
| const rules = keys.filter((k) => !k.startsWith('__')).map((k) => html` |
| <tr> |
| <td> |
| <delete-icon-sk title='Delete rule.' @click=${(e) => ele._deleteRule(e, k)}></delete-icon-sk> |
| </td> |
| <th>${k}</th> |
| <td> |
| <input @change=${(e) => ele._modifyRule(e, k)} .value=${displayParamValue(o[k])}></input> |
| ${displayAddBots(botCentricParams, k, ele)} |
| </td> |
| </tr>`); |
| rules.push(html` |
| <tr> |
| <td> |
| <add-box-icon-sk title='Add rule.' @click=${(e) => ele._addRule(e)}></add-box-icon-sk> |
| </td> |
| <td> |
| <input id='add_param_key'></input> |
| </td> |
| <td> |
| <input id='add_param_value'></input> |
| </td> |
| </tr> |
| `); |
| return rules; |
| } |
| |
| function displayAddBots(botCentricParams, key, ele) { |
| if (botCentricParams && key === 'bot') { |
| return html `<button class="param-btns" @click=${() => ele._botsChooser()}>Add bot</button>`; |
| } |
| return ''; |
| } |
| |
| function displayParamValue(paramValue) { |
| if (paramValue.length > 1) { |
| return `${paramValue.join('|')}` |
| } |
| return paramValue; |
| } |
| |
| function addNote(ele) { |
| if (ele._state.key) { |
| return html` |
| <textarea rows=2 cols=80 placeholder="Add description for the silence"></textarea> |
| <button @click=${ele._addNote}>Submit</button> |
| `; |
| } |
| return html`<textarea rows=2 cols=80 placeholder="Add description for the silence"></textarea>`; |
| } |
| |
| function gotoIncident(incident) { |
| window.location.href = `/?alert_id=${incident.id}&tab=1`; |
| } |
| |
| function matches(ele) { |
| if (!ele._incidents) { |
| return ''; |
| } |
| return ele._incidents.filter( |
| (incident) => paramset.match(ele._state.param_set, incident.params) && incident.active, |
| ).map((incident) => html`<h2 @click=${() => gotoIncident(incident)}> ${incident.params.alertname} ${abbr(incident)}</h2>`); |
| } |
| |
| function classOfH2(silence) { |
| if (!silence.active) { |
| return 'inactive'; |
| } |
| return ''; |
| } |
| |
| function actionButtons(ele) { |
| if (ele._state.active) { |
| return html`<button @click=${ele._save}>Save</button> |
| <button @click=${ele._archive}>Archive</button>`; |
| } |
| return html`<button @click=${ele._reactivate}>Reactivate</button> |
| <delete-icon-sk title='Delete silence.' @click=${ele._delete}></delete-icon-sk>`; |
| } |
| |
| const template = (ele) => html` |
| <h2 class=${classOfH2(ele._state)} @click=${ele._headerClick}>${displaySilence(ele._state)}</h2> |
| <div class=body> |
| <section class=actions> |
| ${actionButtons(ele)} |
| </section> |
| <table class=info> |
| <tr><th>User:</th><td>${ele._state.user}</td></th> |
| <tr><th>Duration:</th><td><input class="duration" @change=${ele._durationChange} value=${ele._state.duration}></input><button class="param-btns" @click=${ele._tillNextShift}>Till next shift</button></td></th> |
| <tr><th>Created</th><td title=${new Date(ele._state.created * 1000).toLocaleString()}>${diffDate(ele._state.created * 1000)}</td></tr> |
| <tr><th>Expires</th><td>${expiresIn(ele._state)}</td></tr> |
| </table> |
| <table class=params> |
| ${table(ele, ele._state.param_set)} |
| </table> |
| <section class=notes> |
| ${notes(ele)} |
| </section> |
| <section class=addNote> |
| ${addNote(ele)} |
| </section> |
| <section class=matches> |
| <h1>Matches</h1> |
| ${matches(ele)} |
| </section> |
| </div> |
| `; |
| |
| define('silence-sk', class extends HTMLElement { |
| constructor() { |
| super(); |
| this._incidents = []; |
| } |
| |
| connectedCallback() { |
| upgradeProperty(this, 'state'); |
| upgradeProperty(this, 'incidents'); |
| } |
| |
| /** @prop state {Object} A Silence. */ |
| get state() { return this._state; } |
| |
| set state(val) { |
| this._state = val; |
| this._render(); |
| } |
| |
| /** @prop incidents {string} The current active incidents. */ |
| get incidents() { return this._incidents; } |
| |
| set incidents(val) { |
| this._incidents = val; |
| this._render(); |
| } |
| |
| _headerClick() { |
| if (this.hasAttribute('collapsed')) { |
| this.removeAttribute('collapsed'); |
| } else { |
| this.setAttribute('collapsed', ''); |
| } |
| } |
| |
| _durationChange(e) { |
| this._state.duration = e.target.value; |
| } |
| |
| // Populates duration till next Monday 9am. |
| _tillNextShift() { |
| this._state.duration = getDurationTillNextDay(1, 9); |
| this._render(); |
| } |
| |
| _save() { |
| const detail = { |
| silence: this._state, |
| }; |
| if (!this._state.key) { |
| const textarea = $$('textarea', this); |
| if (!textarea.value) { |
| errorMessage('Please enter a description for the silence'); |
| textarea.focus(); |
| return; |
| } |
| detail.silence.notes = [{ |
| text: textarea.value, |
| ts: Math.floor(new Date().getTime() / 1000), |
| }]; |
| } |
| this.dispatchEvent(new CustomEvent('save-silence', { detail: detail, bubbles: true })); |
| } |
| |
| _archive() { |
| const detail = { |
| silence: this._state, |
| }; |
| this.dispatchEvent(new CustomEvent('archive-silence', { detail: detail, bubbles: true })); |
| } |
| |
| _reactivate() { |
| const detail = { |
| silence: this._state, |
| }; |
| this.dispatchEvent(new CustomEvent('reactivate-silence', { detail: detail, bubbles: true })); |
| } |
| |
| _delete() { |
| const detail = { |
| silence: this._state, |
| }; |
| this.dispatchEvent(new CustomEvent('delete-silence', { detail: detail, bubbles: true })); |
| } |
| |
| _deleteRule(e, key) { |
| const silence = JSON.parse(JSON.stringify(this._state)); |
| delete silence.param_set[key]; |
| const detail = { |
| silence: silence, |
| }; |
| this.dispatchEvent(new CustomEvent('delete-silence-param', { detail: detail, bubbles: true })); |
| } |
| |
| _modifyRule(e, key) { |
| const silence = JSON.parse(JSON.stringify(this._state)); |
| silence.param_set[key] = [e.target.value]; |
| const detail = { |
| silence: silence, |
| }; |
| this.dispatchEvent(new CustomEvent('modify-silence-param', { detail: detail, bubbles: true })); |
| } |
| |
| _addRule() { |
| const keyInput = $$('#add_param_key', this); |
| if (!keyInput.value) { |
| errorMessage('Please enter a name for the new param'); |
| keyInput.focus(); |
| return; |
| } |
| const valueInput = $$('#add_param_value', this); |
| if (!valueInput.value) { |
| errorMessage('Please enter a value for the new param'); |
| valueInput.focus(); |
| return; |
| } |
| |
| // Dispatch event adding the new silence param. |
| const silence = JSON.parse(JSON.stringify(this._state)); |
| silence.param_set[keyInput.value] = [valueInput.value]; |
| const detail = { |
| silence: silence, |
| }; |
| this.dispatchEvent(new CustomEvent('add-silence-param', { detail: detail, bubbles: true })); |
| |
| // Reset the manual param key and value. |
| keyInput.value = ''; |
| valueInput.value = ''; |
| } |
| |
| _botsChooser() { |
| this.dispatchEvent(new CustomEvent('bot-chooser', { detail: {}, bubbles: true })); |
| } |
| |
| _addNote() { |
| const textarea = $$('textarea', this); |
| const detail = { |
| key: this._state.key, |
| text: textarea.value, |
| }; |
| this.dispatchEvent(new CustomEvent('add-silence-note', { detail: detail, bubbles: true })); |
| textarea.value = ''; |
| } |
| |
| _deleteNote(e, index) { |
| const detail = { |
| key: this._state.key, |
| index: index, |
| }; |
| this.dispatchEvent(new CustomEvent('del-silence-note', { detail: detail, bubbles: true })); |
| } |
| |
| _render() { |
| render(template(this), this, { eventContext: this }); |
| } |
| }); |