reduced server.js to 99 lines. bug fixes.
This commit is contained in:
parent
b62e209e6f
commit
eb992f706e
11 changed files with 116 additions and 165 deletions
|
@ -1,4 +1,4 @@
|
||||||
## v0.30 (dev) - Another rewrite
|
## v0.30 (dev) - HTMX rewrite
|
||||||
* Rewrote the dashboard to use HTMX.
|
* Rewrote the dashboard to use HTMX.
|
||||||
* Removed Socket.io.
|
* Removed Socket.io.
|
||||||
* Views are now HTML instead of EJS.
|
* Views are now HTML instead of EJS.
|
||||||
|
@ -11,6 +11,8 @@
|
||||||
* Fixed list.js sorting.
|
* Fixed list.js sorting.
|
||||||
* Removed stackfiles from templates.json and updated some icons.
|
* Removed stackfiles from templates.json and updated some icons.
|
||||||
* New logo.
|
* New logo.
|
||||||
|
* Improved handling of Docker events.
|
||||||
|
* Improved dashboard responsiveness.
|
||||||
|
|
||||||
## v0.20 (Jan 20th 2024) - The rewrite. Jumping all the way to v0.20.
|
## v0.20 (Jan 20th 2024) - The rewrite. Jumping all the way to v0.20.
|
||||||
* Changed to ES6 imports.
|
* Changed to ES6 imports.
|
||||||
|
|
|
@ -93,3 +93,4 @@ Compose setup:
|
||||||
## Supporters
|
## Supporters
|
||||||
|
|
||||||
* MM (Patreon)
|
* MM (Patreon)
|
||||||
|
* PD (Buymeacoffee)
|
|
@ -356,13 +356,6 @@ export const permissionsModal = (data) => {
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<label class="form-check form-switch col">
|
|
||||||
<span class="form-check-label">Reset</span>
|
|
||||||
<input class="form-check-input" type="checkbox">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<button type="button" class="btn btn-danger" data-bs-dismiss="modal" disabled="">Reset</button>
|
<button type="button" class="btn btn-danger" data-bs-dismiss="modal" disabled="">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { setEvent, cpu, ram, tx, rx, disk, docker } from '../server.js';
|
||||||
import { dockerContainerStats } from 'systeminformation';
|
import { dockerContainerStats } from 'systeminformation';
|
||||||
import { containerCard } from '../components/containerCard.js';
|
import { containerCard } from '../components/containerCard.js';
|
||||||
|
|
||||||
let [ hidden, cardList, sentList ] = [ '', '', ''];
|
let [ hidden, cardList ] = [ '', '' ];
|
||||||
|
|
||||||
export const Dashboard = (req, res) => {
|
export const Dashboard = (req, res) => {
|
||||||
res.render("dashboard", {
|
res.render("dashboard", {
|
||||||
|
@ -16,62 +16,6 @@ export const Dashboard = (req, res) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Start = (req, res) => {
|
|
||||||
let name = req.header('hx-trigger-name');
|
|
||||||
let state = req.header('hx-trigger');
|
|
||||||
|
|
||||||
if (state == 'stopped') {
|
|
||||||
var containerName = docker.getContainer(name);
|
|
||||||
containerName.start();
|
|
||||||
} else if (state == 'paused') {
|
|
||||||
var containerName = docker.getContainer(name);
|
|
||||||
containerName.unpause();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.send("ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const Stop = (req, res) => {
|
|
||||||
|
|
||||||
let name = req.header('hx-trigger-name');
|
|
||||||
let state = req.header('hx-trigger');
|
|
||||||
|
|
||||||
if (state != 'stopped') {
|
|
||||||
var containerName = docker.getContainer(name);
|
|
||||||
containerName.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.send("ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Pause = (req, res) => {
|
|
||||||
|
|
||||||
let name = req.header('hx-trigger-name');
|
|
||||||
let state = req.header('hx-trigger');
|
|
||||||
|
|
||||||
if (state == 'running') {
|
|
||||||
var containerName = docker.getContainer(name);
|
|
||||||
containerName.pause();
|
|
||||||
} else if (state == 'paused') {
|
|
||||||
var containerName = docker.getContainer(name);
|
|
||||||
containerName.unpause();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.send("ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Restart = (req, res) => {
|
|
||||||
|
|
||||||
let name = req.header('hx-trigger-name');
|
|
||||||
var containerName = docker.getContainer(name);
|
|
||||||
containerName.restart();
|
|
||||||
|
|
||||||
res.send("ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const Logs = (req, res) => {
|
export const Logs = (req, res) => {
|
||||||
let name = req.header('hx-trigger-name');
|
let name = req.header('hx-trigger-name');
|
||||||
function containerLogs (data) {
|
function containerLogs (data) {
|
||||||
|
@ -101,18 +45,15 @@ export const Logs = (req, res) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Modal = async (req, res) => {
|
export const Modal = async (req, res) => {
|
||||||
let name = req.header('hx-trigger-name');
|
let name = req.header('hx-trigger-name');
|
||||||
let id = req.header('hx-trigger');
|
let id = req.header('hx-trigger');
|
||||||
|
|
||||||
if (id == 'permissions') {
|
if (id == 'permissions') {
|
||||||
let containerPermissions = await Permission.findAll({ where: {containerName: name}});
|
let containerPermissions = await Permission.findAll({ where: {containerName: name}});
|
||||||
let form = permissionsModal();
|
let form = permissionsModal();
|
||||||
res.send(form);
|
res.send(form);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let containerId = docker.getContainer(name);
|
let containerId = docker.getContainer(name);
|
||||||
let containerInfo = await containerId.inspect();
|
let containerInfo = await containerId.inspect();
|
||||||
let ports_list = [];
|
let ports_list = [];
|
||||||
|
@ -127,7 +68,6 @@ export const Modal = async (req, res) => {
|
||||||
ports_list.push(ports);
|
ports_list.push(ports);
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
let external_port = ports_list[0]?.external || 0;
|
let external_port = ports_list[0]?.external || 0;
|
||||||
let internal_port = ports_list[0]?.internal || 0;
|
let internal_port = ports_list[0]?.internal || 0;
|
||||||
|
|
||||||
|
@ -142,7 +82,6 @@ export const Modal = async (req, res) => {
|
||||||
}
|
}
|
||||||
let form = modal(container_info);
|
let form = modal(container_info);
|
||||||
res.send(form);
|
res.send(form);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Stats = async (req, res) => {
|
export const Stats = async (req, res) => {
|
||||||
|
@ -190,8 +129,6 @@ export const Reset = async (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let stats = {};
|
let stats = {};
|
||||||
export const Chart = async (req, res) => {
|
export const Chart = async (req, res) => {
|
||||||
let name = req.header('hx-trigger-name');
|
let name = req.header('hx-trigger-name');
|
||||||
|
@ -219,27 +156,6 @@ export const Chart = async (req, res) => {
|
||||||
res.send(chart);
|
res.send(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const Installing = (req, res) => {
|
|
||||||
|
|
||||||
let install_info = {
|
|
||||||
name: 'App Name',
|
|
||||||
service: '',
|
|
||||||
id: '',
|
|
||||||
state: 'Installing',
|
|
||||||
image: '',
|
|
||||||
external_port: 0,
|
|
||||||
internal_port: 0,
|
|
||||||
ports: '',
|
|
||||||
link: 'localhost',
|
|
||||||
}
|
|
||||||
let card = containerCard(install_info);
|
|
||||||
res.send(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Get hidden containers
|
// Get hidden containers
|
||||||
async function getHidden() {
|
async function getHidden() {
|
||||||
hidden = await Container.findAll({ where: {visibility:false}});
|
hidden = await Container.findAll({ where: {visibility:false}});
|
||||||
|
@ -296,3 +212,46 @@ export const Containers = async (req, res) => {
|
||||||
await containerCards();
|
await containerCards();
|
||||||
res.send(cardList);
|
res.send(cardList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const Start = (req, res) => {
|
||||||
|
let name = req.header('hx-trigger-name');
|
||||||
|
let state = req.header('hx-trigger');
|
||||||
|
if (state == 'stopped') {
|
||||||
|
var containerName = docker.getContainer(name);
|
||||||
|
containerName.start();
|
||||||
|
} else if (state == 'paused') {
|
||||||
|
var containerName = docker.getContainer(name);
|
||||||
|
containerName.unpause();
|
||||||
|
}
|
||||||
|
res.send("ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Stop = (req, res) => {
|
||||||
|
let name = req.header('hx-trigger-name');
|
||||||
|
let state = req.header('hx-trigger');
|
||||||
|
if (state != 'stopped') {
|
||||||
|
var containerName = docker.getContainer(name);
|
||||||
|
containerName.stop();
|
||||||
|
}
|
||||||
|
res.send("ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Pause = (req, res) => {
|
||||||
|
let name = req.header('hx-trigger-name');
|
||||||
|
let state = req.header('hx-trigger');
|
||||||
|
if (state == 'running') {
|
||||||
|
var containerName = docker.getContainer(name);
|
||||||
|
containerName.pause();
|
||||||
|
} else if (state == 'paused') {
|
||||||
|
var containerName = docker.getContainer(name);
|
||||||
|
containerName.unpause();
|
||||||
|
}
|
||||||
|
res.send("ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Restart = (req, res) => {
|
||||||
|
let name = req.header('hx-trigger-name');
|
||||||
|
var containerName = docker.getContainer(name);
|
||||||
|
containerName.restart();
|
||||||
|
res.send("ok");
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ version: "3.9"
|
||||||
services:
|
services:
|
||||||
dweebui:
|
dweebui:
|
||||||
container_name: dweebui
|
container_name: dweebui
|
||||||
image: lllllllillllllillll/dweebui:v0.21-dev
|
image: lllllllillllllillll/dweebui:v0.30-dev
|
||||||
environment:
|
environment:
|
||||||
PORT: 8000
|
PORT: 8000
|
||||||
SECRET: MrWiskers
|
SECRET: MrWiskers
|
||||||
|
|
|
@ -4,7 +4,7 @@ export const router = express.Router();
|
||||||
// Controllers
|
// Controllers
|
||||||
import { Login, submitLogin, Logout } from "../controllers/login.js";
|
import { Login, submitLogin, Logout } from "../controllers/login.js";
|
||||||
import { Register, submitRegister } from "../controllers/register.js";
|
import { Register, submitRegister } from "../controllers/register.js";
|
||||||
import { Dashboard, Start, Stop, Pause, Restart, Logs, Modal, Stats, Hide, Reset, Chart, Installing, Containers } from "../controllers/dashboard.js";
|
import { Dashboard, Start, Stop, Pause, Restart, Logs, Modal, Stats, Hide, Reset, Chart, Containers } from "../controllers/dashboard.js";
|
||||||
import { Apps, appSearch } from "../controllers/apps.js";
|
import { Apps, appSearch } from "../controllers/apps.js";
|
||||||
import { Users } from "../controllers/users.js";
|
import { Users } from "../controllers/users.js";
|
||||||
import { Images, removeImage } from "../controllers/images.js";
|
import { Images, removeImage } from "../controllers/images.js";
|
||||||
|
@ -39,7 +39,6 @@ router.get("/stats", auth, Stats);
|
||||||
router.post("/hide", auth, Hide);
|
router.post("/hide", auth, Hide);
|
||||||
router.post("/reset", auth, Reset);
|
router.post("/reset", auth, Reset);
|
||||||
router.get("/chart", auth, Chart);
|
router.get("/chart", auth, Chart);
|
||||||
router.get("/installing", auth, Installing);
|
|
||||||
|
|
||||||
router.get("/images", auth, Images);
|
router.get("/images", auth, Images);
|
||||||
router.post("/removeImage", auth, removeImage);
|
router.post("/removeImage", auth, removeImage);
|
||||||
|
|
14
server.js
14
server.js
|
@ -13,6 +13,8 @@ export { setEvent, cpu, ram, tx, rx, disk }
|
||||||
const app = express();
|
const app = express();
|
||||||
const MemoryStore = memorystore(session);
|
const MemoryStore = memorystore(session);
|
||||||
const port = process.env.PORT || 8000;
|
const port = process.env.PORT || 8000;
|
||||||
|
let [ cpu, ram, tx, rx, disk ] = [0, 0, 0, 0, 0];
|
||||||
|
let [ event, sse, eventType ] = [false, false, ''];
|
||||||
|
|
||||||
// Session middleware
|
// Session middleware
|
||||||
const sessionMiddleware = session({
|
const sessionMiddleware = session({
|
||||||
|
@ -52,9 +54,6 @@ app.listen(port, async () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let [ cpu, ram, tx, rx, disk ] = [0, 0, 0, 0, 0];
|
|
||||||
let [ event, sse, eventType ] = [false, false, ''];
|
|
||||||
|
|
||||||
function setEvent(value, type) {
|
function setEvent(value, type) {
|
||||||
event = value;
|
event = value;
|
||||||
eventType = type;
|
eventType = type;
|
||||||
|
@ -78,24 +77,19 @@ let serverMetrics = async () => {
|
||||||
}
|
}
|
||||||
setInterval(serverMetrics, 1000);
|
setInterval(serverMetrics, 1000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let sent_list = '';
|
let sent_list = '';
|
||||||
router.get('/sse_event', (req, res) => {
|
router.get('/sse_event', (req, res) => {
|
||||||
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', });
|
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', });
|
||||||
|
|
||||||
let eventCheck = setInterval(async() => {
|
let eventCheck = setInterval(async() => {
|
||||||
let all_containers = '';
|
let all_containers = '';
|
||||||
|
|
||||||
await docker.listContainers({ all: true }).then(containers => {
|
await docker.listContainers({ all: true }).then(containers => {
|
||||||
containers.forEach(container => {
|
containers.forEach(container => {
|
||||||
all_containers += `${container.Names}: ${container.State}\n`;
|
all_containers += `${container.Names}: ${container.State}\n`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (all_containers != sent_list) {
|
if ((all_containers != sent_list) || event) {
|
||||||
sent_list = all_containers;
|
sent_list = all_containers;
|
||||||
setEvent(true, 'docker');
|
res.write(`event: docker\n`);
|
||||||
res.write(`event: ${eventType}\n`);
|
|
||||||
res.write(`data: there was an event!\n\n`);
|
res.write(`data: there was an event!\n\n`);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
|
@ -82,11 +82,11 @@
|
||||||
prev
|
prev
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item"><a class="page-link" href="/apps?page=1">1</a></li>
|
<li class="page-item"><a class="page-link" href="/apps/1">1</a></li>
|
||||||
<li class="page-item"><a class="page-link" href="/apps?page=2">2</a></li>
|
<li class="page-item"><a class="page-link" href="/apps/2">2</a></li>
|
||||||
<li class="page-item"><a class="page-link" href="/apps?page=3">3</a></li>
|
<li class="page-item"><a class="page-link" href="/apps/3">3</a></li>
|
||||||
<li class="page-item"><a class="page-link" href="/apps?page=4">4</a></li>
|
<li class="page-item"><a class="page-link" href="/apps/4">4</a></li>
|
||||||
<li class="page-item"><a class="page-link" href="/apps?page=5">5</a></li>
|
<li class="page-item"><a class="page-link" href="/apps/5">5</a></li>
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="<%- next %>">
|
<a class="page-link" href="<%- next %>">
|
||||||
next <!-- Download SVG icon from http://tabler-icons.io/i/chevron-right -->
|
next <!-- Download SVG icon from http://tabler-icons.io/i/chevron-right -->
|
||||||
|
|
|
@ -145,6 +145,7 @@
|
||||||
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
||||||
<!-- <a href="#" class="dropdown-item">Status</a> -->
|
<!-- <a href="#" class="dropdown-item">Status</a> -->
|
||||||
<a href="/account" class="dropdown-item">Account</a>
|
<a href="/account" class="dropdown-item">Account</a>
|
||||||
|
<a href="/variables" class="dropdown-item">Variables</a>
|
||||||
<!-- <a href="#" class="dropdown-item">Feedback</a> -->
|
<!-- <a href="#" class="dropdown-item">Feedback</a> -->
|
||||||
<a href="/settings" class="dropdown-item">Settings</a>
|
<a href="/settings" class="dropdown-item">Settings</a>
|
||||||
<!-- <div class="dropdown-divider"></div> -->
|
<!-- <div class="dropdown-divider"></div> -->
|
||||||
|
|
|
@ -50,9 +50,9 @@
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
|
||||||
<span type="button" class="avatar avatar-md bg-green-lt" hx-trigger="load, click" hx-post="/thank" hx-target="#count" name="MM" title="Micheal M" style="margin-right: 5px;">mm</span>
|
<span type="button" class="avatar avatar-md bg-green-lt" hx-trigger="load, click" hx-post="/thank" hx-target="#count" name="MM" title="MM" style="margin-right: 5px;">mm</span>
|
||||||
|
|
||||||
<span type="button" class="avatar avatar-md bg-cyan-lt" hx-trigger="click" hx-post="/thank" hx-target="#count" name="PD" title="Peter D" style="margin-right: 5px;">pd</span>
|
<span type="button" class="avatar avatar-md bg-cyan-lt" hx-trigger="click" hx-post="/thank" hx-target="#count" name="PD" title="PD" style="margin-right: 5px;">pd</span>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -44,60 +44,62 @@
|
||||||
<div class="col d-flex flex-column">
|
<div class="col d-flex flex-column">
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="mb-2">Settings</h2>
|
<h2 class="mb-2">Variables</h2>
|
||||||
<p class="text-muted mb-4">Configure server below</p>
|
<p class="text-muted mb-4">Configure default variables below.</p>
|
||||||
|
|
||||||
<div class="row align-items-center">
|
<!-- <div class="row align-items-center">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Match 1</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Match 2</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Default</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Match 1</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Match 2</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Default</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col-md">
|
<div class="row mt-4">
|
||||||
<div class="form-label">Full Name</div>
|
<div class="col-md">
|
||||||
<input type="text" class="form-control" value="" readonly="">
|
<div class="form-label">Match 1</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Match 2</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Default</div>
|
||||||
|
<input type="text" class="form-control" value="" readonly="">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md">
|
|
||||||
<div class="form-label">First Name</div>
|
|
||||||
<input type="text" class="form-control" value="" readonly="">
|
|
||||||
</div>
|
|
||||||
<div class="col-md">
|
|
||||||
<div class="form-label">Last Name</div>
|
|
||||||
<input type="text" class="form-control" value="" readonly="">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mt-4">Email</h3>
|
|
||||||
<p class="card-subtitle">This contact will be shown to others publicly, so choose it carefully.</p>
|
|
||||||
<div>
|
|
||||||
<div class="row g-2">
|
|
||||||
<div class="col-auto">
|
|
||||||
<input type="text" class="form-control w-auto" value="" readonly="">
|
|
||||||
</div>
|
|
||||||
<div class="col-auto">
|
|
||||||
<a href="#" class="btn">Change</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mt-4">Password</h3>
|
|
||||||
<p class="card-subtitle">You can set a permanent password if you don't want to use temporary login codes.</p>
|
|
||||||
<div>
|
|
||||||
<a href="#" class="btn">
|
|
||||||
Set new password
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mt-4">Public profile</h3>
|
|
||||||
<p class="card-subtitle">Making your profile public means that anyone on the Dashkit network will be able to find
|
|
||||||
you.</p>
|
|
||||||
<div>
|
|
||||||
<label class="form-check form-switch form-switch-lg">
|
|
||||||
<input class="form-check-input" type="checkbox" >
|
|
||||||
<span class="form-check-label form-check-label-on">You're currently visible</span>
|
|
||||||
<span class="form-check-label form-check-label-off">You're
|
|
||||||
currently invisible</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue