Skip to content

Commit

Permalink
Implement "Silence List" Feature as a Modal #539
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-olivert-riera authored Sep 10, 2024
2 parents cc69d63 + 3a5a31a commit c0c5a2a
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 11 deletions.
2 changes: 1 addition & 1 deletion promgen/static/css/promgen.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ a[rel]:after {
font-family: monospace;
}

/* silence-modal */
/* silence-create-modal */
.promgen-labels-list {
padding: 10px 5px;
min-height: 116px;
Expand Down
141 changes: 137 additions & 4 deletions promgen/static/js/promgen.vue.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ const app = Vue.createApp({
this.setSilenceLabels(event.target.dataset);
this.addSilenceLabel('instance', this.selectedHosts.join('|'));
},
openSilenceListModal() {
silenceListStore.showModal();
},
fetchSilences: function () {
fetch('/proxy/v1/silences')
.then(response => response.json())
Expand Down Expand Up @@ -167,8 +170,8 @@ app.component("silence-row", {
},
});

app.component('silence-modal', {
template: '#silence-modal-template',
app.component('silence-create-modal', {
template: '#silence-create-modal-template',
delimiters: ['[[', ']]'],
data: () => ({
state: silenceStore.state,
Expand Down Expand Up @@ -215,7 +218,7 @@ app.component('silence-modal', {
});
},
hideModal() {
const modal = $('#silenceModal');
const modal = $('#silenceCreateModal');
if (modal.length) {
globalStore.setMessages([]);
this.form = {};
Expand All @@ -224,7 +227,7 @@ app.component('silence-modal', {
}
},
showModal() {
const modal = $('#silenceModal');
const modal = $('#silenceCreateModal');
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
Expand Down Expand Up @@ -323,3 +326,133 @@ app.component('exporter-test', {
}
}
});

const silenceListStore = Vue.reactive({
state: {
show: false,
labels: []
},
addFilterLabel(label, value) {
const existingLabel = this.state.labels.find(item => item.label === label && item.value === value);
if (!existingLabel) {
this.state.labels.push({ label, value });
}
},
removeFilterLabel(label, value) {
const index = this.state.labels.findIndex(item => item.label === label && item.value === value);
if (index > -1) {
this.state.labels.splice(index, 1);
}
},
showModal() {
this.state.show = true;
},
hideModal() {
this.state.show = false;
},
});

app.component('silence-list-modal', {
template: '#silence-list-modal-template',
delimiters: ['[[', ']]'],
mixins: [mixins],
data() {
return {
state: silenceListStore.state,
form: {
label: '',
value: ''
},
store: dataStore
};
},
computed: {
activeSilences() {
return this.$root.activeSilences || [];
},
filteredSilences() {
if (!this.state.labels || this.state.labels.length === 0) {
return this.activeSilences;
}

return this.activeSilences.filter(silence => {
return this.state.labels.every(filterLabel => {
return silence.matchers.some(matcher =>
matcher.name === filterLabel.label &&
matcher.value === filterLabel.value
);
});
});
},
uniqueLabels() {
const labels = new Set();
this.activeSilences.forEach(silence => {
silence.matchers.forEach(matcher => {
labels.add(matcher.name);
});
});
return Array.from(labels);
},
filteredValues() {
if (!this.form.label) return [];
const values = new Set();
this.activeSilences.forEach(silence => {
silence.matchers.forEach(matcher => {
if (matcher.name === this.form.label) {
values.add(matcher.value);
}
});
});
return Array.from(values);
}
},
methods: {
hideModal() {
const modal = $('#silenceListModal');
if (modal.length) {
globalStore.setMessages([]);
silenceListStore.state.labels = [];
this.form.label = '';
this.form.value = '';
modal.modal('hide');
}
},
showModal() {
const modal = $('#silenceListModal');
if (modal.length) {
modal.on('hidden.bs.modal', () => {
silenceListStore.hideModal();
});
modal.modal('show');
}
},
addFilterLabel(label, value) {
if (label && value) {
if (!this.state.labels.some(item => item.label === label && item.value === value)) {
silenceListStore.addFilterLabel(label, value);
}
} else if (this.form.label && this.form.value) {
if (!this.state.labels.some(item => item.label === this.form.label && item.value === this.form.value)) {
silenceListStore.addFilterLabel(this.form.label, this.form.value);
}
}
this.form.label = '';
this.form.value = '';
},
removeFilterLabel(label, value) {
silenceListStore.removeFilterLabel(label, value);
},
updateValueOptions() {
this.form.value = '';
}
},
watch: {
"state.show"(val) {
if (val) {
this.showModal();
} else {
this.hideModal();
}
}
},
});
10 changes: 7 additions & 3 deletions promgen/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
{% endblock %}
<div class="container">
{% include 'promgen/global_messages.html' %}
<silence-modal></silence-modal>
<silence-create-modal></silence-create-modal>
<silence-list-modal></silence-list-modal>
{% include 'promgen/global_alerts.html' %}
{% include 'promgen/global_silences.html' %}
{% block content %}{% endblock %}
Expand Down Expand Up @@ -52,11 +53,14 @@
<script type="text/x-template" id="promql-query-template">
{% include 'promgen/vue/promql_query.html' %}
</script>
<script type="text/x-template" id="silence-modal-template">
{% include 'promgen/vue/silence_modal.html' %}
<script type="text/x-template" id="silence-create-modal-template">
{% include 'promgen/vue/silence_create_modal.html' %}
</script>
<script type="text/x-template" id="silence-row-template">
{% include 'promgen/vue/silence_row.html' %}
</script>
<script type="text/x-template" id="silence-list-modal-template">
{% include 'promgen/vue/silence_list_modal.html' %}
</script>
<script src="{% static 'js/promgen.js' %}"></script>
<script src="{% static 'js/mixins.vue.js' %}"></script>
Expand Down
3 changes: 1 addition & 2 deletions promgen/templates/promgen/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@
Alerts
<span v-text="activeAlerts.length" class="badge"></span>
</a>
<a @click="toggleComponent('global-silences')" class="btn btn-warning navbar-btn" role="button">
<a @click="openSilenceListModal" class="btn btn-warning navbar-btn" role="button">
Silences
<span v-text="activeSilences.length" class="badge"></span>
</a>

<ul class="nav navbar-nav navbar-right" v-pre>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div id="silenceModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="silenceModalLabel">
<div id="silenceCreateModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="silenceModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
Expand Down
64 changes: 64 additions & 0 deletions promgen/templates/promgen/vue/silence_list_modal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{% load i18n %}
{% load promgen %}
<div id="silenceListModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="silenceModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" @click="state.show = false" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="silenceModalLabel">Silence</h4>
</div>
<div class="modal-body" style="padding:10px 30px;">

<div class="row mb-4">
<div class="col-md-12">
<div style="display: flex;align-items: center;">
<select v-model="form.label" class="form-control" @change="updateValueOptions">
<option value="">Select a label</option>
<option v-for="label in uniqueLabels" :value="label">[[label]]</option>
</select>
<input type="text" placeholder="=~" style="max-width: 50px; text-align: center;" class="form-control ml-2 mr-2" disabled>
<select v-model="form.value" class="form-control" :disabled="!form.label">
<option value="">Select a value</option>
<option v-for="value in filteredValues" :value="value">[[value]]</option>
</select>
<button type="button" class="btn btn-primary ml-2" @click="addFilterLabel" :disabled="!form.label || !form.value">&plus;</button>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-12">
<div class="labels">
<ul class="list-inline promgen-labels-list">
<li v-for="item in state.labels" :key="`${item.label}-${item.value}`">
<div class="promgen-label-target">
<span>[[item.label]]=~[[item.value]]</span>
<span @click="removeFilterLabel(item.label, item.value)" aria-hidden="true" class="promgen-label-close">&times;</span>
</div>
</li>
</ul>
</div>
</div>
</div>

<table class="table table-bordered table-condensed table-responsive">
<thead>
<tr>
<th>Starts</th>
<th>Ends</th>
<th>Matchers</th>
<th>Comment</th>
<th>Created by</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<template v-for="silence in filteredSilences" :key="silence.id">
<silence-row :silence="silence" label-color="info" @matcher-click="addFilterLabel" />
</template>
</tbody>

</table>
</div>
</div>
</div>
</div>

0 comments on commit c0c5a2a

Please sign in to comment.