Bläddra i källkod

Updated dependencies and CHANGELOG. Navbar tweaks.

lllllllillllllillll 9 månader sedan
förälder
incheckning
ec4746ebd3
10 ändrade filer med 107 tillägg och 50 borttagningar
  1. 25 2
      CHANGELOG.md
  2. 13 7
      README.md
  3. 2 14
      controllers/dashboard.js
  4. 22 2
      controllers/register.js
  5. 6 5
      controllers/settings.js
  6. 5 5
      package-lock.json
  7. 4 4
      package.json
  8. 1 1
      utils/docker.js
  9. 19 7
      utils/system.js
  10. 10 3
      views/register.html

+ 25 - 2
CHANGELOG.md

@@ -9,15 +9,38 @@
 * New - 'Grid view' and 'List view' button (non-functioning).
 * New - 'Grid view' and 'List view' button (non-functioning).
 * Added try blocks to volumes, images, and networks pages to address GitHub issues.
 * Added try blocks to volumes, images, and networks pages to address GitHub issues.
 * Fixed HTTPS env.
 * Fixed HTTPS env.
-* New - One-click sign-in if NO_AUTH env is set to 'true' and you're connecting from localhost.
+* New - Authentication can be reduced or disabled.
 * New (again) - PM2 to keep the app running if it encounters an error.
 * New (again) - PM2 to keep the app running if it encounters an error.
 * New - User registration enabled/disabled from Settings page.
 * New - User registration enabled/disabled from Settings page.
 * Removed 'SECRET' environment variable.
 * Removed 'SECRET' environment variable.
-* New - Custom container links.
+* New - Custom container_card ports links.
+* New - Custom container_card title links.
 * Fixed issue updating view permission.
 * Fixed issue updating view permission.
 * Fixed issue viewing container logs.
 * Fixed issue viewing container logs.
 * App icons are now determined by service label instead of image name.
 * App icons are now determined by service label instead of image name.
 * App icons sourced from new repo with 1000+ icons.
 * App icons sourced from new repo with 1000+ icons.
+* Rewrote most of the app to use containerIDs and UUIDs universally.
+* Dashboard updates now triggered by Docker events instead of constantly polling the API.
+* Sessions now stored in sqlite database instead of memory.
+* Updated tabler from 1.0.0-beta16 to 1.0.0-beta20.
+* Updated htmx (2.0.1) and sse plugin (2.2.1).
+* Seperated css and js customizations into dweebui.css and dweebui.js.
+* New - Preferences page for individual user settings, like language choice.
+* New - Hide username from dashboard.
+* New - Footer displays version with build number.
+* Updated hide container_card to be **instant**.
+* Improved console.log and syslog messages.
+* Fixed modal close buttons.
+* Reduced amount of html being stored in js files.
+* CSS and pages tweaks to make the style more consistent.
+* Improved container cards to be more compact.
+* Improved sponsors and credits pages.
+* New - Secret supporter code.
+* Fixed installs not appearing or appearing multiple times.
+* Improved log view and fixed refresh button.
+* Made app cards more compact.
+
+
 
 
 ## v0.60 (June 9th 2024) - Permissions system and import templates
 ## v0.60 (June 9th 2024) - Permissions system and import templates
 * Converted JS template literals into HTML.
 * Converted JS template literals into HTML.

+ 13 - 7
README.md

@@ -15,20 +15,20 @@
 ## Features
 ## Features
 
 
 * [x] A dynamically updating dashboard that displays server metrics along with container metrics and container controls.
 * [x] A dynamically updating dashboard that displays server metrics along with container metrics and container controls.
-* [x] Multi-user support with permissions system.
-* [ ] Multiple hosts (in development).
 * [x] Container actions: Start, Stop, Pause, Restart, View Details, View Logs.
 * [x] Container actions: Start, Stop, Pause, Restart, View Details, View Logs.
+* [x] Multi-user support with permissions system.
+* [x] Support for multiple hosts.
+* [x] View and manage images, volumes, and networks.
 * [x] Windows, Linux, and MacOS compatable.
 * [x] Windows, Linux, and MacOS compatable.
 * [x] Light/Dark Mode.
 * [x] Light/Dark Mode.
 * [x] Mobile Friendly.
 * [x] Mobile Friendly.
