mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-08-21 06:46:40 +08:00
Merge remote-tracking branch 'origin/master' into show-tags-in-status-page-monitor-select-list
# Conflicts: # src/pages/StatusPage.vue
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<div>
|
||||
<h1 class="mb-3">{{ pageName }}</h1>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="shadow-box">
|
||||
<div class="shadow-box shadow-box-with-fixed-bottom-bar">
|
||||
<div class="row">
|
||||
<div class="col-xl-10">
|
||||
<!-- Title -->
|
||||
@@ -85,35 +85,39 @@
|
||||
|
||||
<h2 class="mt-5">{{ $t("Date and Time") }}</h2>
|
||||
|
||||
<div>⚠️ {{ $t("warningTimezone") }}: <mark>{{ $root.info.serverTimezone }} ({{ $root.info.serverTimezoneOffset }})</mark></div>
|
||||
|
||||
<!-- Strategy -->
|
||||
<div class="my-3">
|
||||
<label for="strategy" class="form-label">{{ $t("Strategy") }}</label>
|
||||
<select id="strategy" v-model="maintenance.strategy" class="form-select">
|
||||
<option value="manual">{{ $t("strategyManual") }}</option>
|
||||
<option value="single">{{ $t("Single Maintenance Window") }}</option>
|
||||
<option value="cron">{{ $t("cronExpression") }}</option>
|
||||
<option value="recurring-interval">{{ $t("Recurring") }} - {{ $t("recurringInterval") }}</option>
|
||||
<option value="recurring-weekday">{{ $t("Recurring") }} - {{ $t("dayOfWeek") }}</option>
|
||||
<option value="recurring-day-of-month">{{ $t("Recurring") }} - {{ $t("dayOfMonth") }}</option>
|
||||
<option v-if="false" value="recurring-day-of-year">{{ $t("Recurring") }} - Day of Year</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Single Maintenance Window -->
|
||||
<template v-if="maintenance.strategy === 'single'">
|
||||
<!-- DateTime Range -->
|
||||
</template>
|
||||
|
||||
<template v-if="maintenance.strategy === 'cron'">
|
||||
<!-- Cron -->
|
||||
<div class="my-3">
|
||||
<label class="form-label">{{ $t("DateTime Range") }}</label>
|
||||
<Datepicker
|
||||
v-model="maintenance.dateRange"
|
||||
:dark="$root.isDark"
|
||||
range
|
||||
:monthChangeOnScroll="false"
|
||||
:minDate="minDate"
|
||||
format="yyyy-MM-dd HH:mm"
|
||||
modelType="yyyy-MM-dd HH:mm:ss"
|
||||
/>
|
||||
<label for="cron" class="form-label">
|
||||
{{ $t("cronExpression") }}
|
||||
</label>
|
||||
<p>{{ $t("cronSchedule") }}{{ cronDescription }}</p>
|
||||
<input id="cron" v-model="maintenance.cron" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<!-- Duration -->
|
||||
<label for="duration" class="form-label">
|
||||
{{ $t("Duration (Minutes)") }}
|
||||
</label>
|
||||
<input id="duration" v-model="maintenance.durationMinutes" type="number" class="form-control" required min="1" step="1">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -180,7 +184,6 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- For any recurring types -->
|
||||
<template v-if="maintenance.strategy === 'recurring-interval' || maintenance.strategy === 'recurring-weekday' || maintenance.strategy === 'recurring-day-of-month'">
|
||||
<!-- Maintenance Time Window of a Day -->
|
||||
<div class="my-3">
|
||||
@@ -192,33 +195,50 @@
|
||||
disableTimeRangeValidation range
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="maintenance.strategy === 'recurring-interval' || maintenance.strategy === 'recurring-weekday' || maintenance.strategy === 'recurring-day-of-month' || maintenance.strategy === 'cron' || maintenance.strategy === 'single'">
|
||||
<!-- Timezone -->
|
||||
<div class="mb-4">
|
||||
<label for="timezone" class="form-label">
|
||||
{{ $t("Timezone") }}
|
||||
</label>
|
||||
<select id="timezone" v-model="maintenance.timezone" class="form-select">
|
||||
<option :value="null">{{ $t("sameAsServerTimezone") }}</option>
|
||||
<option value="UTC">UTC</option>
|
||||
<option
|
||||
v-for="(timezone, index) in timezoneList"
|
||||
:key="index"
|
||||
:value="timezone.value"
|
||||
>
|
||||
{{ timezone.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Date Range -->
|
||||
<div class="my-3">
|
||||
<label class="form-label">{{ $t("Effective Date Range") }}</label>
|
||||
<Datepicker
|
||||
v-model="maintenance.dateRange"
|
||||
:dark="$root.isDark"
|
||||
range datePicker
|
||||
:monthChangeOnScroll="false"
|
||||
:minDate="minDate"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
modelType="yyyy-MM-dd HH:mm:ss"
|
||||
required
|
||||
/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-2">{{ $t("startDateTime") }}</div>
|
||||
<input v-model="maintenance.dateRange[0]" type="datetime-local" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="mb-2">{{ $t("endDateTime") }}</div>
|
||||
<input v-model="maintenance.dateRange[1]" type="datetime-local" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="mt-4 mb-1">
|
||||
<button
|
||||
id="monitor-submit-btn" class="btn btn-primary" type="submit"
|
||||
:disabled="processing"
|
||||
>
|
||||
{{ $t("Save") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fixed-bottom-bar p-3">
|
||||
<button id="monitor-submit-btn" class="btn btn-primary" type="submit" :disabled="processing">{{ $t("Save") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -226,11 +246,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { useToast } from "vue-toastification";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import dayjs from "dayjs";
|
||||
import Datepicker from "@vuepic/vue-datepicker";
|
||||
import { timezoneList } from "../util-frontend";
|
||||
import cronstrue from "cronstrue/i18n";
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
@@ -242,6 +263,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
timezoneList: timezoneList(),
|
||||
processing: false,
|
||||
maintenance: {},
|
||||
affectedMonitors: [],
|
||||
@@ -256,18 +278,6 @@ export default {
|
||||
langKey: "lastDay1",
|
||||
value: "lastDay1",
|
||||
},
|
||||
{
|
||||
langKey: "lastDay2",
|
||||
value: "lastDay2",
|
||||
},
|
||||
{
|
||||
langKey: "lastDay3",
|
||||
value: "lastDay3",
|
||||
},
|
||||
{
|
||||
langKey: "lastDay4",
|
||||
value: "lastDay4",
|
||||
}
|
||||
],
|
||||
weekdays: [
|
||||
{
|
||||
@@ -311,6 +321,34 @@ export default {
|
||||
|
||||
computed: {
|
||||
|
||||
cronDescription() {
|
||||
if (! this.maintenance.cron) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let locale = "";
|
||||
|
||||
if (this.$root.language) {
|
||||
locale = this.$root.language.replace("-", "_");
|
||||
}
|
||||
|
||||
// Special handling
|
||||
// If locale is also not working in your language, you can map it here
|
||||
// https://github.com/bradymholt/cRonstrue/tree/master/src/i18n/locales
|
||||
if (locale === "zh_HK") {
|
||||
locale = "zh_TW";
|
||||
}
|
||||
|
||||
try {
|
||||
return cronstrue.toString(this.maintenance.cron, {
|
||||
locale,
|
||||
});
|
||||
} catch (e) {
|
||||
return this.$t("invalidCronExpression", e.message);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
selectedStatusPagesOptions() {
|
||||
return Object.values(this.$root.statusPageList).map(statusPage => {
|
||||
return {
|
||||
@@ -370,6 +408,8 @@ export default {
|
||||
description: "",
|
||||
strategy: "single",
|
||||
active: 1,
|
||||
cron: "30 3 * * *",
|
||||
durationMinutes: 60,
|
||||
intervalDay: 1,
|
||||
dateRange: [ this.minDate ],
|
||||
timeRange: [{
|
||||
@@ -381,6 +421,7 @@ export default {
|
||||
}],
|
||||
weekdays: [],
|
||||
daysOfMonth: [],
|
||||
timezone: null,
|
||||
};
|
||||
} else if (this.isEdit) {
|
||||
this.$root.getSocket().emit("getMaintenance", this.$route.params.id, (res) => {
|
||||
@@ -501,10 +542,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.shadow-box {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 150px;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<div>
|
||||
<h1 class="mb-3">{{ pageName }}</h1>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="shadow-box">
|
||||
<div class="shadow-box shadow-box-with-fixed-bottom-bar">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-2">{{ $t("General") }}</h2>
|
||||
@@ -283,13 +283,13 @@
|
||||
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
|
||||
<template v-if="monitor.type === 'sqlserver'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
<template v-if="monitor.type === 'postgres'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="postgres://username:password@host:port/database">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
<template v-if="monitor.type === 'mysql'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="mysql://username:password@host:port/database">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
@@ -301,7 +301,7 @@
|
||||
<template v-if="monitor.type === 'redis'">
|
||||
<div class="my-3">
|
||||
<label for="redisConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
<input id="redisConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="redis://user:password@host:port">
|
||||
<input id="redisConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||
|
||||
<template v-if="monitor.type === 'mongodb'">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="mongodb://username:password@host:port/database">
|
||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@@ -546,28 +546,47 @@
|
||||
<option value="ntlm">
|
||||
NTLM
|
||||
</option>
|
||||
<option value="mtls">
|
||||
mTLS
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<template v-if="monitor.authMethod && monitor.authMethod !== null ">
|
||||
<div class="my-3">
|
||||
<label for="basicauth" class="form-label">{{ $t("Username") }}</label>
|
||||
<input id="basicauth-user" v-model="monitor.basic_auth_user" type="text" class="form-control" :placeholder="$t('Username')">
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="basicauth" class="form-label">{{ $t("Password") }}</label>
|
||||
<input id="basicauth-pass" v-model="monitor.basic_auth_pass" type="password" autocomplete="new-password" class="form-control" :placeholder="$t('Password')">
|
||||
</div>
|
||||
<template v-if="monitor.authMethod === 'ntlm' ">
|
||||
<template v-if="monitor.authMethod === 'mtls' ">
|
||||
<div class="my-3">
|
||||
<label for="basicauth" class="form-label">{{ $t("Domain") }}</label>
|
||||
<input id="basicauth-domain" v-model="monitor.authDomain" type="text" class="form-control" :placeholder="$t('Domain')">
|
||||
<label for="tls-cert" class="form-label">{{ $t("Cert") }}</label>
|
||||
<textarea id="tls-cert" v-model="monitor.tlsCert" class="form-control" :placeholder="$t('Cert body')" required></textarea>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label for="tls-key" class="form-label">{{ $t("Key") }}</label>
|
||||
<textarea id="tls-key" v-model="monitor.tlsKey" class="form-control" :placeholder="$t('Key body')" required></textarea>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label for="tls-ca" class="form-label">{{ $t("CA") }}</label>
|
||||
<textarea id="tls-ca" v-model="monitor.tlsCa" class="form-control" :placeholder="$t('Server CA')"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="my-3">
|
||||
<label for="basicauth-user" class="form-label">{{ $t("Username") }}</label>
|
||||
<input id="basicauth-user" v-model="monitor.basic_auth_user" type="text" class="form-control" :placeholder="$t('Username')">
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="basicauth" class="form-label">{{ $t("Workstation") }}</label>
|
||||
<input id="basicauth-workstation" v-model="monitor.authWorkstation" type="text" class="form-control" :placeholder="$t('Workstation')">
|
||||
<label for="basicauth-pass" class="form-label">{{ $t("Password") }}</label>
|
||||
<input id="basicauth-pass" v-model="monitor.basic_auth_pass" type="password" autocomplete="new-password" class="form-control" :placeholder="$t('Password')">
|
||||
</div>
|
||||
<template v-if="monitor.authMethod === 'ntlm' ">
|
||||
<div class="my-3">
|
||||
<label for="ntlm-domain" class="form-label">{{ $t("Domain") }}</label>
|
||||
<input id="ntlm-domain" v-model="monitor.authDomain" type="text" class="form-control" :placeholder="$t('Domain')">
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="ntlm-workstation" class="form-label">{{ $t("Workstation") }}</label>
|
||||
<input id="ntlm-workstation" v-model="monitor.authWorkstation" type="text" class="form-control" :placeholder="$t('Workstation')">
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
@@ -673,6 +692,13 @@ export default {
|
||||
ipOrHostnameRegexPattern: hostNameRegexPattern(),
|
||||
mqttIpOrHostnameRegexPattern: hostNameRegexPattern(true),
|
||||
gameList: null,
|
||||
connectionStringTemplates: {
|
||||
"sqlserver": "Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>",
|
||||
"postgres": "postgres://username:password@host:port/database",
|
||||
"mysql": "mysql://username:password@host:port/database",
|
||||
"redis": "redis://user:password@host:port",
|
||||
"mongodb": "mongodb://username:password@host:port/database",
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -834,6 +860,24 @@ message HealthCheckResponse {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set default database connection string if empty or it is a template from another database monitor type
|
||||
for (let monitorType in this.connectionStringTemplates) {
|
||||
if (this.monitor.type === monitorType) {
|
||||
let isTemplate = false;
|
||||
for (let key in this.connectionStringTemplates) {
|
||||
if (this.monitor.databaseConnectionString === this.connectionStringTemplates[key]) {
|
||||
isTemplate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this.monitor.databaseConnectionString || isTemplate) {
|
||||
this.monitor.databaseConnectionString = this.connectionStringTemplates[monitorType];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
currentGameObject(newGameObject, previousGameObject) {
|
||||
@@ -841,8 +885,7 @@ message HealthCheckResponse {
|
||||
this.monitor.port = newGameObject.options.port;
|
||||
}
|
||||
this.monitor.game = newGameObject.keys[0];
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
@@ -888,7 +931,7 @@ message HealthCheckResponse {
|
||||
interval: 60,
|
||||
retryInterval: this.interval,
|
||||
resendInterval: 0,
|
||||
maxretries: 0,
|
||||
maxretries: 1,
|
||||
notificationIDList: {},
|
||||
ignoreTls: false,
|
||||
upsideDown: false,
|
||||
@@ -925,6 +968,14 @@ message HealthCheckResponse {
|
||||
} else if (this.isEdit || this.isClone) {
|
||||
this.$root.getSocket().emit("getMonitor", this.$route.params.id, (res) => {
|
||||
if (res.ok) {
|
||||
|
||||
if (this.isClone) {
|
||||
// Reset push token for cloned monitors
|
||||
if (res.monitor.type === "push") {
|
||||
res.monitor.pushToken = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.monitor = res.monitor;
|
||||
|
||||
if (this.isClone) {
|
||||
@@ -936,7 +987,16 @@ message HealthCheckResponse {
|
||||
this.monitor.includeSensitiveData = undefined;
|
||||
this.monitor.maintenance = undefined;
|
||||
this.monitor.name = this.$t("cloneOf", [ this.monitor.name ]);
|
||||
this.monitor.tags = undefined; // FIXME: Cloning tags does not work yet
|
||||
this.$refs.tagsManager.newTags = this.monitor.tags.map((monitorTag) => {
|
||||
return {
|
||||
id: monitorTag.tag_id,
|
||||
name: monitorTag.name,
|
||||
color: monitorTag.color,
|
||||
value: monitorTag.value,
|
||||
new: true,
|
||||
};
|
||||
});
|
||||
this.monitor.tags = undefined;
|
||||
}
|
||||
|
||||
// Handling for monitors that are created before 1.7.0
|
||||
@@ -1066,31 +1126,7 @@ message HealthCheckResponse {
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/vars.scss";
|
||||
|
||||
$padding: 20px;
|
||||
|
||||
.shadow-box {
|
||||
padding-top: $padding;
|
||||
padding-bottom: 0;
|
||||
padding-right: $padding;
|
||||
padding-left: $padding;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.fixed-bottom-bar {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
margin-left: -$padding;
|
||||
margin-right: -$padding;
|
||||
z-index: 100;
|
||||
background-color: rgba(white, 0.2);
|
||||
backdrop-filter: blur(2px);
|
||||
border-radius: 0 0 10px 10px;
|
||||
|
||||
.dark & {
|
||||
background-color: rgba($dark-header-bg, 0.9);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -107,6 +107,9 @@ export default {
|
||||
security: {
|
||||
title: this.$t("Security"),
|
||||
},
|
||||
"api-keys": {
|
||||
title: this.$t("API Keys")
|
||||
},
|
||||
proxies: {
|
||||
title: this.$t("Proxies"),
|
||||
},
|
||||
|
@@ -34,9 +34,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-3 form-check form-switch">
|
||||
<input id="switch-theme" v-model="config.theme" class="form-check-input" type="checkbox" true-value="dark" false-value="light">
|
||||
<label class="form-check-label" for="switch-theme">{{ $t("Switch to Dark Theme") }}</label>
|
||||
<div class="my-3">
|
||||
<label for="switch-theme" class="form-label">{{ $t("Theme") }}</label>
|
||||
<select id="switch-theme" v-model="config.theme" class="form-select">
|
||||
<option value="auto">{{ $t("Auto") }}</option>
|
||||
<option value="light">{{ $t("Light") }}</option>
|
||||
<option value="dark">{{ $t("Dark") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="my-3 form-check form-switch">
|
||||
@@ -320,6 +324,11 @@
|
||||
<p v-if="config.showPoweredBy">
|
||||
{{ $t("Powered by") }} <a target="_blank" rel="noopener noreferrer" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
||||
</p>
|
||||
|
||||
<div class="refresh-info mb-2">
|
||||
<div>{{ $t("Last Updated") }}: <date-time :value="lastUpdateTime" /></div>
|
||||
<div>{{ $tc("statusPageRefreshIn", [ updateCountdownText]) }}</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -336,6 +345,7 @@
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import dayjs from "dayjs";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
import Favico from "favico.js";
|
||||
// import highlighting library (you can use any library you want just return html string)
|
||||
import { highlight, languages } from "prismjs/components/prism-core";
|
||||
@@ -351,12 +361,14 @@ import DOMPurify from "dompurify";
|
||||
import Confirm from "../components/Confirm.vue";
|
||||
import PublicGroupList from "../components/PublicGroupList.vue";
|
||||
import MaintenanceTime from "../components/MaintenanceTime.vue";
|
||||
import DateTime from "../components/Datetime.vue";
|
||||
import { getResBaseURL } from "../util-frontend";
|
||||
import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_MAINTENANCE, STATUS_PAGE_PARTIAL_DOWN, UP, MAINTENANCE } from "../util.ts";
|
||||
import Tag from "../components/Tag.vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
|
||||
const toast = useToast();
|
||||
dayjs.extend(duration);
|
||||
|
||||
const leavePageMsg = "Do you really want to leave? you have unsaved changes!";
|
||||
|
||||
@@ -375,6 +387,7 @@ export default {
|
||||
Confirm,
|
||||
PrismEditor,
|
||||
MaintenanceTime,
|
||||
DateTime,
|
||||
Tag,
|
||||
VueMultiselect
|
||||
},
|
||||
@@ -418,6 +431,10 @@ export default {
|
||||
baseURL: "",
|
||||
clickedEditButton: false,
|
||||
maintenanceList: [],
|
||||
autoRefreshInterval: 5,
|
||||
lastUpdateTime: dayjs(),
|
||||
updateCountdown: null,
|
||||
updateCountdownText: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -655,11 +672,13 @@ export default {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
// 5mins a loop
|
||||
// Configure auto-refresh loop
|
||||
this.updateHeartbeatList();
|
||||
feedInterval = setInterval(() => {
|
||||
this.updateHeartbeatList();
|
||||
}, (300 + 10) * 1000);
|
||||
}, (this.autoRefreshInterval * 60 + 10) * 1000);
|
||||
|
||||
this.updateUpdateTimer();
|
||||
|
||||
// Go to edit page if ?edit present
|
||||
// null means ?edit present, but no value
|
||||
@@ -718,10 +737,29 @@ export default {
|
||||
favicon.badge(downMonitors);
|
||||
|
||||
this.loadedData = true;
|
||||
this.lastUpdateTime = dayjs();
|
||||
this.updateUpdateTimer();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup timer to display countdown to refresh
|
||||
* @returns {void}
|
||||
*/
|
||||
updateUpdateTimer() {
|
||||
clearInterval(this.updateCountdown);
|
||||
|
||||
this.updateCountdown = setInterval(() => {
|
||||
const countdown = dayjs.duration(this.lastUpdateTime.add(this.autoRefreshInterval, "minutes").add(10, "seconds").diff(dayjs()));
|
||||
if (countdown.as("seconds") < 0) {
|
||||
clearInterval(this.updateCountdown);
|
||||
} else {
|
||||
this.updateCountdownText = countdown.format("mm:ss");
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
/** Enable editing mode */
|
||||
edit() {
|
||||
if (this.hasToken) {
|
||||
@@ -907,7 +945,11 @@ export default {
|
||||
* @returns {string} Sanitized HTML
|
||||
*/
|
||||
maintenanceHTML(description) {
|
||||
return DOMPurify.sanitize(marked(description));
|
||||
if (description) {
|
||||
return DOMPurify.sanitize(marked(description));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
@@ -1136,4 +1178,8 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
.refresh-info {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user