mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-19 18:56:48 +02:00
rethought beat aggregation system fully server-side
This commit is contained in:
parent
1518fd528b
commit
adc362a2a8
3 changed files with 49 additions and 6 deletions
|
@ -89,6 +89,9 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
|||
let statusPage = await R.findOne("status_page", " id = ? ", [ statusPageID ]);
|
||||
let heartbeatBarDays = statusPage ? (statusPage.heartbeat_bar_days || 0) : 0;
|
||||
|
||||
// Get max beats parameter from query string (for client-side screen width constraints)
|
||||
const maxBeats = parseInt(request.query.maxBeats) || 100;
|
||||
|
||||
// Process all monitors in parallel using Promise.all
|
||||
const monitorPromises = monitorIDList.map(async (monitorID) => {
|
||||
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(monitorID);
|
||||
|
@ -112,7 +115,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
|||
uptime = uptimeCalculator.get24Hour().uptime;
|
||||
} else {
|
||||
// For configured day ranges, use aggregated data from UptimeCalculator
|
||||
heartbeats = await getAggregatedHeartbeats(uptimeCalculator, heartbeatBarDays);
|
||||
heartbeats = await getAggregatedHeartbeats(uptimeCalculator, heartbeatBarDays, maxBeats);
|
||||
// Calculate uptime for the configured range instead of just 24h
|
||||
uptime = uptimeCalculator.get24Hour().uptime; // TODO: Calculate range-specific uptime
|
||||
}
|
||||
|
@ -280,16 +283,16 @@ router.get("/api/status-page/:slug/badge", cache("5 minutes"), async (request, r
|
|||
* Get aggregated heartbeats for status page display
|
||||
* @param {UptimeCalculator} uptimeCalculator The uptime calculator instance
|
||||
* @param {number} days Number of days to show
|
||||
* @param {number} targetBuckets Number of buckets to aggregate into (default 100)
|
||||
* @returns {Promise<Array>} Array of aggregated heartbeat data
|
||||
*/
|
||||
async function getAggregatedHeartbeats(uptimeCalculator, days) {
|
||||
async function getAggregatedHeartbeats(uptimeCalculator, days, targetBuckets = 100) {
|
||||
const now = dayjs.utc();
|
||||
const result = [];
|
||||
|
||||
// Force exact time range: exactly N days ago to exactly now
|
||||
const startTime = now.subtract(days, "day");
|
||||
const totalMinutes = days * 60 * 24;
|
||||
const targetBuckets = 100;
|
||||
const bucketSizeMinutes = totalMinutes / targetBuckets;
|
||||
|
||||
// Get available data from UptimeCalculator for lookup
|
||||
|
|
|
@ -292,7 +292,24 @@ export default {
|
|||
*/
|
||||
resize() {
|
||||
if (this.$refs.wrap) {
|
||||
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatHoverAreaPadding * 2));
|
||||
const newMaxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatHoverAreaPadding * 2));
|
||||
|
||||
// If maxBeat changed and we're in configured days mode, notify parent to reload data
|
||||
if (newMaxBeat !== this.maxBeat && this.normalizedHeartbeatBarDays > 0) {
|
||||
this.maxBeat = newMaxBeat;
|
||||
console.log(`HeartBeat Debug: Container width changed, maxBeat=${newMaxBeat}, notifying parent`);
|
||||
|
||||
// Find the closest parent with reloadHeartbeatData method (StatusPage)
|
||||
let parent = this.$parent;
|
||||
while (parent && !parent.reloadHeartbeatData) {
|
||||
parent = parent.$parent;
|
||||
}
|
||||
if (parent && parent.reloadHeartbeatData) {
|
||||
parent.reloadHeartbeatData(newMaxBeat);
|
||||
}
|
||||
} else {
|
||||
this.maxBeat = newMaxBeat;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -787,10 +787,19 @@ export default {
|
|||
|
||||
/**
|
||||
* Load heartbeat data from API
|
||||
* @param {number|null} maxBeats Maximum number of beats to request from server
|
||||
* @returns {Promise} Promise that resolves when data is loaded
|
||||
*/
|
||||
loadHeartbeatData() {
|
||||
return axios.get("/api/status-page/heartbeat/" + this.slug).then((res) => {
|
||||
loadHeartbeatData(maxBeats = null) {
|
||||
// If maxBeats is provided (from HeartbeatBar resize), use it
|
||||
// Otherwise, use a default that will be updated when components mount
|
||||
const targetMaxBeats = maxBeats || 50; // Default, will be updated by actual container measurement
|
||||
|
||||
console.log(`HeartBeat Debug: Using maxBeats=${targetMaxBeats}, provided=${maxBeats !== null}`);
|
||||
|
||||
return axios.get("/api/status-page/heartbeat/" + this.slug, {
|
||||
params: { maxBeats: targetMaxBeats }
|
||||
}).then((res) => {
|
||||
const { heartbeatList, uptimeList } = res.data;
|
||||
|
||||
this.$root.heartbeatList = heartbeatList;
|
||||
|
@ -844,6 +853,20 @@ export default {
|
|||
}, 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reload heartbeat data with specific maxBeats count
|
||||
* Called by child components when they determine optimal beat count
|
||||
* @param {number} maxBeats Maximum number of beats that fit in container
|
||||
* @returns {void}
|
||||
*/
|
||||
reloadHeartbeatData(maxBeats) {
|
||||
// Only reload if we have configured days (not auto mode)
|
||||
if (this.config && this.config.heartbeatBarDays > 0) {
|
||||
console.log(`HeartBeat Debug: Reloading with maxBeats=${maxBeats} for ${this.config.heartbeatBarDays} days`);
|
||||
this.loadHeartbeatData(maxBeats);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable editing mode
|
||||
* @returns {void}
|
||||
|
|
Loading…
Add table
Reference in a new issue