Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.40 #60

Merged
merged 30 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0f55750
Another big rewrite
lllllllillllllillll Jan 28, 2024
5e45e08
fixed container charts
lllllllillllllillll Jan 29, 2024
f058360
htmx log view
lllllllillllllillll Jan 29, 2024
f94bd91
modal and graph fixes. new supporters page.
lllllllillllllillll Feb 3, 2024
8feb88a
Fixed container stat charts
lllllllillllllillll Feb 4, 2024
883a65f
Added "Thanks" clicker to supporters page
lllllllillllllillll Feb 4, 2024
70ec201
new permissions modal
lllllllillllllillll Feb 6, 2024
1938d7b
updated images, networks, volumes forms
lllllllillllllillll Feb 6, 2024
e786b32
updated dependencies
lllllllillllllillll Feb 6, 2024
377ba6a
working 'remove' on images and networks pages
lllllllillllllillll Feb 7, 2024
13ee350
localized htmx. fixed images/volumes/networks
lllllllillllllillll Feb 8, 2024
71bbb57
checkbox selectAll() fix
lllllllillllllillll Feb 8, 2024
24941d5
updated permissions modal
lllllllillllllillll Feb 8, 2024
95dcedb
fix volumes controller. update templates.json
lllllllillllllillll Feb 9, 2024
003db6d
fixed image,volume,networks form submit.
lllllllillllllillll Feb 10, 2024
04cc1c1
Tweaks to event trigger. Improved Uninstall.
lllllllillllllillll Feb 12, 2024
97481b0
moved routes into dashboard.js
lllllllillllllillll Feb 14, 2024
666f820
Fixed list sort on images, networks, volumes
lllllllillllllillll Feb 17, 2024
a95b042
New logo. Updated dependencies.
lllllllillllllillll Feb 17, 2024
c27f64f
Fixed hide and resetView
lllllllillllllillll Feb 18, 2024
25280ae
Improved dashboard controller and router.
lllllllillllllillll Feb 19, 2024
b62e209
Fixed issue with dashboard and improved event loop
lllllllillllllillll Feb 22, 2024
eb992f7
reduced server.js to 99 lines. bug fixes.
lllllllillllllillll Feb 23, 2024
ea9ead5
updated dependencies: systeminformation. sequelize
lllllllillllllillll Feb 23, 2024
e294ca7
Server metrics styling. Container action indicator
lllllllillllllillll Feb 24, 2024
32c2301
Container cards now display status while waiting
lllllllillllllillll Feb 24, 2024
f97628e
Bumped version to v0.40. Added Podman support.
lllllllillllllillll Feb 25, 2024
d288cdb
updated image to v0.40
lllllllillllllillll Feb 26, 2024
575a689
v0.40 screenshots
lllllllillllllillll Feb 26, 2024
0596793
date of release
lllllllillllllillll Feb 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/db.sqlite
**/node_modules
**/appdata
.gitignore
**/screenshots
11 changes: 3 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
**/node_modules/
**/database.sqlite
**/appdata/
.github
test
.dockerignore
.gitignore
docker-compose.yaml
**/db.sqlite
**/node_modules
**/appdata
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
## v0.40 (Feb 26th 2024) - HTMX rewrite
* Pages rewritten to use HTMX.
* Removed Socket.io.
* Changed view files to *.HTML instead of *.EJS.
* Removed "USER root" from Dockerfile.
* Express sessions configured to use memorystore.
* Improved chart rendering.
* Improvements to container charts.
* Created Variables page.
* Created Supporters page.
* Ability to remove images, volumes, or networks.
* Fixed list.js sorting.
* Fixed apps.js page navigation.
* Removed stackfiles from templates.json and updated some icons.
* New logo.
* Improved handling of Docker events.
* Improved dashboard responsiveness.
* Updated server metrics styles.
* Container cards display pending action.
* Container charts only rendered if container running.
* Created permissions modal.
* Podman support (untested).
* Started a new template for FOSS apps.

## v0.20 (Jan 20th 2024) - The rewrite. Jumping all the way to v0.20.
* Changed to ES6 imports.
* Cleaned up file structure and code layout.
Expand Down
18 changes: 3 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
FROM node:21-alpine

ENV NODE_ENV=production

WORKDIR /app

RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci --omit=dev


USER root

COPY . .

COPY . /app
RUN npm install
EXPOSE 8000

CMD ["node", "server.js"]
CMD node server.js
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.20 ( :fire: Experimental :fire: )
Alpha v0.40 ( :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)
Expand All @@ -10,7 +10,7 @@ Alpha v0.20 ( :fire: Experimental :fire: )
[![GitHub Activity](https://img.shields.io/github/commit-activity/y/lllllllillllllillll/DweebUI)](https://github.com/lllllllillllllillll)
[![Docker Pulls](https://img.shields.io/docker/pulls/lllllllillllllillll/dweebui)](https://hub.docker.com/repository/docker/lllllllillllllillll/dweebui)
[![GitHub License](https://img.shields.io/github/license/lllllllillllllillll/DweebUI)](https://github.com/lllllllillllllillll/DweebUI/blob/main/LICENSE)
[![GitHub License](https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee)](https://www.buymeacoffee.com/lllllllillllllillll)
[![Coffee](https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee)](https://www.buymeacoffee.com/lllllllillllllillll)

* This is a personal project I started to get more familiar with Javascript and Node.js.
* Some UI elements are placeholders and every version may have breaking changes.
Expand All @@ -31,8 +31,9 @@ Alpha v0.20 ( :fire: Experimental :fire: )
* [x] Dashboard provides server metrics, container metrics, and container controls, on a single page.
* [x] View container logs.
* [ ] Update containers (planned).
* [ ] Manage your Docker networks, images, and volumes (in development).
* [x] Manage your Docker networks, images, and volumes.
* [x] Light/Dark Mode.
* [x] Mobile Friendly.
* [x] Easy to install app templates.
* [x] Multi-User built-in.
* [ ] Permissions system (in development).
Expand All @@ -41,6 +42,7 @@ Alpha v0.20 ( :fire: Experimental :fire: )
* [x] Templates.json maintains compatability with Portainer, allowing you to use the template without needing to use DweebUI.
* [x] Automatically persists data in docker volumes if bind mount isn't used.
* [ ] Preset variables (planned).
* [ ] Themes (planned).


## Setup
Expand All @@ -51,17 +53,20 @@ version: "3.9"
services:
dweebui:
container_name: dweebui
image: lllllllillllllillll/dweebui:v0.20
image: lllllllillllllillll/dweebui:v0.40
environment:
NODE_ENV: production
PORT: 8000
SECRET: MrWiskers
restart: unless-stopped
ports:
- 8000:8000
volumes:
- dweebui:/app
# Docker socket
- /var/run/docker.sock:/var/run/docker.sock
# Podman socket
#- /run/podman/podman.sock:/var/run/docker.sock

networks:
- dweebui_net

Expand Down Expand Up @@ -91,4 +96,5 @@ Compose setup:

## Supporters

* MM (Patreon)
* MM (Patreon)
* PD (Buymeacoffee)
99 changes: 64 additions & 35 deletions components/containerCard.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
// export for app.js
export const containerCard = (data) => {

let { name, service, state, external_port, internal_port, ports, link } = data;
let wrapped = name;
let chart = name;
let disable = "";
let chartName = name.replace(/-/g, '');

if (name.length > 13) {
wrapped = name.slice(0, 10) + '...';
}

//disable controls for a docker container depending on its name
let actions = "";
if (name.startsWith('dweebui')) {
actions = 'disabled=""';
}
// 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';
state = 'stopped';
state_indicator = 'red';
} else if (state == 'paused') {
state_indicator = 'orange';
state_indicator = 'orange';
}

let noChart = 'hx-swap="none"';
if (state == 'running') { noChart = ''; }

let ports_data = [];
if (ports) {
ports_data = ports;
Expand All @@ -49,7 +46,7 @@ export const containerCard = (data) => {


return `
<div class="col-sm-6 col-lg-3 deleteme">
<div class="col-sm-6 col-lg-3 pt-1">
<div class="card">
<div class="card-body">
<div class="card-stamp card-stamp-sm">
Expand All @@ -60,38 +57,38 @@ export const containerCard = (data) => {
<div class="ms-auto lh-1">
<div class="card-actions btn-actions">
<div class="card-actions btn-actions">
<button onclick="clicked(this)" name="${name}" value="${state}" id="start" class="btn-action" title="Start" ${actions}><!-- player-play -->
<button class="btn-action" title="Start" data-hx-post="/start" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- player-play -->
<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 onclick="clicked(this)" name="${name}" value="${state}" id="stop" class="btn-action" title="Stop" ${actions}><!-- player-stop -->
<button class="btn-action" title="Stop" data-hx-post="/stop" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- player-stop -->
<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 onclick="clicked(this)" name="${name}" value="${state}" id="pause" class="btn-action" title="Pause" ${actions}><!-- player-pause -->
<button class="btn-action" title="Pause" data-hx-post="/pause" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- player-pause -->
<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 onclick="clicked(this)" name="${name}" value="${state}" id="restart" class="btn-action" title="Restart" ${actions}><!-- reload -->
<button class="btn-action" title="Restart" data-hx-post="/restart" data-hx-trigger="click" data-hx-target="#${name}state" name="${name}" id="${state}" ${disable}><!-- reload -->
<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" onclick="clicked(this)" id="details" data-bs-toggle="modal" data-bs-target="#details_modal" href="#">Details</button>
<button class="dropdown-item text-secondary" onclick="clicked(this)" name="${name}" id="logs" data-bs-toggle="modal" data-bs-target="#log_view" href="#">Logs</button>
<button class="dropdown-item text-secondary" onclick="clicked(this)" name="${name}" id="edit" href="#">Edit</button>
<button class="dropdown-item text-primary" onclick="clicked(this)" name="${name}" id="update" href="#">Update</button>
<button class="dropdown-item text-danger" onclick="clicked(this)" name="${name}" id="remove" data-bs-toggle="modal" data-bs-target="#${name}_uninstall_modal" href="#">Remove</button>
<button class="dropdown-item text-secondary" name="${name}" 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="${name}" 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="${name}" id="edit">Edit</button>
<button class="dropdown-item text-primary" name="${name}" id="update" disabled="">Update</button>
<button class="dropdown-item text-danger" name="${name}" id="remove" data-bs-toggle="modal" data-bs-target="#${name}_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" onclick="clicked(this)" name="${name}" id="hide" value="hide">Hide</button>
<button class="dropdown-item text-secondary" onclick="clicked(this)" name="${name}" id="resetView" value="resetView">Reset View</button>
<button class="dropdown-item text-secondary" onclick="clicked(this)" name="${name}" id="permissions" value="permissions" data-bs-toggle="modal" data-bs-target="#${name}_permissions">Permissions</button>
<button class="dropdown-item text-secondary" data-hx-post="/hide" data-hx-trigger="click" data-hx-swap="none" name="${name}" 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="${name}" id="reset" value="reset">Reset View</button>
<button class="dropdown-item text-secondary" name="${name}" 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>
Expand All @@ -105,13 +102,27 @@ export const containerCard = (data) => {
</a>
</div>
<div class="ms-auto">
<span class="text-${state_indicator} 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>
${state}
</span>
<label id="${name}state">
<span class="text-${state_indicator} 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>
${state}
</span>
</label>
</div>
</div>
<div id="${chart}_chart" class="chart-sm"></div>

<script>
var ${chartName}chart = 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>
${chartName}chart.render();
</script>
</div>

</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -206,18 +217,35 @@ export const containerCard = (data) => {

<div class="mb-2">
<div class="divide-y">

<div class="row">
<div class="col-9">
<div class="d-flex align-items-center">
User:
<select class="form-select ms-2">
<option value="john_doe" selected hidden>John Doe</option>
<option value="john_doe">John Doe</option>
<option value="jane_doe">Jane Doe</option>
</select>
</div>
</div>
</div>

<div class="row">
<div class="col-9">
<label class="row text-start">
<span class="col">Install</span>
<span class="col">
View
</span>
</label>
</div>
<div class="col-3">
<label class="form-check form-check-single form-switch text-end">
<input class="form-check-input" type="checkbox" name="remove_volumes">
<input class="form-check-input" type="checkbox" name="remove_image">
</label>
</div>
</div>

<div class="row">
<div class="col-9">
<label class="row text-start">
Expand All @@ -232,6 +260,7 @@ export const containerCard = (data) => {
</label>
</div>
</div>

<div class="row">
<div class="col-9">
<label class="row text-start">
Expand Down
Loading