This commit is contained in:
Akhilesh Sooji 2024-05-01 11:07:03 -07:00 committed by GitHub
commit 470a1723e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 140 additions and 14 deletions

23
package-lock.json generated
View File

@ -78,7 +78,9 @@
"tar": "~6.2.1",
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"tippy.js": "^6.3.7",
"tough-cookie": "~4.1.3",
"vue3-calendar-heatmap": "^2.0.5",
"ws": "^8.13.0"
},
"devDependencies": {
@ -3083,7 +3085,6 @@
"version": "2.10.2",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.2.tgz",
"integrity": "sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@ -13535,6 +13536,14 @@
"node": ">=4"
}
},
"node_modules/tippy.js": {
"version": "6.3.7",
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
"dependencies": {
"@popperjs/core": "^2.9.0"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -14393,6 +14402,18 @@
"vue": "^3.0.2"
}
},
"node_modules/vue3-calendar-heatmap": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/vue3-calendar-heatmap/-/vue3-calendar-heatmap-2.0.5.tgz",
"integrity": "sha512-qvveNQlTS5Aw7AvRLs0zOyu3uP5iGJlXJAnkrkG2ElDdyQ8H1TJhQ8rL702CROjAg16ezIveUY10nCO7lqZ25w==",
"engines": {
"node": ">=16"
},
"peerDependencies": {
"tippy.js": "^6.3.7",
"vue": "^3.2.29"
}
},
"node_modules/vuedraggable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",

View File

@ -143,7 +143,9 @@
"tar": "~6.2.1",
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"tippy.js": "^6.3.7",
"tough-cookie": "~4.1.3",
"vue3-calendar-heatmap": "^2.0.5",
"ws": "^8.13.0"
},
"devDependencies": {

View File

@ -76,20 +76,32 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
]);
for (let monitorID of monitorIDList) {
// Calculating the percentage of uptime per day with the status count to show full year data
let list = await R.getAll(`
SELECT * FROM heartbeat
SELECT
strftime('%Y-%m-%d', time) AS day,
(COUNT(CASE WHEN status = 1 THEN 1 END) * 100.0) / COUNT(status) AS percentage,
(
SELECT status
FROM heartbeat AS sub
WHERE strftime('%Y-%m-%d', sub.time) = strftime('%Y-%m-%d', main.time)
GROUP BY status
ORDER BY COUNT(*) DESC
LIMIT 1
) as status
FROM heartbeat as main
WHERE monitor_id = ?
ORDER BY time DESC
LIMIT 50
GROUP BY day
ORDER BY day DESC
LIMIT 365
`, [
monitorID,
]);
list = R.convertToBeans("heartbeat", list);
heartbeatList[monitorID] = list.reverse().map(row => row.toPublicJSON());
heartbeatList[monitorID] = list;
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(monitorID);
uptimeList[`${monitorID}_24`] = uptimeCalculator.get24Hour().uptime;
uptimeList[`${monitorID}_1y`] = uptimeCalculator.get1Year().uptime;
}
response.json({

View File

@ -162,6 +162,16 @@ optgroup {
background-color: #161B22;
}
[data-tippy-root] {
color: #333;
font-size: small;
font-weight: 600;
background-color: #fff;
padding: 0.25rem 0.5rem;
border-radius: 0.5rem;
box-shadow: 2px 2px 2px #333;
}
.btn-outline-normal {
padding: 4px 10px;
border: 1px solid #ced4da;

View File

@ -0,0 +1,81 @@
<template>
<div ref="wrap">
<div class="hp-bar-big">
<CalendarHeatmap
:style="{ fill: '#fff', fontSize: 'x-small' }"
class="heatmap" :values="values" :end-date="endDate" no-data-text="Unknown" tooltip-unit="%"
:range-color="['#ebedf0', '#C3D4CB', '#9ABAA7', '#72A182', '#49875E', '#216E39']" :max="100"
/>
</div>
</div>
</template>
<script>
import dayjs from "dayjs";
import { CalendarHeatmap } from "vue3-calendar-heatmap";
export default {
components: { CalendarHeatmap },
props: {
/** ID of the monitor */
monitorId: {
type: Number,
required: true,
},
},
computed: {
// Getting the values in form of percentage
values() {
const data = this.$root.heartbeatList[this.monitorId]?.map(({ day, percentage }) => ({ date: day,
count: percentage.toFixed(1) }));
return data || [];
},
endDate() {
const date = dayjs().format("YYYY-MM-DD");
return date;
},
},
unmounted() {
window.removeEventListener("resize", this.resize);
},
beforeMount() {
if (this.heartbeatList === null) {
if (!(this.monitorId in this.$root.heartbeatList)) {
this.$root.heartbeatList[this.monitorId] = [];
}
}
},
mounted() {
window.addEventListener("resize", this.resize);
this.resize();
},
methods: {
/**
* Resize the heartbeat bar
* @returns {void}
*/
resize() {
if (this.$refs.wrap) {
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2));
}
},
},
};
</script>
<style lang="scss">
@import "../assets/vars.scss";
// This naming is an internal name for the package vue3-calendar-heatmap and it cannot be modified to kebab-case
/* stylelint-disable */
.vch__legend {
display: inline-flex;
padding: 0.25rem 0.5rem;
gap: 1ch;
align-items: center;
}
/* stylelint-enable */
</style>

View File

@ -33,12 +33,12 @@
<template #item="monitor">
<div class="item">
<div class="row">
<div class="col-9 col-md-8 small-padding">
<div class="col-3 col-md-4 small-padding">
<div class="info">
<font-awesome-icon v-if="editMode" icon="arrows-alt-v" class="action drag me-3" />
<font-awesome-icon v-if="editMode" icon="times" class="action remove me-3" @click="removeMonitor(group.index, monitor.index)" />
<Uptime :monitor="monitor.element" type="24" :pill="true" />
<Uptime style="vertical-align: top;" :monitor="monitor.element" type="1y" :pill="true" />
<a
v-if="showLink(monitor)"
:href="monitor.element.url"
@ -48,7 +48,7 @@
>
{{ monitor.element.name }}
</a>
<p v-else class="item-name"> {{ monitor.element.name }} </p>
<p v-else class="item-name" style="white-space: initial;"> {{ monitor.element.name }} </p>
<span
title="Setting"
@ -70,8 +70,8 @@
</div>
</div>
</div>
<div :key="$root.userHeartbeatBar" class="col-3 col-md-4">
<HeartbeatBar size="mid" :monitor-id="monitor.element.id" />
<div :key="$root.userHeartbeatBar" class="col-9 col-md-8">
<HeartbeatBarStatus :monitor-id="monitor.element.id" />
</div>
</div>
</div>
@ -87,7 +87,7 @@
<script>
import MonitorSettingDialog from "./MonitorSettingDialog.vue";
import Draggable from "vuedraggable";
import HeartbeatBar from "./HeartbeatBar.vue";
import HeartbeatBarStatus from "./HeartbeatBarStatus.vue";
import Uptime from "./Uptime.vue";
import Tag from "./Tag.vue";
@ -95,7 +95,7 @@ export default {
components: {
MonitorSettingDialog,
Draggable,
HeartbeatBar,
HeartbeatBarStatus,
Uptime,
Tag,
},