aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/customservices.md12
-rw-r--r--src/components/services/Prometheus.vue143
2 files changed, 155 insertions, 0 deletions
diff --git a/docs/customservices.md b/docs/customservices.md
index ef84948..7a151d1 100644
--- a/docs/customservices.md
+++ b/docs/customservices.md
@@ -93,3 +93,15 @@ For Ping you need to set the type to Ping and provide a url.
93 subtitle: "Bookmark example" tag: "app" 93 subtitle: "Bookmark example" tag: "app"
94 url: "https://www.reddit.com/r/selfhosted/" 94 url: "https://www.reddit.com/r/selfhosted/"
95``` 95```
96
97## Prometheus
98
99For Prometheus you need to set the type to Prometheus and provide a url.
100
101```yaml
102- name: "Prometheus"
103 type: Prometheus
104 logo: "assets/tools/sample.png"
105 url: "http://192.168.0.151/"
106 # subtitle: "Monitor data server"
107```
diff --git a/src/components/services/Prometheus.vue b/src/components/services/Prometheus.vue
new file mode 100644
index 0000000..6efcb34
--- /dev/null
+++ b/src/components/services/Prometheus.vue
@@ -0,0 +1,143 @@
1<template>
2 <Generic :item="item">
3 <template #content>
4 <p class="title is-4">{{ item.name }}</p>
5 <p class="subtitle is-6">
6 <template v-if="item.subtitle">
7 {{ item.subtitle }}
8 </template>
9 <template v-else-if="api"> {{ count }} {{ level }} alerts </template>
10 </p>
11 </template>
12 <template #indicator>
13 <div v-if="api" class="status" :class="level">
14 {{ count }}
15 </div>
16 </template>
17 </Generic>
18</template>
19
20<script>
21import service from "@/mixins/service.js";
22import Generic from "./Generic.vue";
23
24const AlertsStatus = Object.freeze({
25 firing: "firing",
26 pending: "pending",
27 inactive: "inactive",
28});
29
30export default {
31 name: "Prometheus",
32 mixins: [service],
33 props: {
34 item: Object,
35 },
36 components: {
37 Generic,
38 },
39 data: () => ({
40 api: {
41 status: "",
42 count: 0,
43 alerts: {
44 firing: 0,
45 inactive: 0,
46 pending: 0,
47 },
48 },
49 }),
50 computed: {
51 count: function () {
52 return (
53 this.countFiring() || this.countPending() || this.countInactive() || 0
54 );
55 },
56 level: function () {
57 if (this.countFiring()) {
58 return AlertsStatus.firing;
59 } else if (this.countPending()) {
60 return AlertsStatus.pending;
61 }
62 return AlertsStatus.inactive;
63 },
64 },
65 created() {
66 this.fetchStatus();
67 },
68 methods: {
69 fetchStatus: async function () {
70 this.api = await this.fetch("api/v1/alerts").catch((e) => console.log(e));
71 },
72 countFiring: function () {
73 if (this.api) {
74 return this.api.data?.alerts?.filter(
75 (alert) => alert.state === AlertsStatus.firing
76 ).length;
77 }
78 return 0;
79 },
80 countPending: function () {
81 if (this.api) {
82 return this.api.data?.alerts?.filter(
83 (alert) => alert.state === AlertsStatus.pending
84 ).length;
85 }
86 return 0;
87 },
88 countInactive: function () {
89 if (this.api) {
90 return this.api.data?.alerts?.filter(
91 (alert) => alert.state === AlertsStatus.pending
92 ).length;
93 }
94 return 0;
95 },
96 },
97};
98</script>
99
100<style scoped lang="scss">
101.media-left {
102 .image {
103 display: flex;
104 align-items: center;
105 }
106
107 img {
108 max-height: 100%;
109 }
110}
111.status {
112 font-size: 0.8rem;
113 color: var(--text-title);
114
115 &.firing:before {
116 background-color: #d65c68;
117 border-color: #e87d88;
118 box-shadow: 0 0 5px 1px #d65c68;
119 }
120
121 &.pending:before {
122 background-color: #e8bb7d;
123 border-color: #d6a35c;
124 box-shadow: 0 0 5px 1px #e8bb7d;
125 }
126
127 &.inactive:before {
128 background-color: #8fe87d;
129 border-color: #70d65c;
130 box-shadow: 0 0 5px 1px #8fe87d;
131 }
132
133 &:before {
134 content: " ";
135 display: inline-block;
136 width: 7px;
137 height: 7px;
138 margin-right: 10px;
139 border: 1px solid #000;
140 border-radius: 7px;
141 }
142}
143</style>