diff --git a/app/flask_app/templates/chart.html b/app/flask_app/templates/chart.html index 4690859..f8adf2f 100644 --- a/app/flask_app/templates/chart.html +++ b/app/flask_app/templates/chart.html @@ -1,10 +1,12 @@ - + - - + Simple Line Chart + + @@ -43,14 +45,18 @@ x: { type: 'time', // Important for datetime axis time: { - unit: 'hour', + unit: 'minute', tooltipFormat: 'HH:mm:ss', - displayFormats: { - hour: 'HH:mm' - } + displayFormats: { hour: 'HH:mm' } }, min: min, - max: max + max: max, + ticks: { color: '#ffffff' }, // X-axis labels + grid: { color: 'rgba(255, 255, 255, 0.1)' } // X-axis grid lines + }, + y: { + ticks: { color: '#ffffff' }, // Y-axis labels + grid: { color: 'rgba(255, 255, 255, 0.1)' } // Y-axis grid lines } } } diff --git a/app/routes.py b/app/routes.py new file mode 100644 index 0000000..d66be49 --- /dev/null +++ b/app/routes.py @@ -0,0 +1,95 @@ +from flask import Blueprint, render_template, abort, jsonify, send_file, json +from typing import cast, Optional, Any +from datetime import datetime, timedelta, timezone +from config import timeout +from .models import service, log +from app import app, db + +bp = Blueprint( + "main", + "__name__", + url_prefix="/", + static_folder="static", +) + + +# Prepares log data for chart.js chart +def prepare_chart_data( + logs: list[log], +) -> tuple[list[str], list[Optional[int]]]: + if len(logs) <= 0: # Return empty if there are no logs + return ([], []) + + x = [logs[0].dateCreatedUTC().isoformat()] + y = [logs[0].ping] + + for i in range(1, len(logs)): + log1 = logs[i] + log2 = logs[i - 1] + + # Check if the gap in points exceeds a threshold + if (abs(log1.dateCreatedUTC() - log2.dateCreatedUTC())) > timedelta( + milliseconds=1.5 * (timeout + 1000) + ): + x.append(log2.dateCreatedUTC().isoformat()) + y.append(None) + + x.append(log1.dateCreatedUTC().isoformat()) + y.append(log1.ping) + return (x, y) + + +@bp.route("/") +def homepage(): + return render_template("home.html") + + +@bp.route("/chart/") +def chart(id: int): + with app.app_context(): + logs = [] + s = db.session.query(service).filter_by(id=id).first() + if s: + logs = cast( + list[log], + s.logs.order_by(log.dateCreated.desc()) # type: ignore + .limit(300) + .all(), + ) + else: + return abort(code=403) + x, y = prepare_chart_data(logs=logs) + + now = datetime.now(timezone.utc) + max_ = now + min_ = now - timedelta(hours=1) + return render_template( + "chart.html", + dates=x, + values=json.dumps(y), + min=min_.isoformat(), + max=max_.isoformat(), + ) + + +@bp.route("/api/status") +def status(): + results: list[dict[str, Any]] = [] + with app.app_context(): + a = db.session.query(service).all() + for s in a: + b = cast( + Optional[log], + s.logs.order_by( + log.dateCreated.desc() # type: ignore + ).first(), + ) + if b: + results.append(s.to_dict() | b.to_dict()) + + return jsonify(results) + + +@bp.route("/favicon.svg") +def favicon(): + return send_file("/static/favicon.svg")