feat: different monitor timezones from user timezone (#5201)

This commit is contained in:
Marcello Domenis 2024-10-16 18:20:34 -07:00
parent ed6087e233
commit a6610340a5
No known key found for this signature in database
GPG key ID: 922689009EBCEE9F
7 changed files with 70 additions and 14 deletions

View file

@ -0,0 +1,12 @@
exports.up = function (knex) {
return knex.schema
.alterTable("monitor", function (table) {
table.text("timezone").notNullable().defaultTo("auto");
});
};
exports.down = function (knex) {
return knex.schema.alterTable("monitor", function (table) {
table.dropColumn("timezone");
});
};

View file

@ -154,6 +154,7 @@ class Monitor extends BeanModel {
jsonPathOperator: this.jsonPathOperator,
snmpVersion: this.snmpVersion,
conditions: JSON.parse(this.conditions),
timezone: this.timezone,
};
if (includeSensitiveData) {

View file

@ -869,6 +869,7 @@ let needSetup = false;
bean.jsonPathOperator = monitor.jsonPathOperator;
bean.timeout = monitor.timeout;
bean.conditions = JSON.stringify(monitor.conditions);
bean.timezone = monitor.timezone;
bean.validate();

View file

@ -40,6 +40,11 @@ export default {
type: Number,
required: true,
},
/** Monitor Timezone */
monitorTimezone: {
type: String,
required: true,
},
},
data() {
return {
@ -251,7 +256,7 @@ export default {
},
// push datapoint to chartData
pushDatapoint(datapoint, avgPingData, minPingData, maxPingData, downData, colorData) {
const x = this.$root.unixToDateTime(datapoint.timestamp);
const x = this.$root.unixToDateTime(datapoint.timestamp, this.monitorTimezone);
// Show ping values if it was up in this period
avgPingData.push({
@ -306,7 +311,7 @@ export default {
let heartbeatList = (this.monitorId in this.$root.heartbeatList && this.$root.heartbeatList[this.monitorId]) || [];
for (const beat of heartbeatList) {
const beatTime = this.$root.toDayjs(beat.time);
const beatTime = this.$root.toDayjs(beat.time, this.monitorTimezone);
const x = beatTime.format("YYYY-MM-DD HH:mm:ss");
// Insert empty datapoint to separate big gaps
@ -407,7 +412,7 @@ export default {
continue;
}
const beatTime = this.$root.unixToDayjs(datapoint.timestamp);
const beatTime = this.$root.unixToDayjs(datapoint.timestamp, this.monitorTimezone);
// Insert empty datapoint to separate big gaps
if (lastHeartbeatTime && monitorInterval) {
@ -427,7 +432,7 @@ export default {
const gapX = [
lastHeartbeatTime.subtract(monitorInterval, "second").format("YYYY-MM-DD HH:mm:ss"),
this.$root.unixToDateTime(datapoint.timestamp + 60),
this.$root.unixToDateTime(datapoint.timestamp + 60, this.monitorTimezone),
];
for (const x of gapX) {

View file

@ -44,28 +44,31 @@ export default {
/**
* Converts a Unix timestamp to a formatted date and time string.
* @param {number} value - The Unix timestamp to convert.
* @param {string} timezone - The timezone to use for the conversion.
* @returns {string} The formatted date and time string.
*/
unixToDateTime(value) {
return dayjs.unix(value).tz(this.timezone).format("YYYY-MM-DD HH:mm:ss");
unixToDateTime(value, timezone) {
return dayjs.unix(value).tz(timezone === "auto" ? this.timezone : timezone).format("YYYY-MM-DD HH:mm:ss");
},
/**
* Converts a Unix timestamp to a dayjs object.
* @param {number} value - The Unix timestamp to convert.
* @param {string} timezone - The timezone to use for the conversion.
* @returns {dayjs.Dayjs} The dayjs object representing the given timestamp.
*/
unixToDayjs(value) {
return dayjs.unix(value).tz(this.timezone);
unixToDayjs(value, timezone) {
return dayjs.unix(value).tz(timezone === "auto" ? this.timezone : timezone);
},
/**
* Converts the given value to a dayjs object.
* @param {string} value - the value to be converted
* @returns {dayjs.Dayjs} a dayjs object in the timezone of this instance
* @param {string} value - The value to be converted.
* @param {string} timezone - The timezone to use for the conversion.
* @returns {dayjs.Dayjs} The dayjs object in the timezone of this instance.
*/
toDayjs(value) {
return dayjs.utc(value).tz(this.timezone);
toDayjs(value, timezone) {
return dayjs.utc(value).tz(timezone === "auto" ? this.timezone : timezone);
},
/**

View file

@ -184,7 +184,7 @@
<div v-if="showPingChartBox" class="shadow-box big-padding text-center ping-chart-wrapper">
<div class="row">
<div class="col">
<PingChart :monitor-id="monitor.id" />
<PingChart :monitor-id="monitor.id" :monitor-timezone="monitor.timezone" />
</div>
</div>
</div>

View file

@ -8,6 +8,7 @@
<div class="col-md-6">
<h2 class="mb-2">{{ $t("General") }}</h2>
<!-- Monitor Type -->
<div class="my-3">
<label for="type" class="form-label">{{ $t("Monitor Type") }}</label>
<select id="type" v-model="monitor.type" class="form-select" data-testid="monitor-type-select">
@ -563,6 +564,23 @@
<input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1">
</div>
<!-- Monitor Timezone -->
<div class="my-3">
<label for="timezone" class="form-label">{{ $t("Monitor Timezone") }}</label>
<select id="timezone" v-model="monitor.timezone" class="form-select">
<option value="auto">
{{ $t("Default") }}: {{ getUserTimezone }}
</option>
<option
v-for="(timezone, index) in timezoneList"
:key="index"
:value="timezone.value"
>
{{ timezone.name }}
</option>
</select>
</div>
<h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' " class="my-3 form-check" :title="monitor.ignoreTls ? $t('ignoredTLSError') : ''">
@ -1077,6 +1095,8 @@ import { hostNameRegexPattern } from "../util-frontend";
import HiddenInput from "../components/HiddenInput.vue";
import EditMonitorConditions from "../components/EditMonitorConditions.vue";
import { version } from "../../package.json";
import dayjs from "dayjs";
import { timezoneList } from "../util-frontend";
const userAgent = `'Uptime-Kuma/${version}'`;
const toast = useToast();
@ -1122,7 +1142,8 @@ const monitorDefaults = {
kafkaProducerAllowAutoTopicCreation: false,
gamedigGivenPortOnly: true,
remote_browser: null,
conditions: []
conditions: [],
timezone: "auto"
};
export default {
@ -1165,6 +1186,7 @@ export default {
},
draftGroupName: null,
remoteBrowsersEnabled: false,
timezoneList: timezoneList(),
};
},
@ -1217,6 +1239,18 @@ export default {
return command.join(" ");
},
getUserTimezone() {
let timezone = localStorage.timezone;
if (timezone === null || timezone === "auto") {
timezone = this.guessTimezone;
}
return timezone;
},
guessTimezone() {
return dayjs.tz.guess();
},
ipRegex() {
// Allow to test with simple dns server with port (127.0.0.1:5300)