mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2025-10-27 08:49:27 +00:00
Give status info its own page
This commit is contained in:
@@ -37,6 +37,7 @@ class WebServer:
|
|||||||
# Routes for templated pages
|
# Routes for templated pages
|
||||||
bottle.get("/")(lambda: self.serve_template('webpage_spots'))
|
bottle.get("/")(lambda: self.serve_template('webpage_spots'))
|
||||||
bottle.get("/alerts")(lambda: self.serve_template('webpage_alerts'))
|
bottle.get("/alerts")(lambda: self.serve_template('webpage_alerts'))
|
||||||
|
bottle.get("/status")(lambda: self.serve_template('webpage_status'))
|
||||||
bottle.get("/about")(lambda: self.serve_template('webpage_about'))
|
bottle.get("/about")(lambda: self.serve_template('webpage_about'))
|
||||||
bottle.get("/apidocs")(lambda: self.serve_template('webpage_apidocs'))
|
bottle.get("/apidocs")(lambda: self.serve_template('webpage_apidocs'))
|
||||||
# Default route to serve from "webassets"
|
# Default route to serve from "webassets"
|
||||||
@@ -58,7 +59,6 @@ class WebServer:
|
|||||||
self.status = "OK"
|
self.status = "OK"
|
||||||
response.content_type = 'application/json'
|
response.content_type = 'application/json'
|
||||||
response.set_header('Cache-Control', 'no-store')
|
response.set_header('Cache-Control', 'no-store')
|
||||||
print(data)
|
|
||||||
return json.dumps(data, default=serialize_everything)
|
return json.dumps(data, default=serialize_everything)
|
||||||
|
|
||||||
# Accept a spot
|
# Accept a spot
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item ms-4"><a href="/" class="nav-link" id="nav-link-spots">Spots</a></li>
|
<li class="nav-item ms-4"><a href="/" class="nav-link" id="nav-link-spots">Spots</a></li>
|
||||||
<li class="nav-item ms-4"><a href="/alerts" class="nav-link" id="nav-link-alerts">Alerts</a></li>
|
<li class="nav-item ms-4"><a href="/alerts" class="nav-link" id="nav-link-alerts">Alerts</a></li>
|
||||||
|
<li class="nav-item ms-4"><a href="/status" class="nav-link" id="nav-link-status">Status</a></li>
|
||||||
<li class="nav-item ms-4"><a href="/about" class="nav-link" id="nav-link-about">About</a></li>
|
<li class="nav-item ms-4"><a href="/about" class="nav-link" id="nav-link-about">About</a></li>
|
||||||
<li class="nav-item ms-4"><a href="/apidocs" class="nav-link" id="nav-link-api">API</a></li>
|
<li class="nav-item ms-4"><a href="/apidocs" class="nav-link" id="nav-link-api">API</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -23,28 +23,10 @@
|
|||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<p class="d-inline-flex gap-1">
|
<p class="d-inline-flex gap-1">
|
||||||
<button id="settings-button" type="button" class="btn btn-outline-primary" data-bs-toggle="button">Settings</button>
|
<button id="settings-button" type="button" class="btn btn-outline-primary" data-bs-toggle="button">Settings</button>
|
||||||
<button id="status-button" type="button" class="btn btn-outline-primary" data-bs-toggle="button">Status</button>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="status-area" class="appearing-panel card mb-3">
|
|
||||||
<div class="card-header text-white bg-primary">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-auto me-auto">
|
|
||||||
Status
|
|
||||||
</div>
|
|
||||||
<div class="col-auto d-inline-flex">
|
|
||||||
<button id="close-status-button" type="button" class="btn-close btn-close-white" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div id="status-container" class="row row-cols-1 row-cols-md-4 g-4"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="settings-area" class="appearing-panel card mb-3">
|
<div id="settings-area" class="appearing-panel card mb-3">
|
||||||
<div class="card-header text-white bg-primary">
|
<div class="card-header text-white bg-primary">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
7
views/webpage_status.tpl
Normal file
7
views/webpage_status.tpl
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
% rebase('webpage_base.tpl')
|
||||||
|
|
||||||
|
<div id="status-container" class="row row-cols-1 row-cols-md-4 g-4 mt-4"></div>
|
||||||
|
|
||||||
|
<script src="/js/common.js"></script>
|
||||||
|
<script src="/js/status.js"></script>
|
||||||
|
<script>$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --></script>
|
||||||
@@ -146,54 +146,6 @@ function updateTable() {
|
|||||||
$('#table-container').html(table);
|
$('#table-container').html(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load server status
|
|
||||||
function loadStatus() {
|
|
||||||
$.getJSON('/api/status', function(jsonData) {
|
|
||||||
$("#status-container").empty();
|
|
||||||
$("#status-container").append(generateStatusCard("Server Information", [
|
|
||||||
`Software Version: ${jsonData["software-version"]}`,
|
|
||||||
`Server Owner Callsign: ${jsonData["server-owner-callsign"]}`,
|
|
||||||
`Server Uptime: ${moment().subtract(jsonData["uptime"], 'seconds').fromNow()}`,
|
|
||||||
`Memory Use: ${jsonData["mem_use_mb"]} MB`,
|
|
||||||
`Total Spots: ${jsonData["num_spots"]}`
|
|
||||||
]));
|
|
||||||
$("#status-container").append(generateStatusCard("Web Server", [
|
|
||||||
`Status: ${jsonData["webserver"]["status"]}`,
|
|
||||||
`Last API Access: ${moment.unix(jsonData["webserver"]["last_api_access"]).utc().fromNow()}`,
|
|
||||||
`Last Page Access: ${moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow()}`
|
|
||||||
]));
|
|
||||||
$("#status-container").append(generateStatusCard("Cleanup Service", [
|
|
||||||
`Status: ${jsonData["cleanup"]["status"]}`,
|
|
||||||
`Last Ran: ${moment.unix(jsonData["cleanup"]["last_ran"]).utc().fromNow()}`
|
|
||||||
]));
|
|
||||||
jsonData["spot_providers"].forEach(p => {
|
|
||||||
$("#status-container").append(generateStatusCard("Provider: " + p["name"], [
|
|
||||||
`Status: ${p["status"]}`,
|
|
||||||
`Last Updated: ${p["enabled"] ? moment.unix(p["last_updated"]).utc().fromNow() : "N/A"}`,
|
|
||||||
`Latest Spot: ${p["enabled"] ? moment.unix(p["last_spot"]).utc().fromNow() : "N/A"}`
|
|
||||||
]));
|
|
||||||
});
|
|
||||||
jsonData["alert_providers"].forEach(p => {
|
|
||||||
$("#status-container").append(generateStatusCard("Provider: " + p["name"], [
|
|
||||||
`Status: ${p["status"]}`,
|
|
||||||
`Last Updated: ${p["enabled"] ? moment.unix(p["last_updated"]).utc().fromNow() : "N/A"}`
|
|
||||||
]));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a status card
|
|
||||||
function generateStatusCard(title, textLines) {
|
|
||||||
let $col = $("<div class='col'>");
|
|
||||||
let $card = $("<div class='card'>");
|
|
||||||
let $card_body = $("<div class='card-body'>");
|
|
||||||
$card_body.append(`<h5 class='card-title'>${title}</h5>`);
|
|
||||||
$card_body.append(`<p class='card-text'>${textLines.join("<br/>")}</p>`);
|
|
||||||
$card.append($card_body);
|
|
||||||
$col.append($card);
|
|
||||||
return $col;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load server options. Once a successful callback is made from this, we then query spots and set up the timer to query
|
// Load server options. Once a successful callback is made from this, we then query spots and set up the timer to query
|
||||||
// spots repeatedly.
|
// spots repeatedly.
|
||||||
function loadOptions() {
|
function loadOptions() {
|
||||||
@@ -265,27 +217,7 @@ function filtersUpdated() {
|
|||||||
|
|
||||||
// Set up UI element event listeners, after the document is ready
|
// Set up UI element event listeners, after the document is ready
|
||||||
function setUpEventListeners() {
|
function setUpEventListeners() {
|
||||||
$("#status-button").click(function() {
|
|
||||||
// If we are going to display status, load the data for the status panel, and hide the filters panel
|
|
||||||
if (!$("#status-area").is(":visible")) {
|
|
||||||
loadStatus();
|
|
||||||
if ($("#settings-area").is(":visible")) {
|
|
||||||
$("#settings-area").hide();
|
|
||||||
$("#settings-button").button("toggle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$("#status-area").toggle();
|
|
||||||
});
|
|
||||||
$("#close-status-button").click(function() {
|
|
||||||
$("#status-button").button("toggle");
|
|
||||||
$("#status-area").hide();
|
|
||||||
});
|
|
||||||
$("#settings-button").click(function() {
|
$("#settings-button").click(function() {
|
||||||
// If we are going to display filters, hide the filters panel
|
|
||||||
if (!$("#settings-area").is(":visible") && $("#status-area").is(":visible")) {
|
|
||||||
$("#status-area").hide();
|
|
||||||
$("#status-button").button("toggle");
|
|
||||||
}
|
|
||||||
$("#settings-area").toggle();
|
$("#settings-area").toggle();
|
||||||
});
|
});
|
||||||
$("#close-settings-button").click(function() {
|
$("#close-settings-button").click(function() {
|
||||||
|
|||||||
52
webassets/js/status.js
Normal file
52
webassets/js/status.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Load server status
|
||||||
|
function loadStatus() {
|
||||||
|
$.getJSON('/api/status', function(jsonData) {
|
||||||
|
$("#status-container").empty();
|
||||||
|
$("#status-container").append(generateStatusCard("Server Information", [
|
||||||
|
`Software Version: ${jsonData["software-version"]}`,
|
||||||
|
`Server Owner Callsign: ${jsonData["server-owner-callsign"]}`,
|
||||||
|
`Server up since: ${moment().subtract(jsonData["uptime"], 'seconds').fromNow()}`,
|
||||||
|
`Memory Use: ${jsonData["mem_use_mb"]} MB`,
|
||||||
|
`Total Spots: ${jsonData["num_spots"]}`
|
||||||
|
]));
|
||||||
|
$("#status-container").append(generateStatusCard("Web Server", [
|
||||||
|
`Status: ${jsonData["webserver"]["status"]}`,
|
||||||
|
`Last API Access: ${moment.unix(jsonData["webserver"]["last_api_access"]).utc().fromNow()}`,
|
||||||
|
`Last Page Access: ${moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow()}`
|
||||||
|
]));
|
||||||
|
$("#status-container").append(generateStatusCard("Cleanup Service", [
|
||||||
|
`Status: ${jsonData["cleanup"]["status"]}`,
|
||||||
|
`Last Ran: ${moment.unix(jsonData["cleanup"]["last_ran"]).utc().fromNow()}`
|
||||||
|
]));
|
||||||
|
jsonData["spot_providers"].forEach(p => {
|
||||||
|
$("#status-container").append(generateStatusCard("Spot Provider: " + p["name"], [
|
||||||
|
`Status: ${p["status"]}`,
|
||||||
|
`Last Updated: ${p["enabled"] ? moment.unix(p["last_updated"]).utc().fromNow() : "N/A"}`,
|
||||||
|
`Latest Spot: ${p["enabled"] ? moment.unix(p["last_spot"]).utc().fromNow() : "N/A"}`
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
jsonData["alert_providers"].forEach(p => {
|
||||||
|
$("#status-container").append(generateStatusCard("Alert Provider: " + p["name"], [
|
||||||
|
`Status: ${p["status"]}`,
|
||||||
|
`Last Updated: ${p["enabled"] ? moment.unix(p["last_updated"]).utc().fromNow() : "N/A"}`
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a status card
|
||||||
|
function generateStatusCard(title, textLines) {
|
||||||
|
let $col = $("<div class='col'>");
|
||||||
|
let $card = $("<div class='card'>");
|
||||||
|
let $card_body = $("<div class='card-body'>");
|
||||||
|
$card_body.append(`<h5 class='card-title'>${title}</h5>`);
|
||||||
|
$card_body.append(`<p class='card-text'>${textLines.join("<br/>")}</p>`);
|
||||||
|
$card.append($card_body);
|
||||||
|
$col.append($card);
|
||||||
|
return $col;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Startup
|
||||||
|
$(document).ready(function() {
|
||||||
|
loadStatus();
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user