From e44b8542b00f4c67d0cbfbc20b0df95581b26098 Mon Sep 17 00:00:00 2001 From: Samuel ORTION Date: Mon, 15 Aug 2022 11:42:28 +0200 Subject: [PATCH] Add service monitoring and burger menu --- www/assets/app.js | 1 + www/assets/styles/app.css | 110 +++++++++++++----- www/assets/styles/menu.css | 129 ++++++++++++++++++++++ www/src/Controller/AboutController.php | 21 ---- www/src/Controller/AuthController.php | 31 ++++++ www/src/Controller/HomeController.php | 63 ++++++++++- www/src/Controller/ServicesController.php | 73 ++++++++++++ www/src/Controller/SpectroController.php | 1 - www/src/Controller/TodayController.php | 14 +-- www/templates/base.html.twig | 24 ++-- www/templates/chart.html.twig | 7 ++ www/templates/index.html.twig | 2 + www/templates/menu.html.twig | 89 ++++++++------- www/templates/services/status.html.twig | 19 ++++ www/templates/stats.html.twig | 42 +++++++ www/templates/title.html.twig | 2 + www/templates/today/index.html.twig | 4 +- 17 files changed, 515 insertions(+), 117 deletions(-) create mode 100644 www/assets/styles/menu.css delete mode 100644 www/src/Controller/AboutController.php create mode 100644 www/src/Controller/AuthController.php create mode 100644 www/src/Controller/ServicesController.php create mode 100644 www/templates/chart.html.twig create mode 100644 www/templates/services/status.html.twig create mode 100644 www/templates/stats.html.twig create mode 100644 www/templates/title.html.twig diff --git a/www/assets/app.js b/www/assets/app.js index 1d730eb..7ccbda1 100644 --- a/www/assets/app.js +++ b/www/assets/app.js @@ -7,6 +7,7 @@ // any CSS you import will output into a single css file (app.css in this case) import './styles/app.css'; +import './styles/menu.css'; // start the Stimulus application import './bootstrap'; diff --git a/www/assets/styles/app.css b/www/assets/styles/app.css index ae862dc..f0d573e 100644 --- a/www/assets/styles/app.css +++ b/www/assets/styles/app.css @@ -2,15 +2,39 @@ box-sizing: border-box; } +.container { + display: flex; + flex-direction: column; + position: relative; +} + +.column { + flex-direction: column; +} + +.row { + flex-direction: row; +} + +.behind { + position: relative; + z-index: -1; +} + +.above { + position: relative; + z-index: 1; +} + body { background-color: lightgray; margin: 0; padding: 0; + z-index: -10; } header { padding: 1em; - text-align: center; display: flex; flex-direction: row; /** Align text and center of image */ @@ -18,7 +42,7 @@ header { align-items: baseline; } -header img#logo { +header img.logo { width: 100px; height: 100px; } @@ -26,6 +50,7 @@ header img#logo { main { min-height: 100vh; padding: 5em; + z-index: 0; } footer { @@ -44,33 +69,7 @@ footer a:hover { font-style: italic; } -nav ul { - list-style-type: none; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - background-color: #333; - margin: auto; - min-width: 100vw; -} - -nav ul li a, -.dropdown-button { - color: white; - text-decoration: none; - display: block; - padding: 1em 0.5em; -} - -nav ul li a.active, -nav ul li a:hover { - background-color: #999; - color: #101010 -} - -.dropdown-button:hover { +/* .dropdown-button:hover { background-color: #900; color: white } @@ -78,6 +77,7 @@ nav ul li a:hover { .dropdown:hover .dropdown-content { display: block; } +*/ .dropdown-content { display: none; @@ -95,4 +95,56 @@ canvas { .scientific-name { font-style: italic; +} + +.dataviz img { + max-width: 100%; + width: 100%; +} + +#statuses { + display: flex; + flex-direction: column; +} + +#statuses li { + list-style: none; + display: flex; + flex-direction: row; + justify-content: space-between; + +} + +.status .bullet { + border-radius: 50%; + background-color: #999; + width: 1em; + height: 1em; + display: inline-block; + position: relative; + top: 0.15em; + margin-right: 0.5em; + margin-left: 0.5em; +} + +.status.active .bullet { + background-color: #090; +} + +.status.inactive .bullet { + background-color: #900; +} + + +@media screen and (max-width: 700px) { + main { + padding: 1em; + } +} + +.overlay { + z-index: 10; + opacity: 100%; + background-color: rgba(255, 255, 255, 1); + position: relative; } \ No newline at end of file diff --git a/www/assets/styles/menu.css b/www/assets/styles/menu.css new file mode 100644 index 0000000..78fcba2 --- /dev/null +++ b/www/assets/styles/menu.css @@ -0,0 +1,129 @@ +nav { + position: fixed; + top: 0; + left: 0; + --nav-width: 20em; +} + +.toggler{ + z-index:2; + height: 50px; + width: 50px; + position: absolute; + cursor: pointer; + opacity: 0; +} + +.hamburger{ + position: absolute; + top: 0; + left: 0; + height: 40px; + width: 40px; + padding: 0.6rem; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; +} + +.hamburger > div{ + position: relative; + top: 0; + left: 0; + background: black; + height: 2px; + width: 75%; + transition: all 0.4s ease; + color: #000; + +} + +.hamburger > div::before, +.hamburger > div::after{ + content: ''; + position: absolute; + top: -7px; + background: black; + width: 100%; + height: 2px; + transition: all 0.4s ease; +} + +.hamburger > div::after{ + top: 7px; +} + +.toggler:checked + .hamburger > div{ + background: rgba(0,0,0,0); +} + +.toggler:checked + .hamburger > div::before{ + top: 0; + transform: rotate(45deg); + background: black; +} + +.toggler:checked + .hamburger > div::after{ + top: 0; + transform: rotate(135deg); + background: black; +} + +.menu{ + height: 100vh; + width: 0; + visibility: hidden; +} + +.toggler:checked ~ .menu{ + width: fit-content; + height: fit-content; + background-color: rgba(255, 255, 255, 1)!important; +} + +.menu > ul{ + display: flex; + flex-direction: column; + position: fixed; + width: 0; + height: 100vmax; + padding-left: 1em; + padding-right: 1em; + margin-top: 2em; + visibility: hidden; + background-color: white; + z-index: 1; +} + +.menu > ul > li{ + list-style: none; + padding: 0.5rem; +} + +.menu > ul > li > a{ + color: black; + text-decoration: none; + font-size: 2rem; +} + +.toggler:checked ~ .fill { + background: white; + position: absolute; + top: 0; + left: 0; + height: 100vh; + width: var(--nav-width); +} + +.toggler:checked ~ .menu > ul{ + width: 20em; + transition: fit-content .5s ease; + opacity: 1; + transition: opacity .5s, visibility .5s, height .5s, width .5s; + visibility: visible; +} + +.toggler:checked ~ .menu > ul > li > a:hover{ + color: orange; +} \ No newline at end of file diff --git a/www/src/Controller/AboutController.php b/www/src/Controller/AboutController.php deleted file mode 100644 index 3bb9104..0000000 --- a/www/src/Controller/AboutController.php +++ /dev/null @@ -1,21 +0,0 @@ -render('about/index.html.twig', [ - - ]); - } -} \ No newline at end of file diff --git a/www/src/Controller/AuthController.php b/www/src/Controller/AuthController.php new file mode 100644 index 0000000..bdc8d4e --- /dev/null +++ b/www/src/Controller/AuthController.php @@ -0,0 +1,31 @@ +redirectToRoute("login"); + } + + /** + * @Route("/auth/login", name="login") + */ + public function login() + { + return $this->render('auth/login.html.twig', [ + + ]); + } +} \ No newline at end of file diff --git a/www/src/Controller/HomeController.php b/www/src/Controller/HomeController.php index ef0fbf1..150ad72 100644 --- a/www/src/Controller/HomeController.php +++ b/www/src/Controller/HomeController.php @@ -1,21 +1,78 @@ connection = $connection; return $this->render('index.html.twig', [ - + "stats" => $this->get_stats(), + "charts" => $this->last_chart_generated(), ]); } + + /** + * @Route("/about", name="about") + */ + public function about() + { + return $this->render('about/index.html.twig', [ + + ]); + } + + private function get_stats() + { + $stats = array(); + $stats["most-recorded-species"] = $this->get_most_recorded_species(); + $stats["last-detected-species"] = $this->get_last_recorded_species(); + return $stats; + } + + private function get_most_recorded_species() + { + $sql = "SELECT `scientific_name`, `common_name`, COUNT(*) AS contact_count + FROM `taxon` + INNER JOIN `observation` + ON `taxon`.`taxon_id` = `observation`.`taxon_id` + ORDER BY `contact_count` DESC LIMIT 1"; + $stmt = $this->connection->prepare($sql); + $result = $stmt->executeQuery(); + return $result->fetchAllAssociative()[0]; + } + + private function get_last_recorded_species() + { + $sql = "SELECT `scientific_name`, `common_name`, `date`, `audio_file`, `confidence` + FROM `observation` + INNER JOIN `taxon` + ON `observation`.`taxon_id` = `taxon`.`taxon_id` + ORDER BY `date` DESC LIMIT 1"; + $stmt = $this->connection->prepare($sql); + $result = $stmt->executeQuery(); + return $result->fetchAllAssociative()[0]; + } + + private function last_chart_generated() { + + $files = glob($this->getParameter('kernel.project_dir') . '/../var/charts/*.png'); + usort($files, function($a, $b) { + return filemtime($b) - filemtime($a); + }); + $last_chart = basename(array_pop($files)); + return $last_chart; + } + } \ No newline at end of file diff --git a/www/src/Controller/ServicesController.php b/www/src/Controller/ServicesController.php new file mode 100644 index 0000000..b404388 --- /dev/null +++ b/www/src/Controller/ServicesController.php @@ -0,0 +1,73 @@ + $service, + "status" => $this->systemd_service_status($service) + ); + }, $this->services_available); + return $this->render('services/status.html.twig', [ + 'status' => $status + ]); + } + + /** + * @Route("/service/manage/{action}", name="service_manager") + */ + public function service_manage($action, $service) + { + $error = ""; + if (in_array($action, $this->allowed_actions)) { + if (in_array($service, $this->services_available)) { + if(($output = $this->manage_systemd_service($action, $service)) != "true") { + $error = "Error while managing service"; + dump($output); + } + } else { + $error .= "Service not found"; + } + } else { + $error .= "Action not allowed"; + } + if ($error != "") { + return new Response($error, Response::HTTP_BAD_REQUEST); + } else { + return new Response("OK", Response::HTTP_OK); + } + } + + private function manage_systemd_service($action, $service) + { + $command = "./daemon/birdnet_manager.sh ".$action; + $workdir = $this->getParameter("kernel.project_dir") . "/../"; + $command = "cd ".$workdir." && ".$command; + echo $command; + $output = shell_exec($command); + return $output; + } + + private function systemd_service_status($service) + { + $command = "systemctl is-active ".$service; + $result = shell_exec($command); + return $result; + } +} \ No newline at end of file diff --git a/www/src/Controller/SpectroController.php b/www/src/Controller/SpectroController.php index 771b453..d407893 100644 --- a/www/src/Controller/SpectroController.php +++ b/www/src/Controller/SpectroController.php @@ -1,5 +1,4 @@ connection = $connection; - $date = date('Y-m-d'); - return $this->render('today/index.html.twig', [ - "date" => $date, - "species" => $this->recorded_species_by_date($date), - ]); + return $this->redirectToRoute("today_species"); } /** @@ -35,7 +29,7 @@ class TodayController extends AbstractController $date = date('Y-m-d'); return $this->render('today/index.html.twig', [ "date" => $date, - "species" => $this->recorded_species_by_date($date) + "results" => $this->recorded_species_by_date($date), ]); } @@ -92,7 +86,7 @@ class TodayController extends AbstractController FROM observation INNER JOIN taxon ON observation.taxon_id = taxon.taxon_id - WHERE strftime('%Y-%m-%d', `observation`.`date`) =:date + WHERE strftime('%Y-%m-%d', `observation`.`date`) = :date GROUP BY observation.taxon_id"; $stmt = $this->connection->prepare($sql); $stmt->bindValue(':date', $date); @@ -107,7 +101,7 @@ class TodayController extends AbstractController $stmt = $this->connection->prepare($sql); $stmt->bindValue(':id', $id); $result = $stmt->executeQuery(); - $taxon = $result->fetchAssociative(); + $taxon = $result->fetchAllAssociative()[0]; if (!$taxon) { return []; } diff --git a/www/templates/base.html.twig b/www/templates/base.html.twig index d72934e..2335d34 100644 --- a/www/templates/base.html.twig +++ b/www/templates/base.html.twig @@ -18,18 +18,18 @@ {% block body %} -
- -

BirdNET-stream

-
- {% include "menu.html.twig" %} - -
- {% block content %} -

Welcome to BirdNET-stream !

- {% endblock %} -
- {% include "footer.html.twig" %} +
+ {% include "menu.html.twig" %} +
+
+
+
+ {% block content %} +

Welcome to BirdNET-stream !

+ {% endblock %} +
+ {% include "footer.html.twig" %} +
{% endblock %} diff --git a/www/templates/chart.html.twig b/www/templates/chart.html.twig new file mode 100644 index 0000000..12f5af2 --- /dev/null +++ b/www/templates/chart.html.twig @@ -0,0 +1,7 @@ +
+ {% if charts is defined and charts | length > 0 %} + {{ + {% else %} +

{{ "No charts available" | trans }}

+ {% endif %} +
\ No newline at end of file diff --git a/www/templates/index.html.twig b/www/templates/index.html.twig index b43e3f6..c81b557 100644 --- a/www/templates/index.html.twig +++ b/www/templates/index.html.twig @@ -2,4 +2,6 @@ {% block content %}

Welcome to BirdNET-stream !

+ {% include "stats.html.twig" %} + {% include "chart.html.twig" %} {% endblock %} \ No newline at end of file diff --git a/www/templates/menu.html.twig b/www/templates/menu.html.twig index bc3d61b..bdf160c 100644 --- a/www/templates/menu.html.twig +++ b/www/templates/menu.html.twig @@ -1,40 +1,49 @@ - \ No newline at end of file + diff --git a/www/templates/services/status.html.twig b/www/templates/services/status.html.twig new file mode 100644 index 0000000..46139af --- /dev/null +++ b/www/templates/services/status.html.twig @@ -0,0 +1,19 @@ +{% extends "base.html.twig" %} + +{% block content %} +

+ {{ "Services status" | trans }} +

+ {% if status is defined and status | length > 0 %} + + {% else %} +

{{ "No status available" | trans }}

+ {% endif %} +{% endblock %} diff --git a/www/templates/stats.html.twig b/www/templates/stats.html.twig new file mode 100644 index 0000000..bc1625e --- /dev/null +++ b/www/templates/stats.html.twig @@ -0,0 +1,42 @@ +
+

Quick Stats

+ +
\ No newline at end of file diff --git a/www/templates/title.html.twig b/www/templates/title.html.twig new file mode 100644 index 0000000..0ce4402 --- /dev/null +++ b/www/templates/title.html.twig @@ -0,0 +1,2 @@ + +

BirdNET-stream

diff --git a/www/templates/today/index.html.twig b/www/templates/today/index.html.twig index d4c760c..7da98f6 100644 --- a/www/templates/today/index.html.twig +++ b/www/templates/today/index.html.twig @@ -11,7 +11,7 @@ {% endif %} {# Display a list of records if any, else, print message #} - {% if results[0] is defined and results[0] | length > 0 %} + {% if results is defined and results | length > 0 %} + {% else %} +

{{ "No species detected this day" | trans }}

{% endif %} {% endblock %}