A complete maintenance planning system has been created

This commit is contained in:
Karel Krýda
2022-01-23 15:22:00 +01:00
parent c3c4db52ec
commit 0d3414c6d6
32 changed files with 1121 additions and 51 deletions

View File

@@ -5,7 +5,7 @@
v-for="(beat, index) in shortBeatList"
:key="index"
class="beat"
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2) }"
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2), 'maintenance' : (beat.status === 3) }"
:style="beatStyle"
:title="getBeatTitle(beat)"
/>
@@ -200,6 +200,10 @@ export default {
background-color: $warning;
}
&.maintenance {
background-color: $maintenance;
}
&:not(.empty):hover {
transition: all ease-in-out 0.15s;
opacity: 0.8;

View File

@@ -1,7 +1,12 @@
<template>
<div class="shadow-box mb-3">
<div class="list-header">
<div class="placeholder"></div>
<div class="search-wrapper float-start">
<select v-model="selectedList" class="form-control">
<option value="monitor" selected>{{$t('Monitor List')}}</option>
<option value="maintenance">{{$t('Maintenance List')}}</option>
</select>
</div>
<div class="search-wrapper">
<a v-if="searchText == ''" class="search-icon">
<font-awesome-icon icon="search" />
@@ -13,11 +18,25 @@
</div>
</div>
<div class="monitor-list" :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 && selectedList === 'monitor'" class="text-center mt-3">
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
</div>
<div v-if="Object.keys($root.maintenanceList).length === 0 && selectedList === 'maintenance'" class="text-center mt-3">
{{ $t("No Maintenance, please") }} <router-link to="/addMaintenance">{{ $t("add one") }}</router-link>
</div>
<router-link v-for="(item, index) in sortedMonitorList" :key="index" :to="monitorURL(item.id)" class="item" :class="{ 'disabled': ! item.active }">
<router-link v-if="selectedList === 'maintenance'" v-for="(item, index) in sortedMaintenanceList" :key="index" :to="maintenanceURL(item.id)" class="item" :class="{ 'disabled': (Date.parse(item.end_date) < Date.now()) }">
<div class="row">
<div class="col-9 col-md-8 small-padding">
<div class="info">
<Uptime :monitor="null" type="maintenance" :pill="true" />
{{ item.title }}
</div>
</div>
</div>
</router-link>
<router-link v-if="selectedList === 'monitor'" v-for="(item, index) in sortedMonitorList" :key="index" :to="monitorURL(item.id)" class="item" :class="{ 'disabled': ! item.active }">
<div class="row">
<div class="col-9 col-md-8 small-padding" :class="{ 'monitorItem': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }">
<div class="info">
@@ -47,7 +66,7 @@
import HeartbeatBar from "../components/HeartbeatBar.vue";
import Uptime from "../components/Uptime.vue";
import Tag from "../components/Tag.vue";
import { getMonitorRelativeURL } from "../util.ts";
import {getMaintenanceRelativeURL, getMonitorRelativeURL} from "../util.ts";
export default {
components: {
@@ -63,9 +82,60 @@ export default {
data() {
return {
searchText: "",
selectedList: "monitor"
};
},
computed: {
sortedMaintenanceList() {
let result = Object.values(this.$root.maintenanceList);
result.sort((m1, m2) => {
const now = Date.now();
if (Date.parse(m1.end_date) >= now !== Date.parse(m2.end_date) >= now) {
if (Date.parse(m2.end_date) < now) {
return -1;
}
if (Date.parse(m1.end_date) < now) {
return 1;
}
}
if (Date.parse(m1.end_date) >= now && Date.parse(m2.end_date) >= now) {
if (Date.parse(m1.end_date) < Date.parse(m2.end_date)) {
return -1;
}
if (Date.parse(m2.end_date) < Date.parse(m1.end_date)) {
return 1;
}
}
if (Date.parse(m1.end_date) < now && Date.parse(m2.end_date) < now) {
if (Date.parse(m1.end_date) < Date.parse(m2.end_date)) {
return 1;
}
if (Date.parse(m2.end_date) < Date.parse(m1.end_date)) {
return -1;
}
}
return m1.title.localeCompare(m2.title);
});
// Simple filter by search text
// finds maintenance name
if (this.searchText !== "") {
const loweredSearchText = this.searchText.toLowerCase();
result = result.filter(maintenance => {
return maintenance.title.toLowerCase().includes(loweredSearchText)
|| maintenance.description.toLowerCase().includes(loweredSearchText);
});
}
return result;
},
sortedMonitorList() {
let result = Object.values(this.$root.monitorList);
@@ -96,7 +166,7 @@ export default {
// Simple filter by search text
// finds monitor name, tag name or tag value
if (this.searchText != "") {
if (this.searchText !== "") {
const loweredSearchText = this.searchText.toLowerCase();
result = result.filter(monitor => {
return monitor.name.toLowerCase().includes(loweredSearchText)
@@ -112,6 +182,9 @@ export default {
monitorURL(id) {
return getMonitorRelativeURL(id);
},
maintenanceURL(id) {
return getMaintenanceRelativeURL(id);
},
clearSearchText() {
this.searchText = "";
}
@@ -174,4 +247,12 @@ export default {
flex-wrap: wrap;
gap: 0;
}
.bg-maintenance {
background-color: $maintenance;
}
select {
text-align: center;
}
</style>

View File

@@ -24,7 +24,7 @@ import timezone from "dayjs/plugin/timezone";
import "chartjs-adapter-dayjs";
import { LineChart } from "vue-chart-3";
import { useToast } from "vue-toastification";
import { UP, DOWN, PENDING } from "../util.ts";
import { UP, DOWN, PENDING, MAINTENANCE } from "../util.ts";
dayjs.extend(utc);
dayjs.extend(timezone);
@@ -162,7 +162,8 @@ export default {
},
chartData() {
let pingData = []; // Ping Data for Line Chart, y-axis contains ping time
let downData = []; // Down Data for Bar Chart, y-axis is 1 if target is down, 0 if target is up
let downData = []; // Down Data for Bar Chart, y-axis is 1 if target is down (red color), under maintenance (blue color) or pending (orange color), 0 if target is up
let colorData = []; // Color Data for Bar Chart
let heartbeatList = this.heartbeatList ||
(this.monitorId in this.$root.heartbeatList && this.$root.heartbeatList[this.monitorId]) ||
@@ -184,8 +185,9 @@ export default {
});
downData.push({
x,
y: beat.status === DOWN ? 1 : 0,
y: (beat.status === DOWN || beat.status === MAINTENANCE || beat.status === PENDING) ? 1 : 0,
});
colorData.push((beat.status === MAINTENANCE) ? "rgba(23,71,245,0.41)" : ((beat.status === PENDING) ? "rgba(245,182,23,0.41)" : "#DC354568"))
});
return {
@@ -204,7 +206,7 @@ export default {
type: "bar",
data: downData,
borderColor: "#00000000",
backgroundColor: "#DC354568",
backgroundColor: colorData,
yAxisID: "y1",
barThickness: "flex",
barPercentage: 1,

View File

@@ -146,4 +146,8 @@ export default {
}
}
.bg-maintenance {
background-color: $maintenance;
}
</style>

View File

@@ -22,6 +22,10 @@ export default {
return "warning";
}
if (this.status === 3) {
return "maintenance";
}
return "secondary";
},
@@ -38,6 +42,10 @@ export default {
return this.$t("Pending");
}
if (this.status === 3) {
return this.$t("Maintenance");
}
return this.$t("Unknown");
},
},

View File

@@ -15,6 +15,10 @@ export default {
computed: {
uptime() {
if (this.type === "maintenance") {
return this.$t("Maintenance");
}
let key = this.monitor.id + "_" + this.type;
@@ -26,6 +30,10 @@ export default {
},
color() {
if (this.type === "maintenance" || this.monitor.maintenance) {
return "maintenance"
}
if (this.lastHeartBeat.status === 0) {
return "danger"
}