bug fix, made beats bars smaller

This commit is contained in:
Doruk 2025-06-14 21:58:44 +02:00
parent bf7d6deb73
commit 76b9680445
2 changed files with 74 additions and 42 deletions

View file

@ -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;
} }
} }

View file

@ -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));
}
} }
}, },