This commit is contained in:
Akhilesh Sooji 2024-07-31 15:58:28 +00:00 committed by GitHub
commit 7d88b73e01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 1161 additions and 948 deletions

1949
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -191,6 +191,7 @@
"stylelint-config-standard": "~25.0.0",
"terser": "~5.15.0",
"test": "~3.3.0",
"tippy.js": "^6.3.7",
"typescript": "~4.4.4",
"v-pagination-3": "~0.1.7",
"vite": "~5.2.8",
@ -207,6 +208,7 @@
"vue-qrcode": "~1.0.0",
"vue-router": "~4.2.5",
"vue-toastification": "~2.0.0-rc.5",
"vue3-calendar-heatmap": "^2.0.5",
"vuedraggable": "~4.1.0",
"wait-on": "^7.2.0",
"whatwg-url": "~12.0.1"

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

@ -266,10 +266,8 @@ export default {
<style lang="scss" scoped>
@import "../assets/vars.scss";
.wrap {
overflow: hidden;
width: 100%;
white-space: nowrap;
.heat-map {
font-size: x-small;
}
.hp-bar-big {

View file

@ -0,0 +1,104 @@
<template>
<div ref="wrap">
<div class="hp-bar-big">
<CalendarHeatmap
:style="{ fill: 'var(--dark-font-color2)', fontSize: 'xx-small' }"
class="heatmap" :values="values" :end-date="endDate" no-data-text="Unknown" tooltip-unit="%"
:range-color="['aliceblue', 'var(--danger)', 'var(--warning)', 'var(--warning)', 'var(--highlight)', 'var(--primary)']"
:display-legend="false"
round="3"
: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() {
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";
:root {
--highlight-white: #{$highlight-white};
--danger: #{$danger};
--warning: #{$warning};
--warning2: #ffc100;
--highlight: #{$highlight};
--primary: #{$primary};
--dark-font-color2: #{$dark-font-color2};
}
/* stylelint-disable */
// This naming is an internal name for the package vue3-calendar-heatmap and it cannot be modified to kebab-case
.vch__legend {
display: none !important;
}
.hp-bar-big {
padding: 10px;
overflow: visible;
background-color: white;
border-radius: 6px;
}
.heatmap {
rect.vch__day__square {
stroke: none !important;
stroke-width: 0 !important;
&:hover {
fill-opacity: 0.5;
}
}
}
/* 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,
},