Add WIP UI and manager for alerts.
This commit is contained in:
parent
502c7e3bed
commit
ac5409587d
5 changed files with 174 additions and 1 deletions
65
baps_types/alert.py
Normal file
65
baps_types/alert.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
from typing import Any, Dict
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
CRITICAL = "Critical"
|
||||||
|
WARNING = "Warning"
|
||||||
|
|
||||||
|
class Alert:
|
||||||
|
start_time: int = 0
|
||||||
|
last_time: int = 0
|
||||||
|
end_time: int = -1
|
||||||
|
id: str
|
||||||
|
title: str
|
||||||
|
description: str
|
||||||
|
module: str
|
||||||
|
severity: str
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ui_class(self) -> str:
|
||||||
|
if self.severity == CRITICAL:
|
||||||
|
return "danger"
|
||||||
|
if self.severity == WARNING:
|
||||||
|
return "warning"
|
||||||
|
return "info"
|
||||||
|
|
||||||
|
# return self._weight
|
||||||
|
|
||||||
|
# weight.setter
|
||||||
|
# def weight(self, value: int):
|
||||||
|
# self._weight = value
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def __dict__(self):
|
||||||
|
attrs = ["start_time", "last_time", "end_time", "id", "title", "description", "module", "severity"]
|
||||||
|
out = {}
|
||||||
|
for attr in attrs:
|
||||||
|
out[attr] = self.__getattribute__(attr)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
def __init__(self, new_data: Dict[str,Any]):
|
||||||
|
required_vars = [
|
||||||
|
"start_time", # Just in case an alert wants to show starting earlier than it is reported.
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"description",
|
||||||
|
"module",
|
||||||
|
"severity"
|
||||||
|
]
|
||||||
|
|
||||||
|
for key in required_vars:
|
||||||
|
if key not in new_data.keys():
|
||||||
|
raise KeyError("Key {} is missing from data to create Alert.".format(key))
|
||||||
|
|
||||||
|
#if type(new_data[key]) != type(getattr(self,key)):
|
||||||
|
# raise TypeError("Key {} has type {}, was expecting {}.".format(key, type(new_data[key]), type(getattr(self,key))))
|
||||||
|
|
||||||
|
# Account for if the creator didn't want to set a custom time.
|
||||||
|
if key == "start_time" and new_data[key] == -1:
|
||||||
|
new_data[key] = datetime.now()
|
||||||
|
|
||||||
|
setattr(self,key,new_data[key])
|
||||||
|
|
||||||
|
self.last_time = self.start_time
|
29
helpers/alert_manager.py
Normal file
29
helpers/alert_manager.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
from typing import List
|
||||||
|
from baps_types.alert import CRITICAL, Alert
|
||||||
|
|
||||||
|
class AlertManager():
|
||||||
|
_alerts: List[Alert]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._alerts = [Alert(
|
||||||
|
{
|
||||||
|
"start_time": -1,
|
||||||
|
"id": "test",
|
||||||
|
"title": "Test Alert",
|
||||||
|
"description": "This is a test alert.",
|
||||||
|
"module": "Test",
|
||||||
|
"severity": CRITICAL
|
||||||
|
}
|
||||||
|
)]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alerts_current(self):
|
||||||
|
return self._alerts
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alert_count_current(self):
|
||||||
|
return len(self._alerts)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alert_count_previous(self):
|
||||||
|
return len(self._alerts)
|
41
ui-templates/alerts.html
Normal file
41
ui-templates/alerts.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block head %}
|
||||||
|
<meta http-equiv="refresh" content="2;url=/alerts" />
|
||||||
|
{% endblock %}
|
||||||
|
{% block content_inner %}
|
||||||
|
{% if data %}
|
||||||
|
<h2>Current Alerts: {{ data.alert_count_current }}</h2>
|
||||||
|
|
||||||
|
<div class="accordion" id="accordionExample">
|
||||||
|
{% for alert in data.alerts_current %}
|
||||||
|
<div class="card alert-{{ alert.ui_class }}">
|
||||||
|
<div class="card-header" id="headingOne">
|
||||||
|
<h2 class="mb-0">
|
||||||
|
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||||
|
{{ alert.title }}
|
||||||
|
</button>
|
||||||
|
<span class="badge badge-{{ alert.ui_class}}">{{ alert.severity }}</span>
|
||||||
|
</h2>
|
||||||
|
<span class="badge">Since {{ alert.start_time }}</span>
|
||||||
|
<span class="badge">Last Seen {{ alert.last_time }}</span>
|
||||||
|
{% if alert.end_time > -1 %}
|
||||||
|
<span class="badge">Ended {{ alert.end_time }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
|
||||||
|
<div class="card-body">
|
||||||
|
<strong>Module: </strong>{{ alert.module }}<br>
|
||||||
|
{{ alert.description }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<h2>Previous Alerts: {{ data.alert_count_previous }}</h2>
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -1,4 +1,7 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% block head %}
|
||||||
|
<meta http-equiv="refresh" content="2;url=/" />
|
||||||
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
|
@ -16,6 +19,23 @@
|
||||||
<a href="/presenter/" class="btn btn-primary btn-user btn-block">
|
<a href="/presenter/" class="btn btn-primary btn-user btn-block">
|
||||||
Open BAPS Presenter
|
Open BAPS Presenter
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
{% if data.alert_count > 0 %}
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
<h4 class="alert-heading">Something's up! <a href="/alerts" class="btn btn-sm btn-danger float-right"><span class="badge badge-light mr-1">{{data.alert_count}}</span>View Alerts</a></h4>
|
||||||
|
<p>BAPSicle is having some issues. Please review the alerts page.
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
<h4 class="alert-heading">We're all good!</h4>
|
||||||
|
<p>BAPSicle seems to be running well. If this doesn't seem to be the case, try restarting or taking a closer look at the logs.</p>
|
||||||
|
{% endif %}
|
||||||
|
<hr>
|
||||||
|
<a href="/logs" class="btn btn-success">Logs</a>
|
||||||
|
<a href="/restart" class="btn btn-info">Restart</a>
|
||||||
|
<a href="/shutdown" class="btn btn-danger">Shutdown</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<p>Version: {{data.server_version}} - Build: {{data.server_build}} - Branch: {{data.server_branch}}</p>
|
<p>Version: {{data.server_version}} - Build: {{data.server_build}} - Branch: {{data.server_branch}}</p>
|
||||||
<p>Server Name: {{data.server_name}}</p>
|
<p>Server Name: {{data.server_name}}</p>
|
||||||
|
|
|
@ -27,6 +27,7 @@ from helpers.state_manager import StateManager
|
||||||
from helpers.the_terminator import Terminator
|
from helpers.the_terminator import Terminator
|
||||||
from helpers.normalisation import get_normalised_filename_if_available
|
from helpers.normalisation import get_normalised_filename_if_available
|
||||||
from helpers.myradio_api import MyRadioAPI
|
from helpers.myradio_api import MyRadioAPI
|
||||||
|
from helpers.alert_manager import AlertManager
|
||||||
|
|
||||||
env = Environment(
|
env = Environment(
|
||||||
loader=FileSystemLoader("%s/ui-templates/" % os.path.dirname(__file__)),
|
loader=FileSystemLoader("%s/ui-templates/" % os.path.dirname(__file__)),
|
||||||
|
@ -97,6 +98,7 @@ def render_template(file, data, status=200):
|
||||||
logger: LoggingManager
|
logger: LoggingManager
|
||||||
server_state: StateManager
|
server_state: StateManager
|
||||||
api: MyRadioAPI
|
api: MyRadioAPI
|
||||||
|
alerts: AlertManager
|
||||||
|
|
||||||
player_to_q: List[Queue] = []
|
player_to_q: List[Queue] = []
|
||||||
player_from_q: List[Queue] = []
|
player_from_q: List[Queue] = []
|
||||||
|
@ -116,6 +118,7 @@ def ui_index(request):
|
||||||
data = {
|
data = {
|
||||||
"ui_page": "index",
|
"ui_page": "index",
|
||||||
"ui_title": "",
|
"ui_title": "",
|
||||||
|
"alert_count": alerts.alert_count_current,
|
||||||
"server_version": config["server_version"],
|
"server_version": config["server_version"],
|
||||||
"server_build": config["server_build"],
|
"server_build": config["server_build"],
|
||||||
"server_name": config["server_name"],
|
"server_name": config["server_name"],
|
||||||
|
@ -135,6 +138,20 @@ def ui_status(request):
|
||||||
"ui_page": "status", "ui_title": "Status"}
|
"ui_page": "status", "ui_title": "Status"}
|
||||||
return render_template("status.html", data=data)
|
return render_template("status.html", data=data)
|
||||||
|
|
||||||
|
@app.route("/alerts")
|
||||||
|
def ui_alerts(request):
|
||||||
|
channel_states = []
|
||||||
|
for i in range(server_state.get()["num_channels"]):
|
||||||
|
channel_states.append(status(i))
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"alerts_current": alerts.alerts_current,
|
||||||
|
"alerts_count_current": alerts.alert_count_current,
|
||||||
|
"ui_page": "alerts",
|
||||||
|
"ui_title": "Alerts"
|
||||||
|
}
|
||||||
|
return render_template("alerts.html", data=data)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/config/player")
|
@app.route("/config/player")
|
||||||
def ui_config_player(request):
|
def ui_config_player(request):
|
||||||
|
@ -479,13 +496,14 @@ def restart(request):
|
||||||
# Don't use reloader, it causes Nested Processes!
|
# Don't use reloader, it causes Nested Processes!
|
||||||
def WebServer(player_to: List[Queue], player_from: List[Queue], state: StateManager):
|
def WebServer(player_to: List[Queue], player_from: List[Queue], state: StateManager):
|
||||||
|
|
||||||
global player_to_q, player_from_q, server_state, api, app
|
global player_to_q, player_from_q, server_state, api, app, alerts
|
||||||
player_to_q = player_to
|
player_to_q = player_to
|
||||||
player_from_q = player_from
|
player_from_q = player_from
|
||||||
server_state = state
|
server_state = state
|
||||||
|
|
||||||
logger = LoggingManager("WebServer")
|
logger = LoggingManager("WebServer")
|
||||||
api = MyRadioAPI(logger, state)
|
api = MyRadioAPI(logger, state)
|
||||||
|
alerts = AlertManager()
|
||||||
|
|
||||||
process_title = "Web Server"
|
process_title = "Web Server"
|
||||||
setproctitle(process_title)
|
setproctitle(process_title)
|
||||||
|
|
Loading…
Reference in a new issue