summaryrefslogtreecommitdiffstats
path: root/src/pages/DashboardHome.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/DashboardHome.vue')
-rw-r--r--src/pages/DashboardHome.vue248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/pages/DashboardHome.vue b/src/pages/DashboardHome.vue
new file mode 100644
index 0000000..a00dedb
--- /dev/null
+++ b/src/pages/DashboardHome.vue
@@ -0,0 +1,248 @@
+<template>
+ <transition ref="tableContainer" name="slide-fade" appear>
+ <div v-if="$route.name === 'DashboardHome'">
+ <h1 class="mb-3">
+ {{ $t("Quick Stats") }}
+ </h1>
+
+ <div class="shadow-box big-padding text-center mb-4">
+ <div class="row">
+ <div class="col">
+ <h3>{{ $t("Up") }}</h3>
+ <span
+ class="num"
+ :class="$root.stats.up === 0 && 'text-secondary'"
+ >
+ {{ $root.stats.up }}
+ </span>
+ </div>
+ <div class="col">
+ <h3>{{ $t("Down") }}</h3>
+ <span
+ class="num"
+ :class="$root.stats.down > 0 ? 'text-danger' : 'text-secondary'"
+ >
+ {{ $root.stats.down }}
+ </span>
+ </div>
+ <div class="col">
+ <h3>{{ $t("Maintenance") }}</h3>
+ <span
+ class="num"
+ :class="$root.stats.maintenance > 0 ? 'text-maintenance' : 'text-secondary'"
+ >
+ {{ $root.stats.maintenance }}
+ </span>
+ </div>
+ <div class="col">
+ <h3>{{ $t("Unknown") }}</h3>
+ <span class="num text-secondary">{{ $root.stats.unknown }}</span>
+ </div>
+ <div class="col">
+ <h3>{{ $t("pauseDashboardHome") }}</h3>
+ <span class="num text-secondary">{{ $root.stats.pause }}</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="shadow-box table-shadow-box" style="overflow-x: hidden;">
+ <table class="table table-borderless table-hover">
+ <thead>
+ <tr>
+ <th>{{ $t("Name") }}</th>
+ <th>{{ $t("Status") }}</th>
+ <th>{{ $t("DateTime") }}</th>
+ <th>{{ $t("Message") }}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="(beat, index) in displayedRecords" :key="index" :class="{ 'shadow-box': $root.windowWidth <= 550}">
+ <td class="name-column"><router-link :to="`/dashboard/${beat.monitorID}`">{{ $root.monitorList[beat.monitorID]?.name }}</router-link></td>
+ <td><Status :status="beat.status" /></td>
+ <td :class="{ 'border-0':! beat.msg}"><Datetime :value="beat.time" /></td>
+ <td class="border-0">{{ beat.msg }}</td>
+ </tr>
+
+ <tr v-if="importantHeartBeatListLength === 0">
+ <td colspan="4">
+ {{ $t("No important events") }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="d-flex justify-content-center kuma_pagination">
+ <pagination
+ v-model="page"
+ :records="importantHeartBeatListLength"
+ :per-page="perPage"
+ :options="paginationConfig"
+ />
+ </div>
+ </div>
+ </div>
+ </transition>
+ <router-view ref="child" />
+</template>
+
+<script>
+import Status from "../components/Status.vue";
+import Datetime from "../components/Datetime.vue";
+import Pagination from "v-pagination-3";
+
+export default {
+ components: {
+ Datetime,
+ Status,
+ Pagination,
+ },
+ props: {
+ calculatedHeight: {
+ type: Number,
+ default: 0
+ }
+ },
+ data() {
+ return {
+ page: 1,
+ perPage: 25,
+ initialPerPage: 25,
+ paginationConfig: {
+ hideCount: true,
+ chunksNavigation: "scroll",
+ },
+ importantHeartBeatListLength: 0,
+ displayedRecords: [],
+ };
+ },
+ watch: {
+ perPage() {
+ this.$nextTick(() => {
+ this.getImportantHeartbeatListPaged();
+ });
+ },
+
+ page() {
+ this.getImportantHeartbeatListPaged();
+ },
+ },
+
+ mounted() {
+ this.getImportantHeartbeatListLength();
+
+ this.$root.emitter.on("newImportantHeartbeat", this.onNewImportantHeartbeat);
+
+ this.initialPerPage = this.perPage;
+
+ window.addEventListener("resize", this.updatePerPage);
+ this.updatePerPage();
+ },
+
+ beforeUnmount() {
+ this.$root.emitter.off("newImportantHeartbeat", this.onNewImportantHeartbeat);
+
+ window.removeEventListener("resize", this.updatePerPage);
+ },
+
+ methods: {
+ /**
+ * Updates the displayed records when a new important heartbeat arrives.
+ * @param {object} heartbeat - The heartbeat object received.
+ * @returns {void}
+ */
+ onNewImportantHeartbeat(heartbeat) {
+ if (this.page === 1) {
+ this.displayedRecords.unshift(heartbeat);
+ if (this.displayedRecords.length > this.perPage) {
+ this.displayedRecords.pop();
+ }
+ this.importantHeartBeatListLength += 1;
+ }
+ },
+
+ /**
+ * Retrieves the length of the important heartbeat list for all monitors.
+ * @returns {void}
+ */
+ getImportantHeartbeatListLength() {
+ this.$root.getSocket().emit("monitorImportantHeartbeatListCount", null, (res) => {
+ if (res.ok) {
+ this.importantHeartBeatListLength = res.count;
+ this.getImportantHeartbeatListPaged();
+ }
+ });
+ },
+
+ /**
+ * Retrieves the important heartbeat list for the current page.
+ * @returns {void}
+ */
+ getImportantHeartbeatListPaged() {
+ const offset = (this.page - 1) * this.perPage;
+ this.$root.getSocket().emit("monitorImportantHeartbeatListPaged", null, offset, this.perPage, (res) => {
+ if (res.ok) {
+ this.displayedRecords = res.data;
+ }
+ });
+ },
+
+ /**
+ * Updates the number of items shown per page based on the available height.
+ * @returns {void}
+ */
+ updatePerPage() {
+ const tableContainer = this.$refs.tableContainer;
+ const tableContainerHeight = tableContainer.offsetHeight;
+ const availableHeight = window.innerHeight - tableContainerHeight;
+ const additionalPerPage = Math.floor(availableHeight / 58);
+
+ if (additionalPerPage > 0) {
+ this.perPage = Math.max(this.initialPerPage, this.perPage + additionalPerPage);
+ } else {
+ this.perPage = this.initialPerPage;
+ }
+
+ },
+ },
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../assets/vars";
+
+.num {
+ font-size: 30px;
+ color: $primary;
+ font-weight: bold;
+ display: block;
+}
+
+.shadow-box {
+ padding: 20px;
+}
+
+table {
+ font-size: 14px;
+
+ tr {
+ transition: all ease-in-out 0.2ms;
+ }
+
+ @media (max-width: 550px) {
+ table-layout: fixed;
+ overflow-wrap: break-word;
+ }
+}
+
+@media screen and (max-width: 1280px) {
+ .name-column {
+ min-width: 150px;
+ }
+}
+
+@media screen and (min-aspect-ratio: 4/3) {
+ .name-column {
+ min-width: 200px;
+ }
+}
+</style>