mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-19 18:56:48 +02:00
added validate and other improvements
This commit is contained in:
parent
ace9ff20b5
commit
0dde42ee36
5 changed files with 59 additions and 49 deletions
|
@ -433,7 +433,7 @@ class StatusPage extends BeanModel {
|
||||||
showPoweredBy: !!this.show_powered_by,
|
showPoweredBy: !!this.show_powered_by,
|
||||||
googleAnalyticsId: this.google_analytics_tag_id,
|
googleAnalyticsId: this.google_analytics_tag_id,
|
||||||
showCertificateExpiry: !!this.show_certificate_expiry,
|
showCertificateExpiry: !!this.show_certificate_expiry,
|
||||||
heartbeatBarRange: this.heartbeat_bar_range || "auto",
|
heartbeatBarDays: this.heartbeat_bar_days || 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,40 +104,23 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
||||||
list = R.convertToBeans("heartbeat", list);
|
list = R.convertToBeans("heartbeat", list);
|
||||||
heartbeatList[monitorID] = list.reverse().map(row => row.toPublicJSON());
|
heartbeatList[monitorID] = list.reverse().map(row => row.toPublicJSON());
|
||||||
} else {
|
} else {
|
||||||
// Use UptimeCalculator for configured day ranges
|
// For configured day ranges, always use raw heartbeat data for client-side aggregation
|
||||||
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(monitorID);
|
// This ensures consistent behavior between edit mode and published mode
|
||||||
|
const date = new Date();
|
||||||
|
date.setDate(date.getDate() - heartbeatBarDays);
|
||||||
|
const dateFrom = date.toISOString().slice(0, 19).replace("T", " ");
|
||||||
|
|
||||||
if (heartbeatBarDays <= 1) {
|
let list = await R.getAll(`
|
||||||
// Use 24-hour data
|
SELECT * FROM heartbeat
|
||||||
const data = uptimeCalculator.get24Hour();
|
WHERE monitor_id = ? AND time >= ?
|
||||||
heartbeatList[monitorID] = Object.entries(data.minutelyUptimeDataList || {}).map(([ timestamp, uptimeData ]) => ({
|
ORDER BY time DESC
|
||||||
time: dayjs(parseInt(timestamp)).format("YYYY-MM-DD HH:mm:ss"),
|
`, [
|
||||||
status: uptimeData.up > 0 ? 1 : (uptimeData.down > 0 ? 0 : 1),
|
monitorID,
|
||||||
up: uptimeData.up,
|
dateFrom
|
||||||
down: uptimeData.down,
|
]);
|
||||||
ping: uptimeData.avgPing
|
|
||||||
}));
|
list = R.convertToBeans("heartbeat", list);
|
||||||
} else if (heartbeatBarDays <= 30) {
|
heartbeatList[monitorID] = list.reverse().map(row => row.toPublicJSON());
|
||||||
// Use 30-day hourly data
|
|
||||||
const data = uptimeCalculator.get30Day();
|
|
||||||
heartbeatList[monitorID] = Object.entries(data.hourlyUptimeDataList || {}).map(([ timestamp, uptimeData ]) => ({
|
|
||||||
time: dayjs(parseInt(timestamp)).format("YYYY-MM-DD HH:mm:ss"),
|
|
||||||
status: uptimeData.up > 0 ? 1 : (uptimeData.down > 0 ? 0 : 1),
|
|
||||||
up: uptimeData.up,
|
|
||||||
down: uptimeData.down,
|
|
||||||
ping: uptimeData.avgPing
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
// Use daily data for longer ranges
|
|
||||||
const data = uptimeCalculator.getData();
|
|
||||||
heartbeatList[monitorID] = Object.entries(data.dailyUptimeDataList || {}).map(([ timestamp, uptimeData ]) => ({
|
|
||||||
time: dayjs(parseInt(timestamp)).format("YYYY-MM-DD HH:mm:ss"),
|
|
||||||
status: uptimeData.up > 0 ? 1 : (uptimeData.down > 0 ? 0 : 1),
|
|
||||||
up: uptimeData.up,
|
|
||||||
down: uptimeData.down,
|
|
||||||
ping: uptimeData.avgPing
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(monitorID);
|
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(monitorID);
|
||||||
|
|
|
@ -49,8 +49,12 @@ export default {
|
||||||
},
|
},
|
||||||
/** Heartbeat bar days */
|
/** Heartbeat bar days */
|
||||||
heartbeatBarDays: {
|
heartbeatBarDays: {
|
||||||
type: Number,
|
type: [Number, String],
|
||||||
default: 0,
|
default: 0,
|
||||||
|
validator(value) {
|
||||||
|
const num = Number(value);
|
||||||
|
return !isNaN(num) && num >= 0 && num <= 365;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -65,6 +69,15 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalized heartbeatBarDays as a number
|
||||||
|
* @returns {number} Number of days for heartbeat bar
|
||||||
|
*/
|
||||||
|
normalizedHeartbeatBarDays() {
|
||||||
|
const num = Number(this.heartbeatBarDays);
|
||||||
|
return isNaN(num) ? 0 : Math.max(0, Math.min(365, Math.floor(num)));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If heartbeatList is null, get it from $root.heartbeatList
|
* If heartbeatList is null, get it from $root.heartbeatList
|
||||||
* @returns {object} Heartbeat list
|
* @returns {object} Heartbeat list
|
||||||
|
@ -103,12 +116,13 @@ export default {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If heartbeat days is configured (not auto), aggregate by time periods
|
// If heartbeat days is configured (not auto), always use client-side aggregation
|
||||||
if (this.heartbeatBarDays > 0) {
|
// This ensures consistent behavior between edit mode and published mode
|
||||||
|
if (this.normalizedHeartbeatBarDays > 0) {
|
||||||
return this.aggregatedBeatList;
|
return this.aggregatedBeatList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Original logic for short time ranges
|
// Original logic for auto mode (heartbeatBarDays = 0)
|
||||||
let placeholders = [];
|
let placeholders = [];
|
||||||
|
|
||||||
let start = this.beatList.length - this.maxBeat;
|
let start = this.beatList.length - this.maxBeat;
|
||||||
|
@ -138,7 +152,7 @@ export default {
|
||||||
const buckets = [];
|
const buckets = [];
|
||||||
|
|
||||||
// Calculate total hours from days
|
// Calculate total hours from days
|
||||||
const totalHours = this.heartbeatBarDays * 24;
|
const totalHours = this.normalizedHeartbeatBarDays * 24;
|
||||||
|
|
||||||
// Use dynamic maxBeat calculated from screen size
|
// Use dynamic maxBeat calculated from screen size
|
||||||
const totalBuckets = this.maxBeat > 0 ? this.maxBeat : 50;
|
const totalBuckets = this.maxBeat > 0 ? this.maxBeat : 50;
|
||||||
|
@ -245,7 +259,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
timeStyle() {
|
timeStyle() {
|
||||||
// For aggregated mode, don't use padding-based positioning
|
// For aggregated mode, don't use padding-based positioning
|
||||||
if (this.heartbeatBarDays > 0) {
|
if (this.normalizedHeartbeatBarDays > 0) {
|
||||||
return {
|
return {
|
||||||
"margin-left": "0px",
|
"margin-left": "0px",
|
||||||
};
|
};
|
||||||
|
@ -263,11 +277,11 @@ export default {
|
||||||
*/
|
*/
|
||||||
timeSinceFirstBeat() {
|
timeSinceFirstBeat() {
|
||||||
// For aggregated beats, calculate from the configured days
|
// For aggregated beats, calculate from the configured days
|
||||||
if (this.heartbeatBarDays > 0) {
|
if (this.normalizedHeartbeatBarDays > 0) {
|
||||||
if (this.heartbeatBarDays < 2) {
|
if (this.normalizedHeartbeatBarDays < 2) {
|
||||||
return (this.heartbeatBarDays * 24) + "h";
|
return (this.normalizedHeartbeatBarDays * 24) + "h";
|
||||||
} else {
|
} else {
|
||||||
return this.heartbeatBarDays + "d";
|
return this.normalizedHeartbeatBarDays + "d";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,14 +385,15 @@ export default {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// For aggregated beats, show time range and status
|
// For aggregated beats (client-side aggregation), show time range and status
|
||||||
if (beat.beats !== undefined && this.heartbeatBarDays > 0) {
|
if (beat.beats !== undefined && this.normalizedHeartbeatBarDays > 0) {
|
||||||
const start = this.$root.datetime(beat.start);
|
const start = this.$root.datetime(beat.start);
|
||||||
const end = this.$root.datetime(beat.end);
|
const end = this.$root.datetime(beat.end);
|
||||||
const statusText = beat.status === 1 ? "Up" : beat.status === 0 ? "Down" : beat.status === 3 ? "Maintenance" : "No Data";
|
const statusText = beat.status === 1 ? "Up" : beat.status === 0 ? "Down" : beat.status === 3 ? "Maintenance" : "No Data";
|
||||||
return `${start} - ${end}: ${statusText} (${beat.beats.length} checks)`;
|
return `${start} - ${end}: ${statusText} (${beat.beats.length} checks)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For published mode with configured days, show simple timestamp
|
||||||
return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : "");
|
return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : "");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -117,8 +117,12 @@ export default {
|
||||||
},
|
},
|
||||||
/** Heartbeat bar days */
|
/** Heartbeat bar days */
|
||||||
heartbeatBarDays: {
|
heartbeatBarDays: {
|
||||||
type: Number,
|
type: [Number, String],
|
||||||
default: 0,
|
default: 0,
|
||||||
|
validator(value) {
|
||||||
|
const num = Number(value);
|
||||||
|
return !isNaN(num) && num >= 0 && num <= 365;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -627,6 +627,12 @@ export default {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.config = res.config;
|
this.config = res.config;
|
||||||
|
|
||||||
|
if (this.config.heartbeatBarDays === undefined || this.config.heartbeatBarDays === null || this.config.heartbeatBarDays === "") {
|
||||||
|
this.config.heartbeatBarDays = 0;
|
||||||
|
} else {
|
||||||
|
this.config.heartbeatBarDays = parseInt(this.config.heartbeatBarDays, 10) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.config.customCSS) {
|
if (!this.config.customCSS) {
|
||||||
this.config.customCSS = "body {\n" +
|
this.config.customCSS = "body {\n" +
|
||||||
" \n" +
|
" \n" +
|
||||||
|
@ -718,8 +724,10 @@ export default {
|
||||||
this.config.domainNameList = [];
|
this.config.domainNameList = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.config.heartbeatBarRange) {
|
if (this.config.heartbeatBarDays === undefined || this.config.heartbeatBarDays === null || this.config.heartbeatBarDays === "") {
|
||||||
this.config.heartbeatBarRange = "auto";
|
this.config.heartbeatBarDays = 0;
|
||||||
|
} else {
|
||||||
|
this.config.heartbeatBarDays = parseInt(this.config.heartbeatBarDays, 10) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.icon) {
|
if (this.config.icon) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue