mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-22 05:55:16 -05:00
[Status Page] WIP: Checkpoint
This commit is contained in:
parent
3e25f0e9d9
commit
934685637a
6
db/patch-monitor-public.sql
Normal file
6
db/patch-monitor-public.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
alter table monitor
|
||||||
|
add public BOOLEAN default 0 not null;
|
||||||
|
|
||||||
|
COMMIT;
|
@ -30,6 +30,7 @@ class Database {
|
|||||||
static patchList = {
|
static patchList = {
|
||||||
"patch-setting-value-type.sql": true,
|
"patch-setting-value-type.sql": true,
|
||||||
"patch-improve-performance.sql": true,
|
"patch-improve-performance.sql": true,
|
||||||
|
"patch-monitor-public.sql": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,9 +165,36 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString();
|
|||||||
response.json(config);
|
response.json(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status Page Polling Data
|
// Status Page - Monitor List
|
||||||
app.get("/api/status-page", async (_request, response) => {
|
app.get("/api/status-page/monitor-list", async (_request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
|
|
||||||
|
const monitorList = {};
|
||||||
|
let list = await R.find("monitor", " public = 1 ORDER BY weight DESC, name ", [
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (let monitor of list) {
|
||||||
|
monitorList[monitor.id] = await monitor.toJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
response.json(monitorList);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Status Page Polling Data
|
||||||
|
app.get("/api/status-page/heartbeat", async (_request, response) => {
|
||||||
|
allowDevAllOrigin(response);
|
||||||
|
|
||||||
|
const monitorList = {};
|
||||||
|
let list = await R.find("", " ", [
|
||||||
|
])
|
||||||
|
|
||||||
|
for (let monitor of list) {
|
||||||
|
monitorList[monitor.id] = await monitor.toJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
response.json({
|
||||||
|
monitorList: monitorList,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Universal Route Handler, must be at the end of all express route.
|
// Universal Route Handler, must be at the end of all express route.
|
||||||
|
@ -255,6 +255,18 @@ h2 {
|
|||||||
background-color: $dark-bg;
|
background-color: $dark-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monitor-list {
|
||||||
|
.item {
|
||||||
|
&:hover {
|
||||||
|
background-color: $dark-bg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $dark-bg2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 550px) {
|
@media (max-width: 550px) {
|
||||||
.table-shadow-box {
|
.table-shadow-box {
|
||||||
tbody {
|
tbody {
|
||||||
@ -288,3 +300,39 @@ h2 {
|
|||||||
transform: translateY(50px);
|
transform: translateY(50px);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monitor-list {
|
||||||
|
&.scrollbar {
|
||||||
|
min-height: calc(100vh - 240px);
|
||||||
|
max-height: calc(100vh - 30px);
|
||||||
|
overflow-y: auto;
|
||||||
|
position: sticky;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 13px 15px 10px 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition: all ease-in-out 0.15s;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $highlight-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #cdf8f4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,6 +25,10 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
heartbeatList: {
|
||||||
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -38,8 +42,15 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If heartbeatList is null, get it from $root.heartbeatList
|
||||||
|
*/
|
||||||
beatList() {
|
beatList() {
|
||||||
return this.$root.heartbeatList[this.monitorId]
|
if (this.heartbeatList === null) {
|
||||||
|
return this.$root.heartbeatList[this.monitorId];
|
||||||
|
} else {
|
||||||
|
return this.heartbeatList;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
shortBeatList() {
|
shortBeatList() {
|
||||||
@ -118,9 +129,11 @@ export default {
|
|||||||
window.removeEventListener("resize", this.resize);
|
window.removeEventListener("resize", this.resize);
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
|
if (this.heartbeatList === null) {
|
||||||
if (! (this.monitorId in this.$root.heartbeatList)) {
|
if (! (this.monitorId in this.$root.heartbeatList)) {
|
||||||
this.$root.heartbeatList[this.monitorId] = [];
|
this.$root.heartbeatList[this.monitorId] = [];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="shadow-box list mb-3" :class="{ scrollbar: scrollbar }">
|
<div class="shadow-box monitor-list mb-3" :class="{ scrollbar: scrollbar }">
|
||||||
<div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3">
|
<div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3">
|
||||||
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
|
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
@ -87,56 +87,6 @@ export default {
|
|||||||
padding-right: 5px !important;
|
padding-right: 5px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
|
||||||
&.scrollbar {
|
|
||||||
min-height: calc(100vh - 240px);
|
|
||||||
max-height: calc(100vh - 30px);
|
|
||||||
overflow-y: auto;
|
|
||||||
position: sticky;
|
|
||||||
top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 13px 15px 10px 15px;
|
|
||||||
border-radius: 10px;
|
|
||||||
transition: all ease-in-out 0.15s;
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: $highlight-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: #cdf8f4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
.list {
|
|
||||||
.item {
|
|
||||||
&:hover {
|
|
||||||
background-color: $dark-bg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: $dark-bg2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.monitorItem {
|
.monitorItem {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li class="nav-item">
|
<li class="nav-item me-2">
|
||||||
<router-link to="/status-page" class="nav-link status-page">
|
<router-link to="/status-page" class="nav-link status-page">
|
||||||
<font-awesome-icon icon="stream" /> {{ $t("Status Page") }}
|
<font-awesome-icon icon="stream" /> {{ $t("Status Page") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
@ -18,31 +18,25 @@
|
|||||||
<font-awesome-icon icon="check-circle" class="ok" /> All Systems Operational
|
<font-awesome-icon icon="check-circle" class="ok" /> All Systems Operational
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="shadow-box list mt-4" :class="{ scrollbar: scrollbar }">
|
<div class="shadow-box monitor-list mt-4">
|
||||||
<div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3">
|
<div v-if="Object.keys(monitorList).length === 0" class="text-center my-3">
|
||||||
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
|
{{ $t("No Monitors") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-link v-for="(item, index) in sortedMonitorList" :key="index" :to="monitorURL(item.id)" class="item" :class="{ 'disabled': ! item.active }">
|
<div v-for="(item, index) in monitorList" :key="index" class="item">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 col-md-8 small-padding" :class="{ 'monitorItem': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }">
|
<div class="col-6 col-md-8 small-padding">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<Uptime :monitor="item" type="24" :pill="true" />
|
<Uptime :monitor="item" type="24" :pill="true" />
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="$root.userHeartbeatBar == 'normal'" :key="$root.userHeartbeatBar" class="col-6 col-md-4">
|
<div :key="$root.userHeartbeatBar" class="col-6 col-md-4">
|
||||||
<HeartbeatBar size="small" :monitor-id="item.id" />
|
<HeartbeatBar size="small" :monitor-id="item.id" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="$root.userHeartbeatBar == 'bottom'" class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<HeartbeatBar size="small" :monitor-id="item.id" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="mt-4">
|
<footer class="mt-4">
|
||||||
Powered by <a target="_blank" href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a>
|
Powered by <a target="_blank" href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a>
|
||||||
@ -51,9 +45,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useToast } from "vue-toastification"
|
import { useToast } from "vue-toastification";
|
||||||
import axios from "axios";
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
import axios from "axios";
|
||||||
|
import HeartbeatBar from "../components/HeartbeatBar.vue";
|
||||||
|
import Uptime from "../components/Uptime.vue";
|
||||||
|
|
||||||
const env = process.env.NODE_ENV || "production";
|
const env = process.env.NODE_ENV || "production";
|
||||||
|
|
||||||
// change the axios base url for development
|
// change the axios base url for development
|
||||||
@ -62,10 +60,15 @@ if (env === "development" || localStorage.dev === "dev") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
HeartbeatBar,
|
||||||
|
Uptime,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasToken: false,
|
hasToken: false,
|
||||||
config: {},
|
config: {},
|
||||||
|
monitorList: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -76,13 +79,13 @@ export default {
|
|||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
this.hasToken = ("token" in localStorage);
|
this.hasToken = ("token" in localStorage);
|
||||||
this.config = await axios.get("/api/status-page/config");
|
this.config = (await axios.get("/api/status-page/config")).data;
|
||||||
|
|
||||||
// Set Theme
|
// Set Theme
|
||||||
this.$root.statusPageTheme = this.config.statusPageTheme;
|
this.$root.statusPageTheme = this.config.statusPageTheme;
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
|
this.monitorList = (await axios.get("/api/status-page/monitor-list")).data;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
edit() {
|
edit() {
|
||||||
|
Loading…
Reference in New Issue
Block a user