Improved UI for apps.js and new template import

This commit is contained in:
lllllllillllllillll 2024-04-14 14:56:01 -07:00
parent 64ec287286
commit 62b7e73aac
20 changed files with 380 additions and 201 deletions

View File

@ -13,6 +13,7 @@ export const Account = async (req, res) => {
email: user.email,
role: user.role,
avatar: user.avatar,
alert: '',
});

View File

@ -1,148 +1,140 @@
import { readFileSync } from 'fs';
import multer from 'multer';
const upload = multer({storage: multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'templates/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
})
// load the default template then sort the templates by name
let templatesJSON = readFileSync('./templates/templates.json');
let templates = JSON.parse(templatesJSON).templates;
templates = templates.sort((a, b) => {
if (a.name < b.name) {
return -1;
}
});
let alert = '';
export const Apps = (req, res) => {
let page = Number(req.params.page) || 1;
let list_start = (page-1)*28;
let list_end = (page*28);
let last_page = Math.ceil(templates.length/28);
let prev = '/apps/' + (page-1);
let next = '/apps/' + (page+1);
if (page == 1) {
prev = '/apps/' + (page);
}
if (page == last_page) {
next = '/apps/' + (page);
}
let page = Number(req.params.page) || 1;
let list_start = (page-1)*28;
let list_end = (page*28);
let last_page = Math.ceil(templates.length/28);
let prev = '/apps/' + (page-1);
let next = '/apps/' + (page+1);
if (page == 1) { prev = '/apps/' + (page); }
if (page == last_page) { next = '/apps/' + (page); }
let apps_list = '';
for (let i = list_start; i < list_end && i < templates.length; i++) {
let appCard = readFileSync('./views/partials/appCard.html', 'utf8');
let name = templates[i].name || templates[i].title.toLowerCase();
let desc = templates[i].description.slice(0, 60) + "...";
let description = templates[i].description.replaceAll(". ", ".\n") || "no description available";
let note = templates[i].note ? templates[i].note.replaceAll(". ", ".\n") : "no notes available";
let image = templates[i].image;
let logo = templates[i].logo;
let categories = '';
// set data.catagories to 'other' if data.catagories is empty or undefined
if (templates[i].categories == null || templates[i].categories == undefined || templates[i].categories == '') {
templates[i].categories = ['Other'];
}
for (let c = 0; c < templates[i].categories.length; c++) {
categories += CatagoryColor(templates[i].categories[c]);
}
appCard = appCard.replace(/AppName/g, name);
appCard = appCard.replace(/AppShortName/g, name);
appCard = appCard.replace(/AppDesc/g, desc);
appCard = appCard.replace(/AppLogo/g, logo);
appCard = appCard.replace(/AppCategories/g, categories);
apps_list += appCard;
}
res.render("apps", {
name: req.session.user,
role: req.session.role,
avatar: req.session.avatar,
list_start: list_start + 1,
list_end: list_end,
app_count: templates.length,
prev: prev,
next: next,
apps_list: apps_list
});
}
export const appSearch = async (req, res) => {
let search = req.body.search.split(' ');
let apps_list = '';
let results = [];
let page = Number(req.query.page) || 1;
let list_start = (page - 1) * 28;
let list_end = (page * 28);
let last_page = Math.ceil(templates.length / 28);
let prev = '/apps?page=' + (page - 1);
let next = '/apps?page=' + (page + 1);
if (page == 1) {
prev = '/apps?page=' + (page);
}
if (page == last_page) {
next = '/apps?page=' + (page);
}
function searchTemplates(word) {
for (let i = 0; i < templates.length; i++) {
if ((templates[i].description.includes(word)) || (templates[i].name.includes(word)) || (templates[i].title.includes(word))) {
results.push(templates[i]);
}
}
}
searchTemplates(search);
for (let i = 0; i < results.length; i++) {
let apps_list = '';
for (let i = list_start; i < list_end && i < templates.length; i++) {
let appCard = readFileSync('./views/partials/appCard.html', 'utf8');
let name = results[i].name || results[i].title.toLowerCase();
let desc = results[i].description.slice(0, 60) + "...";
let description = results[i].description.replaceAll(". ", ".\n") || "no description available";
let note = results[i].note ? results[i].note.replaceAll(". ", ".\n") : "no notes available";
let image = results[i].image;
let logo = results[i].logo;
let name = templates[i].name || templates[i].title.toLowerCase();
let desc = templates[i].description.slice(0, 60) + "...";
let description = templates[i].description.replaceAll(". ", ".\n") || "no description available";
let note = templates[i].note ? templates[i].note.replaceAll(". ", ".\n") : "no notes available";
let image = templates[i].image;
let logo = templates[i].logo;
let categories = '';
// set data.catagories to 'other' if data.catagories is empty or undefined
if (results[i].categories == null || results[i].categories == undefined || results[i].categories == '') {
results[i].categories = ['Other'];
// set data.catagories to 'other' if data.catagories is empty or undefined
if (templates[i].categories == null || templates[i].categories == undefined || templates[i].categories == '') {
templates[i].categories = ['Other'];
}
for (let c = 0; c < results[i].categories.length; c++) {
categories += CatagoryColor(results[i].categories[c]);
// loop through the categories and add the badge to the card
for (let j = 0; j < templates[i].categories.length; j++) {
categories += CatagoryColor(templates[i].categories[j]);
}
appCard = appCard.replace(/AppName/g, name);
appCard = appCard.replace(/AppShortName/g, name);
appCard = appCard.replace(/AppDesc/g, desc);
appCard = appCard.replace(/AppLogo/g, logo);
appCard = appCard.replace(/AppCategories/g, categories);
apps_list += appCard;
}
res.render("apps", {
name: req.session.user,
role: req.session.role,
avatar: req.session.avatar,
list_start: list_start + 1,
list_end: list_end,
app_count: results.length,
prev: prev,
next: next,
apps_list: apps_list
});
}
// let templatesJSON = readFileSync('./templates/templates.json');
// let templates = JSON.parse(templatesJSON).templates;
res.render("apps", {
name: req.session.user,
role: req.session.role,
avatar: req.session.user.charAt(0).toUpperCase(),
list_start: list_start + 1,
list_end: list_end,
app_count: templates.length,
prev: prev,
next: next,
apps_list: apps_list,
alert: alert || ''
});
alert = '';
}
export const appSearch = async (req, res) => {
let page = Number(req.params.page) || 1;
let list_start = (page-1)*28;
let list_end = (page*28);
let last_page = Math.ceil(templates.length/28);
let prev = '/apps/' + (page-1);
let next = '/apps/' + (page+1);
if (page == 1) { prev = '/apps/' + (page); }
if (page == last_page) { next = '/apps/' + (page); }
let search = req.body.search.split(' ');
let apps_list = '';
let results = [];
function searchTemplates(word) {
for (let i = 0; i < templates.length; i++) {
if ((templates[i].description.includes(word)) || (templates[i].name.includes(word)) || (templates[i].title.includes(word))) {
results.push(templates[i]);
}
}
}
searchTemplates(search);
for (let i = 0; i < results.length; i++) {
let appCard = readFileSync('./views/partials/appCard.html', 'utf8');
let name = results[i].name || results[i].title.toLowerCase();
let desc = results[i].description.slice(0, 60) + "...";
let description = results[i].description.replaceAll(". ", ".\n") || "no description available";
let note = results[i].note ? results[i].note.replaceAll(". ", ".\n") : "no notes available";
let image = results[i].image;
let logo = results[i].logo;let categories = '';
// set data.catagories to 'other' if data.catagories is empty or undefined
if (results[i].categories == null || results[i].categories == undefined || results[i].categories == '') {
results[i].categories = ['Other'];
}
// loop through the categories and add the badge to the card
for (let j = 0; j < results[i].categories.length; j++) {
categories += CatagoryColor(results[i].categories[j]);
}
appCard = appCard.replace(/AppName/g, name);
appCard = appCard.replace(/AppShortName/g, name);
appCard = appCard.replace(/AppDesc/g, desc);
appCard = appCard.replace(/AppLogo/g, logo);
appCard = appCard.replace(/AppCategories/g, categories);
apps_list += appCard;
}
res.render("apps", {
name: req.session.user,
role: req.session.role,
avatar: req.session.avatar,
list_start: list_start + 1,
list_end: list_end,
app_count: results.length,
prev: prev,
next: next,
apps_list: apps_list,
alert: res.locals.alert || ''
});
}
@ -389,4 +381,24 @@ export const LearnMore = async (req, res) => {
export const ImportModal = async (req, res) => {
let modal = readFileSync('./views/modals/import.html', 'utf8');
res.send(modal);
}
}
export const Upload = (req, res) => {
upload.array('files', 10)(req, res, () => {
alert = `<div class="alert alert-success alert-dismissible mb-0 py-2" role="alert">
<div class="d-flex">
<div>
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" 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 12l5 5l10 -10"></path></svg>
</div>
<div>
Template(s) Uploaded!
</div>
</div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close" style="padding-top: 0.5rem;"></a>
</div>`;
res.redirect('/apps');
});
};

View File

@ -17,7 +17,8 @@ export const Dashboard = (req, res) => {
res.render("dashboard", {
name: name,
avatar: avatar,
role: role
role: role,
alert: ''
});
}

View File

@ -50,7 +50,8 @@ export const Images = async function(req, res) {
role: req.session.role,
avatar: req.session.avatar,
image_list: image_list,
image_count: images.length
image_count: images.length,
alert: '',
});
}

