mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-19 18:56:48 +02:00
time calculation & cleanup
This commit is contained in:
parent
9402c0fa00
commit
804bb39f52
2 changed files with 25 additions and 81 deletions
|
@ -263,50 +263,43 @@ router.get("/api/status-page/:slug/badge", cache("5 minutes"), async (request, r
|
||||||
* @returns {Promise<Array>} Array of aggregated heartbeat data
|
* @returns {Promise<Array>} Array of aggregated heartbeat data
|
||||||
*/
|
*/
|
||||||
async function getAggregatedHeartbeats(uptimeCalculator, days) {
|
async function getAggregatedHeartbeats(uptimeCalculator, days) {
|
||||||
const targetBuckets = 100; // Always show ~100 buckets for consistent display
|
|
||||||
const now = dayjs.utc();
|
const now = dayjs.utc();
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
|
// Calculate the actual time range we have
|
||||||
|
const startTime = now.subtract(days, "day").startOf("minute");
|
||||||
|
const endTime = now;
|
||||||
|
const totalMinutes = endTime.diff(startTime, "minute");
|
||||||
|
|
||||||
|
// Calculate how many buckets we can actually show (max 100)
|
||||||
|
const targetBuckets = Math.min(100, totalMinutes);
|
||||||
|
const bucketSizeMinutes = Math.max(1, Math.floor(totalMinutes / targetBuckets));
|
||||||
|
|
||||||
// Determine data granularity based on days
|
// Determine data granularity based on days
|
||||||
let dataPoints;
|
let dataPoints;
|
||||||
let granularity;
|
let granularity;
|
||||||
let bucketSizeMinutes;
|
|
||||||
|
|
||||||
if (days <= 1) {
|
if (days <= 1) {
|
||||||
// For 1 day or less, use minutely data
|
// For 1 day or less, use minutely data
|
||||||
granularity = "minute";
|
granularity = "minute";
|
||||||
dataPoints = uptimeCalculator.getDataArray(days * 24 * 60, granularity);
|
dataPoints = uptimeCalculator.getDataArray(days * 24 * 60, granularity);
|
||||||
bucketSizeMinutes = Math.max(1, Math.floor((days * 24 * 60) / targetBuckets));
|
|
||||||
} else if (days <= 30) {
|
} else if (days <= 30) {
|
||||||
// For 2-30 days, use hourly data
|
// For 2-30 days, use hourly data
|
||||||
granularity = "hour";
|
granularity = "hour";
|
||||||
dataPoints = uptimeCalculator.getDataArray(days * 24, granularity);
|
dataPoints = uptimeCalculator.getDataArray(days * 24, granularity);
|
||||||
bucketSizeMinutes = Math.max(60, Math.floor((days * 24 * 60) / targetBuckets));
|
|
||||||
} else {
|
} else {
|
||||||
// For 31+ days, use daily data
|
// For 31+ days, use daily data
|
||||||
granularity = "day";
|
granularity = "day";
|
||||||
dataPoints = uptimeCalculator.getDataArray(days, granularity);
|
dataPoints = uptimeCalculator.getDataArray(days, granularity);
|
||||||
bucketSizeMinutes = Math.max(1440, Math.floor((days * 24 * 60) / targetBuckets));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create time buckets
|
// Create time buckets
|
||||||
const startTime = now.subtract(days, "day").startOf("minute");
|
|
||||||
const endTime = now;
|
|
||||||
const buckets = [];
|
const buckets = [];
|
||||||
|
const actualBuckets = Math.floor(totalMinutes / bucketSizeMinutes);
|
||||||
|
|
||||||
for (let i = 0; i < targetBuckets; i++) {
|
for (let i = 0; i < actualBuckets; i++) {
|
||||||
const bucketStart = startTime.add(i * bucketSizeMinutes, "minute");
|
const bucketStart = startTime.add(i * bucketSizeMinutes, "minute");
|
||||||
let bucketEnd = bucketStart.add(bucketSizeMinutes, "minute");
|
const bucketEnd = bucketStart.add(bucketSizeMinutes, "minute");
|
||||||
|
|
||||||
// Don't create buckets that start after current time
|
|
||||||
if (bucketStart.isAfter(endTime)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure bucket doesn't extend beyond current time
|
|
||||||
if (bucketEnd.isAfter(endTime)) {
|
|
||||||
bucketEnd = endTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets.push({
|
buckets.push({
|
||||||
start: bucketStart.unix(),
|
start: bucketStart.unix(),
|
||||||
|
@ -374,29 +367,6 @@ async function getAggregatedHeartbeats(uptimeCalculator, days) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we always return targetBuckets number of items by padding at the start
|
|
||||||
while (result.length < targetBuckets) {
|
|
||||||
const firstStartTime = result.length > 0 ? dayjs(result[0]._startTime || result[0].time) : now.subtract(days, "day");
|
|
||||||
const paddedStart = firstStartTime.subtract(bucketSizeMinutes, "minute");
|
|
||||||
const paddedEnd = firstStartTime;
|
|
||||||
|
|
||||||
result.unshift({
|
|
||||||
status: null,
|
|
||||||
time: paddedEnd.toISOString(),
|
|
||||||
msg: "",
|
|
||||||
ping: null,
|
|
||||||
_aggregated: true,
|
|
||||||
_startTime: paddedStart.toISOString(),
|
|
||||||
_endTime: paddedEnd.toISOString(),
|
|
||||||
_counts: {
|
|
||||||
up: 0,
|
|
||||||
down: 0,
|
|
||||||
maintenance: 0,
|
|
||||||
pending: 0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,30 +155,24 @@ export default {
|
||||||
|
|
||||||
// Always do client-side aggregation using fixed time buckets
|
// Always do client-side aggregation using fixed time buckets
|
||||||
const now = dayjs();
|
const now = dayjs();
|
||||||
const buckets = [];
|
|
||||||
|
|
||||||
// Use same logic as server-side: 100 buckets
|
|
||||||
const targetBuckets = 100;
|
|
||||||
const days = this.normalizedHeartbeatBarDays;
|
const days = this.normalizedHeartbeatBarDays;
|
||||||
const bucketSizeMinutes = Math.max(1, Math.floor((days * 24 * 60) / targetBuckets));
|
|
||||||
|
|
||||||
// Create time buckets from oldest to newest
|
// Calculate the actual time range
|
||||||
const startTime = now.subtract(days, "day").startOf("minute");
|
const startTime = now.subtract(days, "day").startOf("minute");
|
||||||
const endTime = now;
|
const endTime = now;
|
||||||
|
const totalMinutes = endTime.diff(startTime, "minute");
|
||||||
for (let i = 0; i < targetBuckets; i++) {
|
|
||||||
let bucketStart = startTime.add(i * bucketSizeMinutes, "minute");
|
|
||||||
let bucketEnd = bucketStart.add(bucketSizeMinutes, "minute");
|
|
||||||
|
|
||||||
// Don't create buckets that start after current time
|
// Calculate bucket size to fit the display width
|
||||||
if (bucketStart.isAfter(endTime)) {
|
const targetBuckets = Math.min(this.maxBeat > 0 ? this.maxBeat : 100, totalMinutes);
|
||||||
break;
|
const bucketSizeMinutes = Math.max(1, Math.floor(totalMinutes / targetBuckets));
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure bucket doesn't extend beyond current time
|
// Create time buckets
|
||||||
if (bucketEnd.isAfter(endTime)) {
|
const buckets = [];
|
||||||
bucketEnd = endTime;
|
const actualBuckets = Math.floor(totalMinutes / bucketSizeMinutes);
|
||||||
}
|
|
||||||
|
for (let i = 0; i < actualBuckets; i++) {
|
||||||
|
const bucketStart = startTime.add(i * bucketSizeMinutes, "minute");
|
||||||
|
const bucketEnd = bucketStart.add(bucketSizeMinutes, "minute");
|
||||||
|
|
||||||
buckets.push({
|
buckets.push({
|
||||||
start: bucketStart,
|
start: bucketStart,
|
||||||
|
@ -225,26 +219,6 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ensure we always return targetBuckets number of items by padding at the start
|
|
||||||
while (buckets.length < targetBuckets) {
|
|
||||||
const firstStart = buckets.length > 0 ? buckets[0].start : now.subtract(days, "day");
|
|
||||||
const paddedStart = firstStart.subtract(bucketSizeMinutes, "minute");
|
|
||||||
const paddedEnd = firstStart;
|
|
||||||
|
|
||||||
buckets.unshift({
|
|
||||||
start: paddedStart,
|
|
||||||
end: paddedEnd,
|
|
||||||
beats: [],
|
|
||||||
status: null,
|
|
||||||
time: paddedEnd.toISOString()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit to maxBeat for display
|
|
||||||
if (buckets.length > this.maxBeat) {
|
|
||||||
return buckets.slice(buckets.length - this.maxBeat);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buckets;
|
return buckets;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -429,7 +403,7 @@ export default {
|
||||||
|
|
||||||
// Use start time for display if available
|
// Use start time for display if available
|
||||||
const displayTime = beat._startTime ? beat._startTime : beat.time;
|
const displayTime = beat._startTime ? beat._startTime : beat.time;
|
||||||
|
|
||||||
if (total === 0) {
|
if (total === 0) {
|
||||||
return `${this.$root.datetime(displayTime)}: No Data`;
|
return `${this.$root.datetime(displayTime)}: No Data`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue