diff options
-rw-r--r-- | docs/customservices.md | 12 | ||||
-rw-r--r-- | src/components/services/Prometheus.vue | 143 |
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 | |||
99 | For 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> | ||
21 | import service from "@/mixins/service.js"; | ||
22 | import Generic from "./Generic.vue"; | ||
23 | |||
24 | const AlertsStatus = Object.freeze({ | ||
25 | firing: "firing", | ||
26 | pending: "pending", | ||
27 | inactive: "inactive", | ||
28 | }); | ||
29 | |||
30 | export 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> | ||