Add charts
This commit is contained in:
parent
c3c0dbbbae
commit
3d627b5bf0
@ -68,5 +68,22 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State<Pool<MySql>>) -> Jso
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(json!({ "backlog": backlog.backlog, "schedule": schedule }))
|
||||
let schedule_long = sqlx::query_as_unchecked!(
|
||||
TimeFrame,
|
||||
"SELECT
|
||||
FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(`utc_time`) / 86400) * 86400) AS `time_key`,
|
||||
COUNT(1) AS `count`
|
||||
FROM reminders
|
||||
WHERE
|
||||
`utc_time` < DATE_ADD(NOW(), INTERVAL 31 DAY) AND
|
||||
`utc_time` >= NOW() AND
|
||||
`enabled` = 1
|
||||
GROUP BY `time_key`
|
||||
ORDER BY `time_key`"
|
||||
)
|
||||
.fetch_all(pool.inner())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(json!({ "backlog": backlog.backlog, "schedule": schedule, "scheduleLong": schedule_long }))
|
||||
}
|
||||
|
@ -580,3 +580,27 @@ input.default-width {
|
||||
.is-locked .field:last-of-type {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.stat-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.stat-box {
|
||||
flex-grow: 1;
|
||||
border-radius: 6px;
|
||||
background-color: #fcfcfc;
|
||||
border-color: #efefef;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.figure {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.figure-num {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
61
web/static/js/admin.js
Normal file
61
web/static/js/admin.js
Normal file
@ -0,0 +1,61 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
fetch("/admin/data")
|
||||
.then((resp) => resp.json())
|
||||
.then((data) => {
|
||||
document.querySelector("#backlog").textContent = data.backlog;
|
||||
|
||||
new Chart(document.getElementById("schedule"), {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: data.schedule.map((row) =>
|
||||
luxon.DateTime.fromISO(row.time_key)
|
||||
),
|
||||
datasets: [
|
||||
{
|
||||
label: "Reminders",
|
||||
data: data.schedule.map((row) => row.count),
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
type: "time",
|
||||
time: {
|
||||
unit: "minute",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
new Chart(document.getElementById("scheduleLong"), {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: data.scheduleLong.map((row) =>
|
||||
luxon.DateTime.fromISO(row.time_key)
|
||||
),
|
||||
datasets: [
|
||||
{
|
||||
label: "Reminders",
|
||||
data: data.scheduleLong.map((row) => row.count),
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
type: "time",
|
||||
time: {
|
||||
unit: "day",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
20
web/static/js/chart.js
Normal file
20
web/static/js/chart.js
Normal file
File diff suppressed because one or more lines are too long
7
web/static/js/chartjs-adapter-luxon.js
Normal file
7
web/static/js/chartjs-adapter-luxon.js
Normal file
@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* chartjs-adapter-luxon v1.3.1
|
||||
* https://www.chartjs.org
|
||||
* (c) 2023 chartjs-adapter-luxon Contributors
|
||||
* Released under the MIT license
|
||||
*/
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Chart,e.luxon)}(this,(function(e,t){"use strict";const n={datetime:t.DateTime.DATETIME_MED_WITH_SECONDS,millisecond:"h:mm:ss.SSS a",second:t.DateTime.TIME_WITH_SECONDS,minute:t.DateTime.TIME_SIMPLE,hour:{hour:"numeric"},day:{day:"numeric",month:"short"},week:"DD",month:{month:"short",year:"numeric"},quarter:"'Q'q - yyyy",year:{year:"numeric"}};e._adapters._date.override({_id:"luxon",_create:function(e){return t.DateTime.fromMillis(e,this.options)},init(e){this.options.locale||(this.options.locale=e.locale)},formats:function(){return n},parse:function(e,n){const i=this.options,r=typeof e;return null===e||"undefined"===r?null:("number"===r?e=this._create(e):"string"===r?e="string"==typeof n?t.DateTime.fromFormat(e,n,i):t.DateTime.fromISO(e,i):e instanceof Date?e=t.DateTime.fromJSDate(e,i):"object"!==r||e instanceof t.DateTime||(e=t.DateTime.fromObject(e,i)),e.isValid?e.valueOf():null)},format:function(e,t){const n=this._create(e);return"string"==typeof t?n.toFormat(t):n.toLocaleString(t)},add:function(e,t,n){const i={};return i[n]=t,this._create(e).plus(i).valueOf()},diff:function(e,t,n){return this._create(e).diff(this._create(t)).as(n).valueOf()},startOf:function(e,t,n){if("isoWeek"===t){n=Math.trunc(Math.min(Math.max(0,n),6));const t=this._create(e);return t.minus({days:(t.weekday-n+7)%7}).startOf("day").valueOf()}return t?this._create(e).startOf(t).valueOf():e},endOf:function(e,t){return this._create(e).endOf(t).valueOf()}})}));
|
@ -1,9 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="EN">
|
||||
<head>
|
||||
<script src="/static/js/reporter.js" type="application/javascript"></script>
|
||||
|
||||
<meta name="description" content="The most powerful Discord Reminders Bot">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="yandex-verification" content="bb77b8681eb64a90"/>
|
||||
<meta name="google-site-verification" content="7h7UVTeEe0AOzHiH3cFtsqMULYGN-zCZdMT_YCkW1Ho"/>
|
||||
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src *; font-src fonts.gstatic.com 'self'"> -->
|
||||
|
||||
<!-- favicon -->
|
||||
<link rel="apple-touch-icon" sizes="180x180"
|
||||
href="/static/favicon/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32"
|
||||
href="/static/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16"
|
||||
href="/static/favicon/favicon-16x16.png">
|
||||
<link rel="manifest" href="/static/favicon/site.webmanifest">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<title>Reminder Bot | Admin</title>
|
||||
|
||||
<!-- styles -->
|
||||
<link rel="stylesheet" href="/static/css/bulma.min.css">
|
||||
<link rel="stylesheet" href="/static/css/fa.css">
|
||||
<link rel="stylesheet" href="/static/css/font.css">
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<link rel="stylesheet" href="/static/css/dtsel.css">
|
||||
|
||||
<script src="/static/js/luxon.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<body style="width: 100%;">
|
||||
|
||||
<p class="title pageTitle">Admin dashboard</p>
|
||||
<section id="main">
|
||||
<div class="stat-row">
|
||||
<div class="stat-box" style="height: 400px;">
|
||||
<canvas id="schedule"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<div class="stat-box figure">
|
||||
<p>Backlog</p>
|
||||
<p class="figure-num" id="backlog">?</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<div class="stat-box" style="height: 400px;">
|
||||
<canvas id="scheduleLong"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/static/js/chart.js" defer></script>
|
||||
<script src="/static/js/chartjs-adapter-luxon.js" defer></script>
|
||||
<script src="/static/js/admin.js" defer></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user