feat(ui): expose 30d badges and response chart selector for duration (#994)

* chore: initial commit for 30d badge/chart UI support

* chore revert some changes

* chore build frontend

* chore remove old line

* rebuild frontend

* re-order list

* feat: add support for 1h response chart

* chore(docs): add section about response time chart

* chore(frontend): add missing select

* chore: code format

* chore: new web build

* Revert "chore: code format"

This reverts commit 517f0ce3c85e16e771cddc26ca67c2085703158b.

* chore(responsechart): remove support for 1h charts

response time is only stored at 1h intervals, having a chart for the past 1h does not make sense.
This commit is contained in:
Tore Stendal Lønøy 2025-02-11 02:55:19 +01:00 committed by GitHub
parent 9fd134ca9c
commit 64b4c53b4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 42 additions and 13 deletions

View File

@ -2343,6 +2343,7 @@ web:
![Uptime 1h](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/1h/badge.svg) ![Uptime 1h](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/1h/badge.svg)
![Uptime 24h](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/24h/badge.svg) ![Uptime 24h](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/24h/badge.svg)
![Uptime 7d](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/7d/badge.svg) ![Uptime 7d](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/7d/badge.svg)
![Uptime 30d](https://status.twin.sh/api/v1/endpoints/core_blog-external/uptimes/30d/badge.svg)
Gatus can automatically generate an SVG badge for one of your monitored endpoints. Gatus can automatically generate an SVG badge for one of your monitored endpoints.
This allows you to put badges in your individual applications' README or even create your own status page if you This allows you to put badges in your individual applications' README or even create your own status page if you
@ -2353,7 +2354,7 @@ The path to generate a badge is the following:
/api/v1/endpoints/{key}/uptimes/{duration}/badge.svg /api/v1/endpoints/{key}/uptimes/{duration}/badge.svg
``` ```
Where: Where:
- `{duration}` is `30d` (alpha), `7d`, `24h` or `1h` - `{duration}` is `30d`, `7d`, `24h` or `1h`
- `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`. - `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`.
For instance, if you want the uptime during the last 24 hours from the endpoint `frontend` in the group `core`, For instance, if you want the uptime during the last 24 hours from the endpoint `frontend` in the group `core`,
@ -2412,15 +2413,28 @@ See more information about the Shields.io badge endpoint [here](https://shields.
![Response time 1h](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/1h/badge.svg) ![Response time 1h](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/1h/badge.svg)
![Response time 24h](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/24h/badge.svg) ![Response time 24h](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/24h/badge.svg)
![Response time 7d](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/7d/badge.svg) ![Response time 7d](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/7d/badge.svg)
![Response time 30d](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/30d/badge.svg)
The endpoint to generate a badge is the following: The endpoint to generate a badge is the following:
``` ```
/api/v1/endpoints/{key}/response-times/{duration}/badge.svg /api/v1/endpoints/{key}/response-times/{duration}/badge.svg
``` ```
Where: Where:
- `{duration}` is `30d` (alpha), `7d`, `24h` or `1h` - `{duration}` is `30d`, `7d`, `24h` or `1h`
- `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`. - `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`.
#### Response time (chart)
![Response time 24h](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/24h/chart.svg)
![Response time 7d](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/7d/chart.svg)
![Response time 30d](https://status.twin.sh/api/v1/endpoints/core_blog-external/response-times/30d/chart.svg)
The endpoint to generate a response time chart is the following:
```
/api/v1/endpoints/{key}/response-times/{duration}/chart.svg
```
Where:
- `{duration}` is `30d`, `7d`, or `24h`
- `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`.
##### How to change the color thresholds of the response time badge ##### How to change the color thresholds of the response time badge
To change the response time badges' threshold, a corresponding configuration can be added to an endpoint. To change the response time badges' threshold, a corresponding configuration can be added to an endpoint.
@ -2472,7 +2486,7 @@ The path to get raw uptime data for an endpoint is:
/api/v1/endpoints/{key}/uptimes/{duration} /api/v1/endpoints/{key}/uptimes/{duration}
``` ```
Where: Where:
- `{duration}` is `30d` (alpha), `7d`, `24h` or `1h` - `{duration}` is `30d`, `7d`, `24h` or `1h`
- `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`. - `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`.
For instance, if you want the raw uptime data for the last 24 hours from the endpoint `frontend` in the group `core`, the URL would look like this: For instance, if you want the raw uptime data for the last 24 hours from the endpoint `frontend` in the group `core`, the URL would look like this:

View File

@ -23,7 +23,7 @@ func UptimeRaw(c *fiber.Ctx) error {
case "1h": case "1h":
from = time.Now().Add(-2 * time.Hour) // Because uptime metrics are stored by hour, we have to cheat a little from = time.Now().Add(-2 * time.Hour) // Because uptime metrics are stored by hour, we have to cheat a little
default: default:
return c.Status(400).SendString("Durations supported: 30d,7d, 24h, 1h") return c.Status(400).SendString("Durations supported: 30d, 7d, 24h, 1h")
} }
key := c.Params("key") key := c.Params("key")
uptime, err := store.Get().GetUptimeByKey(key, from, time.Now()) uptime, err := store.Get().GetUptimeByKey(key, from, time.Now())

View File

@ -20,6 +20,10 @@
<h1 class="text-xl xl:text-3xl font-mono text-gray-400">UPTIME</h1> <h1 class="text-xl xl:text-3xl font-mono text-gray-400">UPTIME</h1>
<hr/> <hr/>
<div class="flex space-x-4 text-center text-2xl mt-6 relative bottom-2 mb-10"> <div class="flex space-x-4 text-center text-2xl mt-6 relative bottom-2 mb-10">
<div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last 30 days</h2>
<img :src="generateUptimeBadgeImageURL('30d')" alt="30d uptime badge" class="mx-auto"/>
</div>
<div class="flex-1"> <div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last 7 days</h2> <h2 class="text-sm text-gray-400 mb-1">Last 7 days</h2>
<img :src="generateUptimeBadgeImageURL('7d')" alt="7d uptime badge" class="mx-auto"/> <img :src="generateUptimeBadgeImageURL('7d')" alt="7d uptime badge" class="mx-auto"/>
@ -35,10 +39,20 @@
</div> </div>
</div> </div>
<div v-if="endpointStatus && endpointStatus.key && showResponseTimeChartAndBadges" class="mt-12"> <div v-if="endpointStatus && endpointStatus.key && showResponseTimeChartAndBadges" class="mt-12">
<h1 class="text-xl xl:text-3xl font-mono text-gray-400">RESPONSE TIME</h1> <div class="flex items-center justify-between">
<hr/> <h1 class="text-xl xl:text-3xl font-mono text-gray-400">RESPONSE TIME</h1>
<img :src="generateResponseTimeChartImageURL()" alt="response time chart" class="mt-6"/> <select v-model="selectedChartDuration" class="text-sm bg-gray-400 text-white border border-gray-600 rounded-md px-3 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="24h">24 hours</option>
<option value="7d">7 days</option>
<option value="30d">30 days</option>
</select>
</div>
<img :src="generateResponseTimeChartImageURL(selectedChartDuration)" alt="response time chart" class="mt-6"/>
<div class="flex space-x-4 text-center text-2xl mt-6 relative bottom-2 mb-10"> <div class="flex space-x-4 text-center text-2xl mt-6 relative bottom-2 mb-10">
<div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last 30 days</h2>
<img :src="generateResponseTimeBadgeImageURL('30d')" alt="7d response time badge" class="mx-auto mt-2"/>
</div>
<div class="flex-1"> <div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last 7 days</h2> <h2 class="text-sm text-gray-400 mb-1">Last 7 days</h2>
<img :src="generateResponseTimeBadgeImageURL('7d')" alt="7d response time badge" class="mx-auto mt-2"/> <img :src="generateResponseTimeBadgeImageURL('7d')" alt="7d response time badge" class="mx-auto mt-2"/>
@ -174,8 +188,8 @@ export default {
generateResponseTimeBadgeImageURL(duration) { generateResponseTimeBadgeImageURL(duration) {
return `${this.serverUrl}/api/v1/endpoints/${this.endpointStatus.key}/response-times/${duration}/badge.svg`; return `${this.serverUrl}/api/v1/endpoints/${this.endpointStatus.key}/response-times/${duration}/badge.svg`;
}, },
generateResponseTimeChartImageURL() { generateResponseTimeChartImageURL(duration) {
return `${this.serverUrl}/api/v1/endpoints/${this.endpointStatus.key}/response-times/24h/chart.svg`; return `${this.serverUrl}/api/v1/endpoints/${this.endpointStatus.key}/response-times/${duration}/chart.svg`;
}, },
changePage(page) { changePage(page) {
this.currentPage = page; this.currentPage = page;
@ -193,6 +207,7 @@ export default {
endpointStatus: {}, endpointStatus: {},
events: [], events: [],
hourlyAverageResponseTime: {}, hourlyAverageResponseTime: {},
selectedChartDuration: '24h',
// Since this page isn't at the root, we need to modify the server URL a bit // Since this page isn't at the root, we need to modify the server URL a bit
serverUrl: SERVER_URL === '.' ? '..' : SERVER_URL, serverUrl: SERVER_URL === '.' ? '..' : SERVER_URL,
currentPage: 1, currentPage: 1,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long