mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-19 18:56:48 +02:00
bug fix, made beats bars smaller
This commit is contained in:
parent
bf7d6deb73
commit
76b9680445
2 changed files with 74 additions and 42 deletions
|
@ -266,40 +266,41 @@ async function getAggregatedHeartbeats(uptimeCalculator, days) {
|
||||||
const now = dayjs.utc();
|
const now = dayjs.utc();
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
// Calculate the actual time range we have
|
// Force exact time range: exactly N days ago to exactly now
|
||||||
const startTime = now.subtract(days, "day").startOf("minute");
|
|
||||||
const endTime = now;
|
const endTime = now;
|
||||||
|
const startTime = now.subtract(days, "day");
|
||||||
const totalMinutes = endTime.diff(startTime, "minute");
|
const totalMinutes = endTime.diff(startTime, "minute");
|
||||||
|
|
||||||
// Calculate how many buckets we can actually show (max 100)
|
// Always create exactly 100 buckets spanning the full time range
|
||||||
const targetBuckets = Math.min(100, totalMinutes);
|
const numBuckets = 100;
|
||||||
const bucketSizeMinutes = Math.max(1, Math.floor(totalMinutes / targetBuckets));
|
const bucketSizeMinutes = totalMinutes / numBuckets;
|
||||||
|
|
||||||
// Determine data granularity based on days
|
// Get available data from UptimeCalculator for lookup
|
||||||
let dataPoints;
|
const availableData = {};
|
||||||
let granularity;
|
let rawDataPoints;
|
||||||
|
|
||||||
if (days <= 1) {
|
if (days <= 1) {
|
||||||
// For 1 day or less, use minutely data
|
const exactMinutes = Math.ceil(days * 24 * 60);
|
||||||
granularity = "minute";
|
rawDataPoints = uptimeCalculator.getDataArray(exactMinutes, "minute");
|
||||||
dataPoints = uptimeCalculator.getDataArray(days * 24 * 60, granularity);
|
|
||||||
} else if (days <= 30) {
|
} else if (days <= 30) {
|
||||||
// For 2-30 days, use hourly data
|
const exactHours = Math.ceil(days * 24);
|
||||||
granularity = "hour";
|
rawDataPoints = uptimeCalculator.getDataArray(exactHours, "hour");
|
||||||
dataPoints = uptimeCalculator.getDataArray(days * 24, granularity);
|
|
||||||
} else {
|
} else {
|
||||||
// For 31+ days, use daily data
|
rawDataPoints = uptimeCalculator.getDataArray(days, "day");
|
||||||
granularity = "day";
|
|
||||||
dataPoints = uptimeCalculator.getDataArray(days, granularity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create time buckets
|
// Create lookup map for available data
|
||||||
const buckets = [];
|
for (const point of rawDataPoints) {
|
||||||
const actualBuckets = Math.floor(totalMinutes / bucketSizeMinutes);
|
if (point && point.timestamp) {
|
||||||
|
availableData[point.timestamp] = point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < actualBuckets; i++) {
|
// Create exactly numBuckets buckets spanning the full requested time range
|
||||||
|
const buckets = [];
|
||||||
|
for (let i = 0; i < numBuckets; i++) {
|
||||||
const bucketStart = startTime.add(i * bucketSizeMinutes, "minute");
|
const bucketStart = startTime.add(i * bucketSizeMinutes, "minute");
|
||||||
const bucketEnd = bucketStart.add(bucketSizeMinutes, "minute");
|
const bucketEnd = startTime.add((i + 1) * bucketSizeMinutes, "minute");
|
||||||
|
|
||||||
buckets.push({
|
buckets.push({
|
||||||
start: bucketStart.unix(),
|
start: bucketStart.unix(),
|
||||||
|
@ -312,22 +313,20 @@ async function getAggregatedHeartbeats(uptimeCalculator, days) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate data points into buckets
|
// Aggregate available data into buckets
|
||||||
for (const dataPoint of dataPoints) {
|
for (const [ timestamp, dataPoint ] of Object.entries(availableData)) {
|
||||||
if (!dataPoint || !dataPoint.timestamp) {
|
const timestampNum = parseInt(timestamp);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the appropriate bucket for this data point
|
// Find the appropriate bucket for this data point
|
||||||
const bucket = buckets.find(b =>
|
const bucket = buckets.find(b =>
|
||||||
dataPoint.timestamp >= b.start && dataPoint.timestamp < b.end
|
timestampNum >= b.start && timestampNum < b.end
|
||||||
);
|
);
|
||||||
|
|
||||||
if (bucket) {
|
if (bucket && dataPoint) {
|
||||||
bucket.up += dataPoint.up || 0;
|
bucket.up += dataPoint.up || 0;
|
||||||
bucket.down += dataPoint.down || 0;
|
bucket.down += dataPoint.down || 0;
|
||||||
bucket.maintenance += dataPoint.maintenance || 0;
|
bucket.maintenance += 0; // UptimeCalculator treats maintenance as up
|
||||||
bucket.pending += dataPoint.pending || 0;
|
bucket.pending += 0; // UptimeCalculator doesn't track pending separately
|
||||||
bucket.hasData = true;
|
bucket.hasData = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,12 @@ export default {
|
||||||
if (!this.beatList) {
|
if (!this.beatList) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For configured ranges, no padding needed since we show all beats
|
||||||
|
if (this.normalizedHeartbeatBarDays > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
let num = this.beatList.length - this.maxBeat;
|
let num = this.beatList.length - this.maxBeat;
|
||||||
|
|
||||||
if (this.move) {
|
if (this.move) {
|
||||||
|
@ -114,17 +120,19 @@ export default {
|
||||||
|
|
||||||
// If heartbeat days is configured (not auto), data should be aggregated from server
|
// If heartbeat days is configured (not auto), data should be aggregated from server
|
||||||
if (this.normalizedHeartbeatBarDays > 0 && this.beatList.length > 0) {
|
if (this.normalizedHeartbeatBarDays > 0 && this.beatList.length > 0) {
|
||||||
// Data is already aggregated from server, use it directly
|
// Data is already aggregated from server covering exact time range requested
|
||||||
// But still limit to maxBeat for display
|
// Show all beats to display the full requested time period
|
||||||
if (this.beatList.length > this.maxBeat) {
|
|
||||||
return this.beatList.slice(this.beatList.length - this.maxBeat);
|
|
||||||
}
|
|
||||||
return this.beatList;
|
return this.beatList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Original logic for auto mode (heartbeatBarDays = 0)
|
// Original logic for auto mode (heartbeatBarDays = 0)
|
||||||
let placeholders = [];
|
let placeholders = [];
|
||||||
|
|
||||||
|
// Handle case where maxBeat is -1 (no limit)
|
||||||
|
if (this.maxBeat <= 0) {
|
||||||
|
return this.beatList;
|
||||||
|
}
|
||||||
|
|
||||||
let start = this.beatList.length - this.maxBeat;
|
let start = this.beatList.length - this.maxBeat;
|
||||||
|
|
||||||
if (this.move) {
|
if (this.move) {
|
||||||
|
@ -144,7 +152,7 @@ export default {
|
||||||
|
|
||||||
wrapStyle() {
|
wrapStyle() {
|
||||||
let topBottom = (((this.beatHeight * this.hoverScale) - this.beatHeight) / 2);
|
let topBottom = (((this.beatHeight * this.hoverScale) - this.beatHeight) / 2);
|
||||||
let leftRight = (((this.beatWidth * this.hoverScale) - this.beatWidth) / 2);
|
let leftRight = (((this.dynamicBeatWidth * this.hoverScale) - this.dynamicBeatWidth) / 2);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
padding: `${topBottom}px ${leftRight}px`,
|
padding: `${topBottom}px ${leftRight}px`,
|
||||||
|
@ -153,8 +161,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
barStyle() {
|
barStyle() {
|
||||||
if (this.move && this.shortBeatList.length > this.maxBeat) {
|
if (this.move && this.maxBeat > 0 && this.shortBeatList.length > this.maxBeat) {
|
||||||
let width = -(this.beatWidth + this.beatHoverAreaPadding * 2);
|
let width = -(this.dynamicBeatWidth + this.beatHoverAreaPadding * 2);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
transition: "all ease-in-out 0.25s",
|
transition: "all ease-in-out 0.25s",
|
||||||
|
@ -175,9 +183,28 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate dynamic beat width for configured ranges
|
||||||
|
* @returns {number} Beat width in pixels
|
||||||
|
*/
|
||||||
|
dynamicBeatWidth() {
|
||||||
|
// For configured ranges, fit all beats to available width
|
||||||
|
if (this.normalizedHeartbeatBarDays > 0 && this.shortBeatList.length > 0) {
|
||||||
|
if (this.$refs.wrap) {
|
||||||
|
const availableWidth = this.$refs.wrap.clientWidth;
|
||||||
|
const totalBeats = this.shortBeatList.length;
|
||||||
|
const totalPadding = totalBeats * (this.beatHoverAreaPadding * 2);
|
||||||
|
const availableForBeats = availableWidth - totalPadding;
|
||||||
|
const calculatedWidth = Math.max(1, Math.floor(availableForBeats / totalBeats));
|
||||||
|
return Math.min(calculatedWidth, this.beatWidth); // Don't exceed original width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.beatWidth;
|
||||||
|
},
|
||||||
|
|
||||||
beatStyle() {
|
beatStyle() {
|
||||||
return {
|
return {
|
||||||
width: this.beatWidth + "px",
|
width: this.dynamicBeatWidth + "px",
|
||||||
height: this.beatHeight + "px",
|
height: this.beatHeight + "px",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -188,7 +215,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
timeStyle() {
|
timeStyle() {
|
||||||
return {
|
return {
|
||||||
"margin-left": this.numPadding * (this.beatWidth + this.beatHoverAreaPadding * 2) + "px",
|
"margin-left": this.numPadding * (this.dynamicBeatWidth + this.beatHoverAreaPadding * 2) + "px",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -285,7 +312,13 @@ export default {
|
||||||
*/
|
*/
|
||||||
resize() {
|
resize() {
|
||||||
if (this.$refs.wrap) {
|
if (this.$refs.wrap) {
|
||||||
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatHoverAreaPadding * 2));
|
// For configured ranges, don't limit maxBeat - show all beats
|
||||||
|
if (this.normalizedHeartbeatBarDays > 0) {
|
||||||
|
this.maxBeat = -1; // No limit
|
||||||
|
} else {
|
||||||
|
// For auto mode, calculate based on screen width
|
||||||
|
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatHoverAreaPadding * 2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue