Browse Source

Server metrics styling. Container action indicator

lllllllillllllillll 1 year ago
parent
commit
e294ca7089
7 changed files with 86 additions and 33 deletions
  1. 1 0
      README.md
  2. 14 9
      components/containerCard.js
  3. 35 4
      controllers/dashboard.js
  4. 4 0
      public/css/meters.css
  5. 2 1
      router/index.js
  6. 5 6
      server.js
  7. 25 13
      views/dashboard.html

+ 1 - 0
README.md

@@ -42,6 +42,7 @@ Alpha v0.30 ( :fire: Experimental :fire: )
 * [x] Templates.json maintains compatability with Portainer, allowing you to use the template without needing to use DweebUI.
 * [x] Automatically persists data in docker volumes if bind mount isn't used.
 * [ ] Preset variables (planned).
+* [ ] Themes (planned).
 
 
 ## Setup

+ 14 - 9
components/containerCard.js

@@ -21,6 +21,9 @@ export const containerCard = (data) => {
       state_indicator = 'orange';
   }
 
+  let noChart = 'hx-swap="none"';
+  if (state == 'running') { noChart = ''; }
+
   let ports_data = [];
   if (ports) {
     ports_data = ports;
@@ -54,16 +57,16 @@ export const containerCard = (data) => {
             <div class="ms-auto lh-1">
               <div class="card-actions btn-actions">
                 <div class="card-actions btn-actions">
-                  <button class="btn-action" title="Start" data-hx-post="/start" data-hx-trigger="click" data-hx-swap="none" name="${name}" id="${state}" ${disable}><!-- player-play -->
+                  <button class="btn-action" title="Start" data-hx-post="/start" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- player-play -->
                     <svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-player-play" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 4v16l13 -8z"></path></svg>
                   </button>
-                  <button class="btn-action" title="Stop" data-hx-post="/stop" data-hx-trigger="click" data-hx-swap="none" name="${name}" id="${state}" ${disable}><!-- player-stop -->
+                  <button class="btn-action" title="Stop" data-hx-post="/stop" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- player-stop -->
                     <svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-player-stop" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 5m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z"></path></svg>
                   </button>
-                  <button class="btn-action" title="Pause" data-hx-post="/pause" data-hx-trigger="click" data-hx-swap="none" name="${name}" id="${state}" ${disable}><!-- player-pause -->
+                  <button class="btn-action" title="Pause" data-hx-post="/pause" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- player-pause -->
                     <svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-player-pause" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M6 5m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z"></path><path d="M14 5m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z"></path></svg>
                   </button>
-                  <button class="btn-action" title="Restart" data-hx-post="/restart" data-hx-trigger="click" data-hx-swap="none" name="${name}" id="${state}" ${disable}><!-- reload -->
+                  <button class="btn-action" title="Restart" data-hx-post="/restart" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- reload -->
                     <svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-reload" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M19.933 13.041a8 8 0 1 1 -9.925 -8.788c3.899 -1 7.935 1.007 9.425 4.747"></path><path d="M20 4v5h-5"></path></svg>                          
                   </button>
                   <div class="dropdown">
@@ -99,10 +102,12 @@ export const containerCard = (data) => {
               </a>
             </div>
             <div class="ms-auto">
-              <span class="text-${state_indicator} align-items-center lh-1">
-                <svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-point-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 7a5 5 0 1 1 -4.995 5.217l-.005 -.217l.005 -.217a5 5 0 0 1 4.995 -4.783z" stroke-width="0" fill="currentColor"></path></svg>
-                ${state}
-              </span>
+              <label id="${name}state">
+                <span class="text-${state_indicator} align-items-center lh-1">
+                    <svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-point-filled" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 7a5 5 0 1 1 -4.995 5.217l-.005 -.217l.005 -.217a5 5 0 0 1 4.995 -4.783z" stroke-width="0" fill="currentColor"></path></svg>
+                    ${state}
+                </span>
+              </label>
             </div>
           </div>
           
@@ -111,7 +116,7 @@ export const containerCard = (data) => {
           </script>
 
           <div class="chart-sm">
-            <div id="${chartName}_chart" data-hx-trigger="load, every 2s" data-hx-get="/chart" name="${chartName}">
+            <div id="${chartName}_chart" data-hx-trigger="load, every 2s" data-hx-get="/chart" name="${chartName}" ${noChart}>
               <script>
                 ${chartName}chart.render();
               </script>

+ 35 - 4
controllers/dashboard.js

@@ -223,7 +223,7 @@ export const Start = (req, res) => {
         var containerName = docker.getContainer(name);
         containerName.unpause();
     }
-    res.send("ok");
+    res.send("starting");
 }
 
 export const Stop = (req, res) => {   
@@ -233,7 +233,7 @@ export const Stop = (req, res) => {
         var containerName = docker.getContainer(name);
         containerName.stop();
     }
-    res.send("ok");
+    res.send("stopping");
 }
 
 export const Pause = (req, res) => {
@@ -246,12 +246,43 @@ export const Pause = (req, res) => {
         var containerName = docker.getContainer(name);
         containerName.unpause();
     }
-    res.send("ok");
+    res.send("pausing");
 }
 
 export const Restart = (req, res) => {   
     let name = req.header('hx-trigger-name');
     var containerName = docker.getContainer(name);
     containerName.restart();
-    res.send("ok");
+    res.send("restarting");
+}
+
+export const Installs = async (req, res) => {
+
+    let name = req.header('hx-trigger-name');
+    let all_containers = '';
+
+    await docker.listContainers({ all: true }).then(containers => {
+        containers.forEach(container => {
+            if (container.Names[0].slice(1) == name) {
+                return;
+            }
+        });
+
+        let install_info = {
+            name: name,
+            service: 'Service Name',
+            id: '',
+            state: '',
+            image: '',
+            external_port: 0,
+            internal_port: 0,
+            ports: '',
+            link: 'localhost',
+        }
+        let card = containerCard(install_info);
+        res.send(card);
+
+    });
+
+    
 }

+ 4 - 0
public/css/meters.css

@@ -83,6 +83,10 @@
   .blue > span {
     background-image: linear-gradient(#2478f5, #22017e);
   }
+
+  .purple > span {
+    background-image: linear-gradient(#bd14d3, #670370);
+  }
   
   .nostripes > span > span,
   .nostripes > span::after {

+ 2 - 1
router/index.js

@@ -4,7 +4,7 @@ export const router = express.Router();
 // Controllers
 import { Login, submitLogin, Logout } from "../controllers/login.js";
 import { Register, submitRegister } from "../controllers/register.js";
-import { Dashboard, Start, Stop, Pause, Restart, Logs, Modal, Stats, Hide, Reset, Chart, Containers } from "../controllers/dashboard.js";
+import { Dashboard, Start, Stop, Pause, Restart, Logs, Modal, Stats, Hide, Reset, Chart, Containers, Installs } from "../controllers/dashboard.js";
 import { Apps, appSearch } from "../controllers/apps.js";
 import { Users } from "../controllers/users.js";
 import { Images, removeImage } from "../controllers/images.js";
@@ -39,6 +39,7 @@ router.get("/stats", auth, Stats);
 router.post("/hide", auth, Hide);
 router.post("/reset", auth, Reset);
 router.get("/chart", auth, Chart);
+router.get("/installs", auth, Installs);
 
 router.get("/images", auth, Images);
 router.post("/removeImage", auth, removeImage);

+ 5 - 6
server.js

@@ -14,7 +14,7 @@ const app = express();
 const MemoryStore = memorystore(session);
 const port = process.env.PORT || 8000;
 let [ cpu, ram, tx, rx, disk ] = [0, 0, 0, 0, 0];
-let [ event, sse, eventType ] = [false, false, ''];
+let [ event, eventType ] = [false, 'docker'];
 
 // Session middleware
 const sessionMiddleware = session({
@@ -87,15 +87,14 @@ router.get('/sse_event', (req, res) => {
                 all_containers += `${container.Names}: ${container.State}\n`;
             });
         });
-        if ((all_containers != sent_list) || event) {
+        if ((all_containers != sent_list) || (event == true)) {
             sent_list = all_containers;
-            res.write(`event: docker\n`);
+            event = false;
+            res.write(`event: ${eventType}\n`);
             res.write(`data: there was an event!\n\n`);
         }
     }, 1000);
     req.on('close', () => {
         clearInterval(eventCheck);
     });
-});
-
-
+});

+ 25 - 13
views/dashboard.html

@@ -30,7 +30,7 @@
 
       <div class="page-body">
         <div class="container-xl">
-          <div class="row row-deck row-cards">
+          <div class="row row-deck row-cards" hx-ext="sse" sse-connect="/sse_event">
             
             <div class="col-12">
               <div class="row row-cards">
@@ -40,7 +40,7 @@
                     <div class="card-body">
                       <div class="row align-items-center">
                         <div class="col-auto">
-                          <span class="bg-primary text-white avatar">
+                          <span class="bg-green text-white avatar">
                             <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-cpu" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 5m0 1a1 1 0 0 1 1 -1h12a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-12a1 1 0 0 1 -1 -1z"></path><path d="M9 9h6v6h-6z"></path><path d="M3 10h2"></path><path d="M3 14h2"></path><path d="M10 3v2"></path><path d="M14 3v2"></path><path d="M21 10h-2"></path><path d="M21 14h-2"></path><path d="M14 21v-2"></path><path d="M10 21v-2"></path></svg>
                           </span>
                         </div>
@@ -65,17 +65,17 @@
                     <div class="card-body">
                       <div class="row align-items-center">
                         <div class="col-auto">
-                          <span class="bg-green text-white avatar">
+                          <span class="bg-blue text-white avatar">
                             <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-container" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M20 4v.01"></path> <path d="M20 20v.01"></path> <path d="M20 16v.01"></path> <path d="M20 12v.01"></path> <path d="M20 8v.01"></path> <path d="M8 4m0 1a1 1 0 0 1 1 -1h6a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-6a1 1 0 0 1 -1 -1z"></path> <path d="M4 4v.01"></path> <path d="M4 20v.01"></path> <path d="M4 16v.01"></path> <path d="M4 12v.01"></path> <path d="M4 8v.01"></path> </svg>                            
                           </span>
                         </div>
 
                         <!-- HTMX -->
-                        <div class="col" name="RAM" id="orange" data-hx-get="/stats" data-hx-trigger="load, every 2s">
+                        <div class="col" name="RAM" id="blue" data-hx-get="/stats" data-hx-trigger="load, every 2s">
                           <div class="font-weight-medium">
                             <label class="ram-text mb-1" for="ram">RAM 0%</label>
                           </div>
-                          <div class="ram-bar meter animate orange">
+                          <div class="ram-bar meter animate blue">
                             <span style="width:20%"><span></span></span>
                           </div>
                         </div>
@@ -90,18 +90,21 @@
                     <div class="card-body">
                       <div class="row align-items-center">
                         <div class="col-auto">
-                          <span class="bg-twitter text-white avatar">
+                          <span class="bg-purple text-white avatar">
                             <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-left-right" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M21 17l-18 0"></path> <path d="M6 10l-3 -3l3 -3"></path> <path d="M3 7l18 0"></path> <path d="M18 20l3 -3l-3 -3"></path> </svg>                            
                           </span>
                         </div>
-                        <div class="col">
+
+                        <!-- HTMX -->
+                        <div class="col" name="NET" id="purple">
                           <div class="font-weight-medium">
                             <label id="net-text" class="net-text mb-1" for="network">Down: 0MB  Up: 0MB</label>
                           </div>
-                          <div id="net-bar" class="meter animate blue">
-                            <span style="width: 20%"><span></span></span>
+                          <div class="ram-bar meter animate purple">
+                            <span style="width:20%"><span></span></span>
                           </div>
                         </div>
+
                       </div>
                     </div>
                   </div>
@@ -112,17 +115,17 @@
                     <div class="card-body">
                       <div class="row align-items-center">
                         <div class="col-auto">
-                          <span class="bg-facebook text-white avatar">
+                          <span class="bg-orange text-white avatar">
                             <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-database" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 6m-8 0a8 3 0 1 0 16 0a8 3 0 1 0 -16 0"></path> <path d="M4 6v6a8 3 0 0 0 16 0v-6"></path> <path d="M4 12v6a8 3 0 0 0 16 0v-6"></path></svg>
                           </span>
                         </div>
 
                         <!-- HTMX -->
-                        <div class="col" name="DISK" id="red" data-hx-get="/stats" data-hx-trigger="load, every 2s">
+                        <div class="col" name="DISK" id="orange" data-hx-get="/stats" data-hx-trigger="load, every 3s">
                           <div class="font-weight-medium">
                             <label class="disk-text mb-1" for="disk">DISK 0%</label>
                           </div>
-                          <div class="meter animate red">
+                          <div class="meter animate orange">
                             <span style="width:20%"><span></span></span>
                           </div>
                         </div>
@@ -136,13 +139,22 @@
               </div>
             </div>
 
+
+            
             <!-- HTMX -->
-            <div class="col-12" hx-ext="sse" sse-connect="/sse_event">
+            <div class="col-12">
               <div class="row row-cards" id="containerCards" data-hx-get="/containers" data-hx-trigger="load, sse:docker" data-hx-swap="innerHTML">
 
               </div>
             </div>
 
+            <!-- HTMX -->
+            <div class="col-12">
+              <div class="row row-cards" data-hx-get="/installs" name="jellyfin" data-hx-trigger="load delay:2s, sse:install" data-hx-swap="beforeend" hx-target="#containerCards">
+
+              </div>
+            </div>
+            
             <!-- HTMX Target-->
             <div id="modals-here" class="modal modal-blur fade" style="display: none" aria-hidden="false" tabindex="-1">
               <div class="modal-dialog modal-lg modal-dialog-centered" role="document">