소스 검색

Working install cards and fixes for dashboard.js

lllllllillllllillll 1 년 전
부모
커밋
5c6e2a9eaa
6개의 변경된 파일64개의 추가작업 그리고 19개의 파일을 삭제
  1. 0 1
      CHANGELOG.md
  2. 45 13
      controllers/dashboard.js
  3. 11 1
      functions/install.js
  4. 6 1
      functions/uninstall.js
  5. 1 2
      router/index.js
  6. 1 1
      views/partials/containerCard.html

+ 0 - 1
CHANGELOG.md

@@ -8,7 +8,6 @@
 * Dynamically generated avatars.
 * Dynamically generated avatars.
 * Updated database models.
 * Updated database models.
 * Persistent Database.
 * Persistent Database.
-* Removed automatic volume creation.
 
 
 ## v0.40 (Feb 26th 2024) - HTMX rewrite
 ## v0.40 (Feb 26th 2024) - HTMX rewrite
 * Pages rewritten to use HTMX.
 * Pages rewritten to use HTMX.

+ 45 - 13
controllers/dashboard.js

@@ -105,6 +105,10 @@ async function createCard (details) {
             state_color = 'orange';
             state_color = 'orange';
             trigger = 'data-hx-trigger="load"';
             trigger = 'data-hx-trigger="load"';
             break;
             break;
+        case 'installing':
+            state_color = 'blue';
+            trigger = 'data-hx-trigger="load"';
+            break;
     }
     }
     // if (name.startsWith('dweebui')) { disable = 'disabled=""'; }
     // if (name.startsWith('dweebui')) { disable = 'disabled=""'; }
     let card  = readFileSync('./views/partials/containerCard.html', 'utf8');
     let card  = readFileSync('./views/partials/containerCard.html', 'utf8');
