diff --git a/promgen/static/css/promgen.css b/promgen/static/css/promgen.css index 777cc071d..d106ccbc3 100644 --- a/promgen/static/css/promgen.css +++ b/promgen/static/css/promgen.css @@ -49,3 +49,66 @@ a[rel]:after { word-break: break-word; font-family: monospace; } + +/* silence-modal */ +.promgen-labels-list { + padding: 10px 5px; + min-height: 116px; + border-radius: 8px 0px 0px 0px; + margin-left: 0px; + background: #F9F9F9; +} + +.promgen-label-target { + height: 32px; + border-radius: 4px; + color: #000000; + border: 0.5px solid #3269BC; + background: #F1F6FF; + padding: 0px 10px; + margin-bottom: 10px; +} + +.promgen-label-target:hover { + text-decoration: none !important; + color: #000000; +} + +.promgen-label-close { + font-size: 20px; + margin-left: 10px; + color: #aaaaaa; + cursor: pointer; +} + +/* Margin Top */ +.mt-0 { margin-top: 0 !important; } +.mt-1 { margin-top: 0.25rem !important; } +.mt-2 { margin-top: 0.5rem !important; } +.mt-3 { margin-top: 1rem !important; } +.mt-4 { margin-top: 1.5rem !important; } +.mt-5 { margin-top: 3rem !important; } + +/* Margin Bottom */ +.mb-0 { margin-bottom: 0 !important; } +.mb-1 { margin-bottom: 0.25rem !important; } +.mb-2 { margin-bottom: 0.5rem !important; } +.mb-3 { margin-bottom: 1rem !important; } +.mb-4 { margin-bottom: 1.5rem !important; } +.mb-5 { margin-bottom: 3rem !important; } + +/* Margin Left (Bootstrap 4) */ +.ml-0 { margin-left: 0 !important; } +.ml-1 { margin-left: 0.25rem !important; } +.ml-2 { margin-left: 0.5rem !important; } +.ml-3 { margin-left: 1rem !important; } +.ml-4 { margin-left: 1.5rem !important; } +.ml-5 { margin-left: 3rem !important; } + +/* Margin Right (Bootstrap 4) */ +.mr-0 { margin-right: 0 !important; } +.mr-1 { margin-right: 0.25rem !important; } +.mr-2 { margin-right: 0.5rem !important; } +.mr-3 { margin-right: 1rem !important; } +.mr-4 { margin-right: 1.5rem !important; } +.mr-5 { margin-right: 3rem !important; } diff --git a/promgen/static/js/promgen.vue.js b/promgen/static/js/promgen.vue.js index 77679d3d5..e9410cc63 100644 --- a/promgen/static/js/promgen.vue.js +++ b/promgen/static/js/promgen.vue.js @@ -25,15 +25,18 @@ const silenceStore = Vue.reactive({ show: false, labels: {} }, - showForm() { - this.state.show = true; - }, setLabels(labels) { this.state.labels = { ...labels }; }, addLabel(label, value) { this.state.labels[label] = value; - } + }, + showModal() { + this.state.show = true; + }, + hideModal() { + this.state.show = false; + }, }); const exporterTestResultStore = Vue.reactive({ @@ -67,16 +70,14 @@ const app = Vue.createApp({ }, setSilenceLabels(labels) { silenceStore.setLabels(labels); - silenceStore.showForm(); - scroll(0, 0); + silenceStore.showModal(); }, setSilenceDataset(event) { this.setSilenceLabels(event.target.dataset); }, addSilenceLabel(label, value) { silenceStore.addLabel(label, value); - silenceStore.showForm(); - scroll(0, 0); + silenceStore.showModal(); }, silenceSelectedHosts(event) { this.setSilenceLabels(event.target.dataset); @@ -116,7 +117,7 @@ const app = Vue.createApp({ // and set the target list let tgt = document.getElementById(target); tgt.setAttribute('list', dst + '.' + src); - } + }, }, computed: { activeServiceAlerts: function () { @@ -149,21 +150,37 @@ const app = Vue.createApp({ app.config.compilerOptions.whitespace = "preserve"; -app.component('silence-form', { - template: '#silence-form-template', +app.component('silence-modal', { + template: '#silence-modal-template', delimiters: ['[[', ']]'], data: () => ({ state: silenceStore.state, form: {} }), + computed: { + globalMessages() { + return globalStore.state.messages; + }, + }, methods: { + addLabel() { + if (this.form.label && this.form.value) { + silenceStore.addLabel(this.form.label, this.form.value); + this.form.label = ''; + this.form.value = ''; + } + }, removeLabel(label) { delete this.state.labels[label]; }, submit() { const body = JSON.stringify({ labels: this.state.labels, - ...this.form + startsAt: this.form.startsAt, + endsAt: this.form.endsAt, + duration: this.form.duration, + createdBy: this.form.createdBy, + comment: this.form.comment }); fetch('/proxy/v1/silences', { method: 'POST', body }) @@ -180,7 +197,39 @@ app.component('silence-form', { } }); }, - } + hideModal() { + const modal = $('#silenceModal'); + if (modal.length) { + globalStore.setMessages([]); + this.form = {}; + this.state = silenceStore.state; + modal.modal('hide'); + } + }, + showModal() { + const modal = $('#silenceModal'); + if (modal.length) { + // Detect when the modal is closed, and update the state accordingly. This is + // necessary in case the user closes the modal by clicking outside of it, instead of + // using the close button. + // + // https://getbootstrap.com/docs/3.3/javascript/#modals-events + modal.on('hidden.bs.modal', function (e) { + silenceStore.hideModal(); + }); + modal.modal('show'); + } + }, + }, + watch: { + "state.show"(val) { + if (val) { + this.showModal(); + } else { + this.hideModal(); + } + }, + }, }); app.component("promql-query", { diff --git a/promgen/templates/base.html b/promgen/templates/base.html index 67841d88e..4acfea225 100644 --- a/promgen/templates/base.html +++ b/promgen/templates/base.html @@ -23,7 +23,7 @@ {% endblock %}