Improved UI for apps.js and new template import
This commit is contained in:
parent
64ec287286
commit
62b7e73aac
|
@ -13,6 +13,7 @@ export const Account = async (req, res) => {
|
|||
email: user.email,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
alert: '',
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
};
|
|
@ -17,7 +17,8 @@ export const Dashboard = (req, res) => {
|
|||
res.render("dashboard", {
|
||||
name: name,
|
||||
avatar: avatar,
|
||||
role: role
|
||||
role: role,
|
||||
alert: ''
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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: '',
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -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: '',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }});
|
||||
|
||||
|
|
|
@ -5,5 +5,6 @@ export const Settings = (req, res) => {
|
|||
name: req.session.user,
|
||||
role: req.session.role,
|
||||
avatar: req.session.avatar,
|
||||
alert: '',
|
||||
});
|
||||
}
|
|
@ -13,6 +13,7 @@ export const Supporters = async (req, res) => {
|
|||
email: user.email,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
alert: '',
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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: '',
|
||||
});
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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: '',
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue