Dashboard cards are now html components.
This commit is contained in:
parent
0596793c89
commit
cfe9660ac2
7 changed files with 151 additions and 34 deletions
|
@ -1,7 +1,7 @@
|
|||
# DweebUI
|
||||
DweebUI is a web interface for managing Docker, with a zero-config dashboard for controlling and monitoring your containers.
|
||||
|
||||
Alpha v0.40 ( :fire: Experimental :fire: )
|
||||
Alpha v0.50 ( :fire: Experimental :fire: )
|
||||
|
||||
|
||||
[:warning: DweebUI is a management interface and should not be directly exposed to the internet :warning:](https://github.com/lllllllillllllillll/DweebUI/wiki/Exposing-DweebUI-to-the-Internet)
|
||||
|
|
|
@ -4,7 +4,10 @@ import { modal } from '../components/modal.js';
|
|||
import { permissionsModal } from '../components/permissions_modal.js';
|
||||
import { setEvent, cpu, ram, tx, rx, disk, docker } from '../server.js';
|
||||
import { dockerContainerStats } from 'systeminformation';
|
||||
import { containerCard } from '../components/containerCard.js';
|
||||
// import { containerCard } from '../components/containerCard.js';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
let containerCard = readFileSync('./views/components/containerCard.html', 'utf8');
|
||||
|
||||
let [ hidden, cardList ] = [ '', '' ];
|
||||
|
||||
|
@ -200,13 +203,69 @@ async function containerCards() {
|
|||
ports: ports_list,
|
||||
link: 'localhost',
|
||||
}
|
||||
let card = containerCard(container_info);
|
||||
|
||||
let name = container.Names[0].slice(1);
|
||||
let state = container.State;
|
||||
|
||||
let wrapped = name;
|
||||
let disable = "";
|
||||
let chartName = name.replace(/-/g, '');
|
||||
|
||||
// shorten long names
|
||||
if (name.length > 13) { wrapped = name.slice(0, 10) + '...'; }
|
||||
// disable buttons for dweebui
|
||||
if (name.startsWith('dweebui')) { disable = 'disabled=""'; }
|
||||
|
||||
// if ( external_port == undefined ) { external_port = 0; }
|
||||
// if ( internal_port == undefined ) { internal_port = 0; }
|
||||
|
||||
let state_indicator = 'green';
|
||||
if (state == 'exited') {
|
||||
state = 'stopped';
|
||||
state_indicator = 'red';
|
||||
} else if (state == 'paused') {
|
||||
state_indicator = 'orange';
|
||||
}
|
||||
|
||||
let noChart = 'hx-swap="none"';
|
||||
if (state == 'running') { noChart = ''; }
|
||||
|
||||
let ports_data = [];
|
||||
// if (ports) {
|
||||
// ports_data = ports;
|
||||
// } else {
|
||||
// for (let i = 0; i < 12; i++) {
|
||||
|
||||
// let port_check = "checked";
|
||||
// let external = i;
|
||||
// let internal = i;
|
||||
// let protocol = "tcp";
|
||||
|
||||
// ports_data.push({
|
||||
// check: port_check,
|
||||
// external: external,
|
||||
// internal: internal,
|
||||
// protocol: protocol
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
let card = containerCard;
|
||||
card = card.replace(/AppName/g, name);
|
||||
card = card.replace(/AppShortName/g, wrapped);
|
||||
card = card.replace(/ChartName/g, chartName);
|
||||
card = card.replace(/AppIcon/g, service);
|
||||
card = card.replace(/AppState/g, state);
|
||||
card = card.replace(/StateColor/g, state_indicator);
|
||||
list += card;
|
||||
}
|
||||
}
|
||||
cardList = list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export const Containers = async (req, res) => {
|
||||
await getHidden();
|
||||
await containerCards();
|
||||
|
@ -271,28 +330,6 @@ export const Installs = async (req, res) => {
|
|||
let name = req.header('hx-trigger-name');
|
||||
let all_containers = '';
|
||||
|
||||
await docker.listContainers({ all: true }).then(containers => {
|
||||
containers.forEach(container => {
|
||||
if (container.Names[0].slice(1) == name) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
let install_info = {
|
||||
name: name,
|
||||
service: 'Service Name',
|
||||
id: '',
|
||||
state: '',
|
||||
image: '',
|
||||
external_port: 0,
|
||||
internal_port: 0,
|
||||
ports: '',
|
||||
link: 'localhost',
|
||||
}
|
||||
let card = containerCard(install_info);
|
||||
res.send(card);
|
||||
|
||||
});
|
||||
|
||||
|
||||
res.send('ok');
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@ version: "3.9"
|
|||
services:
|
||||
dweebui:
|
||||
container_name: dweebui
|
||||
image: lllllllillllllillll/dweebui:v0.40
|
||||
image: lllllllillllllillll/dweebui:v0.50
|
||||
environment:
|
||||
PORT: 8000
|
||||
SECRET: MrWiskers
|
||||
|
|
|
@ -88,6 +88,7 @@ router.get('/sse_event', (req, res) => {
|
|||
});
|
||||
});
|
||||
if ((all_containers != sent_list) || (event == true)) {
|
||||
console.log('event triggered');
|
||||
sent_list = all_containers;
|
||||
event = false;
|
||||
res.write(`event: ${eventType}\n`);
|
||||
|
|
80
views/components/containerCard.html
Normal file
80
views/components/containerCard.html
Normal file
|
@ -0,0 +1,80 @@
|
|||
<div class="col-sm-6 col-lg-3 pt-1">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-stamp card-stamp-sm">
|
||||
<img width="100px" src="https://raw.githubusercontent.com/lllllllillllllillll/DweebUI-Icons/main/AppIcon.png" onerror="this.onerror=null;this.src='https://raw.githubusercontent.com/lllllllillllllillll/DweebUI-Icons/main/docker.png';"></img>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader text-yellow">0:0</div>
|
||||
<div class="ms-auto lh-1">
|
||||
<div class="card-actions btn-actions">
|
||||
<div class="card-actions btn-actions">
|
||||
<button class="btn-action" title="Start" data-hx-post="/start" data-hx-trigger="click" data-hx-target="#AppNamestate" name="AppName" id="${state}" ${disable}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-player-play" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 4v16l13 -8z"></path></svg>
|
||||
</button>
|
||||
<button class="btn-action" title="Stop" data-hx-post="/stop" data-hx-trigger="click" data-hx-target="#AppNamestate" name="AppName" id="${state}" ${disable}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-player-stop" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 5m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z"></path></svg>
|
||||
</button>
|
||||
<button class="btn-action" title="Pause" data-hx-post="/pause" data-hx-trigger="click" data-hx-target="#AppNamestate" name="AppName" id="${state}" ${disable}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-player-pause" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M6 5m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z"></path><path d="M14 5m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z"></path></svg>
|
||||
</button>
|
||||
<button class="btn-action" title="Restart" data-hx-post="/restart" data-hx-trigger="click" data-hx-target="#AppNamestate" name="AppName" id="${state}" ${disable}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-reload" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M19.933 13.041a8 8 0 1 1 -9.925 -8.788c3.899 -1 7.935 1.007 9.425 4.747"></path><path d="M20 4v5h-5"></path></svg>
|
||||
</button>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn-action dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="19" r="1"></circle><circle cx="12" cy="5" r="1"></circle></svg>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<button class="dropdown-item text-secondary" name="AppName" data-hx-get="/modal" data-hx-target="#modals-here" data-hx-trigger="click" data-bs-toggle="modal" data-bs-target="#modals-here">Details</button>
|
||||
<button class="dropdown-item text-secondary" name="AppName" id="logs" data-hx-get="/logs" data-hx-target="#logView" data-bs-toggle="modal" data-bs-target="#log_view">Logs</button>
|
||||
<button class="dropdown-item text-secondary" name="AppName" id="edit">Edit</button>
|
||||
<button class="dropdown-item text-primary" name="AppName" id="update" disabled="">Update</button>
|
||||
<button class="dropdown-item text-danger" name="AppName" id="remove" data-bs-toggle="modal" data-bs-target="#AppName_uninstall_modal" href="#">Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn-action dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon-tabler icon-tabler-eye" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /> <path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" /> </svg>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<button class="dropdown-item text-secondary" data-hx-post="/hide" data-hx-trigger="click" data-hx-swap="none" name="AppName" id="hide" value="hide">Hide</button>
|
||||
<button class="dropdown-item text-secondary" data-hx-post="/reset" data-hx-trigger="click" data-hx-swap="none" name="AppName" id="reset" value="reset">Reset View</button>
|
||||
<button class="dropdown-item text-secondary" name="AppName" id="permissions" data-hx-get="/modal" data-hx-target="#modals-here" data-hx-trigger="click" data-bs-toggle="modal" data-bs-target="#modals-here">Permissions</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-baseline">
|
||||
<div class="h1 me-2" title="AppName" style="margin-bottom: 0;">
|
||||
<a href="http://${link}:${external_port}" target="_blank">
|
||||
AppShortName
|
||||
</a>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<label id="AppState">
|
||||
<span class="text-StateColor 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>
|
||||
AppState
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var ChartNamechart = new ApexCharts(document.querySelector("#ChartName_chart"), options);
|
||||
</script>
|
||||
|
||||
<div class="chart-sm">
|
||||
<div id="ChartName_chart" data-hx-trigger="load, every 2s" data-hx-get="/chart" name="ChartName" ${noChart}>
|
||||
<script>
|
||||
ChartNamechart.render();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -143,17 +143,17 @@
|
|||
|
||||
<!-- HTMX -->
|
||||
<div class="col-12">
|
||||
<div class="row row-cards" id="containerCards" data-hx-get="/containers" data-hx-trigger="load, sse:docker" data-hx-swap="innerHTML">
|
||||
<div class="row row-cards" id="containerCards" data-hx-get="/containers" data-hx-trigger="load" data-hx-swap="beforeend">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HTMX -->
|
||||
<!-- <div class="col-12">
|
||||
<div class="row row-cards" data-hx-get="/installs" name="jellyfin" data-hx-trigger="load delay:2s, sse:install" data-hx-swap="beforeend" hx-target="#containerCards">
|
||||
<div class="col-12">
|
||||
<div class="row row-cards" data-hx-get="/installs" data-hx-trigger="" data-hx-swap="beforeend" hx-target="#containerCards">
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- HTMX Target-->
|
||||
<div id="modals-here" class="modal modal-blur fade" style="display: none" aria-hidden="false" tabindex="-1">
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<li class="list-inline-item"><a href="https://github.com/lllllllillllllillll/DweebUI/tree/main" target="_blank" class="link-secondary" rel="noopener">Source code</a></li>
|
||||
<li class="list-inline-item">
|
||||
<a href="https://github.com/lllllllillllllillll/DweebUI/tree/main" target="_blank" class="link-secondary" rel="noopener">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-pink icon-filled icon-inline" 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 d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" /></svg>
|
||||
Sponsor
|
||||
</a>
|
||||
|
@ -24,7 +23,7 @@
|
|||
</li>
|
||||
<li class="list-inline-item">
|
||||
<a href="https://github.com/lllllllillllllillll/DweebUI/releases" class="link-secondary" rel="noopener">
|
||||
v0.40
|
||||
v0.50
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
Loading…
Add table
Reference in a new issue