add refactored device status template and import module
This commit is contained in:
parent
3bf095e148
commit
a1b16f8d38
|
@ -1,3 +1,531 @@
|
|||
use std::process::Command;
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
use peach_lib::{config_manager, dyndns_client, oled_client};
|
||||
use peach_stats::{
|
||||
stats,
|
||||
stats::{CpuStatPercentages, MemStat},
|
||||
};
|
||||
|
||||
use crate::{templates, utils::theme};
|
||||
|
||||
// ROUTE: /status
|
||||
|
||||
/// Query systemd to determine the state of the networking service.
|
||||
fn retrieve_networking_state() -> Option<String> {
|
||||
// call: `systemctl show networking.service --no-page`
|
||||
let networking_service_output = Command::new("systemctl")
|
||||
.arg("show")
|
||||
.arg("networking.service")
|
||||
.arg("--no-page")
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
let service_info = std::str::from_utf8(&networking_service_output.stdout).ok()?;
|
||||
|
||||
// find the line starting with "ActiveState=" and return the value
|
||||
service_info
|
||||
.lines()
|
||||
.find(|line| line.starts_with("ActiveState="))
|
||||
.map(|line| line.strip_prefix("ActiveState="))
|
||||
.flatten()
|
||||
.map(|state| state.to_string())
|
||||
}
|
||||
|
||||
/// Query systemd to determine the state of the sbot service.
|
||||
fn retrieve_sbot_state() -> Option<String> {
|
||||
// retrieve the name of the go-sbot service or set default
|
||||
let go_sbot_service = config_manager::get_config_value("GO_SBOT_SERVICE")
|
||||
.unwrap_or("go-sbot.service".to_string());
|
||||
|
||||
let sbot_service_output = Command::new("systemctl")
|
||||
.arg("show")
|
||||
.arg(go_sbot_service)
|
||||
.arg("--no-page")
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
let service_info = std::str::from_utf8(&sbot_service_output.stdout).ok()?;
|
||||
|
||||
// find the line starting with "ActiveState=" and return the value
|
||||
service_info
|
||||
.lines()
|
||||
.find(|line| line.starts_with("ActiveState="))
|
||||
.map(|line| line.strip_prefix("ActiveState="))
|
||||
.flatten()
|
||||
.map(|state| state.to_string())
|
||||
}
|
||||
|
||||
fn retrieve_device_status_data() -> (Option<u64>, String) {
|
||||
let uptime = stats::uptime().ok();
|
||||
|
||||
let oled_ping = match oled_client::ping() {
|
||||
Ok(_) => "ONLINE".to_string(),
|
||||
Err(_) => "OFFLINE".to_string(),
|
||||
};
|
||||
|
||||
(uptime, oled_ping)
|
||||
}
|
||||
|
||||
fn retrieve_device_usage_data<'a>() -> (Option<CpuStatPercentages>, Option<MemStat>) {
|
||||
// convert result to Option<CpuStatPercentages>, discard any error
|
||||
let cpu_stat_percent = stats::cpu_stats_percent().ok();
|
||||
let mem_stats = stats::mem_stats().ok();
|
||||
|
||||
(cpu_stat_percent, mem_stats)
|
||||
}
|
||||
|
||||
fn render_network_capsule() -> Markup {
|
||||
let (state, stack_class, img_class) = match retrieve_networking_state() {
|
||||
Some(state) if state.as_str() == "active" => {
|
||||
("active", "stack capsule border-success", "icon icon-medium")
|
||||
}
|
||||
Some(state) if state.as_str() == "inactive" => (
|
||||
"inactive",
|
||||
"stack capsule border-warning",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
Some(state) if state.as_str() == "failed" => (
|
||||
"failed",
|
||||
"stack capsule border-danger",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
_ => (
|
||||
"error",
|
||||
"stack capsule border-danger",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
};
|
||||
|
||||
html! {
|
||||
(PreEscaped("<!-- PEACH-NETWORK STATUS STACK -->"))
|
||||
div class=(stack_class) {
|
||||
img id="networkIcon" class=(img_class) alt="Network" title="Networking service status" src="icons/wifi.svg";
|
||||
div class="stack" style="padding-top: 0.5rem;" {
|
||||
label class="label-small font-near-black" { "Networking" }
|
||||
label class="label-small font-near-black" { (state.to_uppercase()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_oled_capsule(state: String) -> Markup {
|
||||
let (stack_class, img_class) = match state.as_str() {
|
||||
"ONLINE" => ("stack capsule border-success", "icon icon-medium"),
|
||||
_ => (
|
||||
"stack capsule border-warning",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
};
|
||||
|
||||
html! {
|
||||
(PreEscaped("<!-- PEACH-OLED STATUS STACK -->"))
|
||||
div class=(stack_class) {
|
||||
img id="oledIcon" class=(img_class) alt="Display" title="OLED display microservice status" src="icons/lcd.svg";
|
||||
div class="stack" style="padding-top: 0.5rem;" {
|
||||
label class="label-small font-near-black" { "Display" }
|
||||
label class="label-small font-near-black" { (state) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_diagnostics_capsule() -> Markup {
|
||||
// TODO: write a diagnostics module (maybe in peach-lib)
|
||||
|
||||
let diagnostics_state = "CLEAR";
|
||||
|
||||
html! {
|
||||
(PreEscaped("<!-- DIAGNOSTICS AND LOGS STACK -->"))
|
||||
div class="stack capsule border-success" {
|
||||
img id="statsIcon" class="icon icon-medium" alt="Line chart" title="System diagnostics and logs" src="icons/chart.svg";
|
||||
div class="stack" style="padding-top: 0.5rem;" {
|
||||
label class="label-small font-near-black" { "Diagnostics" }
|
||||
label class="label-small font-near-black" { (diagnostics_state) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_dyndns_capsule() -> Markup {
|
||||
let (state, stack_class, img_class) = match dyndns_client::is_dns_updater_online() {
|
||||
Ok(true) => ("ONLINE", "stack capsule border-success", "icon icon-medium"),
|
||||
Ok(false) => (
|
||||
"OFFLINE",
|
||||
"stack capsule border-warning",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
Err(_) => (
|
||||
"ERROR",
|
||||
"stack capsule border-danger",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
};
|
||||
|
||||
html! {
|
||||
(PreEscaped("<!-- DYNDNS STATUS STACK -->"))
|
||||
div class=(stack_class) {
|
||||
img id="dnsIcon" class=(img_class) alt="Dyndns" title="Dyndns status" src="icons/dns.png";
|
||||
div class="stack" style="padding-top: 0.5rem;" {
|
||||
label class="label-small font-near-black" { "Dyn DNS" }
|
||||
label class="label-small font-near-black" { (state) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_config_capsule() -> Markup {
|
||||
let (state, stack_class, img_class) =
|
||||
match config_manager::load_peach_config_from_disc().is_ok() {
|
||||
true => ("LOADED", "stack capsule border-success", "icon icon-medium"),
|
||||
false => (
|
||||
"INVALID",
|
||||
"stack capsule border-warning",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
};
|
||||
|
||||
html! {
|
||||
(PreEscaped("<!-- CONFIG STATUS STACK -->"))
|
||||
div class=(stack_class) {
|
||||
img id="configIcon" class=(img_class) alt="Config" title="Config status" src="icons/clipboard.png";
|
||||
div class="stack" style="padding-top: 0.5rem;" {
|
||||
label class="label-small font-near-black" { "Config" }
|
||||
label class="label-small font-near-black" { (state) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_sbot_capsule() -> Markup {
|
||||
let (state, stack_class, img_class) = match retrieve_sbot_state() {
|
||||
Some(state) if state.as_str() == "active" => {
|
||||
("active", "stack capsule border-success", "icon icon-medium")
|
||||
}
|
||||
Some(state) if state.as_str() == "inactive" => (
|
||||
"inactive",
|
||||
"stack capsule border-warning",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
Some(state) if state.as_str() == "failed" => (
|
||||
"failed",
|
||||
"stack capsule border-danger",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
_ => (
|
||||
"error",
|
||||
"stack capsule border-danger",
|
||||
"icon icon-inactive icon-medium",
|
||||
),
|
||||
};
|
||||
|
||||
html! {
|
||||
(PreEscaped("<!-- SBOT STATUS STACK -->"))
|
||||
div class=(stack_class) {
|
||||
img id="sbotIcon" class=(img_class) alt="Sbot" title="Sbot status" src="icons/hermies.svg";
|
||||
div class="stack" style="padding-top: 0.5rem;" {
|
||||
label class="label-small font-near-black" { "Sbot" }
|
||||
label class="label-small font-near-black" { (state.to_uppercase()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_cpu_usage_meter(cpu_usage_percent: Option<CpuStatPercentages>) -> Markup {
|
||||
html! {
|
||||
@if let Some(cpu_usage) = cpu_usage_percent {
|
||||
@let cpu_usage_total = (cpu_usage.nice + cpu_usage.system + cpu_usage.user).round();
|
||||
div class="flex-grid" {
|
||||
span class="card-text" { "CPU" }
|
||||
span class="label-small push-right" { (cpu_usage_total) "%" }
|
||||
}
|
||||
meter value=(cpu_usage_total) min="0" max="100" title="CPU usage" {
|
||||
div class="meter-gauge" {
|
||||
span style={ "width: " (cpu_usage_total) "%;" } {
|
||||
"CPU Usage"
|
||||
}
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
p class="card-text" { "CPU usage data unavailable" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_mem_usage_meter(mem_stats: Option<MemStat>) -> Markup {
|
||||
html! {
|
||||
@if let Some(mem) = mem_stats {
|
||||
// convert kilobyte values to megabyte values
|
||||
@let mem_free_mb = mem.free / 1024;
|
||||
@let mem_total_mb = mem.total / 1024;
|
||||
@let mem_used_mb = mem.used / 1024;
|
||||
// calculate memory usage as a percentage
|
||||
@let mem_used_percent = mem_used_mb * 100 / mem_total_mb;
|
||||
// render disk free value as megabytes or gigabytes based on size
|
||||
@let mem_free_value = if mem_free_mb > 1024 {
|
||||
format!("{} GB", (mem_free_mb / 1024))
|
||||
} else {
|
||||
format!("{} MB", mem_free_mb)
|
||||
};
|
||||
|
||||
div class="flex-grid" {
|
||||
span class="card-text" { "Memory" }
|
||||
span class="label-small push-right" { (mem_used_percent) "% (" (mem_free_value) " free)" }
|
||||
}
|
||||
meter value=(mem_used_mb) min="0" max=(mem_total_mb) title="Memory usage" {
|
||||
div class="meter-gauge" {
|
||||
span style={ "width: " (mem_used_percent) "%;" } { "Memory Usage" }
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
p class="card-text" { "Memory usage data unavailable" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_disk_usage_meter() -> Markup {
|
||||
let disk_usage_stats = match stats::disk_usage() {
|
||||
Ok(disks) => disks,
|
||||
Err(_) => Vec::new(),
|
||||
};
|
||||
|
||||
// select only the partition we're interested in: /dev/mmcblk0p2 ("/")
|
||||
let disk_usage = disk_usage_stats.iter().find(|disk| disk.mountpoint == "/");
|
||||
|
||||
html! {
|
||||
@if let Some(disk) = disk_usage {
|
||||
// calculate free disk space in megabytes
|
||||
@let disk_free_mb = disk.one_k_blocks_free / 1024;
|
||||
// calculate free disk space in gigabytes
|
||||
@let disk_free_gb = disk_free_mb / 1024;
|
||||
// render disk free value as megabytes or gigabytes based on size
|
||||
@let disk_free_value = if disk_free_mb > 1024 {
|
||||
format!("{} GB", disk_free_gb)
|
||||
} else {
|
||||
format!("{} MB", disk_free_mb)
|
||||
};
|
||||
|
||||
div class="flex-grid" {
|
||||
span class="card-text" { "Disk" }
|
||||
span class="label-small push-right" { (disk.used_percentage) "% (" (disk_free_value) " free)" }
|
||||
}
|
||||
meter value=(disk.used_percentage) min="0" max="100" title="Disk usage" {
|
||||
div class="meter-gauge" {
|
||||
span style={ "width: " (disk.used_percentage) "%;" } {
|
||||
"Disk Usage"
|
||||
}
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
p class="card-text" { "Disk usage data unavailable" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Display system uptime in hours and minutes.
|
||||
fn render_uptime_capsule(uptime: Option<u64>) -> Markup {
|
||||
html! {
|
||||
@if let Some(uptime_secs) = uptime {
|
||||
@let uptime_mins = uptime_secs / 60;
|
||||
@if uptime_mins < 60 {
|
||||
// display system uptime in minutes
|
||||
p class="capsule center-text" {
|
||||
"Uptime: " (uptime_mins) " minutes"
|
||||
}
|
||||
} @else {
|
||||
// display system uptime in hours and minutes
|
||||
@let hours = uptime_mins / 60;
|
||||
@let mins = uptime_mins % 60;
|
||||
p class="capsule center-text" {
|
||||
"Uptime: " (hours) " hours, " (mins) " minutes"
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
p class="card-text" { "Uptime data unavailable" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Device status template builder.
|
||||
pub fn build_template() -> PreEscaped<String> {
|
||||
let (uptime, oled_state) = retrieve_device_status_data();
|
||||
let (cpu_usage, mem_usage) = retrieve_device_usage_data();
|
||||
|
||||
let device_status_template = html! {
|
||||
(PreEscaped("<!-- DEVICE STATUS CARD -->"))
|
||||
div class="card center" {
|
||||
div class="card-container" {
|
||||
// display status capsules for network, oled and diagnostics
|
||||
div class="three-grid" {
|
||||
(render_network_capsule())
|
||||
(render_oled_capsule(oled_state))
|
||||
(render_diagnostics_capsule())
|
||||
}
|
||||
// display status capsules for dyndns, config and sbot
|
||||
div class="three-grid" style="padding-top: 1rem; padding-bottom: 1rem;" {
|
||||
(render_dyndns_capsule())
|
||||
(render_config_capsule())
|
||||
(render_sbot_capsule())
|
||||
}
|
||||
(render_cpu_usage_meter(cpu_usage))
|
||||
(render_mem_usage_meter(mem_usage))
|
||||
(render_disk_usage_meter())
|
||||
(render_uptime_capsule(uptime))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let body = templates::nav::build_template(device_status_template, "Device Status", Some("/"));
|
||||
|
||||
let theme = theme::get_theme();
|
||||
|
||||
templates::base::build_template(body, theme)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
{%- extends "nav" -%}
|
||||
{%- block card -%}
|
||||
{# ASSIGN VARIABLES #}
|
||||
{# ---------------- #}
|
||||
{%- if mem_stats -%}
|
||||
{% set mem_usage_percent = mem_stats.used / mem_stats.total * 100 | round -%}
|
||||
{% set mem_used = mem_stats.used / 1024 | round -%}
|
||||
{% set mem_free = mem_stats.free / 1024 | round -%}
|
||||
{% set mem_total = mem_stats.total / 1024 | round -%}
|
||||
{% endif -%}
|
||||
{% if cpu_stat_percent -%}
|
||||
{% set cpu_usage_percent = cpu_stat_percent.nice + cpu_stat_percent.system + cpu_stat_percent.user | round -%}
|
||||
{%- endif -%}
|
||||
{%- if disk_stats -%}
|
||||
{%- for disk in disk_stats -%}
|
||||
{%- set_global disk_usage_percent = disk.used_percentage -%}
|
||||
{# Calculate free disk space in megabytes #}
|
||||
{%- set_global disk_free = disk.one_k_blocks_free / 1024 | round -%}
|
||||
{%- endfor -%}
|
||||
{%- endif -%}
|
||||
<!-- DEVICE STATUS VIEW -->
|
||||
<div class="card center">
|
||||
<div class="card-container">
|
||||
{# Display microservice status for network, oled & stats #}
|
||||
<div class="three-grid" style="padding-top: 1rem;">
|
||||
<!-- PEACH-NETWORK STATUS STACK -->
|
||||
<div class="stack capsule{% if network_ping == "ONLINE" %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if network_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Network" title="Network microservice status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Networking</label>
|
||||
<label class="label-small font-near-black">{{ network_ping }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- PEACH-OLED STATUS STACK -->
|
||||
<div class="stack capsule{% if oled_ping == "ONLINE" %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="oledIcon" class="icon{% if oled_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Display" title="OLED display microservice status" src="icons/lcd.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Display</label>
|
||||
<label class="label-small font-near-black">{{ oled_ping }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- PEACH-STATS STATUS STACK -->
|
||||
<div class="stack capsule{% if stats_ping == "ONLINE" %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="statsIcon" class="icon{% if stats_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Stats" title="System statistics microservice status" src="icons/chart.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Statistics</label>
|
||||
<label class="label-small font-near-black">{{ stats_ping }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three-grid" style="padding-bottom: 1rem; margin-top: 0px;">
|
||||
<!-- DYNDNS STATUS STACK -->
|
||||
<div class="stack capsule{% if dyndns_is_online %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if dyndns_is_online != true %} icon-inactive {% endif %} icon-medium" alt="Dyndns" title="Dyndns status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Dyn DNS</label>
|
||||
<label class="label-small font-near-black">{% if dyndns_is_online %} ONLINE {% else %} OFFLINE {% endif %} </label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- CONFIG STATUS STACK -->
|
||||
<div class="stack capsule{% if config_is_valid %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if config_is_valid != true %} icon-inactive {% endif %} icon-medium" alt="Config" title="Config status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Config</label>
|
||||
<label class="label-small font-near-black">{% if config_is_valid %} LOADED {% else %} INVALID {% endif %} </label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- SBOT STATUS STACK -->
|
||||
<div class="stack capsule{% if sbot_is_online %} border-success{% else %} border-warning{% endif %}">
|
||||
<img id="networkIcon" class="icon{% if sbot_is_online != true %} icon-inactive {% endif %} icon-medium" alt="Sbot" title="Sbot status" src="icons/wifi.svg">
|
||||
<div class="stack" style="padding-top: 0.5rem;">
|
||||
<label class="label-small font-near-black">Sbot</label>
|
||||
<label class="label-small font-near-black">{% if sbot_is_online %} ONLINE {% else %} OFFLINE {% endif %} </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# Display CPU usage meter #}
|
||||
{%- if cpu_stat_percent -%}
|
||||
<div class="flex-grid">
|
||||
<span class="card-text">CPU</span>
|
||||
<span class="label-small push-right">{{ cpu_usage_percent }}%</span>
|
||||
</div>
|
||||
<meter value="{{ cpu_usage_percent }}" min="0" max="100" title="CPU usage">
|
||||
<div class="meter-gauge">
|
||||
<span style="width: {{ cpu_usage_percent }}%;">CPU Usage</span>
|
||||
</div>
|
||||
</meter>
|
||||
{%- else -%}
|
||||
<p class="card-text">CPU usage data unavailable</p>
|
||||
{% endif -%}
|
||||
{# Display memory usage meter #}
|
||||
{%- if mem_stats %}
|
||||
<div class="flex-grid">
|
||||
<span class="card-text">Memory</span>
|
||||
<span class="label-small push-right">{{ mem_usage_percent }}% ({{ mem_free }} MB free)</span>
|
||||
</div>
|
||||
<meter value="{{ mem_used }}" min="0" max="{{ mem_total }}" title="Memory usage">
|
||||
<div class="meter-gauge">
|
||||
<span style="width: {{ mem_usage_percent }}%;">Memory Usage</span>
|
||||
</div>
|
||||
</meter>
|
||||
{%- else -%}
|
||||
<p class="card-text">Memory usage data unavailable</p>
|
||||
{% endif -%}
|
||||
{# Display disk usage meter #}
|
||||
{%- if disk_stats %}
|
||||
<div class="flex-grid">
|
||||
<span class="card-text">Disk</span>
|
||||
<span class="label-small push-right">{{ disk_usage_percent }}% ({% if disk_free > 1024 %}{{ disk_free / 1024 | round }} GB{% else %}{{ disk_free }} MB{% endif %} free)</span>
|
||||
</div>
|
||||
<meter value="{{ disk_usage_percent }}" min="0" max="100" title="Disk usage">
|
||||
<div class="meter-gauge">
|
||||
<span style="width: {{ disk_usage_percent }}%;">Disk Usage</span>
|
||||
</div>
|
||||
</meter>
|
||||
{%- else -%}
|
||||
<p class="card-text">Disk usage data unavailable</p>
|
||||
{%- endif %}
|
||||
{# Display system uptime in minutes #}
|
||||
{%- if uptime and uptime < 60 %}
|
||||
<p class="capsule center-text">Uptime: {{ uptime }} minutes</p>
|
||||
{# Display system uptime in hours & minutes #}
|
||||
{%- elif uptime and uptime > 60 -%}
|
||||
<p class="capsule center-text">Uptime: {{ uptime / 60 | round(method="floor") }} hours, {{ uptime % 60 }} minutes</p>
|
||||
{%- else -%}
|
||||
<p class="card-text">Uptime data unavailable</p>
|
||||
{%- endif %}
|
||||
<!-- FLASH MESSAGE -->
|
||||
<!-- check for flash message and display accordingly -->
|
||||
{%- if flash_msg and flash_name == "success" -%}
|
||||
<!-- display success message -->
|
||||
<div class="capsule center-text flash-message font-success">{{ flash_msg }}.</div>
|
||||
{%- elif flash_msg and flash_name == "error" -%}
|
||||
<!-- display error message -->
|
||||
<div class="capsule center-text flash-message font-failure">{{ flash_msg }}.</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endblock card %}
|
||||
|
||||
// CONTEXT
|
||||
|
||||
use log::info;
|
||||
use rocket::{
|
||||
get,
|
||||
|
@ -236,3 +764,4 @@ pub fn power_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template
|
|||
};
|
||||
Template::render("power", &context)
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
//pub mod device;
|
||||
pub mod device;
|
||||
pub mod network;
|
||||
pub mod scuttlebutt;
|
||||
|
|
Loading…
Reference in New Issue