diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/services/Prometheus.vue | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/components/services/Prometheus.vue b/src/components/services/Prometheus.vue new file mode 100644 index 0000000..25e9ddd --- /dev/null +++ b/src/components/services/Prometheus.vue | |||
@@ -0,0 +1,167 @@ | |||
1 | <template> | ||
2 | <div> | ||
3 | <div | ||
4 | class="card" | ||
5 | :style="`background-color:${item.background};`" | ||
6 | :class="item.class" | ||
7 | > | ||
8 | <a :href="item.url" :target="item.target" rel="noreferrer"> | ||
9 | <div class="card-content"> | ||
10 | <div :class="mediaClass"> | ||
11 | <slot name="icon"> | ||
12 | <div v-if="item.logo" class="media-left"> | ||
13 | <figure class="image is-48x48"> | ||
14 | <img :src="item.logo" :alt="`${item.name} logo`" /> | ||
15 | </figure> | ||
16 | </div> | ||
17 | <div v-if="item.icon" class="media-left"> | ||
18 | <figure class="image is-48x48"> | ||
19 | <i style="font-size: 35px" :class="['fa-fw', item.icon]"></i> | ||
20 | </figure> | ||
21 | </div> | ||
22 | </slot> | ||
23 | <div class="media-content"> | ||
24 | <slot name="content"> | ||
25 | <p class="title is-4">{{ item.name }}</p> | ||
26 | <p class="subtitle is-6"> | ||
27 | <template v-if="item.subtitle"> | ||
28 | {{ item.subtitle }} | ||
29 | </template> | ||
30 | <template v-else-if="api"> | ||
31 | {{ count }} {{ level }} alerts | ||
32 | </template> | ||
33 | </p> | ||
34 | </slot> | ||
35 | </div> | ||
36 | <div v-if="api" class="status" :class="level"> | ||
37 | {{ count }} | ||
38 | </div> | ||
39 | </div> | ||
40 | <div class="tag" :class="item.tagstyle" v-if="item.tag"> | ||
41 | <strong class="tag-text">#{{ item.tag }}</strong> | ||
42 | </div> | ||
43 | </div> | ||
44 | </a> | ||
45 | </div> | ||
46 | </div> | ||
47 | </template> | ||
48 | |||
49 | <script> | ||
50 | export default { | ||
51 | name: "Prometheus", | ||
52 | props: { | ||
53 | item: Object, | ||
54 | }, | ||
55 | data: () => ({ | ||
56 | api: { | ||
57 | status: "", | ||
58 | count: 0, | ||
59 | alerts: { | ||
60 | firing: 0, | ||
61 | inactive: 0, | ||
62 | pending: 0, | ||
63 | }, | ||
64 | }, | ||
65 | }), | ||
66 | computed: { | ||
67 | mediaClass: function () { | ||
68 | return { media: true, "no-subtitle": !this.item.subtitle }; | ||
69 | }, | ||
70 | count: function () { | ||
71 | return ( | ||
72 | this.countFiring() || this.countPending() || this.countInactive() || 0 | ||
73 | ); | ||
74 | }, | ||
75 | level: function () { | ||
76 | if (this.countFiring()) { | ||
77 | return "firing"; | ||
78 | } else if (this.countPending()) { | ||
79 | return "pending"; | ||
80 | } | ||
81 | return "inactive"; | ||
82 | }, | ||
83 | }, | ||
84 | created() { | ||
85 | this.fetchStatus(); | ||
86 | }, | ||
87 | methods: { | ||
88 | fetchStatus: async function () { | ||
89 | const url = `${this.item.url}/api/v1/alerts`; | ||
90 | this.api = await fetch(url, { method: "get" }) | ||
91 | .then((response) => { | ||
92 | return response.json(); | ||
93 | }) | ||
94 | .catch((e) => console.log(e)); | ||
95 | }, | ||
96 | countFiring: function () { | ||
97 | if (this.api) { | ||
98 | return this.api.data?.alerts?.filter( | ||
99 | (alert) => alert.state === "firing" | ||
100 | ).length; | ||
101 | } | ||
102 | return 0; | ||
103 | }, | ||
104 | countPending: function () { | ||
105 | if (this.api) { | ||
106 | return this.api.data?.alerts?.filter( | ||
107 | (alert) => alert.state === "pending" | ||
108 | ).length; | ||
109 | } | ||
110 | return 0; | ||
111 | }, | ||
112 | countInactive: function () { | ||
113 | if (this.api) { | ||
114 | return this.api.data?.alerts?.filter( | ||
115 | (alert) => alert.state === "inactive" | ||
116 | ).length; | ||
117 | } | ||
118 | return 0; | ||
119 | }, | ||
120 | }, | ||
121 | }; | ||
122 | </script> | ||
123 | |||
124 | <style scoped lang="scss"> | ||
125 | .media-left { | ||
126 | .image { | ||
127 | display: flex; | ||
128 | align-items: center; | ||
129 | } | ||
130 | |||
131 | img { | ||
132 | max-height: 100%; | ||
133 | } | ||
134 | } | ||
135 | .status { | ||
136 | font-size: 0.8rem; | ||
137 | color: var(--text-title); | ||
138 | |||
139 | &.firing:before { | ||
140 | background-color: #d65c68; | ||
141 | border-color: #e87d88; | ||
142 | box-shadow: 0 0 5px 1px #d65c68; | ||
143 | } | ||
144 | |||
145 | &.pending:before { | ||
146 | background-color: #e8bb7d; | ||
147 | border-color: #d6a35c; | ||
148 | box-shadow: 0 0 5px 1px #e8bb7d; | ||
149 | } | ||
150 | |||
151 | &.inactive:before { | ||
152 | background-color: #8fe87d; | ||
153 | border-color: #70d65c; | ||
154 | box-shadow: 0 0 5px 1px #8fe87d; | ||
155 | } | ||
156 | |||
157 | &:before { | ||
158 | content: " "; | ||
159 | display: inline-block; | ||
160 | width: 7px; | ||
161 | height: 7px; | ||
162 | margin-right: 10px; | ||
163 | border: 1px solid #000; | ||
164 | border-radius: 7px; | ||
165 | } | ||
166 | } | ||
167 | </style> | ||