aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/customservices.md15
-rw-r--r--src/components/services/UptimeKuma.vue152
2 files changed, 167 insertions, 0 deletions
diff --git a/docs/customservices.md b/docs/customservices.md
index 509278f..709b16b 100644
--- a/docs/customservices.md
+++ b/docs/customservices.md
@@ -179,3 +179,18 @@ You need to set the type to Emby, provide an api key and choose which stats to s
179 apikey: "MY-SUPER-SECRET-API-KEY" 179 apikey: "MY-SUPER-SECRET-API-KEY"
180 libraryType: "music" #Choose which stats to show. Can be one of: music, series or movies. 180 libraryType: "music" #Choose which stats to show. Can be one of: music, series or movies.
181``` 181```
182
183## Uptime Kuma
184
185Using the Uptime Kuma service you can display info about your instance uptime right on your Homer dashboard.
186
187The following configuration is available for the UptimeKuma service. Needs v1.13.1 or later because of the change in APIs due to [multiple status pages support](https://github.com/louislam/uptime-kuma/releases/tag/1.13.1).
188
189```yaml
190- name: "Uptime Kuma"
191 logo: "assets/tools/sample.png"
192 # subtitle: "A fancy self-hosted monitoring tool" # optional, if no subtitle is defined, Uptime Kuma incidents, if any, will be shown
193 url: "http://192.168.0.151:3001"
194 slug: "myCustomDashboard" # Defaults to "default" if not provided.
195 type: "UptimeKuma"
196```
diff --git a/src/components/services/UptimeKuma.vue b/src/components/services/UptimeKuma.vue
new file mode 100644
index 0000000..5dd75f3
--- /dev/null
+++ b/src/components/services/UptimeKuma.vue
@@ -0,0 +1,152 @@
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="status">
10 {{ statusMessage }}
11 </template>
12 </p>
13 </template>
14 <template #indicator>
15 <div v-if="status" class="status" :class="status">
16 {{ uptime }}&percnt;
17 </div>
18 </template>
19 </Generic>
20</template>
21
22<script>
23import service from "@/mixins/service.js";
24import Generic from "./Generic.vue";
25
26export default {
27 name: "UptimeKuma",
28 mixins: [service],
29 props: {
30 item: Object,
31 },
32 components: {
33 Generic,
34 },
35 data: () => ({
36 incident: null,
37 heartbeat: null,
38 }),
39 computed: {
40 dashboard: function () {
41 return this.item.slug ? this.item.slug : "default";
42 },
43 status: function () {
44 if (!this.incident) {
45 return "";
46 }
47 return this.incident.incident == null ? this.pageStatus : "bad";
48 },
49 lastHeartBeatList: function () {
50 let result = {};
51
52 for (let id in this.heartbeat.heartbeatList) {
53 let index = this.heartbeat.heartbeatList[id].length - 1;
54 result[id] = this.heartbeat.heartbeatList[id][index];
55 }
56
57 return result;
58 },
59 pageStatus: function () {
60 if (!this.heartbeat) {
61 return "";
62 }
63 if (Object.keys(this.heartbeat.heartbeatList).length === 0) {
64 return "";
65 }
66 let result = "good";
67 let hasUp = false;
68 for (let id in this.lastHeartBeatList) {
69 let beat = this.lastHeartBeatList[id];
70 if (beat.status == 1) {
71 hasUp = true;
72 } else {
73 result = "warn";
74 }
75 }
76 if (!hasUp) {
77 result = "bad";
78 }
79 return result;
80 },
81 statusMessage: function () {
82 if (!this.incident) {
83 return "";
84 }
85 if (this.incident.incident) {
86 return this.incident.incident.title;
87 }
88 return this.pageStatus == "warn"
89 ? "Partially Degraded Service"
90 : "All Systems Operational";
91 },
92 uptime: function () {
93 if (!this.heartbeat) {
94 return 0;
95 }
96 const data = Object.values(this.heartbeat.uptimeList);
97 const percent = data.reduce((a, b) => a + b, 0) / data.length || 0;
98 return (percent * 100).toFixed(1);
99 },
100 },
101 created() {
102 this.item.url = `${this.item.url}/status/${this.dashboard}`;
103 this.fetchStatus();
104 },
105 methods: {
106 fetchStatus: function () {
107 this.fetch(`/api/status-page/${this.dashboard}?cachebust=${Date.now()}`)
108 .catch((e) => console.error(e))
109 .then((resp) => (this.incident = resp));
110
111 this.fetch(`/api/status-page/heartbeat/${this.dashboard}?cachebust=${Date.now()}`)
112 .catch((e) => console.error(e))
113 .then((resp) => (this.heartbeat = resp));
114 },
115 },
116};
117</script>
118
119<style scoped lang="scss">
120.status {
121 font-size: 0.8rem;
122 color: var(--text-title);
123
124 &.good:before {
125 background-color: #94e185;
126 border-color: #78d965;
127 box-shadow: 0 0 5px 1px #94e185;
128 }
129
130 &.warn:before {
131 background-color: #f8a306;
132 border-color: #e1b35e;
133 box-shadow: 0 0 5px 1px #f8a306;
134 }
135
136 &.bad:before {
137 background-color: #c9404d;
138 border-color: #c42c3b;
139 box-shadow: 0 0 5px 1px #c9404d;
140 }
141
142 &:before {
143 content: " ";
144 display: inline-block;
145 width: 7px;
146 height: 7px;
147 margin-right: 10px;
148 border: 1px solid #000;
149 border-radius: 7px;
150 }
151}
152</style>