Add files via upload
180
app.js
Normal file
|
@ -0,0 +1,180 @@
|
|||
const express = require("express");
|
||||
const session = require("express-session");
|
||||
const redis = require('connect-redis');
|
||||
const { currentLoad, mem, networkStats, fsSize, dockerContainerStats } = require('systeminformation');
|
||||
const app = express();
|
||||
const routes = require("./routes");
|
||||
const PORT = 8000;
|
||||
var Docker = require('dockerode');
|
||||
var docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
const { dashCard } = require('./components/dashCard');
|
||||
|
||||
let DockerContainers, sent_list, clicked, open_ports, ServerMetrics, card_list, external_port, internal_port;
|
||||
|
||||
const redisClient = require('redis').createClient({
|
||||
legacyMode:true
|
||||
});
|
||||
redisClient.connect().catch(console.log);
|
||||
const RedisStore = redis(session);
|
||||
|
||||
const sessionMiddleware = session({
|
||||
store:new RedisStore({client:redisClient}),
|
||||
secret: "keyboard cat",
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie:{
|
||||
secure:false, // Only set to true if you are using HTTPS.
|
||||
httpOnly:false, // Only set to true if you are using HTTPS.
|
||||
maxAge:3600000 * 8// Session max age in milliseconds. 3600000 = 1 hour.
|
||||
}
|
||||
})
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
app.use([
|
||||
express.static("public"),
|
||||
express.json(),
|
||||
express.urlencoded({ extended: true }),
|
||||
sessionMiddleware,
|
||||
routes
|
||||
]);
|
||||
|
||||
const server = app.listen(PORT, async () => {
|
||||
console.log(`App listening on port ${PORT}`);
|
||||
});
|
||||
|
||||
const io = require('socket.io')(server);
|
||||
io.engine.use(sessionMiddleware);
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
|
||||
const user_session = socket.request.session;
|
||||
|
||||
// display client connection info
|
||||
console.log(`${user_session.user} connected from ${socket.handshake.headers.host} ${socket.handshake.address} \n Active Sessions: ${io.engine.clientsCount}`);
|
||||
|
||||
// send list of running docker containers if sent_list contains data
|
||||
if (sent_list != null) { socket.emit('cards', sent_list); }
|
||||
|
||||
// check if an install is in progress
|
||||
if((app.locals.install != '') && (app.locals.install != null)){
|
||||
socket.emit('install', app.locals.install);
|
||||
}
|
||||
|
||||
// send server metrics to client
|
||||
async function Metrics() {
|
||||
Promise.all([currentLoad(), mem(), networkStats(), fsSize()]).then(([cpuUsage, ramUsage, netUsage, diskUsage]) => {
|
||||
let cpu = Math.round(cpuUsage.currentLoad);
|
||||
let ram = Math.round(((ramUsage.active / ramUsage.total) * 100));
|
||||
let tx = netUsage[0].tx_bytes;
|
||||
let rx = netUsage[0].rx_bytes;
|
||||
let disk = diskUsage[0].use;
|
||||
socket.emit('metrics', { cpu, ram, tx, rx, disk });
|
||||
});
|
||||
}
|
||||
|
||||
async function ContainersList() {
|
||||
card_list = '';
|
||||
open_ports = '';
|
||||
external_port;
|
||||
internal_port;
|
||||
|
||||
docker.listContainers({ all: true }, async function (err, data) {
|
||||
for (const container of data) {
|
||||
|
||||
let imageVersion = container.Image.split('/');
|
||||
let dockerService = imageVersion[imageVersion.length - 1].split(":")[0];
|
||||
|
||||
|
||||
let containerId = docker.getContainer(container.Id);
|
||||
let containerInfo = await containerId.inspect();
|
||||
|
||||
// console.log(containerInfo.Name.split('/')[1]);
|
||||
// console.log(container.Image);
|
||||
// console.log(containerInfo.HostConfig.RestartPolicy.Name);
|
||||
|
||||
|
||||
for (const [key, value] of Object.entries(containerInfo.HostConfig.PortBindings)) {
|
||||
console.log(`${value[0].HostPort}:${key}`);
|
||||
external_port = value[0].HostPort;
|
||||
internal_port = key;
|
||||
}
|
||||
|
||||
// console.log('Volumes:');
|
||||
// for (const [key, value] of Object.entries(containerInfo.Mounts)) {
|
||||
// console.log(`${value.Source}: ${value.Destination}: ${value.RW}`);
|
||||
// }
|
||||
|
||||
|
||||
// console.log('Environment Variables:');
|
||||
// for (const [key, value] of Object.entries(containerInfo.Config.Env)) {
|
||||
// console.log(`${key}: ${value}`);
|
||||
// }
|
||||
|
||||
// console.log('Labels:');
|
||||
// for (const [key, value] of Object.entries(containerInfo.Config.Labels)) {
|
||||
// console.log(`${key}: ${value}`);
|
||||
// }
|
||||
|
||||
// dockerContainerStats(container.Id).then((data) => {
|
||||
// console.log(`${container.Names[0].slice(1)} // CPU: ${Math.round(data[0].cpuPercent)} // RAM: ${Math.round(data[0].memPercent)}`);
|
||||
// });
|
||||
|
||||
let dockerCard = dashCard(container.Names[0].slice(1), dockerService, container.Id, container.State, container.Image, external_port, internal_port);
|
||||
// open_ports += `-L ${external_port}:localhost:${external_port} `
|
||||
card_list += dockerCard;
|
||||
}
|
||||
|
||||
// emit card list is it's different from what was sent last time, then clear install local
|
||||
if (sent_list !== card_list) {
|
||||
sent_list = card_list;
|
||||
app.locals.install = '';
|
||||
socket.emit('cards', card_list);
|
||||
console.log('Cards updated');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Starting Metrics');
|
||||
ServerMetrics = setInterval(Metrics, 1000);
|
||||
|
||||
console.log('Starting Containers List');
|
||||
DockerContainers = setInterval(ContainersList, 1000);
|
||||
|
||||
|
||||
socket.on('clicked', (data) => {
|
||||
// Prevent multiple clicks
|
||||
if (clicked == true) { return; } clicked = true;
|
||||
|
||||
console.log(`${socket.request.session.user} wants to: ${data.action} ${data.container}`);
|
||||
|
||||
if (socket.request.session.role == 'admin') {
|
||||
var containerName = docker.getContainer(data.container);
|
||||
|
||||
if ((data.action == 'start') && (data.state == 'stopped')) {
|
||||
containerName.start();
|
||||
} else if ((data.action == 'start') && (data.state == 'paused')) {
|
||||
containerName.unpause();
|
||||
} else if ((data.action == 'stop') && (data.state != 'stopped')) {
|
||||
containerName.stop();
|
||||
} else if ((data.action == 'pause') && (data.state == 'running')) {
|
||||
containerName.pause();
|
||||
} else if ((data.action == 'pause') && (data.state == 'paused')) {
|
||||
containerName.unpause();
|
||||
} else if (data.action == 'restart') {
|
||||
containerName.restart();
|
||||
}
|
||||
} else {
|
||||
console.log('User is not an admin');
|
||||
}
|
||||
clicked = false;
|
||||
});
|
||||
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('Stopping Metrics');
|
||||
clearInterval(ServerMetrics);
|
||||
console.log('Stopping Containers List');
|
||||
clearInterval(DockerContainers);
|
||||
});
|
||||
|
||||
});
|
978
components/appCard.js
Normal file
|
@ -0,0 +1,978 @@
|
|||
function appCard(data) {
|
||||
|
||||
// make data.title lowercase
|
||||
let app_name = data.name || data.title.toLowerCase();
|
||||
let shortened_name = "";
|
||||
let shortened_desc = data.description.slice(0, 60) + "...";
|
||||
let modal = app_name.replaceAll(" ", "-");
|
||||
let form_id = app_name.replaceAll("-", "_");
|
||||
let note = data.note ? data.note.replaceAll(". ", ".\n") : "no notes available";
|
||||
let description = data.description.replaceAll(". ", ".\n") || "no description available";
|
||||
let command = data.command ? data.command : "";
|
||||
let command_check = command ? "checked" : "";
|
||||
|
||||
|
||||
// if data.network is set to host, bridge, or docker set the radio button to checked
|
||||
let net_host, net_bridge, net_docker = '';
|
||||
let net_name = 'AppBridge';
|
||||
|
||||
if (data.network == 'host') {
|
||||
net_host = 'checked';
|
||||
} else if (data.network) {
|
||||
net_bridge = 'checked';
|
||||
net_name = data.network;
|
||||
} else {
|
||||
net_docker = 'checked';
|
||||
}
|
||||
|
||||
|
||||
if (data.title.length > 28) {
|
||||
shortened_name = (data.title).slice(0, 25) + "...";
|
||||
}
|
||||
else {
|
||||
shortened_name = data.title;
|
||||
}
|
||||
|
||||
|
||||
function CatagoryColor(category) {
|
||||
switch (category) {
|
||||
case 'Other':
|
||||
return '<span class="badge bg-blue-lt">Other</span> ';
|
||||
case 'Productivity':
|
||||
return '<span class="badge bg-blue-lt">Productivity</span> ';
|
||||
case 'Tools':
|
||||
return '<span class="badge bg-blue-lt">Tools</span> ';
|
||||
case 'Dashboard':
|
||||
return '<span class="badge bg-blue-lt">Dashboard</span> ';
|
||||
case 'Communication':
|
||||
return '<span class="badge bg-azure-lt">Communication</span> ';
|
||||
case 'CMS':
|
||||
return '<span class="badge bg-azure-lt">CMS</span> ';
|
||||
case 'Monitoring':
|
||||
return '<span class="badge bg-indigo-lt">Monitoring</span> ';
|
||||
case 'LDAP':
|
||||
return '<span class="badge bg-purple-lt">LDAP</span> ';
|
||||
case 'Arr':
|
||||
return '<span class="badge bg-purple-lt">Arr</span> ';
|
||||
case 'Database':
|
||||
return '<span class="badge bg-red-lt">Database</span> ';
|
||||
case 'Paid':
|
||||
return '<span class="badge bg-red-lt" title="This is a paid product or contains paid features.">Paid</span> ';
|
||||
case 'Gaming':
|
||||
return '<span class="badge bg-pink-lt">Gaming</span> ';
|
||||
case 'Finance':
|
||||
return '<span class="badge bg-orange-lt">Finance</span> ';
|
||||
case 'Networking':
|
||||
return '<span class="badge bg-yellow-lt">Networking</span> ';
|
||||
case 'Authentication':
|
||||
return '<span class="badge bg-lime-lt">Authentication</span> ';
|
||||
case 'Development':
|
||||
return '<span class="badge bg-green-lt">Development</span> ';
|
||||
case 'Media Server':
|
||||
return '<span class="badge bg-teal-lt">Media Server</span> ';
|
||||
case 'Downloaders':
|
||||
return '<span class="badge bg-cyan-lt">Downloaders</span> ';
|
||||
default:
|
||||
return ''; // default to other if the category is not recognized
|
||||
}
|
||||
}
|
||||
|
||||
// set data.catagories to 'other' if data.catagories is empty or undefined
|
||||
if (data.categories == null || data.categories == undefined || data.categories == '') {
|
||||
data.categories = ['Other'];
|
||||
}
|
||||
|
||||
let categories = '';
|
||||
|
||||
for (let i = 0; i < data.categories.length; i++) {
|
||||
categories += CatagoryColor(data.categories[i]);
|
||||
}
|
||||
|
||||
if (data.restart_policy == null) {
|
||||
data.restart_policy = 'unless-stopped';
|
||||
}
|
||||
|
||||
let ports_data = [], volumes_data = [], env_data = [], label_data = [];
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
|
||||
// Get port details
|
||||
try {
|
||||
let ports = data.ports[i];
|
||||
let port_check = ports ? "checked" : "";
|
||||
let port_external = ports.split(":")[0] ? ports.split(":")[0] : ports.split("/")[0];
|
||||
let port_internal = ports.split(":")[1] ? ports.split(":")[1].split("/")[0] : ports.split("/")[0];
|
||||
let port_protocol = ports.split("/")[1] ? ports.split("/")[1] : "";
|
||||
|
||||
// remove /tcp or /udp from port_external if it exists
|
||||
if (port_external.includes("/")) {
|
||||
port_external = port_external.split("/")[0];
|
||||
}
|
||||
|
||||
ports_data.push({
|
||||
check: port_check,
|
||||
external: port_external,
|
||||
internal: port_internal,
|
||||
protocol: port_protocol
|
||||
});
|
||||
} catch {
|
||||
ports_data.push({
|
||||
check: "",
|
||||
external: "",
|
||||
internal: "",
|
||||
protocol: ""
|
||||
});
|
||||
}
|
||||
|
||||
// Get volume details
|
||||
try {
|
||||
let volumes = data.volumes[i];
|
||||
let volume_check = volumes ? "checked" : "";
|
||||
let volume_bind = volumes.bind.split(":")[0] ? volumes.bind.split(":")[0] : "";
|
||||
let volume_container = volumes.container.split(":")[0] ? volumes.container.split(":")[0] : "";
|
||||
let volume_readwrite = volumes.container.endsWith(":ro") ? "ro" : "rw";
|
||||
|
||||
volumes_data.push({
|
||||
check: volume_check,
|
||||
bind: volume_bind,
|
||||
container: volume_container,
|
||||
readwrite: volume_readwrite
|
||||
});
|
||||
} catch {
|
||||
volumes_data.push({
|
||||
check: "",
|
||||
bind: "",
|
||||
container: "",
|
||||
readwrite: ""
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Get environment details
|
||||
try {
|
||||
let env = data.env[i];
|
||||
let env_check = env ? "checked" : "";
|
||||
let env_default = env.default ? env.default : "";
|
||||
let env_description = env.description ? env.description : "";
|
||||
let env_label = env.label ? env.label : "";
|
||||
let env_name = env.name ? env.name : "";
|
||||
|
||||
env_data.push({
|
||||
check: env_check,
|
||||
default: env_default,
|
||||
description: env_description,
|
||||
label: env_label,
|
||||
name: env_name
|
||||
});
|
||||
} catch {
|
||||
env_data.push({
|
||||
check: "",
|
||||
default: "",
|
||||
description: "",
|
||||
label: "",
|
||||
name: ""
|
||||
});
|
||||
}
|
||||
|
||||
// Get label details
|
||||
|
||||
try {
|
||||
let label = data.labels[i];
|
||||
let label_check = label ? "checked" : "";
|
||||
let label_name = label.name ? label.name : "";
|
||||
let label_value = label.value ? label.value : "";
|
||||
|
||||
label_data.push({
|
||||
check: label_check,
|
||||
name: label_name,
|
||||
value: label_value
|
||||
});
|
||||
} catch {
|
||||
label_data.push({
|
||||
check: "",
|
||||
name: "",
|
||||
value: ""
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return `
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body p-4 text-center">
|
||||
<span class="avatar avatar-xlplus mb-3 rounded"><img src='${data.logo}' width="144px" height="144px" loading="lazy"></img></span>
|
||||
<h3 class="m-0 mb-1"><a href="#">${shortened_name}</a></h3>
|
||||
<div class="text-secondary">${shortened_desc}</div>
|
||||
<div class="mt-3">
|
||||
${categories}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<a href="#" class="card-btn" data-bs-toggle="modal" data-bs-target="#${modal}-info"><!-- Download SVG icon from http://tabler-icons.io/i/mail -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-article" 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="M3 4m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path> <path d="M7 8h10"></path> <path d="M7 12h10"></path> <path d="M7 16h10"></path></svg>
|
||||
Learn More
|
||||
</a>
|
||||
<a href="#" class="card-btn" data-bs-toggle="modal" data-bs-target="#${modal}-install"><!-- Download SVG icon from http://tabler-icons.io/i/phone -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-bar-to-down" 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="M4 20l16 0"></path> <path d="M12 14l0 -10"></path> <path d="M12 14l4 -4"></path> <path d="M12 14l-4 -4"></path></svg>
|
||||
Install
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal modal-blur fade" id="${modal}-info" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<div class="modal-title">${data.title}</div>
|
||||
<div>${description}</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">Okay</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal modal-blur fade" id="${modal}-install" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Install ${data.title}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<pre class="text-secondary">${note}</pre>
|
||||
|
||||
<form action="/install" name="${form_id}_install" id="${form_id}_install" method="POST">
|
||||
|
||||
<div class="row mb-3 align-items-end">
|
||||
|
||||
<div class="col-lg-6">
|
||||
<label class="form-label">Container Name: </label>
|
||||
<input type="text" class="form-control" name="service_name" value="${app_name}" hidden/>
|
||||
<input type="text" class="form-control" name="name" value="${app_name}"/>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<label class="form-label">Image: </label>
|
||||
<input type="text" class="form-control" name="image" value="${data.image}"/>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<label class="form-label">Restart Policy: </label>
|
||||
<select class="form-select" name="restart_policy">
|
||||
<option value="${data.restart_policy}" selected hidden>${data.restart_policy}</option>
|
||||
<option value="unless-stopped">unless-stopped</option>
|
||||
<option value="on-failure">on-failure</option>
|
||||
<option value="never">never</option>
|
||||
<option value="always">always</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="form-label">Network Mode</label>
|
||||
<div class="form-selectgroup-boxes row mb-3">
|
||||
<div class="col">
|
||||
<label class="form-selectgroup-item">
|
||||
<input type="radio" name="net_mode" value="host" class="form-selectgroup-input" ${net_host}>
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Host Network</span>
|
||||
<span class="d-block text-secondary">Same as host. No isolation. ex.127.0.0.1</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-selectgroup-item">
|
||||
<input type="radio" name="net_mode" value="${net_name}" class="form-selectgroup-input" ${net_bridge}>
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Bridge Network</span>
|
||||
<span class="d-block text-secondary">Containers can communicate using names.</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-selectgroup-item">
|
||||
<input type="radio" name="net_mode" value="docker" class="form-selectgroup-input" ${net_docker}>
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Docker Network</span>
|
||||
<span class="d-block text-secondary">Isolated on the docker network. ex.172.0.34.2</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="accordion" id="${modal}-accordion">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading-1">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-1" aria-expanded="false">
|
||||
Ports
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse-1" class="accordion-collapse collapse" data-bs-parent="#${modal}-accordion">
|
||||
<div class="accordion-body pt-0">
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="port_0_check" type="checkbox" ${ports_data[0].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">External Port</label>
|
||||
<input type="text" class="form-control" name="port_0_external" value="${ports_data[0].external}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Internal Port</label>
|
||||
<input type="text" class="form-control" name="port_0_internal" value="${ports_data[0].internal}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<label class="form-label">Protocol</label>
|
||||
<select class="form-select" name="port_0_protocol">
|
||||
<option value="${ports_data[0].protocol}" selected hidden>${ports_data[0].protocol}</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="port_1_check" type="checkbox" ${ports_data[1].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_1_external" value="${ports_data[1].external}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_1_internal" value="${ports_data[1].internal}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="port_1_protocol">
|
||||
<option value="${ports_data[1].protocol}" selected hidden>${ports_data[1].protocol}</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="port_2_check" type="checkbox" ${ports_data[2].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_2_external" value="${ports_data[2].external}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_2_internal" value="${ports_data[2].internal}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="port_2_protocol">
|
||||
<option value="${ports_data[2].protocol}" selected hidden>${ports_data[2].protocol}</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="port_3_check" type="checkbox" ${ports_data[3].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_3_external" value="${ports_data[3].external}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_3_internal" value="${ports_data[3].internal}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="port_3_protocol">
|
||||
<option value="${ports_data[3].protocol}" selected hidden>${ports_data[3].protocol}</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="port_4_check" type="checkbox" ${ports_data[4].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_4_external" value="${ports_data[4].external}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_4_internal" value="${ports_data[4].internal}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="port_4_protocol">
|
||||
<option value="${ports_data[4].protocol}" selected hidden>${ports_data[4].protocol}</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="port_5_check" type="checkbox" ${ports_data[5].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_5_external" value="${ports_data[5].external}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="port_5_internal" value="${ports_data[5].internal}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="port_5_protocol">
|
||||
<option value="${ports_data[5].protocol}" selected hidden>${ports_data[5].protocol}</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading-2">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-2" aria-expanded="false">
|
||||
Volumes
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse-2" class="accordion-collapse collapse" data-bs-parent="#${modal}-accordion">
|
||||
<div class="accordion-body pt-0">
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="volume_0_check" type="checkbox" ${volumes_data[0].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_0_bind" value="${volumes_data[0].bind}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_0_container" value="${volumes_data[0].container}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="volume_0_readwrite">
|
||||
<option value="${volumes_data[0].readwrite}" selected hidden>${volumes_data[0].readwrite}</option>
|
||||
<option value="rw">rw</option>
|
||||
<option value="ro">ro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="volume_1_check" type="checkbox" ${volumes_data[1].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_1_bind" value="${volumes_data[1].bind}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_1_container" value="${volumes_data[1].container}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="volume_1_readwrite">
|
||||
<option value="${volumes_data[1].readwrite}" selected hidden>${volumes_data[1].readwrite}</option>
|
||||
<option value="rw">rw</option>
|
||||
<option value="ro">ro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="volume_2_check" type="checkbox" ${volumes_data[2].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_2_bind" value="${volumes_data[2].bind}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_2_container" value="${volumes_data[2].container}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="volume_2_readwrite">
|
||||
<option value="${volumes_data[2].readwrite}" selected hidden>${volumes_data[2].readwrite}</option>
|
||||
<option value="rw">rw</option>
|
||||
<option value="ro">ro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="volume_3_check" type="checkbox" ${volumes_data[3].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_3_bind" value="${volumes_data[3].bind}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_3_container" value="${volumes_data[3].container}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="volume_3_readwrite">
|
||||
<option value="${volumes_data[3].readwrite}" selected hidden>${volumes_data[3].readwrite}</option>
|
||||
<option value="rw">rw</option>
|
||||
<option value="ro">ro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="volume_4_check" type="checkbox" ${volumes_data[4].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_4_bind" value="${volumes_data[4].bind}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_4_container" value="${volumes_data[4].container}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="volume_4_readwrite">
|
||||
<option value="${volumes_data[4].readwrite}" selected hidden>${volumes_data[4].readwrite}</option>
|
||||
<option value="rw">rw</option>
|
||||
<option value="ro">ro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="volume_5_check" type="checkbox" ${volumes_data[5].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_5_bind" value="${volumes_data[5].bind}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="volume_5_container" value="${volumes_data[5].container}"/>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<select class="form-select" name="volume_5_readwrite">
|
||||
<option value="${volumes_data[5].readwrite}" selected hidden>${volumes_data[5].readwrite}</option>
|
||||
<option value="rw">rw</option>
|
||||
<option value="ro">ro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading-3">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-3" aria-expanded="false">
|
||||
Environment Variables
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse-3" class="accordion-collapse collapse" data-bs-parent="#${modal}-accordion">
|
||||
<div class="accordion-body pt-0">
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_0_check" ${env_data[0].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Variable</label>
|
||||
<input type="text" class="form-control" name="env_0_name" value="${env_data[0].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Value</label>
|
||||
<input type="text" class="form-control" name="env_0_default" value="${env_data[0].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_1_check" ${env_data[1].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_1_name" value="${env_data[1].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_1_default" value="${env_data[1].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_2_check" ${env_data[2].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_2_name" value="${env_data[2].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_2_default" value="${env_data[2].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_3_check" ${env_data[3].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_3_name" value="${env_data[3].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_3_default" value="${env_data[3].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_4_check" ${env_data[4].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_4_name" value="${env_data[4].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_4_default" value="${env_data[4].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_5_check" ${env_data[5].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_5_name" value="${env_data[5].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_5_default" value="${env_data[5].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_6_check" ${env_data[6].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_6_name" value="${env_data[6].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_6_default" value="${env_data[6].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_7_check" ${env_data[7].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_7_name" value="${env_data[7].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_7_default" value="${env_data[7].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_8_check" ${env_data[8].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_8_name" value="${env_data[8].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_8_default" value="${env_data[8].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_9_check" ${env_data[9].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_9_name" value="${env_data[9].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_9_default" value="${env_data[9].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_10_check" ${env_data[10].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_10_name" value="${env_data[10].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_10_default" value="${env_data[10].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="env_11_check" ${env_data[11].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_11_name" value="${env_data[11].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="env_11_default" value="${env_data[11].default}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading-4">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-4" aria-expanded="false">
|
||||
Labels
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse-4" class="accordion-collapse collapse" data-bs-parent="#${modal}-accordion">
|
||||
<div class="accordion-body pt-0">
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_0_check" ${label_data[0].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Variable</label>
|
||||
<input type="text" class="form-control" name="label_0_name" value="${label_data[0].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Value</label>
|
||||
<input type="text" class="form-control" name="label_0_value" value="${label_data[0].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_1_check" ${label_data[1].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_1_name" value="${label_data[1].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_1_value" value="${label_data[1].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_2_check" ${label_data[2].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_2_name" value="${label_data[2].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_2_value" value="${label_data[2].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_3_check" ${label_data[3].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_3_name" value="${label_data[3].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_3_value" value="${label_data[3].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_4_check" ${label_data[4].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_4_name" value="${label_data[4].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_4_value" value="${label_data[4].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_5_check" ${label_data[5].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_5_name" value="${label_data[5].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_5_value" value="${label_data[5].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_6_check" ${label_data[6].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_6_name" value="${label_data[6].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_6_value" value="${label_data[6].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_7_check" ${label_data[7].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_7_name" value="${label_data[7].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_7_value" value="${label_data[7].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_8_check" ${label_data[8].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_8_name" value="${label_data[8].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_8_value" value="${label_data[8].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_9_check" ${label_data[9].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_9_name" value="${label_data[9].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_9_value" value="${label_data[9].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_10_check" ${label_data[10].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_10_name" value="${label_data[10].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_10_value" value="${label_data[10].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" type="checkbox" name="label_11_check" ${label_data[11].check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_11_name" value="${label_data[11].name}"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" name="label_11_value" value="${label_data[11].value}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading-5">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-5" aria-expanded="false">
|
||||
Extras
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse-5" class="accordion-collapse collapse" data-bs-parent="#${modal}-accordion">
|
||||
<div class="accordion-body pt-0">
|
||||
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="command_check" type="checkbox" ${command_check}>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Command</label>
|
||||
<input type="text" class="form-control" name="command" value="${command}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-end">
|
||||
<div class="col-auto">
|
||||
<input class="form-check-input" name="hwa_check" type="checkbox">
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Nvidia Hardware Acceleration</label>
|
||||
<input type="text" class="form-control" name="command" value="Nvidia"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn me-auto" data-bs-dismiss="modal">Close</button>
|
||||
<input type="submit" form="${form_id}_install" class="btn btn-success" value="Install"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = { appCard };
|
1067
components/dashCard.js
Normal file
18
components/siteCard.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
function siteCard(type, domain, host, port, id) {
|
||||
|
||||
let site = `<tr>`
|
||||
site += `<td><input class="form-check-input m-0 align-middle" name="select${id}" value="${domain}" type="checkbox" aria-label="Select invoice"></td>`
|
||||
site += `<td><span class="text-muted">${id}</span></td>`
|
||||
site += `<td><a href="https://${domain}" class="text-reset" tabindex="-1" target="_blank">${domain}</a></td>`
|
||||
site += `<td>${type}</td>`
|
||||
site += `<td>${host}</td>`
|
||||
site += `<td>${port}</td>`
|
||||
site += `<td><span class="badge bg-success me-1"></span> Enabled</td>`
|
||||
site += `<td><span class="badge bg-success me-1"></span> Enabled</td>`
|
||||
site += `<td class="text-end"><a class="btn" href="#"> Edit </a></td>`
|
||||
site += `</tr>`
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
module.exports = { siteCard };
|
22
controllers/account.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const User = require('../database/UserModel');
|
||||
|
||||
exports.Account = async function(req, res) {
|
||||
if (req.session.user) {
|
||||
// Get the user.
|
||||
let user = await User.findOne({ where: { UUID: req.session.UUID }});
|
||||
// Render the home page
|
||||
res.render("pages/account", {
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
name: user.first_name + ' ' + user.last_name,
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
isLoggedIn: true
|
||||
});
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
151
controllers/app_actions.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
const { writeFileSync, mkdirSync, appendFileSync } = require("fs");
|
||||
const { exec } = require("child_process");
|
||||
const { dashCard } = require('../components/dashCard');
|
||||
|
||||
|
||||
|
||||
exports.Install = async function (req, res) {
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
console.log(req.body);
|
||||
|
||||
let { service_name, name, image, command_check, command, net_mode, restart_policy } = req.body;
|
||||
|
||||
let { port_0_check, port_1_check, port_2_check, port_3_check, port_4_check, port_5_check } = req.body;
|
||||
let { volume_0_check, volume_1_check, volume_2_check, volume_3_check, volume_4_check, volume_5_check } = req.body;
|
||||
let { env_0_check, env_1_check, env_2_check, env_3_check, env_4_check, env_5_check, env_6_check, env_7_check, env_8_check, env_9_check, env_10_check, env_11_check } = req.body;
|
||||
let { label_0_check, label_1_check, label_2_check, label_3_check, label_4_check, label_5_check, label_6_check, label_7_check, label_8_check, label_9_check, label_10_check, label_11_check } = req.body;
|
||||
|
||||
|
||||
let installCard = dashCard(req.body.name, req.body.service_name, '', 'installing', req.body.image, 0, 0);
|
||||
req.app.locals.install = installCard;
|
||||
|
||||
let compose_file = `version: '3'`;
|
||||
compose_file += `\nservices:`
|
||||
compose_file += `\n ${service_name}:`
|
||||
compose_file += `\n container_name: ${name}`;
|
||||
compose_file += `\n image: ${image}`;
|
||||
|
||||
// Command
|
||||
if (command_check == 'on') {
|
||||
compose_file += `\n command: ${command}`
|
||||
}
|
||||
|
||||
// Network mode
|
||||
if (net_mode == 'host') {
|
||||
compose_file += `\n network_mode: 'host'`
|
||||
}
|
||||
else if (net_mode != 'host' && net_mode != 'docker') {
|
||||
compose_file += `\n network_mode: '${net_mode}'`
|
||||
}
|
||||
|
||||
// Restart policy
|
||||
if (restart_policy != '') {
|
||||
compose_file += `\n restart: ${restart_policy}`
|
||||
}
|
||||
|
||||
// Ports
|
||||
if ((port_0_check == 'on' || port_1_check == 'on' || port_2_check == 'on' || port_3_check == 'on' || port_4_check == 'on' || port_5_check == 'on') && (net_mode != 'host')) {
|
||||
compose_file += `\n ports:`
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
if (req.body[`port_${i}_check`] == 'on') {
|
||||
compose_file += `\n - ${req.body[`port_${i}_external`]}:${req.body[`port_${i}_internal`]}/${req.body[`port_${i}_protocol`]}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Volumes
|
||||
if (volume_0_check == 'on' || volume_1_check == 'on' || volume_2_check == 'on' || volume_3_check == 'on' || volume_4_check == 'on' || volume_5_check == 'on') {
|
||||
compose_file += `\n volumes:`
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
if (req.body[`volume_${i}_check`] == 'on') {
|
||||
compose_file += `\n - ${req.body[`volume_${i}_bind`]}:${req.body[`volume_${i}_container`]}:${req.body[`volume_${i}_readwrite`]}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Environment variables
|
||||
if (env_0_check == 'on' || env_1_check == 'on' || env_2_check == 'on' || env_3_check == 'on' || env_4_check == 'on' || env_5_check == 'on' || env_6_check == 'on' || env_7_check == 'on' || env_8_check == 'on' || env_9_check == 'on' || env_10_check == 'on' || env_11_check == 'on') {
|
||||
compose_file += `\n environment:`
|
||||
}
|
||||
for (let i = 0; i < 12; i++) {
|
||||
if (req.body[`env_${i}_check`] == 'on') {
|
||||
compose_file += `\n - ${req.body[`env_${i}_name`]}=${req.body[`env_${i}_default`]}`
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Add labels
|
||||
if (label_0_check == 'on' || label_1_check == 'on' || label_2_check == 'on' || label_3_check == 'on' || label_4_check == 'on' || label_5_check == 'on' || label_6_check == 'on' || label_7_check == 'on' || label_8_check == 'on' || label_9_check == 'on' || label_10_check == 'on' || label_11_check == 'on') {
|
||||
compose_file += `\n labels:`
|
||||
}
|
||||
for (let i = 0; i < 12; i++) {
|
||||
if (req.body[`label_${i}_check`] == 'on') {
|
||||
compose_file += `\n - ${req.body[`label_${i}_name`]}=${req.body[`label_${i}_value`]}`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add hardware acceleration to the docker-compose file if one of the environment variables has the label DRINODE
|
||||
if (env_0_check == 'on' || env_1_check == 'on' || env_2_check == 'on' || env_3_check == 'on' || env_4_check == 'on' || env_5_check == 'on' || env_6_check == 'on' || env_7_check == 'on' || env_8_check == 'on' || env_9_check == 'on' || env_10_check == 'on' || env_11_check == 'on') {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
if (req.body[`env_${i}_check`] == 'on') {
|
||||
if (req.body[`env_${i}_name`] == 'DRINODE') {
|
||||
compose_file += `\n deploy:`
|
||||
compose_file += `\n resources:`
|
||||
compose_file += `\n reservations:`
|
||||
compose_file += `\n devices:`
|
||||
compose_file += `\n - driver: nvidia`
|
||||
compose_file += `\n count: 1`
|
||||
compose_file += `\n capabilities: [gpu]`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
mkdirSync(`./appdata/${name}`, { recursive: true });
|
||||
writeFileSync(`./appdata/${name}/docker-compose.yml`, compose_file, function (err) { console.log(err) });
|
||||
|
||||
exec(`docker compose -f ./appdata/${name}/docker-compose.yml up -d`, (error, stdout, stderr) => {
|
||||
if (error) { console.error(`error: ${error.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
console.log(`stdout:\n${stdout}`);
|
||||
});
|
||||
} catch { console.log('error creating directory or compose file') }
|
||||
|
||||
|
||||
// Redirect to the home page
|
||||
res.redirect("/");
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
exports.Uninstall = async function (req, res) {
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
|
||||
if (req.body.confirm == 'Yes') {
|
||||
exec(`docker compose -f ./appdata/${req.body.service_name}/docker-compose.yml down`, (error, stdout, stderr) => {
|
||||
if (error) { console.error(`error: ${error.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
console.log(`stdout:\n${stdout}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Redirect to the home page
|
||||
res.redirect("/");
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
129
controllers/apps.js
Normal file
|
@ -0,0 +1,129 @@
|
|||
const User = require('../database/UserModel');
|
||||
const { appCard } = require('../components/appCard')
|
||||
const templates_json = require('../templates.json');
|
||||
let templates = templates_json.templates;
|
||||
|
||||
// sort templates alphabetically
|
||||
templates = templates.sort((a, b) => {
|
||||
if (a.name < b.name) {
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
exports.Apps = async function(req, res) {
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
// Get the user.
|
||||
let user = await User.findOne({ where: { UUID: req.session.UUID }});
|
||||
|
||||
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);
|
||||
|
||||
// generate values for prev and next buttons so that i can go back and forth between pages
|
||||
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);
|
||||
}
|
||||
|
||||
let apps_list = '';
|
||||
for (let i = list_start; i < list_end && i < templates.length; i++) {
|
||||
let app_card = appCard(templates[i]);
|
||||
apps_list += app_card;
|
||||
}
|
||||
|
||||
// Render the home page
|
||||
res.render("pages/apps", {
|
||||
name: user.first_name + ' ' + user.last_name,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
isLoggedIn: true,
|
||||
list_start: list_start + 1,
|
||||
list_end: list_end,
|
||||
app_count: templates.length,
|
||||
prev: prev,
|
||||
next: next,
|
||||
apps_list: apps_list
|
||||
});
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
exports.processApps = async function(req, res) {
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
// Get the user.
|
||||
let user = await User.findOne({ where: { UUID: req.session.UUID }});
|
||||
|
||||
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);
|
||||
|
||||
// generate values for prev and next buttons so that i can go back and forth between pages
|
||||
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);
|
||||
}
|
||||
|
||||
let apps_list = '';
|
||||
let search_results = [];
|
||||
|
||||
let search = req.body.search;
|
||||
|
||||
// split value of search into an array of words
|
||||
search = search.split(' ');
|
||||
|
||||
try {console.log(search[0]);} catch (error) {}
|
||||
try {console.log(search[1]);} catch (error) {}
|
||||
try {console.log(search[2]);} catch (error) {}
|
||||
|
||||
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))) {
|
||||
search_results.push(templates[i]);
|
||||
}
|
||||
}
|
||||
// console.log(search_results);
|
||||
}
|
||||
|
||||
searchTemplates(search);
|
||||
|
||||
for (let i = 0; i < search_results.length; i++) {
|
||||
let app_card = appCard(search_results[i]);
|
||||
apps_list += app_card;
|
||||
}
|
||||
|
||||
// Render the home page
|
||||
res.render("pages/apps", {
|
||||
name: user.first_name + ' ' + user.last_name,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
isLoggedIn: true,
|
||||
list_start: list_start + 1,
|
||||
list_end: list_end,
|
||||
app_count: templates.length,
|
||||
prev: prev,
|
||||
next: next,
|
||||
apps_list: apps_list
|
||||
});
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
22
controllers/dashboard.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const User = require('../database/UserModel');
|
||||
|
||||
|
||||
exports.Dashboard = async function (req, res) {
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
// get user data with matching UUID from sqlite database
|
||||
let user = await User.findOne({ where: { UUID: req.session.UUID } });
|
||||
|
||||
// Render the home page
|
||||
res.render("pages/dashboard", {
|
||||
name: user.first_name + ' ' + user.last_name,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
isLoggedIn: true
|
||||
});
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
60
controllers/login.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
const User = require('../database/UserModel');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
|
||||
exports.Login = function(req,res){
|
||||
|
||||
// check whether we have a session
|
||||
if(req.session.user){
|
||||
// Redirect to log out.
|
||||
res.redirect("/logout");
|
||||
}else{
|
||||
// Render the login page.
|
||||
res.render("pages/login",{
|
||||
"error":"",
|
||||
"isLoggedIn": false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
exports.processLogin = async function(req,res){
|
||||
// get the data.
|
||||
let email = req.body.email;
|
||||
let password = req.body.password;
|
||||
// check if we have data.
|
||||
if(email && password){
|
||||
// check if the user exists.
|
||||
let existingUser = await User.findOne({ where: {email:email}});
|
||||
if(existingUser){
|
||||
// compare the password.
|
||||
let match = await bcrypt.compare(password,existingUser.password);
|
||||
if(match){
|
||||
// set the session.
|
||||
req.session.user = existingUser.username;
|
||||
req.session.UUID = existingUser.UUID;
|
||||
req.session.role = existingUser.role;
|
||||
|
||||
// Redirect to the home page.
|
||||
res.redirect("/");
|
||||
}else{
|
||||
// return an error.
|
||||
res.render("pages/login",{
|
||||
"error":"Invalid password",
|
||||
isLoggedIn: false
|
||||
});
|
||||
}
|
||||
}else{
|
||||
// return an error.
|
||||
res.render("pages/login",{
|
||||
"error":"User with that email does not exist.",
|
||||
isLoggedIn:false
|
||||
});
|
||||
}
|
||||
}else{
|
||||
res.status(400);
|
||||
res.render("pages/login",{
|
||||
"error":"Please fill in all the fields.",
|
||||
isLoggedIn:false
|
||||
});
|
||||
}
|
||||
}
|
6
controllers/logout.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
exports.Logout = function(req,res){
|
||||
// clear the session.
|
||||
req.session.destroy();
|
||||
// Redirect to the login page.
|
||||
res.redirect("/login");
|
||||
}
|
85
controllers/register.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
const User = require('../database/UserModel');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
|
||||
exports.Register = function(req,res){
|
||||
// Check whether we have a session
|
||||
if(req.session.user){
|
||||
// Redirect to log out.
|
||||
res.redirect("/logout");
|
||||
} else {
|
||||
// Render the signup page.
|
||||
res.render("pages/register",{
|
||||
"error":"",
|
||||
isLoggedIn:false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
exports.processRegister = async function(req,res){
|
||||
|
||||
// Get the data.
|
||||
let { first_name, last_name, username, email, password, avatar, tos } = req.body;
|
||||
let role = "user";
|
||||
|
||||
// Check the data.
|
||||
if(first_name && last_name && email && password && username && tos){
|
||||
|
||||
// Check if there is an existing user with that username.
|
||||
let existingUser = await User.findOne({ where: {username:username}});
|
||||
|
||||
let adminUser = await User.findOne({ where: {role:"admin"}});
|
||||
|
||||
if(!existingUser){
|
||||
// hash the password.
|
||||
let hashedPassword = bcrypt.hashSync(password,10);
|
||||
|
||||
if(!adminUser){
|
||||
console.log('Creating admin User');
|
||||
role = "admin";
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await User.create({
|
||||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
username: username,
|
||||
email: email,
|
||||
password: hashedPassword,
|
||||
role: role,
|
||||
group: 'all',
|
||||
avatar: `<img src="./static/avatars/${avatar}">`
|
||||
});
|
||||
|
||||
console.log(`Created: ${user.first_name}`);
|
||||
|
||||
// set the session.
|
||||
req.session.user = user.username;
|
||||
req.session.UUID = user.UUID;
|
||||
req.session.role = user.role;
|
||||
// Redirect to the home page.
|
||||
res.redirect("/");
|
||||
}
|
||||
catch (err) {
|
||||
// return an error.
|
||||
res.render("pages/register",{
|
||||
"error":"Something went wrong when creating account.",
|
||||
isLoggedIn:false
|
||||
});
|
||||
}
|
||||
|
||||
}else{
|
||||
// return an error.
|
||||
res.render("pages/register",{
|
||||
"error":"User with that username already exists.",
|
||||
isLoggedIn:false
|
||||
});
|
||||
}
|
||||
}else{
|
||||
// Redirect to the signup page.
|
||||
res.render("pages/register",{
|
||||
"error":"Please fill in all the fields and accept TOS.",
|
||||
isLoggedIn:false
|
||||
});
|
||||
}
|
||||
}
|
21
controllers/settings.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
const User = require('../database/UserModel.js');
|
||||
|
||||
exports.Settings = async function(req, res) {
|
||||
if (req.session.role == "admin") {
|
||||
// Get the user.
|
||||
let user = await User.findOne({ where: { UUID: req.session.UUID }});
|
||||
|
||||
|
||||
|
||||
// Render the home page
|
||||
res.render("pages/settings", {
|
||||
name: user.first_name + ' ' + user.last_name,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
isLoggedIn: true
|
||||
});
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
197
controllers/site_actions.js
Normal file
|
@ -0,0 +1,197 @@
|
|||
const { readFileSync, writeFileSync, appendFileSync, readdirSync } = require('fs');
|
||||
const { execSync } = require("child_process");
|
||||
const { siteCard } = require('../components/siteCard');
|
||||
|
||||
|
||||
exports.AddSite = async function (req, res) {
|
||||
|
||||
let { domain, type, host, port } = req.body;
|
||||
|
||||
if ((req.session.role == "admin") && ( domain && type && host && port)) {
|
||||
|
||||
|
||||
let { domain, type, host, port } = req.body;
|
||||
|
||||
// build caddyfile
|
||||
let caddyfile = `${domain} {`
|
||||
caddyfile += `\n\t${type} ${host}:${port}`
|
||||
caddyfile += `\n\theader {`
|
||||
caddyfile += `\n\t\tStrict-Transport-Security "max-age=31536000; includeSubDomains; preload"`
|
||||
caddyfile += `\n\t}`
|
||||
caddyfile += `\n}`
|
||||
|
||||
// save caddyfile
|
||||
writeFileSync(`/home/docker/caddy/sites/${domain}.Caddyfile`, caddyfile, function (err) { console.log(err) });
|
||||
|
||||
|
||||
// format caddyfile
|
||||
execSync(`docker exec caddy caddy fmt --overwrite /etc/caddy/sites/${domain}.Caddyfile`, (err, stdout, stderr) => {
|
||||
if (err) { console.error(`error: ${err.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
if (stdout) { console.log(`stdout:\n${stdout}`); return; }
|
||||
console.log(`Formatted ${domain}.Caddyfile`)
|
||||
});
|
||||
|
||||
|
||||
let site = siteCard(type, domain, host, port, 0);
|
||||
|
||||
// reload caddy config to enable new site
|
||||
execSync(`docker exec caddy caddy reload --config /etc/caddy/Caddyfile`, (err, stdout, stderr) => {
|
||||
if (err) { console.error(`error: ${err.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
if (stdout) { console.log(`stdout:\n${stdout}`); return; }
|
||||
console.log(`reloaded caddy config`)
|
||||
});
|
||||
|
||||
// append the site to site_list.ejs
|
||||
appendFileSync('./views/partials/site_list.ejs', site, function (err) { console.log(err) });
|
||||
|
||||
res.redirect("/");
|
||||
} else {
|
||||
// Redirect
|
||||
console.log('not admin or missing info')
|
||||
res.redirect("/");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.RemoveSite = async function (req, res) {
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
|
||||
for (const [key, value] of Object.entries(req.body)) {
|
||||
console.log(`${key}: ${value}`);
|
||||
execSync(`rm /home/docker/caddy/sites/${value}.Caddyfile`, (err, stdout, stderr) => {
|
||||
if (err) { console.error(`error: ${err.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
console.log(`removed ${value}.Caddyfile`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// reload caddy config to disable sites
|
||||
try {
|
||||
execSync(`docker exec caddy caddy reload --config /etc/caddy/Caddyfile`, (err, stdout, stderr) => {
|
||||
if (err) { console.error(`error: ${err.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
console.log(`reloaded caddy config`)
|
||||
}); } catch (error) { console.log("No sites to reload") }
|
||||
|
||||
|
||||
console.log('Removed Site(s)')
|
||||
|
||||
res.redirect("/refreshsites");
|
||||
} else {
|
||||
res.redirect("/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
exports.RefreshSites = async function (req, res) {
|
||||
|
||||
let domain, type, host, port;
|
||||
let id = 1;
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
|
||||
// Clear site_list.ejs
|
||||
writeFileSync('./views/partials/site_list.ejs', '', function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('site_list.ejs has been cleared');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// check if /home/docker/caddy/sites/ contains any .json files, then delete them
|
||||
try {
|
||||
let files = readdirSync('/home/docker/caddy/sites/');
|
||||
files.forEach(file => {
|
||||
if (file.includes(".json")) {
|
||||
execSync(`rm /home/docker/caddy/sites/${file}`, (err, stdout, stderr) => {
|
||||
if (err) { console.error(`error: ${err.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
console.log(`removed ${file}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) { console.log("No .json files to delete") }
|
||||
|
||||
// get list of Caddyfiles
|
||||
let sites = readdirSync('/home/docker/caddy/sites/');
|
||||
|
||||
sites.forEach(site_name => {
|
||||
|
||||
// convert the caddyfile of each site to json
|
||||
execSync(`docker exec caddy caddy adapt --config /etc/caddy/sites/${site_name} --pretty >> /home/docker/caddy/sites/${site_name}.json`, (err, stdout, stderr) => {
|
||||
if (err) { console.error(`error: ${err.message}`); return; }
|
||||
if (stderr) { console.error(`stderr: ${stderr}`); return; }
|
||||
console.log(`stdout:\n${stdout}`);
|
||||
});
|
||||
|
||||
// read the json file
|
||||
let site_file = readFileSync(`/home/docker/caddy/sites/${site_name}.json`, 'utf8');
|
||||
|
||||
// fix whitespace and parse the json file
|
||||
site_file = site_file.replace(/ /g, " ");
|
||||
site_file = JSON.parse(site_file);
|
||||
|
||||
// get the domain, type, host, and port from the json file
|
||||
try { domain = site_file.apps.http.servers.srv0.routes[0].match[0].host[0] } catch (error) { console.log("No Domain") }
|
||||
try { type = site_file.apps.http.servers.srv0.routes[0].handle[0].routes[0].handle[1].handler } catch (error) { console.log("No Type") }
|
||||
try { host = site_file.apps.http.servers.srv0.routes[0].handle[0].routes[0].handle[1].upstreams[0].dial.split(":")[0] } catch (error) { console.log("Not Localhost") }
|
||||
try { port = site_file.apps.http.servers.srv0.routes[0].handle[0].routes[0].handle[1].upstreams[0].dial.split(":")[1] } catch (error) { console.log("No Port") }
|
||||
|
||||
// build the site card
|
||||
let site = siteCard(type, domain, host, port, id);
|
||||
|
||||
// append the site card to site_list.ejs
|
||||
appendFileSync('./views/partials/site_list.ejs', site, function (err) { console.log(err) });
|
||||
|
||||
id++;
|
||||
|
||||
});
|
||||
|
||||
res.redirect("/");
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
exports.DisableSite = async function (req, res) {
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
|
||||
console.log(req.body)
|
||||
console.log('Disable Site')
|
||||
|
||||
res.redirect("/");
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.EnableSite = async function (req, res) {
|
||||
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
|
||||
console.log(req.body)
|
||||
console.log('Enable Site')
|
||||
|
||||
res.redirect("/");
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
54
controllers/users.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
const User = require('../database/UserModel');
|
||||
|
||||
exports.Users = async function(req, res) {
|
||||
if (req.session.role == "admin") {
|
||||
|
||||
// Get the user.
|
||||
let user = await User.findOne({ where: { UUID: req.session.UUID }});
|
||||
let user_list = `
|
||||
<tr>
|
||||
<th><input class="form-check-input" type="checkbox"></th>
|
||||
<th>ID</th>
|
||||
<th>Avatar</th>
|
||||
<th>Name</th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>UUID</th>
|
||||
<th>Role</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>`
|
||||
|
||||
let users = await User.findAll();
|
||||
users.forEach((account) => {
|
||||
full_name = account.first_name + ' ' + account.last_name;
|
||||
user_info = `
|
||||
<tr>
|
||||
<td><input class="form-check-input" type="checkbox"></td>
|
||||
<td>${user.id}</td>
|
||||
<td><span class="avatar me-2">${account.avatar}</span></td>
|
||||
<td>${full_name}</td>
|
||||
<td>${account.username}</td>
|
||||
<td>${account.email}</td>
|
||||
<td>${account.UUID}</td>
|
||||
<td>${account.role}</td>
|
||||
<td><span class="badge badge-outline text-green">Active</span></td>
|
||||
<td><a href="#" class="btn">Edit</a></td>
|
||||
</tr>`
|
||||
|
||||
user_list += user_info;
|
||||
});
|
||||
|
||||
// Render the home page
|
||||
res.render("pages/users", {
|
||||
name: user.first_name + ' ' + user.last_name,
|
||||
role: user.role,
|
||||
avatar: user.avatar,
|
||||
isLoggedIn: true,
|
||||
user_list: user_list
|
||||
});
|
||||
} else {
|
||||
// Redirect to the login page
|
||||
res.redirect("/login");
|
||||
}
|
||||
}
|
63
database/UserModel.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
const { Sequelize, DataTypes } = require('sequelize');
|
||||
|
||||
const sequelize = new Sequelize({
|
||||
dialect: 'sqlite',
|
||||
storage: 'database/db.sqlite',
|
||||
logging: false
|
||||
});
|
||||
|
||||
|
||||
const User = sequelize.define('User', {
|
||||
// Model attributes are defined here
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true
|
||||
},
|
||||
first_name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
last_name: {
|
||||
type: DataTypes.STRING
|
||||
// allowNull defaults to true
|
||||
},
|
||||
username: {
|
||||
type: DataTypes.STRING
|
||||
// allowNull defaults to true
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING
|
||||
// allowNull defaults to true
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
// allowNull: false
|
||||
},
|
||||
role: {
|
||||
type: DataTypes.STRING
|
||||
// allowNull defaults to true
|
||||
},
|
||||
group: {
|
||||
type: DataTypes.STRING
|
||||
// allowNull defaults to true
|
||||
},
|
||||
avatar: {
|
||||
type: DataTypes.STRING
|
||||
// allowNull defaults to true
|
||||
},
|
||||
UUID: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4
|
||||
}
|
||||
});
|
||||
|
||||
async function syncModel() {
|
||||
await sequelize.sync();
|
||||
console.log('User model synced');
|
||||
}
|
||||
|
||||
syncModel();
|
||||
|
||||
|
||||
module.exports = User;
|
23
package.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "dweeb-ui",
|
||||
"version": "1.0.0",
|
||||
"main": "app.js",
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.1.0",
|
||||
"child_process": "^1.0.2",
|
||||
"connect-redis": "^6.1.3",
|
||||
"dockerode": "^3.3.5",
|
||||
"ejs": "^3.1.9",
|
||||
"express": "^4.18.2",
|
||||
"express-session": "^1.17.3",
|
||||
"redis": "^4.6.5",
|
||||
"sequelize": "^6.32.1",
|
||||
"socket.io": "^4.6.1",
|
||||
"sqlite3": "^5.1.6",
|
||||
"systeminformation": "^5.17.12"
|
||||
},
|
||||
"description": ""
|
||||
}
|
9
public/css/demo.min.css
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* Tabler v1.0.0-beta19 (https://tabler.io)
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
*/
|
||||
.highlight pre,pre.highlight{max-height:30rem;margin:1.5rem 0;overflow:auto;border-radius:var(--tblr-border-radius)}.highlight pre,pre.highlight{scrollbar-color:rgba(var(--tblr-scrollbar-color,var(--tblr-body-color-rgb)),.16) transparent}.highlight pre::-webkit-scrollbar,pre.highlight::-webkit-scrollbar{width:1rem;height:1rem;-webkit-transition:background .3s;transition:background .3s}@media (prefers-reduced-motion:reduce){.highlight pre::-webkit-scrollbar,pre.highlight::-webkit-scrollbar{-webkit-transition:none;transition:none}}.highlight pre::-webkit-scrollbar-thumb,pre.highlight::-webkit-scrollbar-thumb{border-radius:1rem;border:5px solid transparent;box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color,var(--tblr-body-color-rgb)),.16)}.highlight pre::-webkit-scrollbar-track,pre.highlight::-webkit-scrollbar-track{background:0 0}.highlight pre:hover::-webkit-scrollbar-thumb,pre.highlight:hover::-webkit-scrollbar-thumb{box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color,var(--tblr-body-color-rgb)),.32)}.highlight pre::-webkit-scrollbar-corner,pre.highlight::-webkit-scrollbar-corner{background:0 0}.highlight{margin:0}.highlight code>*{margin:0!important;padding:0!important}.highlight .c,.highlight .c1{color:#a0aec0}.highlight .nc,.highlight .nt,.highlight .nx{color:#ff8383}.highlight .na,.highlight .p{color:#ffe484}.highlight .dl,.highlight .s,.highlight .s2{color:#b5f4a5}.highlight .k{color:#93ddfd}.highlight .mi,.highlight .s1{color:#d9a9ff}.example{padding:2rem;margin:1rem 0 2rem;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:3px 3px 0 0;position:relative;min-height:12rem;display:flex;align-items:center;overflow-x:auto}.example-centered{justify-content:center}.example-centered .example-content{flex:0 auto}.example-content{font-size:.875rem;line-height:1.4285714286;color:var(--tblr-body-color);flex:1;max-width:100%}.example-content .page-header{margin-bottom:0}.example-bg{background:#f6f8fb}.example-code{margin:2rem 0;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-top:none}.example-code pre{margin:0;border:0;border-radius:0 0 3px 3px}.example+.example-code{margin-top:-2rem}.example-column{margin:0 auto}.example-column>.card:last-of-type{margin-bottom:0}.example-column-1{max-width:26rem}.example-column-2{max-width:52rem}.example-modal-backdrop{background:#182433;opacity:.24;position:absolute;width:100%;left:0;top:0;height:100%;border-radius:2px 2px 0 0}.card-sponsor{background:var(--tblr-primary-lt) no-repeat center/100% 100%;border-color:var(--tblr-primary);min-height:316px}.dropdown-menu-demo{display:inline-block;width:100%;position:relative;top:0;margin-bottom:1rem!important}.demo-icon-preview{position:-webkit-sticky;position:sticky;top:0}.demo-icon-preview i,.demo-icon-preview svg{width:15rem;height:15rem;font-size:15rem;stroke-width:1.5;margin:0 auto;display:block}@media (max-width:575.98px){.demo-icon-preview i,.demo-icon-preview svg{width:10rem;height:10rem;font-size:10rem}}.demo-icon-preview-icon pre{margin:0;-webkit-user-select:all;-moz-user-select:all;user-select:all}.demo-dividers>p{opacity:.2;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.demo-icons-list{display:flex;flex-wrap:wrap;padding:0;margin:0 -2px -1px 0;list-style:none}.demo-icons-list>*{flex:1 0 4rem}.demo-icons-list-wrap{overflow:hidden}.demo-icons-list-item{display:flex;flex-direction:column;align-items:center;justify-content:center;aspect-ratio:1;text-align:center;padding:.5rem;border-right:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);color:inherit;cursor:pointer}.demo-icons-list-item .icon{width:1.5rem;height:1.5rem;font-size:1.5rem}.demo-icons-list-item:hover{text-decoration:none}.settings-btn{position:fixed;right:-1px;top:10rem;border-top-right-radius:0;border-bottom-right-radius:0;box-shadow:rgba(var(--tblr-body-color-rgb),.04) 0 2px 4px 0}.settings-scheme{display:inline-block;border-radius:50%;height:3rem;width:3rem;position:relative;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);box-shadow:rgba(var(--tblr-body-color-rgb),.04) 0 2px 4px 0}.settings-scheme-light{background:linear-gradient(135deg,#fff 50%,#fcfdfe 50%)}.settings-scheme-mixed{background-image:linear-gradient(135deg,#182433 50%,#fff 50%)}.settings-scheme-transparent{background:#fcfdfe}.settings-scheme-dark{background:#182433}.settings-scheme-colored{background-image:linear-gradient(135deg,var(--tblr-primary) 50%,#fcfdfe 50%)}
|
120
public/css/meters.css
Normal file
|
@ -0,0 +1,120 @@
|
|||
|
||||
|
||||
.meter {
|
||||
box-sizing: content-box;
|
||||
height: 15px; /* Can be anything */
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
position: relative;
|
||||
background: #a7a7a752;
|
||||
border-radius: 25px;
|
||||
padding: 3px;
|
||||
box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.meter > span {
|
||||
display: block;
|
||||
height: 100%;
|
||||
border-top-right-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
border-top-left-radius: 20px;
|
||||
border-bottom-left-radius: 20px;
|
||||
background-color: rgb(43, 194, 83);
|
||||
background-image: linear-gradient(
|
||||
center bottom,
|
||||
rgb(43, 194, 83) 37%,
|
||||
rgb(84, 240, 84) 69%
|
||||
);
|
||||
box-shadow: inset 0 2px 9px rgba(255, 255, 255, 0.3),
|
||||
inset 0 -2px 6px rgba(0, 0, 0, 0.4);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.meter > span:after,
|
||||
.animate > span > span {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-image: linear-gradient(
|
||||
-45deg,
|
||||
rgba(255, 255, 255, 0.2) 25%,
|
||||
transparent 25%,
|
||||
transparent 50%,
|
||||
rgba(255, 255, 255, 0.2) 50%,
|
||||
rgba(255, 255, 255, 0.2) 75%,
|
||||
transparent 75%,
|
||||
transparent
|
||||
);
|
||||
z-index: 1;
|
||||
background-size: 50px 50px;
|
||||
animation: move 2s linear infinite;
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-top-left-radius: 20px;
|
||||
border-bottom-left-radius: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.animate > span:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 50px 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.orange > span {
|
||||
background-image: linear-gradient(#f1a165, #f36d0a);
|
||||
}
|
||||
|
||||
.red > span {
|
||||
background-image: linear-gradient(#f0a3a3, #f42323);
|
||||
}
|
||||
|
||||
.blue > span {
|
||||
background-image: linear-gradient(#2478f5, #22017e);
|
||||
}
|
||||
|
||||
.nostripes > span > span,
|
||||
.nostripes > span::after {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.border {
|
||||
--tblr-card-spacer-y: 1rem;
|
||||
--tblr-card-spacer-x: 1.5rem;
|
||||
--tblr-card-title-spacer-y: 1.25rem;
|
||||
--tblr-card-border-width: var(--tblr-border-width);
|
||||
--tblr-card-border-color: var(--tblr-border-color);
|
||||
--tblr-card-border-radius: var(--tblr-border-radius);
|
||||
--tblr-card-box-shadow: var(--tblr-shadow-card);
|
||||
--tblr-card-inner-border-radius: calc(var(--tblr-border-radius) - (var(--tblr-border-width)));
|
||||
--tblr-card-cap-padding-y: 1rem;
|
||||
--tblr-card-cap-padding-x: 1.5rem;
|
||||
--tblr-card-cap-bg: var(--tblr-bg-surface-tertiary);
|
||||
--tblr-card-cap-color: inherit;
|
||||
--tblr-card-color: inherit;
|
||||
--tblr-card-bg: var(--tblr-bg-surface);
|
||||
--tblr-card-img-overlay-padding: 1rem;
|
||||
--tblr-card-group-margin: 1.5rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
height: var(--tblr-card-height);
|
||||
word-wrap: break-word;
|
||||
background-color: var(--tblr-card-bg);
|
||||
background-clip: border-box;
|
||||
border: var(--tblr-card-border-width) solid var(--tblr-card-border-color);
|
||||
border-radius: var(--tblr-card-border-radius);
|
||||
|
||||
}
|
28661
public/css/tabler.min.css
vendored
Normal file
35
public/js/demo-theme.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*!
|
||||
* Tabler v1.0.0-beta19 (https://tabler.io)
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
*/
|
||||
(function (factory) {
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
factory();
|
||||
})((function () { 'use strict';
|
||||
|
||||
var themeStorageKey = "tablerTheme";
|
||||
var defaultTheme = "light";
|
||||
var selectedTheme;
|
||||
var params = new Proxy(new URLSearchParams(window.location.search), {
|
||||
get: function get(searchParams, prop) {
|
||||
return searchParams.get(prop);
|
||||
}
|
||||
});
|
||||
if (!!params.theme) {
|
||||
localStorage.setItem(themeStorageKey, params.theme);
|
||||
selectedTheme = params.theme;
|
||||
} else {
|
||||
var storedTheme = localStorage.getItem(themeStorageKey);
|
||||
selectedTheme = storedTheme ? storedTheme : defaultTheme;
|
||||
}
|
||||
if (selectedTheme === 'dark') {
|
||||
document.body.setAttribute("data-bs-theme", selectedTheme);
|
||||
} else {
|
||||
document.body.removeAttribute("data-bs-theme");
|
||||
}
|
||||
|
||||
}));
|
132
public/js/demo.js
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*!
|
||||
* Tabler v1.0.0-beta19 (https://tabler.io)
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
*/
|
||||
(function (factory) {
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
factory();
|
||||
})((function () { 'use strict';
|
||||
|
||||
function _iterableToArrayLimit(arr, i) {
|
||||
var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"];
|
||||
if (null != _i) {
|
||||
var _s,
|
||||
_e,
|
||||
_x,
|
||||
_r,
|
||||
_arr = [],
|
||||
_n = !0,
|
||||
_d = !1;
|
||||
try {
|
||||
if (_x = (_i = _i.call(arr)).next, 0 === i) {
|
||||
if (Object(_i) !== _i) return;
|
||||
_n = !1;
|
||||
} else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0);
|
||||
} catch (err) {
|
||||
_d = !0, _e = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return;
|
||||
} finally {
|
||||
if (_d) throw _e;
|
||||
}
|
||||
}
|
||||
return _arr;
|
||||
}
|
||||
}
|
||||
function _slicedToArray(arr, i) {
|
||||
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
||||
}
|
||||
function _arrayWithHoles(arr) {
|
||||
if (Array.isArray(arr)) return arr;
|
||||
}
|
||||
function _unsupportedIterableToArray(o, minLen) {
|
||||
if (!o) return;
|
||||
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
||||
var n = Object.prototype.toString.call(o).slice(8, -1);
|
||||
if (n === "Object" && o.constructor) n = o.constructor.name;
|
||||
if (n === "Map" || n === "Set") return Array.from(o);
|
||||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
||||
}
|
||||
function _arrayLikeToArray(arr, len) {
|
||||
if (len == null || len > arr.length) len = arr.length;
|
||||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
||||
return arr2;
|
||||
}
|
||||
function _nonIterableRest() {
|
||||
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
}
|
||||
|
||||
var items = {
|
||||
"menu-position": {
|
||||
localStorage: "tablerMenuPosition",
|
||||
default: "top"
|
||||
},
|
||||
"menu-behavior": {
|
||||
localStorage: "tablerMenuBehavior",
|
||||
default: "sticky"
|
||||
},
|
||||
"container-layout": {
|
||||
localStorage: "tablerContainerLayout",
|
||||
default: "boxed"
|
||||
}
|
||||
};
|
||||
var config = {};
|
||||
for (var _i = 0, _Object$entries = Object.entries(items); _i < _Object$entries.length; _i++) {
|
||||
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
||||
key = _Object$entries$_i[0],
|
||||
params = _Object$entries$_i[1];
|
||||
var lsParams = localStorage.getItem(params.localStorage);
|
||||
config[key] = lsParams ? lsParams : params.default;
|
||||
}
|
||||
var parseUrl = function parseUrl() {
|
||||
var search = window.location.search.substring(1);
|
||||
var params = search.split("&");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var arr = params[i].split("=");
|
||||
var _key = arr[0];
|
||||
var value = arr[1];
|
||||
if (!!items[_key]) {
|
||||
localStorage.setItem(items[_key].localStorage, value);
|
||||
config[_key] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
var toggleFormControls = function toggleFormControls(form) {
|
||||
for (var _i2 = 0, _Object$entries2 = Object.entries(items); _i2 < _Object$entries2.length; _i2++) {
|
||||
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
|
||||
_key2 = _Object$entries2$_i[0];
|
||||
_Object$entries2$_i[1];
|
||||
var elem = form.querySelector("[name=\"settings-".concat(_key2, "\"][value=\"").concat(config[_key2], "\"]"));
|
||||
if (elem) {
|
||||
elem.checked = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
var submitForm = function submitForm(form) {
|
||||
for (var _i3 = 0, _Object$entries3 = Object.entries(items); _i3 < _Object$entries3.length; _i3++) {
|
||||
var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
|
||||
_key3 = _Object$entries3$_i[0],
|
||||
_params2 = _Object$entries3$_i[1];
|
||||
var value = form.querySelector("[name=\"settings-".concat(_key3, "\"]:checked")).value;
|
||||
localStorage.setItem(_params2.localStorage, value);
|
||||
config[_key3] = value;
|
||||
}
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
new bootstrap.Offcanvas(form).hide();
|
||||
};
|
||||
parseUrl();
|
||||
var form = document.querySelector("#offcanvasSettings");
|
||||
if (form) {
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
submitForm(form);
|
||||
});
|
||||
toggleFormControls(form);
|
||||
}
|
||||
|
||||
}));
|
9
public/js/demo.min.js
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* Tabler v1.0.0-beta19 (https://tabler.io)
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
*/
|
||||
!function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){"use strict";function t(t,r){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,a,l,i=[],c=!0,u=!1;try{if(a=(r=r.call(t)).next,0===e){if(Object(r)!==r)return;c=!1}else for(;!(c=(n=a.call(r)).done)&&(i.push(n.value),i.length!==e);c=!0);}catch(t){u=!0,o=t}finally{try{if(!c&&null!=r.return&&(l=r.return(),Object(l)!==l))return}finally{if(u)throw o}}return i}}(t,r)||function(t,r){if(!t)return;if("string"==typeof t)return e(t,r);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(t);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return e(t,r)}(t,r)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}for(var r={"menu-position":{localStorage:"tablerMenuPosition",default:"top"},"menu-behavior":{localStorage:"tablerMenuBehavior",default:"sticky"},"container-layout":{localStorage:"tablerContainerLayout",default:"boxed"}},n={},o=0,a=Object.entries(r);o<a.length;o++){var l=t(a[o],2),i=l[0],c=l[1],u=localStorage.getItem(c.localStorage);n[i]=u||c.default}!function(){for(var t=window.location.search.substring(1).split("&"),e=0;e<t.length;e++){var o=t[e].split("="),a=o[0],l=o[1];r[a]&&(localStorage.setItem(r[a].localStorage,l),n[a]=l)}}();var f=document.querySelector("#offcanvasSettings");f&&(f.addEventListener("submit",(function(e){e.preventDefault(),function(e){for(var o=0,a=Object.entries(r);o<a.length;o++){var l=t(a[o],2),i=l[0],c=l[1],u=e.querySelector('[name="settings-'.concat(i,'"]:checked')).value;localStorage.setItem(c.localStorage,u),n[i]=u}window.dispatchEvent(new Event("resize")),new bootstrap.Offcanvas(e).hide()}(f)})),function(e){for(var o=0,a=Object.entries(r);o<a.length;o++){var l=t(a[o],2),i=l[0];l[1];var c=e.querySelector('[name="settings-'.concat(i,'"][value="').concat(n[i],'"]'));c&&(c.checked=!0)}}(f))}));
|
128
public/js/main.js
Normal file
|
@ -0,0 +1,128 @@
|
|||
// SOCKET IO
|
||||
const socket = io({
|
||||
auth: {
|
||||
token: "abc"
|
||||
}
|
||||
});
|
||||
|
||||
// ON CONNECT EVENT
|
||||
socket.on('connect', () => {
|
||||
console.log('Connected');
|
||||
});
|
||||
|
||||
// SELECT METRICS ELEMENTS
|
||||
const cpuText = document.getElementById('cpu-text');
|
||||
const cpuBar = document.getElementById('cpu-bar');
|
||||
const ramText = document.getElementById('ram-text');
|
||||
const ramBar = document.getElementById('ram-bar');
|
||||
const netText = document.getElementById('net-text');
|
||||
const netBar = document.getElementById('net-bar');
|
||||
const diskText = document.getElementById('disk-text');
|
||||
const diskBar = document.getElementById('disk-bar');
|
||||
|
||||
const dockerCards = document.getElementById('cards');
|
||||
|
||||
//Update usage bars
|
||||
socket.on('metrics', ({ cpu, ram, tx, rx, disk}) => {
|
||||
cpuText.innerHTML = `<span>CPU ${cpu} %</span>`;
|
||||
cpuBar.innerHTML = `<span style="width: ${cpu}%"><span></span></span>`;
|
||||
ramText.innerHTML = `<span>RAM ${ram} %</span>`;
|
||||
ramBar.innerHTML = `<span style="width: ${ram}%"><span></span></span>`;
|
||||
diskText.innerHTML = `<span>DISK ${disk} %</span>`;
|
||||
diskBar.innerHTML = `<span style="width: ${disk}%"><span></span></span>`;
|
||||
});
|
||||
|
||||
function drawCharts() {
|
||||
var elements = document.querySelectorAll("#cardChart");
|
||||
|
||||
Array.from(elements).forEach(function(element) {
|
||||
if (window.ApexCharts) {
|
||||
new ApexCharts(element, {
|
||||
chart: {
|
||||
type: "line",
|
||||
fontFamily: 'inherit',
|
||||
height: 40.0,
|
||||
sparkline: {
|
||||
enabled: true
|
||||
},
|
||||
animations: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
fill: {
|
||||
opacity: 1
|
||||
},
|
||||
stroke: {
|
||||
width: [2, 1],
|
||||
dashArray: [0, 3],
|
||||
lineCap: "round",
|
||||
curve: "smooth"
|
||||
},
|
||||
series: [{
|
||||
name: "CPU",
|
||||
data: [37, 35, 44, 28, 36, 24, 65, 31, 37, 39, 62, 51, 35, 41, 35, 27, 93, 53, 61, 27, 54, 43, 4, 46, 39, 62, 51, 35, 41, 67]
|
||||
}, {
|
||||
name: "RAM",
|
||||
data: [93, 54, 51, 24, 35, 35, 31, 67, 19, 43, 28, 36, 62, 61, 27, 39, 35, 41, 27, 35, 51, 46, 62, 37, 44, 53, 41, 65, 39, 37]
|
||||
}],
|
||||
tooltip: {
|
||||
theme: 'dark'
|
||||
},
|
||||
grid: {
|
||||
strokeDashArray: 4
|
||||
},
|
||||
xaxis: {
|
||||
labels: {
|
||||
padding: 0
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
type: 'datetime'
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
padding: 4
|
||||
}
|
||||
},
|
||||
labels: [
|
||||
'2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24', '2020-06-25', '2020-06-26', '2020-06-27', '2020-06-28', '2020-06-29', '2020-06-30', '2020-07-01', '2020-07-02', '2020-07-03', '2020-07-04', '2020-07-05', '2020-07-06', '2020-07-07', '2020-07-08', '2020-07-09', '2020-07-10', '2020-07-11', '2020-07-12', '2020-07-13', '2020-07-14', '2020-07-15', '2020-07-16', '2020-07-17', '2020-07-18', '2020-07-19'
|
||||
],
|
||||
colors: [tabler.getColor("primary"), tabler.getColor("gray-600")],
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
}).render();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buttonAction(button) {
|
||||
|
||||
// if the button name is 'CaddyProxyManager' and the value is 'install' grab the div with the id of 'sites' and remove d-none class. also add the d-none class to the div with the id of 'CaddyInstallCard'
|
||||
if (button.name == 'CaddyProxyManager' && button.value == 'install') {
|
||||
document.getElementById('sites').classList.remove('d-none');
|
||||
document.getElementById('CaddyInstallCard').classList.add('d-none');
|
||||
}
|
||||
|
||||
socket.emit('clicked', {container: button.name, state: button.id, action: button.value});
|
||||
}
|
||||
|
||||
socket.on('cards', (data) => {
|
||||
|
||||
console.log('cards deleted');
|
||||
let deleteMeElements = document.querySelectorAll('.deleteme');
|
||||
deleteMeElements.forEach((element) => {
|
||||
element.parentNode.removeChild(element);
|
||||
});
|
||||
|
||||
dockerCards.insertAdjacentHTML("afterend", data);
|
||||
drawCharts();
|
||||
});
|
||||
|
||||
|
||||
socket.on('install', (data) => {
|
||||
|
||||
console.log('added install card');
|
||||
dockerCards.insertAdjacentHTML("afterend", data);
|
||||
});
|
15
public/js/tabler.min.js
vendored
Normal file
2
public/libs/apexcharts/dist/apexcharts.amd.js
vendored
Normal file
14
public/libs/apexcharts/dist/apexcharts.common.js
vendored
Normal file
581
public/libs/apexcharts/dist/apexcharts.css
vendored
Normal file
|
@ -0,0 +1,581 @@
|
|||
@keyframes opaque {
|
||||
0% {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes resizeanim {
|
||||
0%,to {
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
.apexcharts-canvas {
|
||||
position: relative;
|
||||
user-select: none
|
||||
}
|
||||
|
||||
.apexcharts-canvas ::-webkit-scrollbar {
|
||||
-webkit-appearance: none;
|
||||
width: 6px
|
||||
}
|
||||
|
||||
.apexcharts-canvas ::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0,0,0,.5);
|
||||
box-shadow: 0 0 1px rgba(255,255,255,.5);
|
||||
-webkit-box-shadow: 0 0 1px rgba(255,255,255,.5)
|
||||
}
|
||||
|
||||
.apexcharts-inner {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.apexcharts-text tspan {
|
||||
font-family: inherit
|
||||
}
|
||||
|
||||
.legend-mouseover-inactive {
|
||||
transition: .15s ease all;
|
||||
opacity: .2
|
||||
}
|
||||
|
||||
.apexcharts-legend-text {
|
||||
padding-left: 15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
.apexcharts-series-collapsed {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.apexcharts-tooltip {
|
||||
border-radius: 5px;
|
||||
box-shadow: 2px 2px 6px -4px #999;
|
||||
cursor: default;
|
||||
font-size: 14px;
|
||||
left: 62px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
z-index: 12;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-active {
|
||||
opacity: 1;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-light {
|
||||
border: 1px solid #e3e3e3;
|
||||
background: rgba(255,255,255,.96)
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-dark {
|
||||
color: #fff;
|
||||
background: rgba(30,30,30,.8)
|
||||
}
|
||||
|
||||
.apexcharts-tooltip * {
|
||||
font-family: inherit
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-title {
|
||||
padding: 6px;
|
||||
font-size: 15px;
|
||||
margin-bottom: 4px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {
|
||||
background: #eceff1;
|
||||
border-bottom: 1px solid #ddd
|
||||
}
|
||||
|
||||
.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {
|
||||
background: rgba(0,0,0,.7);
|
||||
border-bottom: 1px solid #333
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-value,.apexcharts-tooltip-text-y-value,.apexcharts-tooltip-text-z-value {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
font-weight: 600
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-label:empty,.apexcharts-tooltip-text-goals-value:empty,.apexcharts-tooltip-text-y-label:empty,.apexcharts-tooltip-text-y-value:empty,.apexcharts-tooltip-text-z-value:empty,.apexcharts-tooltip-title:empty {
|
||||
display: none
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
|
||||
padding: 6px 0 5px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-goals-group,.apexcharts-tooltip-text-goals-label,.apexcharts-tooltip-text-goals-value {
|
||||
display: flex
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-text-goals-label:not(:empty),.apexcharts-tooltip-text-goals-value:not(:empty) {
|
||||
margin-top: -6px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-marker {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group {
|
||||
padding: 0 10px;
|
||||
display: none;
|
||||
text-align: left;
|
||||
justify-content: left;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group.apexcharts-active,.apexcharts-tooltip-series-group:last-child {
|
||||
padding-bottom: 4px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-series-group-hidden {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
line-height: 0;
|
||||
padding: 0!important
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-y-group {
|
||||
padding: 6px 0 5px
|
||||
}
|
||||
|
||||
.apexcharts-custom-tooltip,.apexcharts-tooltip-box {
|
||||
padding: 4px 8px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-boxPlot {
|
||||
display: flex;
|
||||
flex-direction: column-reverse
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-box>div {
|
||||
margin: 4px 0
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-box span.value {
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-rangebar {
|
||||
padding: 5px 8px
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-rangebar .category {
|
||||
font-weight: 600;
|
||||
color: #777
|
||||
}
|
||||
|
||||
.apexcharts-tooltip-rangebar .series-name {
|
||||
font-weight: 700;
|
||||
display: block;
|
||||
margin-bottom: 5px
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip,.apexcharts-yaxistooltip {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
color: #373d3f;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
background: #eceff1;
|
||||
border: 1px solid #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip {
|
||||
padding: 9px 10px;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip.apexcharts-theme-dark {
|
||||
background: rgba(0,0,0,.7);
|
||||
border: 1px solid rgba(0,0,0,.5);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip:after,.apexcharts-xaxistooltip:before {
|
||||
left: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip:after {
|
||||
border-color: transparent;
|
||||
border-width: 6px;
|
||||
margin-left: -6px
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip:before {
|
||||
border-color: transparent;
|
||||
border-width: 7px;
|
||||
margin-left: -7px
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom:after,.apexcharts-xaxistooltip-bottom:before {
|
||||
bottom: 100%
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top:after,.apexcharts-xaxistooltip-top:before {
|
||||
top: 100%
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom:after {
|
||||
border-bottom-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom:before {
|
||||
border-bottom-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:before {
|
||||
border-bottom-color: rgba(0,0,0,.5)
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top:after {
|
||||
border-top-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top:before {
|
||||
border-top-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip-top.apexcharts-theme-dark:after,.apexcharts-xaxistooltip-top.apexcharts-theme-dark:before {
|
||||
border-top-color: rgba(0,0,0,.5)
|
||||
}
|
||||
|
||||
.apexcharts-xaxistooltip.apexcharts-active {
|
||||
opacity: 1;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip {
|
||||
padding: 4px 10px
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip.apexcharts-theme-dark {
|
||||
background: rgba(0,0,0,.7);
|
||||
border: 1px solid rgba(0,0,0,.5);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip:after,.apexcharts-yaxistooltip:before {
|
||||
top: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip:after {
|
||||
border-color: transparent;
|
||||
border-width: 6px;
|
||||
margin-top: -6px
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip:before {
|
||||
border-color: transparent;
|
||||
border-width: 7px;
|
||||
margin-top: -7px
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left:after,.apexcharts-yaxistooltip-left:before {
|
||||
left: 100%
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right:after,.apexcharts-yaxistooltip-right:before {
|
||||
right: 100%
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left:after {
|
||||
border-left-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left:before {
|
||||
border-left-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-left.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-left.apexcharts-theme-dark:before {
|
||||
border-left-color: rgba(0,0,0,.5)
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right:after {
|
||||
border-right-color: #eceff1
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right:before {
|
||||
border-right-color: #90a4ae
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-right.apexcharts-theme-dark:after,.apexcharts-yaxistooltip-right.apexcharts-theme-dark:before {
|
||||
border-right-color: rgba(0,0,0,.5)
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip.apexcharts-active {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.apexcharts-yaxistooltip-hidden {
|
||||
display: none
|
||||
}
|
||||
|
||||
.apexcharts-xcrosshairs,.apexcharts-ycrosshairs {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-xcrosshairs.apexcharts-active,.apexcharts-ycrosshairs.apexcharts-active {
|
||||
opacity: 1;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-ycrosshairs-hidden {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.apexcharts-selection-rect {
|
||||
cursor: move
|
||||
}
|
||||
|
||||
.svg_select_boundingRect,.svg_select_points_rot {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
visibility: hidden
|
||||
}
|
||||
|
||||
.apexcharts-selection-rect+g .svg_select_boundingRect,.apexcharts-selection-rect+g .svg_select_points_rot {
|
||||
opacity: 0;
|
||||
visibility: hidden
|
||||
}
|
||||
|
||||
.apexcharts-selection-rect+g .svg_select_points_l,.apexcharts-selection-rect+g .svg_select_points_r {
|
||||
cursor: ew-resize;
|
||||
opacity: 1;
|
||||
visibility: visible
|
||||
}
|
||||
|
||||
.svg_select_points {
|
||||
fill: #efefef;
|
||||
stroke: #333;
|
||||
rx: 2
|
||||
}
|
||||
|
||||
.apexcharts-svg.apexcharts-zoomable.hovering-zoom {
|
||||
cursor: crosshair
|
||||
}
|
||||
|
||||
.apexcharts-svg.apexcharts-zoomable.hovering-pan {
|
||||
cursor: move
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon,.apexcharts-pan-icon,.apexcharts-reset-icon,.apexcharts-selection-icon,.apexcharts-toolbar-custom-icon,.apexcharts-zoom-icon,.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
color: #6e8192;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon svg,.apexcharts-reset-icon svg,.apexcharts-zoom-icon svg,.apexcharts-zoomin-icon svg,.apexcharts-zoomout-icon svg {
|
||||
fill: #6e8192
|
||||
}
|
||||
|
||||
.apexcharts-selection-icon svg {
|
||||
fill: #444;
|
||||
transform: scale(.76)
|
||||
}
|
||||
|
||||
.apexcharts-theme-dark .apexcharts-menu-icon svg,.apexcharts-theme-dark .apexcharts-pan-icon svg,.apexcharts-theme-dark .apexcharts-reset-icon svg,.apexcharts-theme-dark .apexcharts-selection-icon svg,.apexcharts-theme-dark .apexcharts-toolbar-custom-icon svg,.apexcharts-theme-dark .apexcharts-zoom-icon svg,.apexcharts-theme-dark .apexcharts-zoomin-icon svg,.apexcharts-theme-dark .apexcharts-zoomout-icon svg {
|
||||
fill: #f3f4f5
|
||||
}
|
||||
|
||||
.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected svg,.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected svg {
|
||||
fill: #008ffb
|
||||
}
|
||||
|
||||
.apexcharts-theme-light .apexcharts-menu-icon:hover svg,.apexcharts-theme-light .apexcharts-reset-icon:hover svg,.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover svg,.apexcharts-theme-light .apexcharts-zoomin-icon:hover svg,.apexcharts-theme-light .apexcharts-zoomout-icon:hover svg {
|
||||
fill: #333
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon,.apexcharts-selection-icon {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.apexcharts-reset-icon {
|
||||
margin-left: 5px
|
||||
}
|
||||
|
||||
.apexcharts-menu-icon,.apexcharts-reset-icon,.apexcharts-zoom-icon {
|
||||
transform: scale(.85)
|
||||
}
|
||||
|
||||
.apexcharts-zoomin-icon,.apexcharts-zoomout-icon {
|
||||
transform: scale(.7)
|
||||
}
|
||||
|
||||
.apexcharts-zoomout-icon {
|
||||
margin-right: 3px
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon {
|
||||
transform: scale(.62);
|
||||
position: relative;
|
||||
left: 1px;
|
||||
top: 0
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon svg {
|
||||
fill: #fff;
|
||||
stroke: #6e8192;
|
||||
stroke-width: 2
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon.apexcharts-selected svg {
|
||||
stroke: #008ffb
|
||||
}
|
||||
|
||||
.apexcharts-pan-icon:not(.apexcharts-selected):hover svg {
|
||||
stroke: #333
|
||||
}
|
||||
|
||||
.apexcharts-toolbar {
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
max-width: 176px;
|
||||
text-align: right;
|
||||
border-radius: 3px;
|
||||
padding: 0 6px 2px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.apexcharts-menu {
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
right: 10px;
|
||||
opacity: 0;
|
||||
min-width: 110px;
|
||||
transition: .15s ease all;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-menu.apexcharts-menu-open {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.apexcharts-menu-item {
|
||||
padding: 6px 7px;
|
||||
font-size: 12px;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.apexcharts-theme-light .apexcharts-menu-item:hover {
|
||||
background: #eee
|
||||
}
|
||||
|
||||
.apexcharts-theme-dark .apexcharts-menu {
|
||||
background: rgba(0,0,0,.7);
|
||||
color: #fff
|
||||
}
|
||||
|
||||
@media screen and (min-width:768px) {
|
||||
.apexcharts-canvas:hover .apexcharts-toolbar {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
.apexcharts-canvas .apexcharts-element-hidden,.apexcharts-datalabel.apexcharts-element-hidden,.apexcharts-hide .apexcharts-series-points {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.apexcharts-datalabel,.apexcharts-datalabel-label,.apexcharts-datalabel-value,.apexcharts-datalabels,.apexcharts-pie-label {
|
||||
cursor: default;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-pie-label-delay {
|
||||
opacity: 0;
|
||||
animation-name: opaque;
|
||||
animation-duration: .3s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-timing-function: ease
|
||||
}
|
||||
|
||||
.apexcharts-annotation-rect,.apexcharts-area-series .apexcharts-area,.apexcharts-area-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-gridline,.apexcharts-line,.apexcharts-line-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,.apexcharts-point-annotation-label,.apexcharts-radar-series path,.apexcharts-radar-series polygon,.apexcharts-toolbar svg,.apexcharts-tooltip .apexcharts-marker,.apexcharts-xaxis-annotation-label,.apexcharts-yaxis-annotation-label,.apexcharts-zoom-rect {
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.apexcharts-marker {
|
||||
transition: .15s ease all
|
||||
}
|
||||
|
||||
.resize-triggers {
|
||||
animation: 1ms resizeanim;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.contract-trigger:before,.resize-triggers,.resize-triggers>div {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0
|
||||
}
|
||||
|
||||
.resize-triggers>div {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #eee;
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
.contract-trigger:before {
|
||||
overflow: hidden;
|
||||
width: 200%;
|
||||
height: 200%
|
||||
}
|
14
public/libs/apexcharts/dist/apexcharts.esm.js
vendored
Normal file
14
public/libs/apexcharts/dist/apexcharts.min.js
vendored
Normal file
63
public/libs/apexcharts/dist/locales/ar.json
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "ar",
|
||||
"options": {
|
||||
"months": [
|
||||
"يناير",
|
||||
"فبراير",
|
||||
"مارس",
|
||||
"أبريل",
|
||||
"مايو",
|
||||
"يونيو",
|
||||
"يوليو",
|
||||
"أغسطس",
|
||||
"سبتمبر",
|
||||
"أكتوبر",
|
||||
"نوفمبر",
|
||||
"ديسمبر"
|
||||
],
|
||||
"shortMonths": [
|
||||
"يناير",
|
||||
"فبراير",
|
||||
"مارس",
|
||||
"أبريل",
|
||||
"مايو",
|
||||
"يونيو",
|
||||
"يوليو",
|
||||
"أغسطس",
|
||||
"سبتمبر",
|
||||
"أكتوبر",
|
||||
"نوفمبر",
|
||||
"ديسمبر"
|
||||
],
|
||||
"days": [
|
||||
"الأحد",
|
||||
"الإثنين",
|
||||
"الثلاثاء",
|
||||
"الأربعاء",
|
||||
"الخميس",
|
||||
"الجمعة",
|
||||
"السبت"
|
||||
],
|
||||
"shortDays": [
|
||||
"أحد",
|
||||
"إثنين",
|
||||
"ثلاثاء",
|
||||
"أربعاء",
|
||||
"خميس",
|
||||
"جمعة",
|
||||
"سبت"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "تحميل بصيغة SVG",
|
||||
"exportToPNG": "تحميل بصيغة PNG",
|
||||
"exportToCSV": "تحميل بصيغة CSV",
|
||||
"menu": "القائمة",
|
||||
"selection": "تحديد",
|
||||
"selectionZoom": "تكبير التحديد",
|
||||
"zoomIn": "تكبير",
|
||||
"zoomOut": "تصغير",
|
||||
"pan": "تحريك",
|
||||
"reset": "إعادة التعيين"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/ca.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "ca",
|
||||
"options": {
|
||||
"months": [
|
||||
"Gener",
|
||||
"Febrer",
|
||||
"Març",
|
||||
"Abril",
|
||||
"Maig",
|
||||
"Juny",
|
||||
"Juliol",
|
||||
"Agost",
|
||||
"Setembre",
|
||||
"Octubre",
|
||||
"Novembre",
|
||||
"Desembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Gen.",
|
||||
"Febr.",
|
||||
"Març",
|
||||
"Abr.",
|
||||
"Maig",
|
||||
"Juny",
|
||||
"Jul.",
|
||||
"Ag.",
|
||||
"Set.",
|
||||
"Oct.",
|
||||
"Nov.",
|
||||
"Des."
|
||||
],
|
||||
"days": [
|
||||
"Diumenge",
|
||||
"Dilluns",
|
||||
"Dimarts",
|
||||
"Dimecres",
|
||||
"Dijous",
|
||||
"Divendres",
|
||||
"Dissabte"
|
||||
],
|
||||
"shortDays": ["Dg", "Dl", "Dt", "Dc", "Dj", "Dv", "Ds"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Descarregar SVG",
|
||||
"exportToPNG": "Descarregar PNG",
|
||||
"exportToCSV": "Descarregar CSV",
|
||||
"menu": "Menú",
|
||||
"selection": "Seleccionar",
|
||||
"selectionZoom": "Seleccionar Zoom",
|
||||
"zoomIn": "Augmentar",
|
||||
"zoomOut": "Disminuir",
|
||||
"pan": "Navegació",
|
||||
"reset": "Reiniciar Zoom"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/cs.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "cs",
|
||||
"options": {
|
||||
"months": [
|
||||
"Leden",
|
||||
"Únor",
|
||||
"Březen",
|
||||
"Duben",
|
||||
"Květen",
|
||||
"Červen",
|
||||
"Červenec",
|
||||
"Srpen",
|
||||
"Září",
|
||||
"Říjen",
|
||||
"Listopad",
|
||||
"Prosinec"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Led",
|
||||
"Úno",
|
||||
"Bře",
|
||||
"Dub",
|
||||
"Kvě",
|
||||
"Čvn",
|
||||
"Čvc",
|
||||
"Srp",
|
||||
"Zář",
|
||||
"Říj",
|
||||
"Lis",
|
||||
"Pro"
|
||||
],
|
||||
"days": [
|
||||
"Neděle",
|
||||
"Pondělí",
|
||||
"Úterý",
|
||||
"Středa",
|
||||
"Čtvrtek",
|
||||
"Pátek",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Ne", "Po", "Út", "St", "Čt", "Pá", "So"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Stáhnout SVG",
|
||||
"exportToPNG": "Stáhnout PNG",
|
||||
"exportToCSV": "Stáhnout CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Vybrat",
|
||||
"selectionZoom": "Zoom: Vybrat",
|
||||
"zoomIn": "Zoom: Přiblížit",
|
||||
"zoomOut": "Zoom: Oddálit",
|
||||
"pan": "Přesouvat",
|
||||
"reset": "Resetovat"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/de.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "de",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"März",
|
||||
"April",
|
||||
"Mai",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"August",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Dezember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mär",
|
||||
"Apr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dez"
|
||||
],
|
||||
"days": [
|
||||
"Sonntag",
|
||||
"Montag",
|
||||
"Dienstag",
|
||||
"Mittwoch",
|
||||
"Donnerstag",
|
||||
"Freitag",
|
||||
"Samstag"
|
||||
],
|
||||
"shortDays": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVG speichern",
|
||||
"exportToPNG": "PNG speichern",
|
||||
"exportToCSV": "CSV speichern",
|
||||
"menu": "Menü",
|
||||
"selection": "Auswahl",
|
||||
"selectionZoom": "Auswahl vergrößern",
|
||||
"zoomIn": "Vergrößern",
|
||||
"zoomOut": "Verkleinern",
|
||||
"pan": "Verschieben",
|
||||
"reset": "Zoom zurücksetzen"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/el.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "el",
|
||||
"options": {
|
||||
"months": [
|
||||
"Ιανουάριος",
|
||||
"Φεβρουάριος",
|
||||
"Μάρτιος",
|
||||
"Απρίλιος",
|
||||
"Μάιος",
|
||||
"Ιούνιος",
|
||||
"Ιούλιος",
|
||||
"Αύγουστος",
|
||||
"Σεπτέμβριος",
|
||||
"Οκτώβριος",
|
||||
"Νοέμβριος",
|
||||
"Δεκέμβριος"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Ιαν",
|
||||
"Φευ",
|
||||
"Μαρ",
|
||||
"Απρ",
|
||||
"Μάι",
|
||||
"Ιουν",
|
||||
"Ιουλ",
|
||||
"Αυγ",
|
||||
"Σεπ",
|
||||
"Οκτ",
|
||||
"Νοε",
|
||||
"Δεκ"
|
||||
],
|
||||
"days": [
|
||||
"Κυριακή",
|
||||
"Δευτέρα",
|
||||
"Τρίτη",
|
||||
"Τετάρτη",
|
||||
"Πέμπτη",
|
||||
"Παρασκευή",
|
||||
"Σάββατο"
|
||||
],
|
||||
"shortDays": ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Λήψη SVG",
|
||||
"exportToPNG": "Λήψη PNG",
|
||||
"exportToCSV": "Λήψη CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Επιλογή",
|
||||
"selectionZoom": "Μεγένθυση βάση επιλογής",
|
||||
"zoomIn": "Μεγένθυνση",
|
||||
"zoomOut": "Σμίκρυνση",
|
||||
"pan": "Μετατόπιση",
|
||||
"reset": "Επαναφορά μεγένθυνσης"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/en.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "en",
|
||||
"options": {
|
||||
"months": [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
],
|
||||
"shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Download SVG",
|
||||
"exportToPNG": "Download PNG",
|
||||
"exportToCSV": "Download CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selection",
|
||||
"selectionZoom": "Selection Zoom",
|
||||
"zoomIn": "Zoom In",
|
||||
"zoomOut": "Zoom Out",
|
||||
"pan": "Panning",
|
||||
"reset": "Reset Zoom"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/es.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "es",
|
||||
"options": {
|
||||
"months": [
|
||||
"Enero",
|
||||
"Febrero",
|
||||
"Marzo",
|
||||
"Abril",
|
||||
"Mayo",
|
||||
"Junio",
|
||||
"Julio",
|
||||
"Agosto",
|
||||
"Septiembre",
|
||||
"Octubre",
|
||||
"Noviembre",
|
||||
"Diciembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Ene",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Abr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ago",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dic"
|
||||
],
|
||||
"days": [
|
||||
"Domingo",
|
||||
"Lunes",
|
||||
"Martes",
|
||||
"Miércoles",
|
||||
"Jueves",
|
||||
"Viernes",
|
||||
"Sábado"
|
||||
],
|
||||
"shortDays": ["Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Descargar SVG",
|
||||
"exportToPNG": "Descargar PNG",
|
||||
"exportToCSV": "Descargar CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Seleccionar",
|
||||
"selectionZoom": "Seleccionar Zoom",
|
||||
"zoomIn": "Aumentar",
|
||||
"zoomOut": "Disminuir",
|
||||
"pan": "Navegación",
|
||||
"reset": "Reiniciar Zoom"
|
||||
}
|
||||
}
|
||||
}
|
63
public/libs/apexcharts/dist/locales/et.json
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "et",
|
||||
"options": {
|
||||
"months": [
|
||||
"jaanuar",
|
||||
"veebruar",
|
||||
"märts",
|
||||
"aprill",
|
||||
"mai",
|
||||
"juuni",
|
||||
"juuli",
|
||||
"august",
|
||||
"september",
|
||||
"oktoober",
|
||||
"november",
|
||||
"detsember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"jaan",
|
||||
"veebr",
|
||||
"märts",
|
||||
"apr",
|
||||
"mai",
|
||||
"juuni",
|
||||
"juuli",
|
||||
"aug",
|
||||
"sept",
|
||||
"okt",
|
||||
"nov",
|
||||
"dets"
|
||||
],
|
||||
"days": [
|
||||
"pühapäev",
|
||||
"esmaspäev",
|
||||
"teisipäev",
|
||||
"kolmapäev",
|
||||
"neljapäev",
|
||||
"reede",
|
||||
"laupäev"
|
||||
],
|
||||
"shortDays": [
|
||||
"P",
|
||||
"E",
|
||||
"T",
|
||||
"K",
|
||||
"N",
|
||||
"R",
|
||||
"L"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Lae alla SVG",
|
||||
"exportToPNG": "Lae alla PNG",
|
||||
"exportToCSV": "Lae alla CSV",
|
||||
"menu": "Menüü",
|
||||
"selection": "Valik",
|
||||
"selectionZoom": "Valiku suum",
|
||||
"zoomIn": "Suurenda",
|
||||
"zoomOut": "Vähenda",
|
||||
"pan": "Panoraamimine",
|
||||
"reset": "Lähtesta suum"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/fa.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "fa",
|
||||
"options": {
|
||||
"months": [
|
||||
"فروردین",
|
||||
"اردیبهشت",
|
||||
"خرداد",
|
||||
"تیر",
|
||||
"مرداد",
|
||||
"شهریور",
|
||||
"مهر",
|
||||
"آبان",
|
||||
"آذر",
|
||||
"دی",
|
||||
"بهمن",
|
||||
"اسفند"
|
||||
],
|
||||
"shortMonths": [
|
||||
"فرو",
|
||||
"ارد",
|
||||
"خرد",
|
||||
"تیر",
|
||||
"مرد",
|
||||
"شهر",
|
||||
"مهر",
|
||||
"آبا",
|
||||
"آذر",
|
||||
"دی",
|
||||
"بهمـ",
|
||||
"اسفـ"
|
||||
],
|
||||
"days": [
|
||||
"یکشنبه",
|
||||
"دوشنبه",
|
||||
"سه شنبه",
|
||||
"چهارشنبه",
|
||||
"پنجشنبه",
|
||||
"جمعه",
|
||||
"شنبه"
|
||||
],
|
||||
"shortDays": ["ی", "د", "س", "چ", "پ", "ج", "ش"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "دانلود SVG",
|
||||
"exportToPNG": "دانلود PNG",
|
||||
"exportToCSV": "دانلود CSV",
|
||||
"menu": "منو",
|
||||
"selection": "انتخاب",
|
||||
"selectionZoom": "بزرگنمایی انتخابی",
|
||||
"zoomIn": "بزرگنمایی",
|
||||
"zoomOut": "کوچکنمایی",
|
||||
"pan": "پیمایش",
|
||||
"reset": "بازنشانی بزرگنمایی"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/fi.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "fi",
|
||||
"options": {
|
||||
"months": [
|
||||
"Tammikuu",
|
||||
"Helmikuu",
|
||||
"Maaliskuu",
|
||||
"Huhtikuu",
|
||||
"Toukokuu",
|
||||
"Kesäkuu",
|
||||
"Heinäkuu",
|
||||
"Elokuu",
|
||||
"Syyskuu",
|
||||
"Lokakuu",
|
||||
"Marraskuu",
|
||||
"Joulukuu"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Tammi",
|
||||
"Helmi",
|
||||
"Maalis",
|
||||
"Huhti",
|
||||
"Touko",
|
||||
"Kesä",
|
||||
"Heinä",
|
||||
"Elo",
|
||||
"Syys",
|
||||
"Loka",
|
||||
"Marras",
|
||||
"Joulu"
|
||||
],
|
||||
"days": [
|
||||
"Sunnuntai",
|
||||
"Maanantai",
|
||||
"Tiistai",
|
||||
"Keskiviikko",
|
||||
"Torstai",
|
||||
"Perjantai",
|
||||
"Lauantai"
|
||||
],
|
||||
"shortDays": ["Su", "Ma", "Ti", "Ke", "To", "Pe", "La"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Lataa SVG",
|
||||
"exportToPNG": "Lataa PNG",
|
||||
"exportToCSV": "Lataa CSV",
|
||||
"menu": "Valikko",
|
||||
"selection": "Valinta",
|
||||
"selectionZoom": "Valinnan zoomaus",
|
||||
"zoomIn": "Lähennä",
|
||||
"zoomOut": "Loitonna",
|
||||
"pan": "Panoroi",
|
||||
"reset": "Nollaa zoomaus"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/fr.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "fr",
|
||||
"options": {
|
||||
"months": [
|
||||
"janvier",
|
||||
"février",
|
||||
"mars",
|
||||
"avril",
|
||||
"mai",
|
||||
"juin",
|
||||
"juillet",
|
||||
"août",
|
||||
"septembre",
|
||||
"octobre",
|
||||
"novembre",
|
||||
"décembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"janv.",
|
||||
"févr.",
|
||||
"mars",
|
||||
"avr.",
|
||||
"mai",
|
||||
"juin",
|
||||
"juill.",
|
||||
"août",
|
||||
"sept.",
|
||||
"oct.",
|
||||
"nov.",
|
||||
"déc."
|
||||
],
|
||||
"days": [
|
||||
"dimanche",
|
||||
"lundi",
|
||||
"mardi",
|
||||
"mercredi",
|
||||
"jeudi",
|
||||
"vendredi",
|
||||
"samedi"
|
||||
],
|
||||
"shortDays": ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Télécharger au format SVG",
|
||||
"exportToPNG": "Télécharger au format PNG",
|
||||
"exportToCSV": "Télécharger au format CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Sélection",
|
||||
"selectionZoom": "Sélection et zoom",
|
||||
"zoomIn": "Zoomer",
|
||||
"zoomOut": "Dézoomer",
|
||||
"pan": "Navigation",
|
||||
"reset": "Réinitialiser le zoom"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/he.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "he",
|
||||
"options": {
|
||||
"months": [
|
||||
"ינואר",
|
||||
"פברואר",
|
||||
"מרץ",
|
||||
"אפריל",
|
||||
"מאי",
|
||||
"יוני",
|
||||
"יולי",
|
||||
"אוגוסט",
|
||||
"ספטמבר",
|
||||
"אוקטובר",
|
||||
"נובמבר",
|
||||
"דצמבר"
|
||||
],
|
||||
"shortMonths": [
|
||||
"ינו׳",
|
||||
"פבר׳",
|
||||
"מרץ",
|
||||
"אפר׳",
|
||||
"מאי",
|
||||
"יוני",
|
||||
"יולי",
|
||||
"אוג׳",
|
||||
"ספט׳",
|
||||
"אוק׳",
|
||||
"נוב׳",
|
||||
"דצמ׳"
|
||||
],
|
||||
"days": [
|
||||
"ראשון",
|
||||
"שני",
|
||||
"שלישי",
|
||||
"רביעי",
|
||||
"חמישי",
|
||||
"שישי",
|
||||
"שבת"
|
||||
],
|
||||
"shortDays": ["א׳", "ב׳", "ג׳", "ד׳", "ה׳", "ו׳", "ש׳"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "הורד SVG",
|
||||
"exportToPNG": "הורד PNG",
|
||||
"exportToCSV": "הורד CSV",
|
||||
"menu": "תפריט",
|
||||
"selection": "בחירה",
|
||||
"selectionZoom": "זום בחירה",
|
||||
"zoomIn": "הגדלה",
|
||||
"zoomOut": "הקטנה",
|
||||
"pan": "הזזה",
|
||||
"reset": "איפוס תצוגה"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/hi.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "hi",
|
||||
"options": {
|
||||
"months": [
|
||||
"जनवरी",
|
||||
"फ़रवरी",
|
||||
"मार्च",
|
||||
"अप्रैल",
|
||||
"मई",
|
||||
"जून",
|
||||
"जुलाई",
|
||||
"अगस्त",
|
||||
"सितंबर",
|
||||
"अक्टूबर",
|
||||
"नवंबर",
|
||||
"दिसंबर"
|
||||
],
|
||||
"shortMonths": [
|
||||
"जनवरी",
|
||||
"फ़रवरी",
|
||||
"मार्च",
|
||||
"अप्रैल",
|
||||
"मई",
|
||||
"जून",
|
||||
"जुलाई",
|
||||
"अगस्त",
|
||||
"सितंबर",
|
||||
"अक्टूबर",
|
||||
"नवंबर",
|
||||
"दिसंबर"
|
||||
],
|
||||
"days": [
|
||||
"रविवार",
|
||||
"सोमवार",
|
||||
"मंगलवार",
|
||||
"बुधवार",
|
||||
"गुरुवार",
|
||||
"शुक्रवार",
|
||||
"शनिवार"
|
||||
],
|
||||
"shortDays": ["रवि", "सोम", "मंगल", "बुध", "गुरु", "शुक्र", "शनि"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "निर्यात SVG",
|
||||
"exportToPNG": "निर्यात PNG",
|
||||
"exportToCSV": "निर्यात CSV",
|
||||
"menu": "सूची",
|
||||
"selection": "चयन",
|
||||
"selectionZoom": "ज़ूम करना",
|
||||
"zoomIn": "ज़ूम इन",
|
||||
"zoomOut": "ज़ूम आउट",
|
||||
"pan": "पैनिंग",
|
||||
"reset": "फिर से कायम करना"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/hr.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "hr",
|
||||
"options": {
|
||||
"months": [
|
||||
"Siječanj",
|
||||
"Veljača",
|
||||
"Ožujak",
|
||||
"Travanj",
|
||||
"Svibanj",
|
||||
"Lipanj",
|
||||
"Srpanj",
|
||||
"Kolovoz",
|
||||
"Rujan",
|
||||
"Listopad",
|
||||
"Studeni",
|
||||
"Prosinac"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Sij",
|
||||
"Velj",
|
||||
"Ožu",
|
||||
"Tra",
|
||||
"Svi",
|
||||
"Lip",
|
||||
"Srp",
|
||||
"Kol",
|
||||
"Ruj",
|
||||
"Lis",
|
||||
"Stu",
|
||||
"Pro"
|
||||
],
|
||||
"days": [
|
||||
"Nedjelja",
|
||||
"Ponedjeljak",
|
||||
"Utorak",
|
||||
"Srijeda",
|
||||
"Četvrtak",
|
||||
"Petak",
|
||||
"Subota"
|
||||
],
|
||||
"shortDays": ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Preuzmi SVG",
|
||||
"exportToPNG": "Preuzmi PNG",
|
||||
"exportToCSV": "Preuzmi CSV",
|
||||
"menu": "Izbornik",
|
||||
"selection": "Odabir",
|
||||
"selectionZoom": "Odabirno povećanje",
|
||||
"zoomIn": "Uvećajte prikaz",
|
||||
"zoomOut": "Umanjite prikaz",
|
||||
"pan": "Pomicanje",
|
||||
"reset": "Povratak na zadani prikaz"
|
||||
}
|
||||
}
|
||||
}
|
64
public/libs/apexcharts/dist/locales/hu.json
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "hu",
|
||||
"options": {
|
||||
"months": [
|
||||
"január",
|
||||
"február",
|
||||
"március",
|
||||
"április",
|
||||
"május",
|
||||
"június",
|
||||
"július",
|
||||
"augusztus",
|
||||
"szeptember",
|
||||
"október",
|
||||
"november",
|
||||
"december"
|
||||
],
|
||||
"shortMonths": [
|
||||
"jan",
|
||||
"feb",
|
||||
"mar",
|
||||
"ápr",
|
||||
"máj",
|
||||
"jún",
|
||||
"júl",
|
||||
"aug",
|
||||
"szept",
|
||||
"okt",
|
||||
"nov",
|
||||
"dec"
|
||||
],
|
||||
"days": [
|
||||
"hétfő",
|
||||
"kedd",
|
||||
"szerda",
|
||||
"csütörtök",
|
||||
"péntek",
|
||||
"szombat",
|
||||
"vasárnap"
|
||||
],
|
||||
"shortDays": [
|
||||
"H",
|
||||
"K",
|
||||
"Sze",
|
||||
"Cs",
|
||||
"P",
|
||||
"Szo",
|
||||
"V"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Exportálás SVG-be",
|
||||
"exportToPNG": "Exportálás PNG-be",
|
||||
"exportToCSV": "Exportálás CSV-be",
|
||||
"menu": "Fő ajánlat",
|
||||
"download": "SVG letöltése",
|
||||
"selection": "Kiválasztás",
|
||||
"selectionZoom": "Nagyító kiválasztása",
|
||||
"zoomIn": "Nagyítás",
|
||||
"zoomOut": "Kicsinyítés",
|
||||
"pan": "Képcsúsztatás",
|
||||
"reset": "Nagyító visszaállítása"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/hy.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "hy",
|
||||
"options": {
|
||||
"months": [
|
||||
"Հունվար",
|
||||
"Փետրվար",
|
||||
"Մարտ",
|
||||
"Ապրիլ",
|
||||
"Մայիս",
|
||||
"Հունիս",
|
||||
"Հուլիս",
|
||||
"Օգոստոս",
|
||||
"Սեպտեմբեր",
|
||||
"Հոկտեմբեր",
|
||||
"Նոյեմբեր",
|
||||
"Դեկտեմբեր"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Հնվ",
|
||||
"Փտվ",
|
||||
"Մրտ",
|
||||
"Ապր",
|
||||
"Մյս",
|
||||
"Հնս",
|
||||
"Հլիս",
|
||||
"Օգս",
|
||||
"Սեպ",
|
||||
"Հոկ",
|
||||
"Նոյ",
|
||||
"Դեկ"
|
||||
],
|
||||
"days": [
|
||||
"Կիրակի",
|
||||
"Երկուշաբթի",
|
||||
"Երեքշաբթի",
|
||||
"Չորեքշաբթի",
|
||||
"Հինգշաբթի",
|
||||
"Ուրբաթ",
|
||||
"Շաբաթ"
|
||||
],
|
||||
"shortDays": ["Կիր", "Երկ", "Երք", "Չրք", "Հնգ", "Ուրբ", "Շբթ"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Բեռնել SVG",
|
||||
"exportToPNG": "Բեռնել PNG",
|
||||
"exportToCSV": "Բեռնել CSV",
|
||||
"menu": "Մենյու",
|
||||
"selection": "Ընտրված",
|
||||
"selectionZoom": "Ընտրված հատվածի խոշորացում",
|
||||
"zoomIn": "Խոշորացնել",
|
||||
"zoomOut": "Մանրացնել",
|
||||
"pan": "Տեղափոխում",
|
||||
"reset": "Բերել սկզբնական վիճակի"
|
||||
}
|
||||
}
|
||||
}
|
47
public/libs/apexcharts/dist/locales/id.json
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "id",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Maret",
|
||||
"April",
|
||||
"Mei",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Agustus",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Desember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Agu",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Des"
|
||||
],
|
||||
"days": ["Minggu", "Senin", "Selasa", "Rabu", "kamis", "Jumat", "Sabtu"],
|
||||
"shortDays": ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Unduh SVG",
|
||||
"exportToPNG": "Unduh PNG",
|
||||
"exportToCSV": "Unduh CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Pilihan",
|
||||
"selectionZoom": "Perbesar Pilihan",
|
||||
"zoomIn": "Perbesar",
|
||||
"zoomOut": "Perkecil",
|
||||
"pan": "Geser",
|
||||
"reset": "Atur Ulang Zoom"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/it.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "it",
|
||||
"options": {
|
||||
"months": [
|
||||
"Gennaio",
|
||||
"Febbraio",
|
||||
"Marzo",
|
||||
"Aprile",
|
||||
"Maggio",
|
||||
"Giugno",
|
||||
"Luglio",
|
||||
"Agosto",
|
||||
"Settembre",
|
||||
"Ottobre",
|
||||
"Novembre",
|
||||
"Dicembre"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Gen",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mag",
|
||||
"Giu",
|
||||
"Lug",
|
||||
"Ago",
|
||||
"Set",
|
||||
"Ott",
|
||||
"Nov",
|
||||
"Dic"
|
||||
],
|
||||
"days": [
|
||||
"Domenica",
|
||||
"Lunedì",
|
||||
"Martedì",
|
||||
"Mercoledì",
|
||||
"Giovedì",
|
||||
"Venerdì",
|
||||
"Sabato"
|
||||
],
|
||||
"shortDays": ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Scarica SVG",
|
||||
"exportToPNG": "Scarica PNG",
|
||||
"exportToCSV": "Scarica CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selezione",
|
||||
"selectionZoom": "Seleziona Zoom",
|
||||
"zoomIn": "Zoom In",
|
||||
"zoomOut": "Zoom Out",
|
||||
"pan": "Sposta",
|
||||
"reset": "Reimposta Zoom"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/ja.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "ja",
|
||||
"options": {
|
||||
"months": [
|
||||
"1月",
|
||||
"2月",
|
||||
"3月",
|
||||
"4月",
|
||||
"5月",
|
||||
"6月",
|
||||
"7月",
|
||||
"8月",
|
||||
"9月",
|
||||
"10月",
|
||||
"11月",
|
||||
"12月"
|
||||
],
|
||||
"shortMonths": [
|
||||
"1月",
|
||||
"2月",
|
||||
"3月",
|
||||
"4月",
|
||||
"5月",
|
||||
"6月",
|
||||
"7月",
|
||||
"8月",
|
||||
"9月",
|
||||
"10月",
|
||||
"11月",
|
||||
"12月"
|
||||
],
|
||||
"days": [
|
||||
"日曜日",
|
||||
"月曜日",
|
||||
"火曜日",
|
||||
"水曜日",
|
||||
"木曜日",
|
||||
"金曜日",
|
||||
"土曜日"
|
||||
],
|
||||
"shortDays": ["日", "月", "火", "水", "木", "金", "土"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVGダウンロード",
|
||||
"exportToPNG": "PNGダウンロード",
|
||||
"exportToCSV": "CSVダウンロード",
|
||||
"menu": "メニュー",
|
||||
"selection": "選択",
|
||||
"selectionZoom": "選択ズーム",
|
||||
"zoomIn": "拡大",
|
||||
"zoomOut": "縮小",
|
||||
"pan": "パン",
|
||||
"reset": "ズームリセット"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/ka.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "ka",
|
||||
"options": {
|
||||
"months": [
|
||||
"იანვარი",
|
||||
"თებერვალი",
|
||||
"მარტი",
|
||||
"აპრილი",
|
||||
"მაისი",
|
||||
"ივნისი",
|
||||
"ივლისი",
|
||||
"აგვისტო",
|
||||
"სექტემბერი",
|
||||
"ოქტომბერი",
|
||||
"ნოემბერი",
|
||||
"დეკემბერი"
|
||||
],
|
||||
"shortMonths": [
|
||||
"იან",
|
||||
"თებ",
|
||||
"მარ",
|
||||
"აპრ",
|
||||
"მაი",
|
||||
"ივნ",
|
||||
"ივლ",
|
||||
"აგვ",
|
||||
"სექ",
|
||||
"ოქტ",
|
||||
"ნოე",
|
||||
"დეკ"
|
||||
],
|
||||
"days": [
|
||||
"კვირა",
|
||||
"ორშაბათი",
|
||||
"სამშაბათი",
|
||||
"ოთხშაბათი",
|
||||
"ხუთშაბათი",
|
||||
"პარასკევი",
|
||||
"შაბათი"
|
||||
],
|
||||
"shortDays": ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "გადმოქაჩე SVG",
|
||||
"exportToPNG": "გადმოქაჩე PNG",
|
||||
"exportToCSV": "გადმოქაჩე CSV",
|
||||
"menu": "მენიუ",
|
||||
"selection": "არჩევა",
|
||||
"selectionZoom": "არჩეულის გადიდება",
|
||||
"zoomIn": "გადიდება",
|
||||
"zoomOut": "დაპატარაება",
|
||||
"pan": "გადაჩოჩება",
|
||||
"reset": "გადიდების გაუქმება"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/ko.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "ko",
|
||||
"options": {
|
||||
"months": [
|
||||
"1월",
|
||||
"2월",
|
||||
"3월",
|
||||
"4월",
|
||||
"5월",
|
||||
"6월",
|
||||
"7월",
|
||||
"8월",
|
||||
"9월",
|
||||
"10월",
|
||||
"11월",
|
||||
"12월"
|
||||
],
|
||||
"shortMonths": [
|
||||
"1월",
|
||||
"2월",
|
||||
"3월",
|
||||
"4월",
|
||||
"5월",
|
||||
"6월",
|
||||
"7월",
|
||||
"8월",
|
||||
"9월",
|
||||
"10월",
|
||||
"11월",
|
||||
"12월"
|
||||
],
|
||||
"days": [
|
||||
"일요일",
|
||||
"월요일",
|
||||
"화요일",
|
||||
"수요일",
|
||||
"목요일",
|
||||
"금요일",
|
||||
"토요일"
|
||||
],
|
||||
"shortDays": ["일", "월", "화", "수", "목", "금", "토"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVG 다운로드",
|
||||
"exportToPNG": "PNG 다운로드",
|
||||
"exportToCSV": "CSV 다운로드",
|
||||
"menu": "메뉴",
|
||||
"selection": "선택",
|
||||
"selectionZoom": "선택영역 확대",
|
||||
"zoomIn": "확대",
|
||||
"zoomOut": "축소",
|
||||
"pan": "패닝",
|
||||
"reset": "원래대로"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/lt.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "lt",
|
||||
"options": {
|
||||
"months": [
|
||||
"Sausis",
|
||||
"Vasaris",
|
||||
"Kovas",
|
||||
"Balandis",
|
||||
"Gegužė",
|
||||
"Birželis",
|
||||
"Liepa",
|
||||
"Rugpjūtis",
|
||||
"Rugsėjis",
|
||||
"Spalis",
|
||||
"Lapkritis",
|
||||
"Gruodis"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Sau",
|
||||
"Vas",
|
||||
"Kov",
|
||||
"Bal",
|
||||
"Geg",
|
||||
"Bir",
|
||||
"Lie",
|
||||
"Rgp",
|
||||
"Rgs",
|
||||
"Spl",
|
||||
"Lap",
|
||||
"Grd"
|
||||
],
|
||||
"days": [
|
||||
"Sekmadienis",
|
||||
"Pirmadienis",
|
||||
"Antradienis",
|
||||
"Trečiadienis",
|
||||
"Ketvirtadienis",
|
||||
"Penktadienis",
|
||||
"Šeštadienis"
|
||||
],
|
||||
"shortDays": ["Sk", "Per", "An", "Tr", "Kt", "Pn", "Št"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Atsisiųsti SVG",
|
||||
"exportToPNG": "Atsisiųsti PNG",
|
||||
"exportToCSV": "Atsisiųsti CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Pasirinkimas",
|
||||
"selectionZoom": "Zoom: Pasirinkimas",
|
||||
"zoomIn": "Zoom: Priartinti",
|
||||
"zoomOut": "Zoom: Atitolinti",
|
||||
"pan": "Perkėlimas",
|
||||
"reset": "Atstatyti"
|
||||
}
|
||||
}
|
||||
}
|
64
public/libs/apexcharts/dist/locales/lv.json
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "lv",
|
||||
"options": {
|
||||
"months": [
|
||||
"janvāris",
|
||||
"februāris",
|
||||
"marts",
|
||||
"aprīlis",
|
||||
"maijs",
|
||||
"jūnijs",
|
||||
"jūlijs",
|
||||
"augusts",
|
||||
"septembris",
|
||||
"oktobris",
|
||||
"novembris",
|
||||
"decembris"
|
||||
],
|
||||
"shortMonths": [
|
||||
"janv",
|
||||
"febr",
|
||||
"marts",
|
||||
"apr",
|
||||
"maijs",
|
||||
"jūn",
|
||||
"jūl",
|
||||
"aug",
|
||||
"sept",
|
||||
"okt",
|
||||
"nov",
|
||||
"dec"
|
||||
],
|
||||
"days": [
|
||||
"svētdiena",
|
||||
"pirmdiena",
|
||||
"otrdiena",
|
||||
"trešdiena",
|
||||
"ceturtdiena",
|
||||
"piektdiena",
|
||||
"sestdiena"
|
||||
],
|
||||
"shortDays": [
|
||||
"Sv",
|
||||
"P",
|
||||
"O",
|
||||
"T",
|
||||
"C",
|
||||
"P",
|
||||
"S"
|
||||
],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Lejuplādēt SVG",
|
||||
"exportToPNG": "Lejuplādēt PNG",
|
||||
"exportToCSV": "Lejuplādēt CSV",
|
||||
"menu": "Izvēlne",
|
||||
"selection": "Atlase",
|
||||
"selectionZoom": "Pietuvināt atlasi",
|
||||
"zoomIn": "Pietuvināt",
|
||||
"zoomOut": "Attālināt",
|
||||
"pan": "Pārvietoties diagrammā",
|
||||
"reset": "Atiestatīt pietuvinājumu"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
55
public/libs/apexcharts/dist/locales/nb.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "nb",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"Mars",
|
||||
"April",
|
||||
"Mai",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"August",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Desember"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Des"
|
||||
],
|
||||
"days": [
|
||||
"Søndag",
|
||||
"Mandag",
|
||||
"Tirsdag",
|
||||
"Onsdag",
|
||||
"Torsdag",
|
||||
"Fredag",
|
||||
"Lørdag"
|
||||
],
|
||||
"shortDays": ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Last ned SVG",
|
||||
"exportToPNG": "Last ned PNG",
|
||||
"exportToCSV": "Last ned CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Velg",
|
||||
"selectionZoom": "Zoom: Velg",
|
||||
"zoomIn": "Zoome inn",
|
||||
"zoomOut": "Zoome ut",
|
||||
"pan": "Skyving",
|
||||
"reset": "Start på nytt"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/nl.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "nl",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Maart",
|
||||
"April",
|
||||
"Mei",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Augustus",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mrt",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Zondag",
|
||||
"Maandag",
|
||||
"Dinsdag",
|
||||
"Woensdag",
|
||||
"Donderdag",
|
||||
"Vrijdag",
|
||||
"Zaterdag"
|
||||
],
|
||||
"shortDays": ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Download SVG",
|
||||
"exportToPNG": "Download PNG",
|
||||
"exportToCSV": "Download CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selectie",
|
||||
"selectionZoom": "Zoom selectie",
|
||||
"zoomIn": "Zoom in",
|
||||
"zoomOut": "Zoom out",
|
||||
"pan": "Verplaatsen",
|
||||
"reset": "Standaardwaarden"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/pl.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "pl",
|
||||
"options": {
|
||||
"months": [
|
||||
"Styczeń",
|
||||
"Luty",
|
||||
"Marzec",
|
||||
"Kwiecień",
|
||||
"Maj",
|
||||
"Czerwiec",
|
||||
"Lipiec",
|
||||
"Sierpień",
|
||||
"Wrzesień",
|
||||
"Październik",
|
||||
"Listopad",
|
||||
"Grudzień"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Sty",
|
||||
"Lut",
|
||||
"Mar",
|
||||
"Kwi",
|
||||
"Maj",
|
||||
"Cze",
|
||||
"Lip",
|
||||
"Sie",
|
||||
"Wrz",
|
||||
"Paź",
|
||||
"Lis",
|
||||
"Gru"
|
||||
],
|
||||
"days": [
|
||||
"Niedziela",
|
||||
"Poniedziałek",
|
||||
"Wtorek",
|
||||
"Środa",
|
||||
"Czwartek",
|
||||
"Piątek",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Nd", "Pn", "Wt", "Śr", "Cz", "Pt", "Sb"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Pobierz SVG",
|
||||
"exportToPNG": "Pobierz PNG",
|
||||
"exportToCSV": "Pobierz CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Wybieranie",
|
||||
"selectionZoom": "Zoom: Wybieranie",
|
||||
"zoomIn": "Zoom: Przybliż",
|
||||
"zoomOut": "Zoom: Oddal",
|
||||
"pan": "Przesuwanie",
|
||||
"reset": "Resetuj"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/pt-br.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "pt-br",
|
||||
"options": {
|
||||
"months": [
|
||||
"Janeiro",
|
||||
"Fevereiro",
|
||||
"Março",
|
||||
"Abril",
|
||||
"Maio",
|
||||
"Junho",
|
||||
"Julho",
|
||||
"Agosto",
|
||||
"Setembro",
|
||||
"Outubro",
|
||||
"Novembro",
|
||||
"Dezembro"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Fev",
|
||||
"Mar",
|
||||
"Abr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ago",
|
||||
"Set",
|
||||
"Out",
|
||||
"Nov",
|
||||
"Dez"
|
||||
],
|
||||
"days": [
|
||||
"Domingo",
|
||||
"Segunda",
|
||||
"Terça",
|
||||
"Quarta",
|
||||
"Quinta",
|
||||
"Sexta",
|
||||
"Sábado"
|
||||
],
|
||||
"shortDays": ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Baixar SVG",
|
||||
"exportToPNG": "Baixar PNG",
|
||||
"exportToCSV": "Baixar CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selecionar",
|
||||
"selectionZoom": "Selecionar Zoom",
|
||||
"zoomIn": "Aumentar",
|
||||
"zoomOut": "Diminuir",
|
||||
"pan": "Navegação",
|
||||
"reset": "Reiniciar Zoom"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/pt.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "pt",
|
||||
"options": {
|
||||
"months": [
|
||||
"Janeiro",
|
||||
"Fevereiro",
|
||||
"Março",
|
||||
"Abril",
|
||||
"Maio",
|
||||
"Junho",
|
||||
"Julho",
|
||||
"Agosto",
|
||||
"Setembro",
|
||||
"Outubro",
|
||||
"Novembro",
|
||||
"Dezembro"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Fev",
|
||||
"Mar",
|
||||
"Abr",
|
||||
"Mai",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ag",
|
||||
"Set",
|
||||
"Out",
|
||||
"Nov",
|
||||
"Dez"
|
||||
],
|
||||
"days": [
|
||||
"Domingo",
|
||||
"Segunda-feira",
|
||||
"Terça-feira",
|
||||
"Quarta-feira",
|
||||
"Quinta-feira",
|
||||
"Sexta-feira",
|
||||
"Sábado"
|
||||
],
|
||||
"shortDays": ["Do", "Se", "Te", "Qa", "Qi", "Sx", "Sa"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Baixar SVG",
|
||||
"exportToPNG": "Baixar PNG",
|
||||
"exportToCSV": "Baixar CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Selecionar",
|
||||
"selectionZoom": "Zoom: Selecionar",
|
||||
"zoomIn": "Zoom: Aumentar",
|
||||
"zoomOut": "Zoom: Diminuir",
|
||||
"pan": "Deslocamento",
|
||||
"reset": "Redefinir"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/rs.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "rs",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"Mart",
|
||||
"April",
|
||||
"Maj",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Avgust",
|
||||
"Septembar",
|
||||
"Oktobar",
|
||||
"Novembar",
|
||||
"Decembar"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Maj",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Avg",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Nedelja",
|
||||
"Ponedeljak",
|
||||
"Utorak",
|
||||
"Sreda",
|
||||
"Četvrtak",
|
||||
"Petak",
|
||||
"Subota"
|
||||
],
|
||||
"shortDays": ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Preuzmi SVG",
|
||||
"exportToPNG": "Preuzmi PNG",
|
||||
"exportToCSV": "Preuzmi CSV",
|
||||
"menu": "Meni",
|
||||
"selection": "Odabir",
|
||||
"selectionZoom": "Odabirno povećanje",
|
||||
"zoomIn": "Uvećajte prikaz",
|
||||
"zoomOut": "Umanjite prikaz",
|
||||
"pan": "Pomeranje",
|
||||
"reset": "Resetuj prikaz"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/ru.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "ru",
|
||||
"options": {
|
||||
"months": [
|
||||
"Январь",
|
||||
"Февраль",
|
||||
"Март",
|
||||
"Апрель",
|
||||
"Май",
|
||||
"Июнь",
|
||||
"Июль",
|
||||
"Август",
|
||||
"Сентябрь",
|
||||
"Октябрь",
|
||||
"Ноябрь",
|
||||
"Декабрь"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Янв",
|
||||
"Фев",
|
||||
"Мар",
|
||||
"Апр",
|
||||
"Май",
|
||||
"Июн",
|
||||
"Июл",
|
||||
"Авг",
|
||||
"Сен",
|
||||
"Окт",
|
||||
"Ноя",
|
||||
"Дек"
|
||||
],
|
||||
"days": [
|
||||
"Воскресенье",
|
||||
"Понедельник",
|
||||
"Вторник",
|
||||
"Среда",
|
||||
"Четверг",
|
||||
"Пятница",
|
||||
"Суббота"
|
||||
],
|
||||
"shortDays": ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Сохранить SVG",
|
||||
"exportToPNG": "Сохранить PNG",
|
||||
"exportToCSV": "Сохранить CSV",
|
||||
"menu": "Меню",
|
||||
"selection": "Выбор",
|
||||
"selectionZoom": "Выбор с увеличением",
|
||||
"zoomIn": "Увеличить",
|
||||
"zoomOut": "Уменьшить",
|
||||
"pan": "Перемещение",
|
||||
"reset": "Сбросить увеличение"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/se.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "se",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Mars",
|
||||
"April",
|
||||
"Maj",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Augusti",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Maj",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Söndag",
|
||||
"Måndag",
|
||||
"Tisdag",
|
||||
"Onsdag",
|
||||
"Torsdag",
|
||||
"Fredag",
|
||||
"Lördag"
|
||||
],
|
||||
"shortDays": ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Ladda SVG",
|
||||
"exportToPNG": "Ladda PNG",
|
||||
"exportToCSV": "Ladda CSV",
|
||||
"menu": "Meny",
|
||||
"selection": "Selektion",
|
||||
"selectionZoom": "Val av zoom",
|
||||
"zoomIn": "Zooma in",
|
||||
"zoomOut": "Zooma ut",
|
||||
"pan": "Panorering",
|
||||
"reset": "Återställ zoomning"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/sk.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "sk",
|
||||
"options": {
|
||||
"months": [
|
||||
"Január",
|
||||
"Február",
|
||||
"Marec",
|
||||
"Apríl",
|
||||
"Máj",
|
||||
"Jún",
|
||||
"Júl",
|
||||
"August",
|
||||
"September",
|
||||
"Október",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Máj",
|
||||
"Jún",
|
||||
"Júl",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Nedeľa",
|
||||
"Pondelok",
|
||||
"Utorok",
|
||||
"Streda",
|
||||
"Štvrtok",
|
||||
"Piatok",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Ne", "Po", "Ut", "St", "Št", "Pi", "So"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Stiahnuť SVG",
|
||||
"exportToPNG": "Stiahnuť PNG",
|
||||
"exportToCSV": "Stiahnuť CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Vyberanie",
|
||||
"selectionZoom": "Zoom: Vyberanie",
|
||||
"zoomIn": "Zoom: Priblížiť",
|
||||
"zoomOut": "Zoom: Vzdialiť",
|
||||
"pan": "Presúvanie",
|
||||
"reset": "Resetovať"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/sl.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "sl",
|
||||
"options": {
|
||||
"months": [
|
||||
"Januar",
|
||||
"Februar",
|
||||
"Marec",
|
||||
"April",
|
||||
"Maj",
|
||||
"Junij",
|
||||
"Julij",
|
||||
"Avgust",
|
||||
"Septemer",
|
||||
"Oktober",
|
||||
"November",
|
||||
"December"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Maj",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Avg",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"days": [
|
||||
"Nedelja",
|
||||
"Ponedeljek",
|
||||
"Torek",
|
||||
"Sreda",
|
||||
"Četrtek",
|
||||
"Petek",
|
||||
"Sobota"
|
||||
],
|
||||
"shortDays": ["Ne", "Po", "To", "Sr", "Če", "Pe", "So"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Prenesi SVG",
|
||||
"exportToPNG": "Prenesi PNG",
|
||||
"exportToCSV": "Prenesi CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Izbiranje",
|
||||
"selectionZoom": "Zoom: Izbira",
|
||||
"zoomIn": "Zoom: Približaj",
|
||||
"zoomOut": "Zoom: Oddalji",
|
||||
"pan": "Pomikanje",
|
||||
"reset": "Resetiraj"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/sq.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "sq",
|
||||
"options": {
|
||||
"months": [
|
||||
"Janar",
|
||||
"Shkurt",
|
||||
"Mars",
|
||||
"Prill",
|
||||
"Maj",
|
||||
"Qershor",
|
||||
"Korrik",
|
||||
"Gusht",
|
||||
"Shtator",
|
||||
"Tetor",
|
||||
"Nëntor",
|
||||
"Dhjetor"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Jan",
|
||||
"Shk",
|
||||
"Mar",
|
||||
"Pr",
|
||||
"Maj",
|
||||
"Qer",
|
||||
"Korr",
|
||||
"Gush",
|
||||
"Sht",
|
||||
"Tet",
|
||||
"Nën",
|
||||
"Dhj"
|
||||
],
|
||||
"days": [
|
||||
"e Dielë",
|
||||
"e Hënë",
|
||||
"e Martë",
|
||||
"e Mërkurë",
|
||||
"e Enjte",
|
||||
"e Premte",
|
||||
"e Shtunë"
|
||||
],
|
||||
"shortDays": ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Sht"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Shkarko SVG",
|
||||
"exportToPNG": "Shkarko PNG",
|
||||
"exportToCSV": "Shkarko CSV",
|
||||
"menu": "Menu",
|
||||
"selection": "Seleksiono",
|
||||
"selectionZoom": "Seleksiono Zmadhim",
|
||||
"zoomIn": "Zmadho",
|
||||
"zoomOut": "Zvogëlo",
|
||||
"pan": "Spostoje",
|
||||
"reset": "Rikthe dimensionin"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/th.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "th",
|
||||
"options": {
|
||||
"months": [
|
||||
"มกราคม",
|
||||
"กุมภาพันธ์",
|
||||
"มีนาคม",
|
||||
"เมษายน",
|
||||
"พฤษภาคม",
|
||||
"มิถุนายน",
|
||||
"กรกฎาคม",
|
||||
"สิงหาคม",
|
||||
"กันยายน",
|
||||
"ตุลาคม",
|
||||
"พฤศจิกายน",
|
||||
"ธันวาคม"
|
||||
],
|
||||
"shortMonths": [
|
||||
"ม.ค.",
|
||||
"ก.พ.",
|
||||
"มี.ค.",
|
||||
"เม.ย.",
|
||||
"พ.ค.",
|
||||
"มิ.ย.",
|
||||
"ก.ค.",
|
||||
"ส.ค.",
|
||||
"ก.ย.",
|
||||
"ต.ค.",
|
||||
"พ.ย.",
|
||||
"ธ.ค."
|
||||
],
|
||||
"days": [
|
||||
"อาทิตย์",
|
||||
"จันทร์",
|
||||
"อังคาร",
|
||||
"พุธ",
|
||||
"พฤหัสบดี",
|
||||
"ศุกร์",
|
||||
"เสาร์"
|
||||
],
|
||||
"shortDays": ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "ดาวน์โหลด SVG",
|
||||
"exportToPNG": "ดาวน์โหลด PNG",
|
||||
"exportToCSV": "ดาวน์โหลด CSV",
|
||||
"menu": "เมนู",
|
||||
"selection": "เลือก",
|
||||
"selectionZoom": "เลือกจุดที่จะซูม",
|
||||
"zoomIn": "ซูมเข้า",
|
||||
"zoomOut": "ซูมออก",
|
||||
"pan": "ปรากฎว่า",
|
||||
"reset": "รีเซ็ตการซูม"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/tr.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "tr",
|
||||
"options": {
|
||||
"months": [
|
||||
"Ocak",
|
||||
"Şubat",
|
||||
"Mart",
|
||||
"Nisan",
|
||||
"Mayıs",
|
||||
"Haziran",
|
||||
"Temmuz",
|
||||
"Ağustos",
|
||||
"Eylül",
|
||||
"Ekim",
|
||||
"Kasım",
|
||||
"Aralık"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Oca",
|
||||
"Şub",
|
||||
"Mar",
|
||||
"Nis",
|
||||
"May",
|
||||
"Haz",
|
||||
"Tem",
|
||||
"Ağu",
|
||||
"Eyl",
|
||||
"Eki",
|
||||
"Kas",
|
||||
"Ara"
|
||||
],
|
||||
"days": [
|
||||
"Pazar",
|
||||
"Pazartesi",
|
||||
"Salı",
|
||||
"Çarşamba",
|
||||
"Perşembe",
|
||||
"Cuma",
|
||||
"Cumartesi"
|
||||
],
|
||||
"shortDays": ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "SVG İndir",
|
||||
"exportToPNG": "PNG İndir",
|
||||
"exportToCSV": "CSV İndir",
|
||||
"menu": "Menü",
|
||||
"selection": "Seçim",
|
||||
"selectionZoom": "Seçim Yakınlaştır",
|
||||
"zoomIn": "Yakınlaştır",
|
||||
"zoomOut": "Uzaklaştır",
|
||||
"pan": "Kaydır",
|
||||
"reset": "Yakınlaştırmayı Sıfırla"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/ua.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "ua",
|
||||
"options": {
|
||||
"months": [
|
||||
"Січень",
|
||||
"Лютий",
|
||||
"Березень",
|
||||
"Квітень",
|
||||
"Травень",
|
||||
"Червень",
|
||||
"Липень",
|
||||
"Серпень",
|
||||
"Вересень",
|
||||
"Жовтень",
|
||||
"Листопад",
|
||||
"Грудень"
|
||||
],
|
||||
"shortMonths": [
|
||||
"Січ",
|
||||
"Лют",
|
||||
"Бер",
|
||||
"Кві",
|
||||
"Тра",
|
||||
"Чер",
|
||||
"Лип",
|
||||
"Сер",
|
||||
"Вер",
|
||||
"Жов",
|
||||
"Лис",
|
||||
"Гру"
|
||||
],
|
||||
"days": [
|
||||
"Неділя",
|
||||
"Понеділок",
|
||||
"Вівторок",
|
||||
"Середа",
|
||||
"Четвер",
|
||||
"П'ятниця",
|
||||
"Субота"
|
||||
],
|
||||
"shortDays": ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "Зберегти SVG",
|
||||
"exportToPNG": "Зберегти PNG",
|
||||
"exportToCSV": "Зберегти CSV",
|
||||
"menu": "Меню",
|
||||
"selection": "Вибір",
|
||||
"selectionZoom": "Вибір із збільшенням",
|
||||
"zoomIn": "Збільшити",
|
||||
"zoomOut": "Зменшити",
|
||||
"pan": "Переміщення",
|
||||
"reset": "Скинути збільшення"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/zh-cn.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "zh-cn",
|
||||
"options": {
|
||||
"months": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"shortMonths": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"days": [
|
||||
"星期天",
|
||||
"星期一",
|
||||
"星期二",
|
||||
"星期三",
|
||||
"星期四",
|
||||
"星期五",
|
||||
"星期六"
|
||||
],
|
||||
"shortDays": ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "下载 SVG",
|
||||
"exportToPNG": "下载 PNG",
|
||||
"exportToCSV": "下载 CSV",
|
||||
"menu": "菜单",
|
||||
"selection": "选择",
|
||||
"selectionZoom": "选择缩放",
|
||||
"zoomIn": "放大",
|
||||
"zoomOut": "缩小",
|
||||
"pan": "平移",
|
||||
"reset": "重置缩放"
|
||||
}
|
||||
}
|
||||
}
|
55
public/libs/apexcharts/dist/locales/zh-tw.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "zh-tw",
|
||||
"options": {
|
||||
"months": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"shortMonths": [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月"
|
||||
],
|
||||
"days": [
|
||||
"星期日",
|
||||
"星期一",
|
||||
"星期二",
|
||||
"星期三",
|
||||
"星期四",
|
||||
"星期五",
|
||||
"星期六"
|
||||
],
|
||||
"shortDays": ["週日", "週一", "週二", "週三", "週四", "週五", "週六"],
|
||||
"toolbar": {
|
||||
"exportToSVG": "下載 SVG",
|
||||
"exportToPNG": "下載 PNG",
|
||||
"exportToCSV": "下載 CSV",
|
||||
"menu": "菜單",
|
||||
"selection": "選擇",
|
||||
"selectionZoom": "選擇縮放",
|
||||
"zoomIn": "放大",
|
||||
"zoomOut": "縮小",
|
||||
"pan": "平移",
|
||||
"reset": "重置縮放"
|
||||
}
|
||||
}
|
||||
}
|
BIN
public/static/avatars/burns.jpg
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
public/static/avatars/frank.jpg
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
public/static/avatars/moe.jpg
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
public/static/avatars/poochie.jpg
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
public/static/avatars/rus.jpg
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
public/static/avatars/skinner.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
3
public/static/logo-small-white.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 68">
|
||||
<path d="M64.6 16.2C63 9.9 58.1 5 51.8 3.4 40 1.5 28 1.5 16.2 3.4 9.9 5 5 9.9 3.4 16.2 1.5 28 1.5 40 3.4 51.8 5 58.1 9.9 63 16.2 64.6c11.8 1.9 23.8 1.9 35.6 0C58.1 63 63 58.1 64.6 51.8c1.9-11.8 1.9-23.8 0-35.6zM33.3 36.3c-2.8 4.4-6.6 8.2-11.1 11-1.5.9-3.3.9-4.8.1s-2.4-2.3-2.5-4c0-1.7.9-3.3 2.4-4.1 2.3-1.4 4.4-3.2 6.1-5.3-1.8-2.1-3.8-3.8-6.1-5.3-2.3-1.3-3-4.2-1.7-6.4s4.3-2.9 6.5-1.6c4.5 2.8 8.2 6.5 11.1 10.9 1 1.4 1 3.3.1 4.7zM49.2 46H37.8c-2.1 0-3.8-1-3.8-3s1.7-3 3.8-3h11.4c2.1 0 3.8 1 3.8 3s-1.7 3-3.8 3z" fill="#ffffff"/>
|
||||
</svg>
|
After Width: | Height: | Size: 599 B |
1
public/static/logo-small.svg
Normal file
After Width: | Height: | Size: 5.5 KiB |
4
public/static/logo-white.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 232 68">
|
||||
<path d="M64.6 16.2C63 9.9 58.1 5 51.8 3.4 40 1.5 28 1.5 16.2 3.4 9.9 5 5 9.9 3.4 16.2 1.5 28 1.5 40 3.4 51.8 5 58.1 9.9 63 16.2 64.6c11.8 1.9 23.8 1.9 35.6 0C58.1 63 63 58.1 64.6 51.8c1.9-11.8 1.9-23.8 0-35.6zM33.3 36.3c-2.8 4.4-6.6 8.2-11.1 11-1.5.9-3.3.9-4.8.1s-2.4-2.3-2.5-4c0-1.7.9-3.3 2.4-4.1 2.3-1.4 4.4-3.2 6.1-5.3-1.8-2.1-3.8-3.8-6.1-5.3-2.3-1.3-3-4.2-1.7-6.4s4.3-2.9 6.5-1.6c4.5 2.8 8.2 6.5 11.1 10.9 1 1.4 1 3.3.1 4.7zM49.2 46H37.8c-2.1 0-3.8-1-3.8-3s1.7-3 3.8-3h11.4c2.1 0 3.8 1 3.8 3s-1.7 3-3.8 3z" fill="#fff"/>
|
||||
<path d="M105.8 46.1c.4 0 .9.2 1.2.6s.6 1 .6 1.7c0 .9-.5 1.6-1.4 2.2s-2 .9-3.2.9c-2 0-3.7-.4-5-1.3s-2-2.6-2-5.4V31.6h-2.2c-.8 0-1.4-.3-1.9-.8s-.9-1.1-.9-1.9c0-.7.3-1.4.8-1.8s1.2-.7 1.9-.7h2.2v-3.1c0-.8.3-1.5.8-2.1s1.3-.8 2.1-.8 1.5.3 2 .8.8 1.3.8 2.1v3.1h3.4c.8 0 1.4.3 1.9.8s.8 1.2.8 1.9-.3 1.4-.8 1.8-1.2.7-1.9.7h-3.4v13c0 .7.2 1.2.5 1.5s.8.5 1.4.5c.3 0 .6-.1 1.1-.2.5-.2.8-.3 1.2-.3zm28-20.7c.8 0 1.5.3 2.1.8.5.5.8 1.2.8 2.1v20.3c0 .8-.3 1.5-.8 2.1-.5.6-1.2.8-2.1.8s-1.5-.3-2-.8-.8-1.2-.8-2.1c-.8.9-1.9 1.7-3.2 2.4-1.3.7-2.8 1-4.3 1-2.2 0-4.2-.6-6-1.7-1.8-1.1-3.2-2.7-4.2-4.7s-1.6-4.3-1.6-6.9c0-2.6.5-4.9 1.5-6.9s2.4-3.6 4.2-4.8c1.8-1.1 3.7-1.7 5.9-1.7 1.5 0 3 .3 4.3.8 1.3.6 2.5 1.3 3.4 2.1 0-.8.3-1.5.8-2.1.5-.5 1.2-.7 2-.7zm-9.7 21.3c2.1 0 3.8-.8 5.1-2.3s2-3.4 2-5.7-.7-4.2-2-5.8c-1.3-1.5-3-2.3-5.1-2.3-2 0-3.7.8-5 2.3-1.3 1.5-2 3.5-2 5.8s.6 4.2 1.9 5.7 3 2.3 5.1 2.3zm32.1-21.3c2.2 0 4.2.6 6 1.7 1.8 1.1 3.2 2.7 4.2 4.7s1.6 4.3 1.6 6.9-.5 4.9-1.5 6.9-2.4 3.6-4.2 4.8c-1.8 1.1-3.7 1.7-5.9 1.7-1.5 0-3-.3-4.3-.9s-2.5-1.4-3.4-2.3v.3c0 .8-.3 1.5-.8 2.1-.5.6-1.2.8-2.1.8s-1.5-.3-2.1-.8c-.5-.5-.8-1.2-.8-2.1V18.9c0-.8.3-1.5.8-2.1.5-.6 1.2-.8 2.1-.8s1.5.3 2.1.8c.5.6.8 1.3.8 2.1v10c.8-1 1.8-1.8 3.2-2.5 1.3-.7 2.8-1 4.3-1zm-.7 21.3c2 0 3.7-.8 5-2.3s2-3.5 2-5.8-.6-4.2-1.9-5.7-3-2.3-5.1-2.3-3.8.8-5.1 2.3-2 3.4-2 5.7.7 4.2 2 5.8c1.3 1.6 3 2.3 5.1 2.3zm23.6 1.9c0 .8-.3 1.5-.8 2.1s-1.3.8-2.1.8-1.5-.3-2-.8-.8-1.3-.8-2.1V18.9c0-.8.3-1.5.8-2.1s1.3-.8 2.1-.8 1.5.3 2 .8.8 1.3.8 2.1v29.7zm29.3-10.5c0 .8-.3 1.4-.9 1.9-.6.5-1.2.7-2 .7h-15.8c.4 1.9 1.3 3.4 2.6 4.4 1.4 1.1 2.9 1.6 4.7 1.6 1.3 0 2.3-.1 3.1-.4.7-.2 1.3-.5 1.8-.8.4-.3.7-.5.9-.6.6-.3 1.1-.4 1.6-.4.7 0 1.2.2 1.7.7s.7 1 .7 1.7c0 .9-.4 1.6-1.3 2.4-.9.7-2.1 1.4-3.6 1.9s-3 .8-4.6.8c-2.7 0-5-.6-7-1.7s-3.5-2.7-4.6-4.6-1.6-4.2-1.6-6.6c0-2.8.6-5.2 1.7-7.2s2.7-3.7 4.6-4.8 3.9-1.7 6-1.7 4.1.6 6 1.7 3.4 2.7 4.5 4.7c.9 1.9 1.5 4.1 1.5 6.3zm-12.2-7.5c-3.7 0-5.9 1.7-6.6 5.2h12.6v-.3c-.1-1.3-.8-2.5-2-3.5s-2.5-1.4-4-1.4zm30.3-5.2c1 0 1.8.3 2.4.8.7.5 1 1.2 1 1.9 0 1-.3 1.7-.8 2.2-.5.5-1.1.8-1.8.7-.5 0-1-.1-1.6-.3-.2-.1-.4-.1-.6-.2-.4-.1-.7-.1-1.1-.1-.8 0-1.6.3-2.4.8s-1.4 1.3-1.9 2.3-.7 2.3-.7 3.7v11.4c0 .8-.3 1.5-.8 2.1-.5.6-1.2.8-2.1.8s-1.5-.3-2.1-.8c-.5-.6-.8-1.3-.8-2.1V28.8c0-.8.3-1.5.8-2.1.5-.6 1.2-.8 2.1-.8s1.5.3 2.1.8c.5.6.8 1.3.8 2.1v.6c.7-1.3 1.8-2.3 3.2-3 1.3-.7 2.8-1 4.3-1z" fill-rule="evenodd" clip-rule="evenodd" fill="#fff"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
1
public/static/logo.svg
Normal file
After Width: | Height: | Size: 5.4 KiB |
47
routes/index.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
|
||||
const { Dashboard } = require("../controllers/dashboard");
|
||||
|
||||
const { AddSite, RemoveSite, RefreshSites, DisableSite, EnableSite } = require("../controllers/site_actions");
|
||||
const { Install, Uninstall } = require("../controllers/app_actions");
|
||||
|
||||
const {Apps, processApps} = require("../controllers/apps");
|
||||
const { Users } = require("../controllers/users");
|
||||
const {Account} = require("../controllers/account");
|
||||
const {Settings} = require("../controllers/settings");
|
||||
const {Logout} = require("../controllers/logout");
|
||||
const {Login, processLogin} = require("../controllers/login");
|
||||
const {Register, processRegister} = require("../controllers/register");
|
||||
|
||||
|
||||
|
||||
router.get("/", Dashboard);
|
||||
|
||||
router.post("/install", Install)
|
||||
router.post("/uninstall", Uninstall)
|
||||
|
||||
router.post("/addsite", AddSite)
|
||||
router.post("/removesite", RemoveSite)
|
||||
router.get("/refreshsites", RefreshSites)
|
||||
router.post("/disablesite", DisableSite)
|
||||
router.post("/enablesite", EnableSite)
|
||||
|
||||
|
||||
router.get("/users", Users);
|
||||
|
||||
router.get("/apps", Apps);
|
||||
router.post("/apps", processApps);
|
||||
|
||||
router.get("/settings", Settings);
|
||||
router.get("/account", Account);
|
||||
|
||||
router.get("/login",Login); // Login page
|
||||
router.post("/login",processLogin); // Process login
|
||||
|
||||
router.get("/register", Register); // Register page
|
||||
router.post("/register",processRegister); // Process Register
|
||||
|
||||
router.get("/logout",Logout); // Logout
|
||||
|
||||
module.exports = router;
|
69
setup.sh
Normal file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
|
||||
# To demo DweebUI, run this script on a fresh Debian 12.2 install. This script will open port 443/tcp for Reverse Proxy and 22/tcp for SSH.
|
||||
|
||||
# Manual Install:
|
||||
# cd DweebUI
|
||||
# chmod +x setup.sh
|
||||
# sudo ./setup.sh
|
||||
|
||||
# Install dependencies
|
||||
apt-get install -y curl unzip ufw gnupg ca-certificates lsb-release gpg
|
||||
|
||||
# Enable firewall
|
||||
ufw allow ssh && ufw --force enable
|
||||
|
||||
# Opens port 443/tcp for Reverse Proxy
|
||||
ufw allow https
|
||||
|
||||
# Install Docker
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
|
||||
echo \
|
||||
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
|
||||
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
# Create docker network
|
||||
docker network create -d bridge AppBridge
|
||||
|
||||
# Install redis
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||
apt-get update -y
|
||||
apt-get install -y redis
|
||||
systemctl enable --now redis-server
|
||||
|
||||
# Install nodejs
|
||||
mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
NODE_MAJOR=20
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install nodejs -y
|
||||
|
||||
|
||||
# Install pnpm and nodejs modules
|
||||
npm install -g pnpm
|
||||
pnpm i
|
||||
|
||||
# Prep for caddy
|
||||
mkdir -p /home/docker/caddy/sites
|
||||
echo "import sites/*" > /home/docker/caddy/Caddyfile.tmp
|
||||
mv /home/docker/caddy/Caddyfile.tmp /home/docker/caddy/Caddyfile
|
||||
|
||||
|
||||
# Install pm2 and start DweebUI
|
||||
npm install pm2 -g
|
||||
pm2 start app.js --name "dweebui"
|
||||
pm2 log
|
||||
|
||||
|
||||
# Creates a 'docker-compose' alias, since the command changed to 'docker compose' in Debian 11.
|
||||
echo '#!/bin/sh
|
||||
docker compose "$@"' > /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
5869
templates.json
Normal file
145
views/pages/account.ejs
Normal file
|
@ -0,0 +1,145 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Settings - Tabler - Premium and Open Source dashboard template with responsive and high quality UI.</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1684106062" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<script src="./js/demo-theme.min.js?1684106062"></script>
|
||||
<div class="page">
|
||||
<!-- Navbar -->
|
||||
<%- include('../partials/navbar.ejs') %>
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Account Settings
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="card">
|
||||
<div class="row g-0">
|
||||
<div class="col-3 d-none d-md-block border-end">
|
||||
<div class="card-body">
|
||||
<h4 class="subheader">Business settings</h4>
|
||||
<div class="list-group list-group-transparent">
|
||||
<a href="/account" class="list-group-item list-group-item-action d-flex align-items-center active">Accounts</a>
|
||||
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">My Notifications</a>
|
||||
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">Connected Apps</a>
|
||||
<a href="/settings" class="list-group-item list-group-item-action d-flex align-items-center">Settings</a>
|
||||
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">Billing & Invoices</a>
|
||||
</div>
|
||||
<h4 class="subheader mt-4">Experience</h4>
|
||||
<div class="list-group list-group-transparent">
|
||||
<a href="#" class="list-group-item list-group-item-action">Credits</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col d-flex flex-column">
|
||||
<div class="card-body">
|
||||
<h2 class="mb-4">My Account</h2>
|
||||
<h3 class="card-title">Profile Details</h3>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="avatar avatar-xl"><%- avatar %></span>
|
||||
</div>
|
||||
<div class="col-auto"><a href="#" class="btn">
|
||||
Change avatar
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-auto"><a href="#" class="btn btn-ghost-danger">
|
||||
Delete avatar
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="card-title mt-4">Profile</h3>
|
||||
<div class="row g-3">
|
||||
<div class="col-md">
|
||||
<div class="form-label">Full Name</div>
|
||||
<input type="text" class="form-control" value="<%= name %>" readonly="<%= name %>">
|
||||
</div>
|
||||
<div class="col-md">
|
||||
<div class="form-label">First Name</div>
|
||||
<input type="text" class="form-control" value="<%= first_name %>" readonly="<%= first_name %>">
|
||||
</div>
|
||||
<div class="col-md">
|
||||
<div class="form-label">Last Name</div>
|
||||
<input type="text" class="form-control" value="<%= last_name %>" readonly="<%= last_name %>">
|
||||
</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="<%= email %>" readonly="<%= email %>">
|
||||
</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 class="card-footer bg-transparent mt-auto">
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="#" class="btn">
|
||||
Cancel
|
||||
</a>
|
||||
<a href="#" class="btn btn-primary">
|
||||
Submit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('../partials/footer.ejs') %>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1684106062" defer></script>
|
||||
<script src="./js/demo.min.js?1684106062" defer></script>
|
||||
</body>
|
||||
</html>
|
93
views/pages/apps.ejs
Normal file
|
@ -0,0 +1,93 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Apps list.</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1685973381" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1685973381" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<script src="./js/demo-theme.min.js?1685973381"></script>
|
||||
<div class="page">
|
||||
<!-- Navbar -->
|
||||
|
||||
<%- include('../partials/navbar.ejs') %>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Apps
|
||||
</h2>
|
||||
<div class="text-secondary mt-1"><%= list_start %> - <%= list_end %> of <%= app_count %> Apps.</div>
|
||||
</div>
|
||||
<!-- Page title actions -->
|
||||
<div class="col-auto ms-auto d-print-none">
|
||||
<div class="d-flex">
|
||||
<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-outline-success h-50" value="search"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="row row-cards">
|
||||
|
||||
<%- apps_list %>
|
||||
|
||||
</div>
|
||||
<div class="d-flex mt-4">
|
||||
<ul class="pagination ms-auto">
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="<%- prev %>" tabindex="-1" aria-disabled="true">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-left -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M15 6l-6 6l6 6" /></svg>
|
||||
prev
|
||||
</a>
|
||||
</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?page=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?page=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="<%- next %>">
|
||||
next <!-- Download SVG icon from http://tabler-icons.io/i/chevron-right -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M9 6l6 6l-6 6" /></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include('../partials/footer.ejs') %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1685973381" defer></script>
|
||||
<script src="./js/demo.min.js?1685973381" defer></script>
|
||||
</body>
|
||||
</html>
|
278
views/pages/dashboard.ejs
Normal file
|
@ -0,0 +1,278 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Dashboard.</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./css/meters.css" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<div class="page">
|
||||
<!-- Navbar -->
|
||||
<%- include('../partials/navbar.ejs') %>
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="row row-deck row-cards">
|
||||
|
||||
<div class="col-12" id="cards">
|
||||
<div class="row row-cards">
|
||||
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card card-sm">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<span class="bg-primary text-white avatar"><!-- Download SVG icon from http://tabler-icons.io/i/currency-dollar -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-cpu" 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 5m0 1a1 1 0 0 1 1 -1h12a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-12a1 1 0 0 1 -1 -1z"></path><path d="M9 9h6v6h-6z"></path><path d="M3 10h2"></path><path d="M3 14h2"></path><path d="M10 3v2"></path><path d="M14 3v2"></path><path d="M21 10h-2"></path><path d="M21 14h-2"></path><path d="M14 21v-2"></path><path d="M10 21v-2"></path></svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="font-weight-medium">
|
||||
<label id="cpu-text" class="cpu-text mb-1" for="cpu">CPU 0%</label>
|
||||
</div>
|
||||
<div id="cpu-bar" class="cpu-bar meter animate">
|
||||
<span style="width: 25%"><span></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card card-sm">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<span class="bg-green text-white avatar"><!-- Download SVG icon from http://tabler-icons.io/i/shopping-cart -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-container" 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="M20 4v.01"></path> <path d="M20 20v.01"></path> <path d="M20 16v.01"></path> <path d="M20 12v.01"></path> <path d="M20 8v.01"></path> <path d="M8 4m0 1a1 1 0 0 1 1 -1h6a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-6a1 1 0 0 1 -1 -1z"></path> <path d="M4 4v.01"></path> <path d="M4 20v.01"></path> <path d="M4 16v.01"></path> <path d="M4 12v.01"></path> <path d="M4 8v.01"></path> </svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="font-weight-medium">
|
||||
<label id="ram-text" class="ram-text mb-1" for="ram">RAM 0%</label>
|
||||
</div>
|
||||
<div id="ram-bar" class="ram-bar meter animate orange">
|
||||
<span style="width: 25%"><span></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card card-sm">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<span class="bg-twitter text-white avatar"><!-- Download SVG icon from http://tabler-icons.io/i/brand-twitter -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-left-right" 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="M21 17l-18 0"></path> <path d="M6 10l-3 -3l3 -3"></path> <path d="M3 7l18 0"></path> <path d="M18 20l3 -3l-3 -3"></path> </svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="font-weight-medium">
|
||||
<label id="net-text" class="net-text mb-1" for="network">NET</label>
|
||||
</div>
|
||||
<div id="net-bar" class="meter animate blue">
|
||||
<span style="width: 25%"><span></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card card-sm">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<span class="bg-facebook text-white avatar"><!-- Download SVG icon from http://tabler-icons.io/i/brand-facebook -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-database" 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 6m-8 0a8 3 0 1 0 16 0a8 3 0 1 0 -16 0"></path> <path d="M4 6v6a8 3 0 0 0 16 0v-6"></path> <path d="M4 12v6a8 3 0 0 0 16 0v-6"></path></svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="font-weight-medium">
|
||||
<label id="disk-text" class="disk-text mb-1" for="disk">Disk Space</label>
|
||||
</div>
|
||||
<div id="disk-bar" class="meter animate red">
|
||||
<span style="width: 25%"><span></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mt-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Caddy Proxy Manager</h3>
|
||||
<!-- create a button that is aligned to the right -->
|
||||
<div class="card-options btn-list">
|
||||
<a href="/refreshsites" class="btn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-refresh" 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="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4"></path> <path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"></path> </svg>
|
||||
Re-Scan
|
||||
</a>
|
||||
<a href="#" class="btn" data-bs-toggle="modal" data-bs-target="#add-site">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-plus" 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 5l0 14"></path> <path d="M5 12l14 0"></path> </svg>
|
||||
Add Site
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal modal-blur fade" id="add-site" tabindex="-1" style="display: none;" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<form action="/addsite" id="addsite" method="POST">
|
||||
<div class="mb-3">
|
||||
<div class="form-label">Type</div>
|
||||
<select class="form-select" name="type">
|
||||
<option value="reverse_proxy">Reverse Proxy</option>
|
||||
<option value="proxy">Proxy</option>
|
||||
<option value="file_server">File Server</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Domain / Subdomain</label>
|
||||
<input type="text" class="form-control" name="domain" placeholder="media.mydomainname.com">
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="row g-2">
|
||||
<div class="col-8">
|
||||
<label class="form-label">Hostname / Host IP</label>
|
||||
<input type="text" class="form-control" name="host" placeholder="localhost">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label class="form-label">Port</label>
|
||||
<input type="text" class="form-control" name="port" placeholder="8000">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="divide-y">
|
||||
<div>
|
||||
<label class="row">
|
||||
<span class="col" title="HTTP Strict Transport Security (HSTS) is a simple and widely supported standard to protect visitors by ensuring that their browsers always connect to a website over HTTPS.">HSTS</span>
|
||||
<span class="col-auto">
|
||||
<label class="form-check form-check-single form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="hsts" checked="" disabled="">
|
||||
</label>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-label">Container</div>
|
||||
<select class="form-select" name="container" disabled="">
|
||||
<option value="0" selected></option>
|
||||
<option value="1">Jellyfin</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-link link-secondary me-auto" data-bs-dismiss="modal">Cancel</button>
|
||||
<input type="submit" form="addsite" class="btn btn-success" value="Add"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="table-responsive">
|
||||
<form method="POST">
|
||||
<table class="table card-table table-vcenter text-nowrap datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1"><input class="form-check-input m-0 align-middle" name="select-all" type="checkbox" aria-label="Select all invoices"></th>
|
||||
<th class="w-1">No. <!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick" 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="M6 15l6 -6l6 6" /></svg>
|
||||
</th>
|
||||
<th>Domain / Subdomain</th>
|
||||
<th>Type</th>
|
||||
<th>Host/IP</th>
|
||||
<th>Port</th>
|
||||
<th>HTTP/3</th>
|
||||
<th>HSTS</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<%- include('../partials/site_list.ejs') %>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer d-flex align-items-center">
|
||||
|
||||
<span class="dropdown">
|
||||
<button class="btn dropdown-toggle align-text-top" data-bs-toggle="dropdown">Actions</button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<button class="dropdown-item" type="submit" formaction="/enablesite">
|
||||
Enable
|
||||
</button>
|
||||
<button class="dropdown-item" type="submit" formaction="/disablesite">
|
||||
Disable
|
||||
</button>
|
||||
<button class="dropdown-item" type="submit" formaction="/removesite">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
</form>
|
||||
|
||||
<p class="m-0 text-muted ms-auto">Imported: /home/docker/caddy/Caddyfile</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include('../partials/footer.ejs') %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Libs JS -->
|
||||
<script src="./libs/apexcharts/dist/apexcharts.min.js?1684106062" defer></script>
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1684106062" defer></script>
|
||||
<script src="./js/demo.min.js?1684106062" defer></script>
|
||||
<!-- Socket.io -->
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script src="./js/main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
81
views/pages/login.ejs
Normal file
|
@ -0,0 +1,81 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>DweebUI - Login</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1674944402" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1674944402" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class=" d-flex flex-column">
|
||||
<script src="./js/demo-theme.js?1674944402"></script>
|
||||
<div class="page page-center">
|
||||
<div class="container container-tight py-4">
|
||||
<div class="text-center mb-4">
|
||||
<a href="." class="navbar-brand navbar-brand-autodark"><img src="./static/logo.svg" height="36" alt=""></a>
|
||||
</div>
|
||||
<div class="card card-md">
|
||||
<div class="card-body">
|
||||
<h2 class="h2 text-center mb-4">Login to your account</h2>
|
||||
<form action="/login" method="POST" novalidate>
|
||||
|
||||
<% if(error) { %>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= error %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="email" name="email">
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">
|
||||
Password
|
||||
<span class="form-label-description">
|
||||
<a href="./forgot-password.html">I forgot password</a>
|
||||
</span>
|
||||
</label>
|
||||
<div class="input-group input-group-flat">
|
||||
<input type="password" class="form-control" id="password" name="password" autocomplete="off">
|
||||
<span class="input-group-text">
|
||||
<a href="#" class="link-secondary" title="Show password" data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M12 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M22 12c-2.667 4.667 -6 7 -10 7s-7.333 -2.333 -10 -7c2.667 -4.667 6 -7 10 -7s7.333 2.333 10 7" /></svg>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-check">
|
||||
<input type="checkbox" class="form-check-input"/>
|
||||
<span class="form-check-label">Remember me on this device</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-footer">
|
||||
<button type="submit" class="btn btn-primary w-100">Sign in</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center text-muted mt-3">
|
||||
Don't have account yet? <a href="/register" tabindex="-1">Sign up</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1674944402" defer></script>
|
||||
<script src="./js/demo.min.js?1674944402" defer></script>
|
||||
</body>
|
||||
</html>
|
182
views/pages/register.ejs
Normal file
|
@ -0,0 +1,182 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>DweebUI - Register</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1684106062" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class=" d-flex flex-column">
|
||||
<script src="./js/demo-theme.js?1684106062"></script>
|
||||
<div class="page page-center">
|
||||
|
||||
|
||||
<form class="container container-tight py-4" action="/register" method="POST" novalidate>
|
||||
|
||||
<!-- <div class="text-center mb-4">
|
||||
<a href="." class="navbar-brand navbar-brand-autodark"><img src="./static/logo.svg" height="36" alt=""></a>
|
||||
</div> -->
|
||||
|
||||
<div class="card">
|
||||
|
||||
<div class="card-body text-center py-4">
|
||||
<h1 class="mt-1">Welcome to DweebUI!</h1>
|
||||
<p class="text-muted">A Docker Web Interface</p>
|
||||
|
||||
<% if(error) { %>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= error %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
|
||||
<div class="row row-cards">
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="mb-2">
|
||||
<label class="form-label">First Name</label>
|
||||
<input type="text" class="form-control" id="first_name" name="first_name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Last Name</label>
|
||||
<input type="text" class="form-control" id="last_name" name="last_name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Username</label>
|
||||
<input type="email" class="form-control" id="username" name="username">
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="email" name="email">
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Password</label>
|
||||
<div class="input-group input-group-flat">
|
||||
<input type="password" class="form-control" id="password" name="password" autocomplete="off">
|
||||
<span class="input-group-text">
|
||||
<a href="#" class="link-secondary" title="Show password" data-bs-toggle="tooltip"><!-- Download SVG icon from http://tabler-icons.io/i/eye -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 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>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="form-label">Avatar</label>
|
||||
<div class="mb-2">
|
||||
<div class="row g-2">
|
||||
<div class="col-6 col-sm-4">
|
||||
<label class="form-imagecheck mb-2">
|
||||
<input name="avatar" type="radio" value="rus.jpg" class="form-imagecheck-input" checked/>
|
||||
<span class="form-imagecheck-figure">
|
||||
<img src="./static/avatars/rus.jpg" alt="Group of people sightseeing in the city" class="form-imagecheck-image">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 col-sm-4">
|
||||
<label class="form-imagecheck mb-2">
|
||||
<input name="avatar" type="radio" value="burns.jpg" class="form-imagecheck-input"/>
|
||||
<span class="form-imagecheck-figure">
|
||||
<img src="./static/avatars/burns.jpg" alt="Color Palette Guide. Sample Colors Catalog." class="form-imagecheck-image">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 col-sm-4">
|
||||
<label class="form-imagecheck mb-2">
|
||||
<input name="avatar" type="radio" value="frank.jpg" class="form-imagecheck-input" />
|
||||
<span class="form-imagecheck-figure">
|
||||
<img src="./static/avatars/frank.jpg" alt="Stylish workplace with computer at home" class="form-imagecheck-image">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 col-sm-4">
|
||||
<label class="form-imagecheck mb-2">
|
||||
<input name="avatar" type="radio" value="moe.jpg" class="form-imagecheck-input"/>
|
||||
<span class="form-imagecheck-figure">
|
||||
<img src="./static/avatars/moe.jpg" alt="Pink desk in the home office" class="form-imagecheck-image">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 col-sm-4">
|
||||
<label class="form-imagecheck mb-2">
|
||||
<input name="avatar" type="radio" value="poochie.jpg" class="form-imagecheck-input" />
|
||||
<span class="form-imagecheck-figure">
|
||||
<img src="./static/avatars/poochie.jpg" alt="Young woman sitting on the sofa and working on her laptop" class="form-imagecheck-image">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 col-sm-4">
|
||||
<label class="form-imagecheck mb-2">
|
||||
<input name="avatar" type="radio" value="skinner.jpg" class="form-imagecheck-input" />
|
||||
<span class="form-imagecheck-figure">
|
||||
<img src="./static/avatars/skinner.jpg" alt="Coffee on a table with other items" class="form-imagecheck-image">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-check">
|
||||
<input type="checkbox" class="form-check-input" name="tos"/>
|
||||
<span class="form-check-label">Agree to <a href="/TOS" tabindex="-1">Terms of Service.</a>.</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row align-items-center mt-2">
|
||||
|
||||
<div class="col">
|
||||
<a href="/login">Sign-in</a>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
|
||||
<div class="d-none d-md-flex">
|
||||
|
||||
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip" data-bs-placement="bottom">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" /></svg>
|
||||
</a>
|
||||
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip" data-bs-placement="bottom">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" /><path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" /></svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Install</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1684106062" defer></script>
|
||||
<script src="./js/demo.min.js?1684106062" defer></script>
|
||||
</body>
|
||||
</html>
|
145
views/pages/settings.ejs
Normal file
|
@ -0,0 +1,145 @@
|
|||
<!doctype html>
|
||||
<!--
|
||||
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Settings</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1684106062" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<script src="./js/demo-theme.min.js?1684106062"></script>
|
||||
<div class="page">
|
||||
<!-- Navbar -->
|
||||
<%- include('../partials/navbar.ejs') %>
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Account Settings
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="card">
|
||||
<div class="row g-0">
|
||||
<div class="col-3 d-none d-md-block border-end">
|
||||
<div class="card-body">
|
||||
<h4 class="subheader">Business settings</h4>
|
||||
<div class="list-group list-group-transparent">
|
||||
<a href="/account" class="list-group-item list-group-item-action d-flex align-items-center">Account</a>
|
||||
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">My Notifications</a>
|
||||
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">Connected Apps</a>
|
||||
<a href="/settings" class="list-group-item list-group-item-action d-flex align-items-center active">Settings</a>
|
||||
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">Billing & Invoices</a>
|
||||
</div>
|
||||
<h4 class="subheader mt-4">Experience</h4>
|
||||
<div class="list-group list-group-transparent">
|
||||
<a href="#" class="list-group-item list-group-item-action">Credits</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col d-flex flex-column">
|
||||
|
||||
<div class="card-body">
|
||||
<h2 class="mb-2">Settings</h2>
|
||||
<p class="text-muted mb-4">Configure server below</p>
|
||||
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<a href="./QuickConnect.bat" class="btn" download="QuickConnect.bat">
|
||||
<!-- Download SVG icon from https://tabler-icons.io/i/brand-tabler-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-windows" 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="M17.8 20l-12 -1.5c-1 -.1 -1.8 -.9 -1.8 -1.9v-9.2c0 -1 .8 -1.8 1.8 -1.9l12 -1.5c1.2 -.1 2.2 .8 2.2 1.9v12.1c0 1.2 -1.1 2.1 -2.2 1.9z"></path> <path d="M12 5l0 14"></path> <path d="M4 12l16 0"></path> </svg>
|
||||
Windows QuickConnect
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md">
|
||||
<div class="form-label">Full Name</div>
|
||||
<input type="text" class="form-control" value="" readonly="">
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include('../partials/footer.ejs') %>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1684106062" defer></script>
|
||||
<script src="./js/demo.min.js?1684106062" defer></script>
|
||||
</body>
|
||||
</html>
|
81
views/pages/users.ejs
Normal file
|
@ -0,0 +1,81 @@
|
|||
<!doctype html>
|
||||
<!--
|
||||
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Users</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./css/tabler.min.css?1685973381" rel="stylesheet"/>
|
||||
<link href="./css/demo.min.css?1685973381" rel="stylesheet"/>
|
||||
<style>
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<script src="./js/demo-theme.min.js?1685973381"></script>
|
||||
<div class="page">
|
||||
<!-- Navbar -->
|
||||
|
||||
<%- include('../partials/navbar.ejs') %>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Users
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="row row-cards">
|
||||
|
||||
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter table-mobile-md card-table">
|
||||
<tbody>
|
||||
|
||||
<%- user_list %>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('../partials/footer.ejs') %>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./js/tabler.min.js?1685973381" defer></script>
|
||||
<script src="./js/demo.min.js?1685973381" defer></script>
|
||||
</body>
|
||||
</html>
|
34
views/partials/footer.ejs
Normal file
|
@ -0,0 +1,34 @@
|
|||
<footer class="footer footer-transparent d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row text-center align-items-center flex-row-reverse">
|
||||
<div class="col-lg-auto ms-lg-auto">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item"><a href="https://github.com/lllllllillllllillll/DweebUI/blob/main/README.md" target="_blank" class="link-secondary" rel="noopener">Documentation</a></li>
|
||||
<li class="list-inline-item"><a href="https://github.com/lllllllillllllillll/DweebUI/blob/main/LICENSE" class="link-secondary">License</a></li>
|
||||
<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>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item">
|
||||
Copyright © 2023
|
||||
<a href="https://dweebui.com" class="link-secondary">DweebUI</a>.
|
||||
All rights reserved.
|
||||
</li>
|
||||
<li class="list-inline-item">
|
||||
<a href="#" class="link-secondary" rel="noopener">
|
||||
v0.01
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
253
views/partials/navbar.ejs
Normal file
|
@ -0,0 +1,253 @@
|
|||
<header class="navbar navbar-expand-md d-print-none">
|
||||
|
||||
<script>
|
||||
|
||||
var themeStorageKey = "tablerTheme";
|
||||
var defaultTheme = "light";
|
||||
var selectedTheme;
|
||||
|
||||
(function (factory) {
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
factory();
|
||||
})((function () {
|
||||
'use strict';
|
||||
|
||||
var params = new Proxy(new URLSearchParams(window.location.search), {
|
||||
get: function get(searchParams, prop) {
|
||||
return searchParams.get(prop);
|
||||
}
|
||||
});
|
||||
if (!!params.theme) {
|
||||
localStorage.setItem(themeStorageKey, params.theme);
|
||||
selectedTheme = params.theme;
|
||||
} else {
|
||||
var storedTheme = localStorage.getItem(themeStorageKey);
|
||||
selectedTheme = storedTheme ? storedTheme : defaultTheme;
|
||||
}
|
||||
if (selectedTheme === 'dark') {
|
||||
document.body.setAttribute("data-bs-theme", selectedTheme);
|
||||
} else {
|
||||
document.body.removeAttribute("data-bs-theme");
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
|
||||
function toggleTheme(button) {
|
||||
if (button.value == 'dark-theme') {
|
||||
document.body.setAttribute("data-bs-theme", 'dark');
|
||||
localStorage.setItem(themeStorageKey, 'dark');
|
||||
}
|
||||
else if (button.value == 'light-theme') {
|
||||
document.body.removeAttribute("data-bs-theme");
|
||||
localStorage.setItem(themeStorageKey, 'light');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<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">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
|
||||
<a href="#">
|
||||
<img src="./static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
|
||||
</a>
|
||||
</h1>
|
||||
<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">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/lock -->
|
||||
<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>
|
||||
VPN
|
||||
</a>
|
||||
<a href="#" class="btn text-green">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/shield -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-shield" 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 3a12 12 0 0 0 8.5 3a12 12 0 0 1 -8.5 15a12 12 0 0 1 -8.5 -15a12 12 0 0 0 8.5 -3"></path> </svg>
|
||||
Firewall
|
||||
</a>
|
||||
<a href="#" class="btn text-green">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/shield -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-screen-share" 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="M21 12v3a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10a1 1 0 0 1 1 -1h9"></path> <path d="M7 20l10 0"></path> <path d="M9 16l0 4"></path> <path d="M15 16l0 4"></path> <path d="M17 4h4v4"></path> <path d="M16 9l5 -5"></path> </svg>
|
||||
VNC
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none d-md-flex">
|
||||
|
||||
<button class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom" value="dark-theme" onclick="toggleTheme(this)">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" /> </svg>
|
||||
</button>
|
||||
|
||||
<button class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom" value="light-theme" onclick="toggleTheme(this)">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" /> <path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" /> </svg>
|
||||
</button>
|
||||
|
||||
<div class="nav-item dropdown d-none d-md-flex me-3">
|
||||
<a href="#" class="nav-link px-0" data-bs-toggle="dropdown" tabindex="-1" aria-label="Show notifications">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/bell -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6" /> <path d="M9 17v1a3 3 0 0 0 6 0v-1" /> </svg>
|
||||
<!-- <span class="badge bg-red"></span> -->
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-arrow dropdown-menu-end dropdown-menu-card">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Alerts</h3>
|
||||
</div>
|
||||
<div class="list-group list-group-flush list-group-hoverable">
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot status-dot-animated bg-green d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">App Installed</a>
|
||||
<div class="d-block text-muted text-truncate mt-n1">
|
||||
Just an example of an app install notification.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-muted" 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="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /> </svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot status-dot-animated bg-red d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">App Uninstalled</a>
|
||||
<div class="d-block text-muted text-truncate mt-n1">
|
||||
Just an example of an app uninstall notification.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-muted" 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="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /> </svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-item dropdown">
|
||||
<a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown" aria-label="Open user menu">
|
||||
<span class="avatar avatar-sm"><%- avatar %></span>
|
||||
<div class="d-none d-xl-block ps-2">
|
||||
<div>
|
||||
<%= name %>
|
||||
</div>
|
||||
<div class="mt-1 small text-muted">
|
||||
<%= role %>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
||||
<a href="#" class="dropdown-item">Status</a>
|
||||
<a href="/account" class="dropdown-item">Account</a>
|
||||
<a href="#" class="dropdown-item">Feedback</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="/settings" class="dropdown-item">Settings</a>
|
||||
<a href="/logout" class="dropdown-item">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<header class="navbar-expand-md">
|
||||
<div class="collapse navbar-collapse" id="navbar-menu">
|
||||
<div class="navbar">
|
||||
<div class="container-xl">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./">
|
||||
<span
|
||||
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from https://tabler-icons.io/i/dashboard -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-dashboard" 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 13m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path> <path d="M13.45 11.55l2.05 -2.05"></path> <path d="M6.4 20a9 9 0 1 1 11.2 0z"></path> </svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Dashboard
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/apps">
|
||||
<span
|
||||
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from https://tabler-icons.io/i/apps -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-apps" 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="M4 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path> <path d="M4 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path> <path d="M14 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path> <path d="M14 7l6 0"></path> <path d="M17 4l0 6"></path> </svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Apps
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/users">
|
||||
<span
|
||||
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from https://tabler-icons.io/i/user -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-user" 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="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0"></path> <path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"></path> </svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Users
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#navbar-help" data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside" role="button" aria-expanded="false">
|
||||
<span
|
||||
class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/lifebuoy -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-tool" 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="M7 10h3v-3l-3.5 -3.5a6 6 0 0 1 8 8l6 6a2 2 0 0 1 -3 3l-6 -6a6 6 0 0 1 -8 -8l3.5 3.5"></path> </svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Tools
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#" target="_blank" rel="noopener">
|
||||
VPN
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
Firewall
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" target="_blank" rel="noopener">
|
||||
Backups
|
||||
</a>
|
||||
<a class="dropdown-item text-pink" href="#" target="_blank"
|
||||
rel="noopener">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-inline me-1" 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 project!
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="my-2 my-md-0 flex-grow-1 flex-md-grow-0 order-first order-md-last">
|
||||
<form action="./" method="get" autocomplete="off" novalidate>
|
||||
<div class="input-icon">
|
||||
<span class="input-icon-addon">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/search -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="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 d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" /> <path d="M21 21l-6 -6" /> </svg>
|
||||
</span>
|
||||
<input type="text" value="" class="form-control" placeholder="Search…" aria-label="Search in website">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
0
views/partials/site_list.ejs
Normal file
12
views/partials/users_list.ejs
Normal file
|
@ -0,0 +1,12 @@
|
|||
<tr>
|
||||
<td><input class="form-check-input" type="checkbox"></td>
|
||||
<td>1</td>
|
||||
<td><span class="avatar me-2" style="background-image: url(./static/avatars/burns.jpg)"></span></td>
|
||||
<td>John Doe</td>
|
||||
<td>JDoe</td>
|
||||
<td>JDoe@gmail.com</td>
|
||||
<td>685468468465138</td>
|
||||
<td>Admin</td>
|
||||
<td><span class="badge badge-outline text-green">Active</span></td>
|
||||
<td><a href="#" class="btn">Edit</a></td>
|
||||
</tr>
|