Files
tacticalrmm-web/src/components/AlertsIcon.vue

188 lines
4.9 KiB
Vue

<template>
<q-btn dense flat icon="notifications">
<q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{
alertsCountText()
}}</q-badge>
<q-menu :style="{ 'max-height': `${$q.screen.height - 100}px` }">
<q-list separator>
<q-item v-if="alertsCount === 0">No New Alerts</q-item>
<q-item v-for="alert in topAlerts" :key="alert.id">
<q-item-section>
<q-item-label overline
><router-link :to="`/agents/${alert.agent_id}`"
>{{ alert.client }} - {{ alert.site }} -
{{ alert.hostname }}</router-link
></q-item-label
>
<q-item-label lines="1">
<q-icon
size="xs"
:class="`text-${alertIconColor(alert.severity)}`"
:name="alert.severity"
></q-icon>
{{ alert.message }}
</q-item-label>
</q-item-section>
<q-item-section side top>
<q-item-label caption>{{
getTimeLapse(alert.alert_time)
}}</q-item-label>
<q-item-label>
<q-icon
name="snooze"
size="xs"
class="cursor-pointer"
@click="snoozeAlert(alert)"
v-close-popup
>
<q-tooltip>Snooze alert</q-tooltip>
</q-icon>
<q-icon
name="flag"
size="xs"
class="cursor-pointer"
@click="resolveAlert(alert)"
v-close-popup
>
<q-tooltip>Resolve alert</q-tooltip>
</q-icon>
</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showOverview"
>View All Alerts ({{ alertsCount }})</q-item
>
</q-list>
</q-menu>
</q-btn>
</template>
<script>
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
import AlertsOverview from "@/components/modals/alerts/AlertsOverview.vue";
import { getTimeLapse } from "@/utils/format";
export default {
name: "AlertsIcon",
mixins: [mixins],
setup() {
return {
getTimeLapse,
};
},
data() {
return {
alertsCount: 0,
topAlerts: [],
poll: null,
};
},
computed: {
...mapState([
"dash_info_color",
"dash_warning_color",
"dash_negative_color",
]),
badgeColor() {
const severities = this.topAlerts.map((alert) => alert.severity);
if (severities.includes("error")) return this.dash_negative_color;
else if (severities.includes("warning")) return this.dash_warning_color;
else return this.dash_info_color;
},
},
methods: {
getAlerts() {
this.$axios.patch("alerts/", { top: 10 }).then((r) => {
this.alertsCount = r.data.alerts_count;
this.topAlerts = r.data.alerts;
});
},
showOverview() {
this.$q
.dialog({
component: AlertsOverview,
})
.onDismiss(() => {
this.getAlerts();
});
},
snoozeAlert(alert) {
this.$q
.dialog({
title: "Snooze Alert",
message: "How many days to snooze alert?",
prompt: {
model: "",
type: "number",
isValid: (val) => !!val && val > 0 && val < 9999,
},
cancel: true,
})
.onOk((days) => {
this.$q.loading.show();
const data = {
id: alert.id,
type: "snooze",
snooze_days: days,
};
this.$axios
.put(`alerts/${alert.id}/`, data)
.then(() => {
this.getAlerts();
this.$q.loading.hide();
this.notifySuccess(`The alert has been snoozed for ${days} days`);
})
.catch(() => {
this.$q.loading.hide();
});
});
},
resolveAlert(alert) {
this.$q.loading.show();
const data = {
id: alert.id,
type: "resolve",
};
this.$axios
.put(`alerts/${alert.id}/`, data)
.then(() => {
this.getAlerts();
this.$q.loading.hide();
this.notifySuccess("The alert has been resolved");
})
.catch(() => {
this.$q.loading.hide();
});
},
alertIconColor(severity) {
if (severity === "error") return this.dash_negative_color;
else if (severity === "warning") return this.dash_warning_color;
else return this.dash_info_color;
},
alertsCountText() {
if (this.alertsCount > 99) return "99+";
else return this.alertsCount;
},
pollAlerts() {
this.poll = setInterval(() => {
this.getAlerts();
}, 60 * 1 * 1000);
},
},
mounted() {
this.getAlerts();
this.pollAlerts();
},
beforeUnmount() {
clearInterval(this.poll);
},
};
</script>