View File

@ -43,7 +43,8 @@ export const Networks = async function(req, res) {
role: req.session.role,
avatar: req.session.avatar,
network_list: network_list,
network_count: networks.length
network_count: networks.length,
alert: '',
});
}

View File

@ -24,20 +24,21 @@ export const Portal = (req, res) => {
async function CardList () {
let name = req.session.user;
let containers = await Permission.findAll({ attributes: ['containerName'], where: { user: name }});
// for (let i = 0; i < containers.length; i++) {
// let details = await containerInfo(containers[i].containerName);
// let card = await createCard(details);
// cardList += card;
// }
for (let i = 0; i < containers.length; i++) {
console.log(containers[i].containerName);
let details = await containerInfo(containers[i].containerName);
let card = await createCard(details);
cardList += card;
}
// for (let i = 0; i < containers.length; i++) {
// console.log(containers[i].containerName);
// }
}
export const UserContainers = async (req, res) => {
let cardList = '';
let name = req.session.user;
let containers = await Permission.findAll({ attributes: ['containerName'], where: { user: name }});

View File

@ -5,5 +5,6 @@ export const Settings = (req, res) => {
name: req.session.user,
role: req.session.role,
avatar: req.session.avatar,
alert: '',
});
}

View File

@ -13,6 +13,7 @@ export const Supporters = async (req, res) => {
email: user.email,
role: user.role,
avatar: user.avatar,
alert: '',
});