-* [x] Manage your Docker networks, images, and volumes.
-* [x] Easy to install app templates.
-* [x] Docker Compose Support.
+* [x] Easy to install app templates (Compatible with Portainer).
+* [x] Docker Compose.
 * [ ] Available updates without image pull (in development).
 * [ ] Available updates without image pull (in development).
 * [ ] Update containers (planned).
 * [ ] Update containers (planned).
-* [x] Templates.json maintains compatability with Portainer, allowing you to use the template without needing to use DweebUI.
 * [ ] Preset variables (planned).
 * [ ] Preset variables (planned).
 * [ ] Themes (planned).
 * [ ] Themes (planned).
+* [*] International language support (Languages still being updated).
 
 
 ## About
 ## About
 
 
@@ -39,7 +39,13 @@
 
 
 ## Setup
 ## Setup
 
 
-Docker Compose: 
+
+### Docker Run:
+```
+docker run -d --name=DweebUI -p 8000:8000 -v dweebui:/app/database -v /var/run/docker.sock:/var/run/docker.sock lllllllillllllillll/dweebui:v0.7X-dev
+```
+
+### Docker Compose: 
 ```
 ```
 version: "3.9"
 version: "3.9"
 services:
 services:

+ 2 - 14
controllers/dashboard.js

@@ -13,14 +13,8 @@ let container_link = 'http://localhost';
 // Dashboard
 // Dashboard
 export const Dashboard = async function (req, res) {
 export const Dashboard = async function (req, res) {
 
 
-    let host = req.params.host;
-    req.session.host = host;
-
-
-    // if (host != 1) {
-    //     let test = await GetContainerLists(host);
-    //     console.log(test);
-    // }
+    let host = req.params.host || 1;
+    req.session.host = `${host}`;
 
 
     // Create the lists needed for the dashboard
     // Create the lists needed for the dashboard
     const [list, created] = await ContainerLists.findOrCreate({
     const [list, created] = await ContainerLists.findOrCreate({
@@ -36,7 +30,6 @@ export const Dashboard = async function (req, res) {
     });
     });
     if (created) { console.log(`New entry created in ContainerLists for ${req.session.username}`); }
     if (created) { console.log(`New entry created in ContainerLists for ${req.session.username}`); }
 
 
-
     res.render("dashboard",{ 
     res.render("dashboard",{ 
         alert: '',
         alert: '',
         username: req.session.username,
         username: req.session.username,
@@ -250,11 +243,6 @@ async function createCard (details) {
     container_card = container_card.replace(/AppService/g, containerService);
     container_card = container_card.replace(/AppService/g, containerService);
     container_card = container_card.replace(/AppState/g, containerState);
     container_card = container_card.replace(/AppState/g, containerState);
     container_card = container_card.replace(/StateColor/g, containerStateColor);
     container_card = container_card.replace(/StateColor/g, containerStateColor);
-
-
-    let update_status = `<div class="text-yellow">
-                            <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>
-                        </div>`;
     
     
 
 
     if (details.external_port == 0 && details.internal_port == 0) {
     if (details.external_port == 0 && details.internal_port == 0) {

+ 22 - 2
controllers/register.js

@@ -50,10 +50,30 @@ export const submitRegister = async function(req,res){
 
 
     else if (await User.findOne({ where: { [Op.or]: [{ username: username }, { email: email }] }})) { 
     else if (await User.findOne({ where: { [Op.or]: [{ username: username }, { email: email }] }})) { 
         error = "Username or email already exists"; 
         error = "Username or email already exists"; 
-        await Syslog.create({ username: user.username, uniqueID: email, event: "Failed Registration", message: "Username or email already exists", ip: req.socket.remoteAddress });
+        await Syslog.create({ username: username, uniqueID: email, event: "Failed Registration", message: "Username or email already exists", ip: req.socket.remoteAddress });
+    }
+
+    if (error != '') { 
+        
+        let secret_input = '';
+        let user_registration = await ServerSettings.findOne({ where: { key: 'user_registration' }});
+        if (user_registration == null ) { user_registration = false; }
+        else { user_registration = user_registration.value; }
+        
+        if (user_registration) {
+            secret_input = `<div class="mb-3"><label class="form-label">Secret</label>
+                                    <div class="input-group input-group-flat">
+                                        <input type="text" class="form-control" autocomplete="off" name="registration_secret">
+                                    </div>
+                                </div>`}    
+
+        res.render("register", { 
+            "error": error,
+            "reg_secret": secret_input,
+        }); 
+        return; 
     }
     }
 
 
-    if (error) { res.render("register", { "error": error }); return; }
 
 
     // Returns 'admin' if no users have been created.
     // Returns 'admin' if no users have been created.
     async function Role() {
     async function Role() {

+ 6 - 5
controllers/settings.js

@@ -1,6 +1,6 @@
 import { ServerSettings } from '../database/config.js';
 import { ServerSettings } from '../database/config.js';
 import { Alert, getLanguage, Navbar, Sidebar, Footer } from '../utils/system.js';
 import { Alert, getLanguage, Navbar, Sidebar, Footer } from '../utils/system.js';
-import { read, readdirSync, readFileSync } from 'fs';
+import { read, readdirSync, readFileSync, writeFileSync } from 'fs';
 
 
 export const Settings = async function(req,res){
 export const Settings = async function(req,res){
 
 
@@ -216,15 +216,16 @@ export const updateLanguages = async function(req,res){
             
             
             if (language_dev != language_local) {
             if (language_dev != language_local) {
                 console.log(`\x1b[31mLanguage: ${languages[i].language} is out of date.\x1b[0m`);
                 console.log(`\x1b[31mLanguage: ${languages[i].language} is out of date.\x1b[0m`);
+                console.log(`\x1b[31mUpdating ${languages[i].language}...\x1b[0m`);
+                writeFileSync(`./languages/${languages[i].language}`, language_dev);
+                console.log(`\x1b[32mLanguage: ${languages[i].language} has been updated.\x1b[0m`);
             } else {
             } else {
                 console.log(`\x1b[32mLanguage: ${languages[i].language} is up to date.\x1b[0m`);
                 console.log(`\x1b[32mLanguage: ${languages[i].language} is up to date.\x1b[0m`);
             }
             }
         }
         }
 
 
-        setTimeout(() => {
-            inProgress = false;
-            console.log('Languages Updated');
-        }, 2000);
+        inProgress = false;
+        console.log('Language update complete');
 
 
         return;
         return;
     } else {
     } else {

+ 5 - 5
package-lock.json

@@ -1,27 +1,27 @@
 {
 {
   "name": "dweebui",
   "name": "dweebui",
-  "version": "0.70.453",
+  "version": "0.70.457",
   "lockfileVersion": 3,
   "lockfileVersion": 3,
   "requires": true,
   "requires": true,
   "packages": {
   "packages": {
     "": {
     "": {
       "name": "dweebui",
       "name": "dweebui",
-      "version": "0.70.453",
+      "version": "0.70.457",
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
-        "adm-zip": "^0.5.15",
+        "adm-zip": "^0.5.16",
         "bcrypt": "^5.1.1",
         "bcrypt": "^5.1.1",
         "connect-session-sequelize": "^7.1.7",
         "connect-session-sequelize": "^7.1.7",
         "dockerode": "^4.0.2",
         "dockerode": "^4.0.2",
         "dockerode-compose": "^1.4.0",
         "dockerode-compose": "^1.4.0",
         "ejs": "^3.1.10",
         "ejs": "^3.1.10",
-        "express": "^4.19.2",
+        "express": "^4.21.0",
         "express-session": "^1.18.0",
         "express-session": "^1.18.0",
         "multer": "^1.4.5-lts.1",
         "multer": "^1.4.5-lts.1",
         "sequelize": "^6.37.3",
         "sequelize": "^6.37.3",
         "sqlite3": "^5.1.7",
         "sqlite3": "^5.1.7",
         "systeminformation": "^5.23.5",
         "systeminformation": "^5.23.5",
-        "yaml": "^2.5.0"
+        "yaml": "^2.5.1"
       }
       }
     },
     },
     "node_modules/@balena/dockerignore": {
     "node_modules/@balena/dockerignore": {

+ 4 - 4
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "dweebui",
   "name": "dweebui",
-  "version": "0.70.453",
+  "version": "0.70.457",
   "main": "server.js",
   "main": "server.js",
   "type": "module",
   "type": "module",
   "scripts": {
   "scripts": {
@@ -12,18 +12,18 @@
   "license": "MIT",
   "license": "MIT",
   "description": "DweebUI is a WebUI for managing your containers. https://dweebui.com",
   "description": "DweebUI is a WebUI for managing your containers. https://dweebui.com",
   "dependencies": {
   "dependencies": {
-    "adm-zip": "^0.5.15",
+    "adm-zip": "^0.5.16",
     "bcrypt": "^5.1.1",
     "bcrypt": "^5.1.1",
     "connect-session-sequelize": "^7.1.7",
     "connect-session-sequelize": "^7.1.7",
     "dockerode": "^4.0.2",
     "dockerode": "^4.0.2",
     "dockerode-compose": "^1.4.0",
     "dockerode-compose": "^1.4.0",
     "ejs": "^3.1.10",
     "ejs": "^3.1.10",
-    "express": "^4.19.2",
+    "express": "^4.21.0",
     "express-session": "^1.18.0",
     "express-session": "^1.18.0",
     "multer": "^1.4.5-lts.1",
     "multer": "^1.4.5-lts.1",
     "sequelize": "^6.37.3",
     "sequelize": "^6.37.3",
     "sqlite3": "^5.1.7",
     "sqlite3": "^5.1.7",
     "systeminformation": "^5.23.5",
     "systeminformation": "^5.23.5",
-    "yaml": "^2.5.0"
+    "yaml": "^2.5.1"
   }
   }
 }
 }

+ 1 - 1
utils/docker.js

@@ -14,7 +14,7 @@ export async function GetContainerLists(hostid) {
 
 
     let host = hostid || 1;
     let host = hostid || 1;
 
 
-    if (host == 1) {
+    if (host == 1 || host == 0) {
         let containers = await docker.listContainers({ all: true });
         let containers = await docker.listContainers({ all: true });
         return containers;
         return containers;
     }
     }

+ 19 - 7
utils/system.js

@@ -8,6 +8,8 @@ export async function Navbar (req) {
 
 
     let username = req.session.username;
     let username = req.session.username;
 
 
+    let host = '' + req.session.host;
+
     let language = await getLanguage(req);
     let language = await getLanguage(req);
 
 
     // Check if the user wants to hide their profile name.
     // Check if the user wants to hide their profile name.
@@ -20,9 +22,11 @@ export async function Navbar (req) {
     let sponsored = await ServerSettings.findOne({ where: { key: 'sponsored' }});
     let sponsored = await ServerSettings.findOne({ where: { key: 'sponsored' }});
     if (sponsored) { username = `<label class="text-yellow">${username}</label>`; }
     if (sponsored) { username = `<label class="text-yellow">${username}</label>`; }
 
 
-    let [host2_toggle, host2_tag, host2_ip, host2_port] = ['', '', '', ''];
-    let [host3_toggle, host3_tag, host3_ip, host3_port] = ['', '', '', ''];
-    let [host4_toggle, host4_tag, host4_ip, host4_port] = ['', '', '', ''];
+    let [host0_active, host0_toggle, host0_tag, host0_ip, host0_port] = ['', '', '', '', ''];
+    let [host1_active, host1_toggle, host1_tag, host1_ip, host1_port] = ['', '', '', '', ''];
+    let [host2_active, host2_toggle, host2_tag, host2_ip, host2_port] = ['', '', '', '', ''];
+    let [host3_active, host3_toggle, host3_tag, host3_ip, host3_port] = ['', '', '', '', ''];
+    let [host4_active, host4_toggle, host4_tag, host4_ip, host4_port] = ['', '', '', '', ''];
 
 
     const [host2, created2] = await ServerSettings.findOrCreate({ where: { key: 'host2' }, defaults: { key: 'host2', value: '' }});
     const [host2, created2] = await ServerSettings.findOrCreate({ where: { key: 'host2' }, defaults: { key: 'host2', value: '' }});
     const [host3, created3] = await ServerSettings.findOrCreate({ where: { key: 'host3' }, defaults: { key: 'host3', value: '' }});
     const [host3, created3] = await ServerSettings.findOrCreate({ where: { key: 'host3' }, defaults: { key: 'host3', value: '' }});
@@ -34,10 +38,17 @@ export async function Navbar (req) {
     if (host4.value) { host4_toggle = 'checked'; [host4_tag, host4_ip, host4_port] = host4.value.split(','); }
     if (host4.value) { host4_toggle = 'checked'; [host4_tag, host4_ip, host4_port] = host4.value.split(','); }
     
     
     let host_buttons = '';
     let host_buttons = '';
-    if (host2_toggle || host3_toggle || host4_toggle) { host_buttons += '<a href="/0/dashboard" class="btn" title="All">All</a>  <a href="/1/dashboard" class="btn" title="Host 1">Host 1</a>'; }
-    if (host2_toggle) { host_buttons += `<a href="/2/dashboard" class="btn" title="${host2_tag}">${host2_tag}</a>`; }
-    if (host3_toggle) { host_buttons += `<a href="/3/dashboard" class="btn" title="${host3_tag}">${host3_tag}</a>`; }
-    if (host4_toggle) { host_buttons += `<a href="/4/dashboard" class="btn" title="${host4_tag}">${host4_tag}</a>`; }
+
+    if (host == '0') { host0_active = 'text-yellow'; }
+    if (host == '1') { host1_active = 'text-yellow'; }
+    if (host == '2') { host2_active = 'text-yellow'; }
+    if (host == '3') { host3_active = 'text-yellow'; }
+    if (host == '4') { host4_active = 'text-yellow'; }
+
+    if (host2_toggle || host3_toggle || host4_toggle) { host_buttons += `<a href="/0/dashboard" class="btn ${host0_active}" title="All">All</a>  <a href="/1/dashboard" class="btn ${host1_active}" title="Host 1">Host 1</a>`; }
+    if (host2_toggle) { host_buttons += `<a href="/2/dashboard" class="btn ${host2_active}" title="${host2_tag}">${host2_tag}</a>`; }
+    if (host3_toggle) { host_buttons += `<a href="/3/dashboard" class="btn ${host3_active}" title="${host3_tag}">${host3_tag}</a>`; }
+    if (host4_toggle) { host_buttons += `<a href="/4/dashboard" class="btn ${host4_active}" title="${host4_tag}">${host4_tag}</a>`; }
 
 
     let navbar = readFileSync('./views/partials/navbar.html', 'utf8');
     let navbar = readFileSync('./views/partials/navbar.html', 'utf8');
 
 
@@ -68,6 +79,7 @@ export async function Navbar (req) {
 
 
         navbar = navbar.replace(/Username/g, username);
         navbar = navbar.replace(/Username/g, username);
         navbar = navbar.replace(/Userrole/g, req.session.role);
         navbar = navbar.replace(/Userrole/g, req.session.role);
+        navbar = navbar.replace(/HostButtons/g, host_buttons);
         return navbar;
         return navbar;
     }
     }
 }
 }

+ 10 - 3
views/register.html

@@ -22,6 +22,13 @@
         <form class="card card-md" action="/register" method="post" autocomplete="off" novalidate>
         <form class="card card-md" action="/register" method="post" autocomplete="off" novalidate>
           <div class="card-body">
           <div class="card-body">
             <h2 class="card-title text-center mb-4">Create new account</h2>
             <h2 class="card-title text-center mb-4">Create new account</h2>
+
+            <% if(error) { %>
+              <div class="alert alert-danger" role="alert">
+                  <%= error %>
+              </div>
+            <% } %>
+
             <div class="mb-3">
             <div class="mb-3">
               <label class="form-label">Name</label>
               <label class="form-label">Name</label>
               <input type="text" class="form-control" name="name">
               <input type="text" class="form-control" name="name">
@@ -50,9 +57,9 @@
             </div>
             </div>
 
 
 
 
-            <% if(reg_secret) { %>
-              <%- reg_secret %>
-            <% } %>
+
+            <%- reg_secret %>
+
 
 
             <!-- <div class="mb-3">
             <!-- <div class="mb-3">
               <label class="form-check">
               <label class="form-check">