feat: configurable time range for the status page heartbeat bar - #7620
feat: configurable time range for the status page heartbeat bar#7620zigapovhe wants to merge 103 commits into
Conversation
Add a configurable range option (7/30/60/90/180/365 days) for heartbeat bars on status pages. This allows status page owners to customize how much historical data is shown to visitors. Changes: - Add database migration for heartbeat_bar_range_days column - Update StatusPage model to include heartbeat bar range setting - Modify heartbeat API endpoint to respect configured range - Add UI controls in status page editor for range selection - Update English translations for new settings - Default to 90 days for backward compatibility Resolves louislam#1888
- Removed fallback to "auto" for heartbeat bar range in the StatusPage model. - Simplified heartbeat range logic in the status page router to ensure consistent date handling. - Updated socket handler to directly assign heartbeat bar range from config.
|
Thanks for the PR! If anyone would like to help with testing, run: |
|
Hello and thanks for lending a paw to Uptime Kuma! 🐻👋 |
|
Hello, do you have updates? we are interested in this feature too |
|
@mapperCoderZ and others watching this: the PR is finished and waiting for review. I've been running it myself for a while without problems, but my own testing doesn't count for much here. The maintainers are probably waiting for some independent test reports before picking it up, so that's currently the best way to help: Needs Node.js and Docker. Try a few day ranges (and switching back to 0), monitors with slow intervals, check that the uptime badge still shows the right thing. And please report back even if everything just works, that's useful info too. |
|
@zigapovhe, thank you for pointing this out. I’ll be rolling this PR out across our existing deployments and will report back with results to help with maintainer acceptance. |
|
Hello @zigapovhe — I tested the PR against an independent copy of one of our existing Uptime Kuma deployments, using a cloned copy of the production SQLite database/config, so the test data is representative of a real deployment. I tested the Heartbeat Bar Days functionality with:
Everything behaved as expected in my testing. The heartbeat bars are now displaying correctly across the different time ranges and available widths. The number of bars initially looked surprising for ranges such as 14 and 30 days, but after checking the behavior it makes sense that the history is aggregated according to the available display width, rather than producing exactly one bar per day. The 1-day view correctly represents the 24-hour period, while longer ranges are appropriately aggregated to fit the available width. Existing historical uptime/downtime was also preserved correctly. I also tested the 365-day limit. Values above 365 are not accepted, and the field is constrained/reset to the 365-day maximum. I didn't encounter any errors or regressions during testing. I've attached screenshots from the different ranges, including the edit-mode preview and the 365-day validation, for reference. Test result: ✅ PASS Thanks for putting this together — the width-related issue appears to be resolved and the heartbeat history is behaving correctly across the tested ranges. Note: The static logo is not loading in the screenshots because it has not been configured in this test deployment. This is unrelated to the changes in this PR. |
|
It's working on my database, it's approx 1 month of history, installed many months ago and based on kuma 1.23.16, and 30 HTTPS/JSON probes Maybe. I do not understand if it's a bug, when I Go to "Edit a status page", the latest 3hours disappear. not really anoying by the way, maybe it's by design: |
|
@shafay07 @mapperCoderZ thanks for testing on real databases, exactly what this PR needed. @mapperCoderZ the disappearing hours in edit mode were a real bug, the bar wasn't resizing when the editor sidebar opens so the newest beats got clipped off the right edge. Fixed and pushed, running |
|
@Xgabi86 thanks for trying it out. That's expected with a range configured: each beat covers a whole bucket (a day at 35d), and a bucket with any downtime shows red, so a 2 minute dip from earlier colors the newest beat even while the monitor is up. The overall status and badge use the real latest heartbeat, which is why the page says operational. Proportional fill per bucket is planned as a follow-up. |
86c4015 to
9d2ba96
Compare
Would it be possible to display a brief history of the day's incidents by hovering the mouse over the bar for that day? |
|
@Xgabi86 good idea, but that would need a separate endpoint. The bar is drawn from aggregated stats (up/down counts per bucket), so there's no incident timing in the data it gets. Showing outages per day means fetching the status-change heartbeats for that bucket from the status page, which is its own feature. Out of scope here. |












Summary
This picks up #5916 by @peaktwilight and finishes it the way we discussed in
that thread. Their commits are included, I built on top of them.
In this pull request, the following changes are made:
heartbeat_bar_days(0–365). Default is 0,which keeps the current behaviour (last ~100 raw heartbeats). Any other value
makes the bar cover that many days.
UptimeCalculator into time-anchored buckets (hourly tier up to 30 days, daily
above that). UptimeCalculator itself is untouched, the bucketing sits in
server/utils/heartbeat-buckets.js.interval. This is what fixes the grey gaps that killed the previous attempts:
getDataArray()is sparse, so asking for more slots than the tier storesleaves holes. With the cap, a grey beat really means "no data recorded".
feat(status page): Add configurable heartbeat bar range options (100beats, 1..365 days) #5916. Proportional fill can come in a follow-up.
over the full width. 1 day is the sparsest case, it can only ever have 24
hourly beats. For fine-grained recent history the default 0 is the better
view anyway.
"current status". The API sends the real latest heartbeat separately and the
uptime badge / overall status / favicon use that.
Tests: unit tests for the bucketing (tier boundaries, gaps, slow intervals,
empty data, range end) plus an e2e test for the setting, including the server
side clamp.
7/30/60/90/180/365days) #1888API changes on
/api/status-page/heartbeat/:slug, since it's public:uptimeListalsogets a plain
<id>key (the<id>_24keys stay) and there's a new emptylastHeartbeatListfield.heartbeatListentries are buckets (pingis null,
timeis the bucket end, empty buckets are0),uptimeListiskeyed by
<id>with the uptime for the range, andlastHeartbeatListhasthe latest real heartbeat per monitor.
maxBeatsquery param (1–100).Nothing changes for existing installs, the migration defaults everything to 0.
Two pre-existing issues I ran into while testing, not touched here (can open
issues for them): entering edit mode fires an async
getStatusPagethat canoverwrite form input typed within the first second (this is also why the RSS
custom title e2e sometimes fails on fast local machines), and the uptime badge
doesn't update live in edit mode.
Please follow this checklist to avoid unnecessary back and forth (click to expand)
I understand that I am responsible for and able to explain every line of code I submit.
I used Claude as an assistant for this PR. I reviewed everything, I can explain
every line, and I tested it manually (all ranges, resizing, save/clamp round
trip, auto mode) on top of the automated tests.
Screenshots for Visual Changes
Same status page at different
heartbeat_bar_daysvalues. Test data has a3-day monitoring gap, some down days and a maintenance window.
35 days (red = down days, grey = the monitoring gap, blue = maintenance):

0 (default, unchanged behaviour)
1 day
7 days
90 days
365 days