View File

@ -30,7 +30,8 @@ export const Syslogs = async function(req, res) {
name: req.session.user || 'Dev',
role: req.session.role || 'Dev',
avatar: req.session.avatar || '<img src="/img/avatars/rus.jpg">',
logs: logs
logs: logs,
alert: '',
});
}

View File

@ -44,7 +44,7 @@ export const Users = async (req, res) => {
<td>${account.role}</td>
<td>${account.lastLogin}</td>
<td>${active}</td>
<td><a href="#" class="btn">Edit</a></td>
<td><a href="#" class="btn">View</a></td>
</tr>`
user_list += info;

View File

@ -64,7 +64,8 @@ export const Volumes = async function(req, res) {
role: req.session.role,
avatar: req.session.avatar,
volume_list: volume_list,
volume_count: volumes.length
volume_count: volumes.length,
alert: '',
});
}

127
package-lock.json generated
View File

@ -17,6 +17,7 @@
"express-session": "^1.18.0",
"js-yaml": "^4.1.0",
"memorystore": "^1.6.7",
"multer": "^1.4.5-lts.1",
"sequelize": "^6.37.1",
"sqlite3": "^5.1.7",
"systeminformation": "^5.22.6"
@ -186,6 +187,11 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
@ -357,6 +363,11 @@
"ieee754": "^1.1.13"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/buildcheck": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz",
@ -366,6 +377,17 @@
"node": ">=10.0.0"
}
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -500,6 +522,47 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"engines": [
"node >= 0.8"
],
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"node_modules/concat-stream/node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/concat-stream/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/concat-stream/node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@ -537,6 +600,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cpu-features": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.9.tgz",
@ -1313,6 +1381,11 @@
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
"optional": true
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -1665,6 +1738,34 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/multer": {
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/multer/node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/nan": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz",
@ -1924,6 +2025,11 @@
"node": ">=10"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@ -2454,6 +2560,14 @@
"node": ">= 0.8"
}
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -2636,6 +2750,11 @@
"node": ">= 0.6"
}
},
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"node_modules/uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
@ -2765,6 +2884,14 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"engines": {
"node": ">=0.4"
}
},
"node_modules/yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",

View File

@ -20,6 +20,7 @@
"express-session": "^1.18.0",
"js-yaml": "^4.1.0",
"memorystore": "^1.6.7",
"multer": "^1.4.5-lts.1",
"sequelize": "^6.37.1",
"sqlite3": "^5.1.7",
"systeminformation": "^5.22.6"

View File

@ -6036,7 +6036,7 @@ fieldset:disabled .btn {
color: var(--tblr-alert-color);
background-color: var(--tblr-alert-bg);
border: var(--tblr-alert-border);
border-radius: var(--tblr-alert-border-radius)
border-radius: var(--tblr-alert-border-radius);
}
.alert-heading {
@ -20221,11 +20221,11 @@ body[data-bs-theme=dark] .hide-theme-dark {
}
.alert {
--tblr-alert-color: var(--tblr-muted);
background: #fff;
--tblr-alert-color: var(--tblr-secondary);
--tblr-alert-bg: var(--tblr-surface);
border: var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);
border-left: .25rem var(--tblr-border-style) var(--tblr-alert-color);
box-shadow: rgba(24, 36, 51, .04) 0 2px 4px 0
border-left: 0.25rem var(--tblr-border-style) var(--tblr-alert-color);
box-shadow: rgba(24, 36, 51, 0.04) 0 2px 4px 0;
}
.alert>:last-child {

View File

@ -7,7 +7,7 @@ export const router = express.Router();
import { Login, submitLogin, Logout } from "../controllers/login.js";
import { Register, submitRegister } from "../controllers/register.js";
import { Dashboard, Logs, Modals, Stats, Chart, SSE, Card, updateCards, Containers, Action, UpdatePermissions } from "../controllers/dashboard.js";
import { Apps, appSearch, InstallModal, ImportModal, LearnMore } from "../controllers/apps.js";
import { Apps, appSearch, InstallModal, ImportModal, LearnMore, Upload } from "../controllers/apps.js";
import { Users } from "../controllers/users.js";
import { Images, removeImage } from "../controllers/images.js";
import { Networks, removeNetwork } from "../controllers/networks.js";
@ -30,34 +30,31 @@ const auth = async (req, res, next) => {
// console.log("Auth: ", user, role, path, trigger, req.path);
if (!user) { res.redirect('/login'); return; }
else if (role == "admin") { next(); return; }
else if (path == "/portal" || path == "/account" || path == "/supporters" || path == "/thank" || path == "/user_containers") { next(); return; }
else { res.redirect('/portal'); return; }
else if (role == 'admin' || path == "/portal" || path == "/account" || path == "/supporters" || path == "/thank" || path == "/user_containers") { next(); return; }
// else { res.redirect('/portal'); return; }
// let action = req.path.split("/")[2];
// else if (trigger == "portal" || "supporters" || "account" || "thank") { res.redirect() return; }
let action = req.path.split("/")[2];
// if (action == "start" || action == "stop" || action == "pause" || action == "restart") {
// let permission = await Permission.findOne({ where: { containerName: trigger, user: user }, attributes: [`${action}`] });
if (action == "start" || action == "stop" || action == "pause" || action == "restart") {
let permission = await Permission.findOne({ where: { containerName: trigger, user: user }, attributes: [`${action}`] });
// if (permission) {
// if (permission[action] == true) {
// console.log(`User ${user} has permission to ${action} ${trigger}`);
// next();
// }
// else {
// console.log(`User ${user} does not have permission to ${action} ${trigger}`);
// }
// } else {
// console.log(`No entry found for ${user} in ${trigger} permissions`);
// }
// }
// else {
// res.redirect('/portal');
// }
if (permission) {
if (permission[action] == true) {
console.log(`User ${user} has permission to ${action} ${trigger}`);
next();
}
else {
console.log(`User ${user} does not have permission to ${action} ${trigger}`);
}
} else {
console.log(`No entry found for ${user} in ${trigger} permissions`);
}
}
else {
res.redirect('/portal');
}
}
@ -93,6 +90,7 @@ router.post("/apps", auth, appSearch);
router.get("/install_modal", auth, InstallModal)
router.get("/import_modal", auth, ImportModal)
router.get("/learn_more", auth, LearnMore)
router.post("/upload", auth, Upload);
router.get("/users", auth, Users);
router.get("/syslogs", auth, Syslogs);

View File

@ -27,38 +27,65 @@
<div class="page-wrapper">
<!-- Page header -->
<div class="mt-3 d-print-none">
<div class="mt-3">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<label class="text-secondary"><%= list_start %> - <%= list_end %> of <%= app_count %> Apps.</label>
</div>
<!-- Page title actions -->
<div class="col-auto ms-auto d-print-none">
<div class="d-flex align-items-center">
<div class="me-2">
<select class="form-select">
<option>Category:</option>
<option>Media</option>
<option>Tools</option>
<option>Gaming</option>
<option>FOSS</option>
<option>Database</option>
</select>
<div class="row row-cards">
<div class="col-md-6 col-lg-3">
<div class="card">
<div class="card-body text-center">
<div class="d-flex align-items-center">
<div class="me-auto"><%= list_start %> - <%= list_end %> of <%= app_count %> Apps</div>
<button class="btn btn-primary" name="Import" id="Import" data-hx-get="/import_modal" data-hx-target="#modals-here" hx-swap="innerHTML" data-hx-trigger="click" data-bs-toggle="modal" data-bs-target="#modals-here">Import</button>
</div>
</div>
<div class="me-2">
<select class="form-select">
<option>Templates.json (default)</option>
<option>Compose</option>
</select>
</div>
<button class="btn btn-primary h-50" name="Import" id="Import" data-hx-get="/import_modal" data-hx-target="#modals-here" hx-swap="innerHTML" data-hx-trigger="click" data-bs-toggle="modal" data-bs-target="#modals-here">Import</button>
<form action="/apps" id="search" name="search" method="POST">
<input type="search" class="form-control" name="search" placeholder="Search apps…" >
</form>
<input type="submit" form="search" class="btn btn-primary h-50" value="Search">
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card">
<div class="card-body text-center">
<div class="d-flex align-items-center">
<select class="form-select">
<option>All</option>
<option>Media</option>
<option>Tools</option>
<option>Gaming</option>
<option>FOSS</option>
<option>Database</option>
</select>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card">
<div class="card-body text-center">
<div class="d-flex align-items-center">
<select class="form-select">
<option>Templates.json (default)</option>
<option>Compose</option>
</select>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card">
<div class="card-body text-center">
<div class="text-secondary d-flex align-items-center">
<form action="/apps" id="search" name="search" method="POST" class="d-flex">
<input type="search" class="form-control me-2" name="search" placeholder="Search apps…" >
<input type="submit" form="search" class="btn btn-primary" value="Search">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -69,7 +96,6 @@
<%- apps_list %>
<!-- HTMX Target-->
<div id="modals-here" class="modal modal-blur fade" style="display: none" aria-hidden="false" tabindex="-1">
<div class="modal-dialog modal-sm modal-dialog-centered modal-dialog-scrollables">

View File

@ -3,18 +3,20 @@
<div class="modal-content">
<div class="modal-body">
<div class="modal-title">Import Template(s)</div>
<div class="text-muted">Templates can be *.json, *.yml, or .yaml</div>
<div class="text-muted">Template(s) can be *.json, *.yml, or *.yaml</div>
<div class="mt-3">
<div class="form-label">Choose file(s)</div>
<input type="file" class="form-control">
<div class="form-label">Choose file(s):</div>
<form method="post" action="/upload" enctype="multipart/form-data" id="upload">
<input type="file" name="files" multiple />
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link link-secondary me-auto" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Upload</button>
<button type="submit" class="btn btn-primary" data-bs-dismiss="modal" form="upload">Upload</button>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
<div class="col-md-6 col-lg-3">
<div class="card">
<div class="card-body p-4 text-center">
<div class="card-body text-center">
<span class="avatar avatar-xlplus mb-3 rounded"><img src='AppLogo' width="144px" height="144px" loading="lazy"/></span>
<h3 class="m-0 mb-1"><a href="#">AppShortName</a></h3>
<div class="text-secondary">AppDesc</div>

View File

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

View File

@ -27,7 +27,7 @@
}
}
</script>
<header class="navbar navbar-expand-md d-print-none">
<header class="navbar navbar-expand-md d-print-none py-0">
<div class="container-xl">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu"
aria-controls="navbar-menu" aria-expanded="false" aria-label="Toggle navigation">
@ -40,13 +40,17 @@
<a href="#">
<img src="/images/dweebui.svg" alt="DweebUI" title="DweebUI" class="navbar-brand-image">
</a>
</h1>
<% if(alert) { %>
<%- alert %>
<% } %>
<div class="navbar-nav flex-row order-md-last">
<div class="nav-item d-none d-md-flex me-3">
<!-- <div class="btn-list">
<a href="#" class="btn text-green">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-lock" 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 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6z"></path> <path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path> <path d="M8 11v-4a4 4 0 1 1 8 0v4"></path> </svg>