@@ -124,6 +128,30 @@ let [ cardList, newCards, containersArray, sentArray, updatesArray ] = [ '', '',
 let hidden = await Container.findAll({ where: {visibility:false}});
 let hidden = await Container.findAll({ where: {visibility:false}});
 hidden = hidden.map((container) => container.name);
 hidden = hidden.map((container) => container.name);
 
 
+
+
+export async function addCard (name, state) {
+    console.log(`Adding card for ${name}: ${state}`);
+
+    let details = {
+        name: name,
+        image: name,
+        service: name,
+        state: 'installing',
+        external_port: 0,
+        internal_port: 0,
+        ports: [],
+        link: 'localhost',
+    
+    }
+    createCard(details).then(card => {
+        cardList += card;
+    });
+}
+
+
+
+
 // HTMX server-side events
 // HTMX server-side events
 export const SSE = (req, res) => {
 export const SSE = (req, res) => {
     res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
     res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
@@ -180,7 +208,7 @@ export const SSE = (req, res) => {
             sentArray = containersArray.slice();
             sentArray = containersArray.slice();
         }
         }
 
 
-    }, 1000);
+    }, 500);
 
 
 
 
     req.on('close', () => {
     req.on('close', () => {
@@ -211,14 +239,6 @@ export const Chart = async (req, res) => {
     res.send(chart);
     res.send(chart);
 }
 }
 
 
-
-export const Installs = async (req, res) => {
-    let name = req.header('hx-trigger-name');
-    let all_containers = '';
-    res.send('ok');
-}
-
-
 export const updateCards = async (req, res) => {
 export const updateCards = async (req, res) => {
     console.log('updateCards called');
     console.log('updateCards called');
     res.send(newCards);
     res.send(newCards);
@@ -232,13 +252,21 @@ export const Containers = async (req, res) => {
 
 
 export const Card = async (req, res) => {
 export const Card = async (req, res) => {
     let name = req.header('hx-trigger-name');
     let name = req.header('hx-trigger-name');
-    console.log(`Updated card for ${name}`);
-    let details = await containerInfo(name);
-    let card = await createCard(details);
-    res.send(card);
+    console.log(`${name} requesting updated card`);
+    // return nothing if in hidden or not found in containersArray
+    if (hidden.includes(name) || !containersArray.find(c => c.container === name)) {
+        res.send('');
+        return;
+    } else {
+        let details = await containerInfo(name);
+        let card = await createCard(details);
+        res.send(card);
+    }
 }
 }
 
 
 
 
+
+
 function status (state) {
 function status (state) {
     let status = `<span class="text-yellow align-items-center lh-1">
     let status = `<span class="text-yellow 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>
                     <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>
@@ -322,6 +350,10 @@ export const Action = async (req, res) => {
     } else if ((action == 'pause') && (state == 'paused')) {
     } else if ((action == 'pause') && (state == 'paused')) {
         var containerName = docker.getContainer(name);
         var containerName = docker.getContainer(name);
         containerName.unpause();
         containerName.unpause();
+        res.send(status('starting'));
+    }   else if ((action == 'pause') && (state == 'running')) {
+        var containerName = docker.getContainer(name);
+        containerName.pause();
         res.send(status('pausing'));
         res.send(status('pausing'));
     // Restart
     // Restart
     } else if (action == 'restart') {
     } else if (action == 'restart') {

+ 11 - 1
functions/install.js

@@ -4,6 +4,7 @@ import { execSync } from "child_process";
 import { docker } from "../server.js";
 import { docker } from "../server.js";
 import DockerodeCompose from "dockerode-compose";
 import DockerodeCompose from "dockerode-compose";
 import { Syslog } from "../database/models.js";
 import { Syslog } from "../database/models.js";
+import { addCard } from "../controllers/dashboard.js";
 
 
 // This entire page hurts to look at. 
 // This entire page hurts to look at. 
 export const Install = async (req, res) => {
 export const Install = async (req, res) => {
@@ -20,6 +21,8 @@ export const Install = async (req, res) => {
 
 
         let docker_volumes = [];
         let docker_volumes = [];
 
 
+        addCard(name, 'installing');
+
         if (image.startsWith('https://')){
         if (image.startsWith('https://')){
             mkdirSync(`./appdata/${name}`, { recursive: true });
             mkdirSync(`./appdata/${name}`, { recursive: true });
             execSync(`curl -o ./appdata/${name}/${name}_stack.yml -L ${image}`);
             execSync(`curl -o ./appdata/${name}/${name}_stack.yml -L ${image}`);
@@ -88,6 +91,13 @@ export const Install = async (req, res) => {
                 if ((data[`volume${i}`] == 'on') && (data[`volume_${i}_bind`] != '') && (data[`volume_${i}_container`] != '')) {
                 if ((data[`volume${i}`] == 'on') && (data[`volume_${i}_bind`] != '') && (data[`volume_${i}_container`] != '')) {
                     compose_file += `\n      - ${data[`volume_${i}_bind`]}:${data[`volume_${i}_container`]}:${data[`volume_${i}_readwrite`]}`
                     compose_file += `\n      - ${data[`volume_${i}_bind`]}:${data[`volume_${i}_container`]}:${data[`volume_${i}_readwrite`]}`
                 }
                 }
+
+                // if bind is empty create a docker volume (ex container_name_config:/config) convert any '/' in container name to '_'
+                else if ((data[`volume${i}`] == 'on') && (data[`volume_${i}_bind`] == '') && (data[`volume_${i}_container`] != '')) {
+                    let volume_name = data[`volume_${i}_container`].replace(/\//g, '_');
+                    compose_file += `\n      - ${name}_${volume_name}:${data[`volume_${i}_container`]}:${data[`volume_${i}_readwrite`]}`
+                    docker_volumes.push(`${name}_${volume_name}`);
+                } 
                 
                 
             }
             }
 
 
@@ -170,7 +180,7 @@ export const Install = async (req, res) => {
                     message: `${name} installation failed - error creating directory or compose file : ${err}`,
                     message: `${name} installation failed - error creating directory or compose file : ${err}`,
                     ip: req.socket.remoteAddress
                     ip: req.socket.remoteAddress
                 });
                 });
-             }
+            }
 
 
             try {
             try {
                 (async () => {
                 (async () => {

+ 6 - 1
functions/uninstall.js

@@ -10,7 +10,8 @@ export const Uninstall = async (req, res) => {
 
 
     if (confirm == 'Yes') {
     if (confirm == 'Yes') {
 
 
-        var containerName = docker.getContainer(`${service_name}`);
+        let containerName = docker.getContainer(service_name);
+        console.log(`Stopping ${service_name}...`)
         try {
         try {
             await containerName.stop();
             await containerName.stop();
         } catch {
         } catch {
@@ -18,6 +19,7 @@ export const Uninstall = async (req, res) => {
         }
         }
 
 
         try {
         try {
+            console.log(`Removing ${service_name}...`);
             containerName.remove();
             containerName.remove();
             
             
             const syslog = await Syslog.create({
             const syslog = await Syslog.create({
@@ -38,7 +40,10 @@ export const Uninstall = async (req, res) => {
                 ip: req.socket.remoteAddress
                 ip: req.socket.remoteAddress
             });
             });
         }
         }
+    } else {
+        console.log(`Didn't confirm uninstallation of ${service_name}...`);
     }
     }
+
     res.redirect('/');
     res.redirect('/');
 }
 }
 
 

+ 1 - 2
router/index.js

@@ -4,7 +4,7 @@ export const router = express.Router();
 // Controllers
 // Controllers
 import { Login, submitLogin, Logout } from "../controllers/login.js";
 import { Login, submitLogin, Logout } from "../controllers/login.js";
 import { Register, submitRegister } from "../controllers/register.js";
 import { Register, submitRegister } from "../controllers/register.js";
-import { Dashboard, Logs, Modals, Stats, Chart, Installs, SSE, Card, updateCards, Containers, Action } from "../controllers/dashboard.js";
+import { Dashboard, Logs, Modals, Stats, Chart, SSE, Card, updateCards, Containers, Action } from "../controllers/dashboard.js";
 import { Apps, appSearch, InstallModal, LearnMore } from "../controllers/apps.js";
 import { Apps, appSearch, InstallModal, LearnMore } from "../controllers/apps.js";
 import { Users } from "../controllers/users.js";
 import { Users } from "../controllers/users.js";
 import { Images, removeImage } from "../controllers/images.js";
 import { Images, removeImage } from "../controllers/images.js";
@@ -34,7 +34,6 @@ router.get("/logs", auth, Logs);
 router.get("/modals", auth, Modals);
 router.get("/modals", auth, Modals);
 router.get("/stats", auth, Stats);
 router.get("/stats", auth, Stats);
 router.get("/chart", auth, Chart);
 router.get("/chart", auth, Chart);
-router.get("/installs", auth, Installs);
 router.get("/sse_event", auth, SSE);
 router.get("/sse_event", auth, SSE);
 router.get("/containers", auth, Containers);
 router.get("/containers", auth, Containers);
 router.get("/card", auth, Card);
 router.get("/card", auth, Card);

+ 1 - 1
views/partials/containerCard.html

@@ -48,7 +48,7 @@
           </div>
           </div>
         </div>
         </div>
         <div class="d-flex align-items-baseline">
         <div class="d-flex align-items-baseline">
-          <div class="h1 me-2" title="AppName">
+          <div class="h1 me-2" title="AppName" style="margin-bottom: 0;">
             <a href="http://${link}:${external_port}" target="_blank">
             <a href="http://${link}:${external_port}" target="_blank">
               AppShortName
               AppShortName
             </a>
             </a>