mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-22 15:20:09 +01:00
New darkmode theme
This commit is contained in:
parent
a053504bb8
commit
13b9d15d8f
20
src/api.py
20
src/api.py
@ -2,10 +2,15 @@ import ipaddress, subprocess, datetime, os, util
|
||||
from datetime import datetime, timedelta
|
||||
from flask import jsonify
|
||||
from util import *
|
||||
import configparser
|
||||
|
||||
notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."}
|
||||
good = {"status": True, "reason": ""}
|
||||
|
||||
def ret(status=True, reason="", data=""):
|
||||
return {"status": status, "reason": reason, "data": data}
|
||||
|
||||
|
||||
|
||||
def togglePeerAccess(data, g):
|
||||
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
||||
@ -70,7 +75,7 @@ class managePeer:
|
||||
})
|
||||
return {"status": True, "reason": "", "data": chartData}
|
||||
|
||||
class addConfiguration:
|
||||
class manageConfiguration:
|
||||
def AddressCheck(self, data):
|
||||
address = data['address']
|
||||
address = address.replace(" ", "")
|
||||
@ -165,4 +170,15 @@ class addConfiguration:
|
||||
except Exception as e:
|
||||
return {"status": False, "reason": "Can't delete peer", "data": str(e)}
|
||||
|
||||
return good
|
||||
return good
|
||||
|
||||
def getConfigurationInfo(self, configName, WG_CONF_PATH):
|
||||
conf = configparser.ConfigParser(strict=False)
|
||||
try:
|
||||
with open(f'{WG_CONF_PATH}/{configName}.conf', 'r'):
|
||||
conf.read(f'{WG_CONF_PATH}/{configName}.conf')
|
||||
if not conf.has_section("Interface"):
|
||||
return ret(status=False, reason="No [Interface] in configuration file")
|
||||
return ret(data=dict(conf['Interface']))
|
||||
except FileNotFoundError as err:
|
||||
return ret(status=False, reason=str(err))
|
@ -3,6 +3,7 @@
|
||||
Under Apache-2.0 License
|
||||
"""
|
||||
|
||||
from crypt import methods
|
||||
import sqlite3
|
||||
import configparser
|
||||
import hashlib
|
||||
@ -1599,7 +1600,7 @@ def addConfigurationAddressCheck():
|
||||
returnData = {"status": True, "reason": ""}
|
||||
required = ['address']
|
||||
if checkJSONAllParameter(required, data):
|
||||
returnData = api.addConfiguration.AddressCheck(api.addConfiguration, data)
|
||||
returnData = api.manageConfiguration.AddressCheck(api.manageConfiguration, data)
|
||||
else:
|
||||
return jsonify(api.notEnoughParameter)
|
||||
return jsonify(returnData)
|
||||
@ -1610,7 +1611,7 @@ def addConfigurationPortCheck():
|
||||
returnData = {"status": True, "reason": ""}
|
||||
required = ['port']
|
||||
if checkJSONAllParameter(required, data):
|
||||
returnData = api.addConfiguration.PortCheck(api.addConfiguration, data, get_conf_list())
|
||||
returnData = api.manageConfiguration.PortCheck(api.manageConfiguration, data, get_conf_list())
|
||||
else:
|
||||
return jsonify(api.notEnoughParameter)
|
||||
return jsonify(returnData)
|
||||
@ -1621,7 +1622,7 @@ def addConfigurationNameCheck():
|
||||
returnData = {"status": True, "reason": ""}
|
||||
required = ['name']
|
||||
if checkJSONAllParameter(required, data):
|
||||
returnData = api.addConfiguration.NameCheck(api.addConfiguration, data, get_conf_list())
|
||||
returnData = api.manageConfiguration.NameCheck(api.manageConfiguration, data, get_conf_list())
|
||||
else:
|
||||
return jsonify(api.notEnoughParameter)
|
||||
return jsonify(returnData)
|
||||
@ -1641,36 +1642,40 @@ def addConfiguration():
|
||||
if i not in data.keys():
|
||||
return jsonify(api.notEnoughParameter)
|
||||
config = get_conf_list()
|
||||
nameCheck = api.addConfiguration.NameCheck(api.addConfiguration, {"name": data['addConfigurationName']}, config)
|
||||
nameCheck = api.manageConfiguration.NameCheck(api.manageConfiguration, {"name": data['addConfigurationName']}, config)
|
||||
if not nameCheck['status']:
|
||||
return nameCheck
|
||||
|
||||
portCheck = api.addConfiguration.PortCheck(api.addConfiguration, {"port": data['addConfigurationListenPort']}, config)
|
||||
portCheck = api.manageConfiguration.PortCheck(api.manageConfiguration, {"port": data['addConfigurationListenPort']}, config)
|
||||
if not portCheck['status']:
|
||||
return portCheck
|
||||
|
||||
addressCheck = api.addConfiguration.AddressCheck(api.addConfiguration, {"address": data['addConfigurationAddress']})
|
||||
addressCheck = api.manageConfiguration.AddressCheck(api.manageConfiguration, {"address": data['addConfigurationAddress']})
|
||||
if not addressCheck['status']:
|
||||
return addressCheck
|
||||
|
||||
returnData = api.addConfiguration.addConfiguration(api.addConfiguration, data, config, WG_CONF_PATH)
|
||||
returnData = api.manageConfiguration.addConfiguration(api.manageConfiguration, data, config, WG_CONF_PATH)
|
||||
return jsonify(returnData)
|
||||
|
||||
@app.route('/api/deleteConfiguration', methods=['POST'])
|
||||
def deleteConfiguration():
|
||||
data = request.get_json()
|
||||
returnData = {"status": True, "reason": "", "data":""}
|
||||
required = ['name']
|
||||
if not checkJSONAllParameter(required, data):
|
||||
return jsonify(api.notEnoughParameter)
|
||||
|
||||
returnData = api.addConfiguration.deleteConfiguration(api.addConfiguration, data, get_conf_list(), g, WG_CONF_PATH)
|
||||
|
||||
|
||||
|
||||
|
||||
returnData = api.manageConfiguration.deleteConfiguration(api.manageConfiguration, data, get_conf_list(), g, WG_CONF_PATH)
|
||||
return returnData
|
||||
|
||||
@app.route('/api/getConfigurationInfo', methods=['GET'])
|
||||
def getConfigurationInfo():
|
||||
data = request.args.to_dict()
|
||||
required = ['configName']
|
||||
if not checkJSONAllParameter(required, data):
|
||||
return jsonify(api.notEnoughParameter)
|
||||
else:
|
||||
return api.manageConfiguration.getConfigurationInfo(api.manageConfiguration, data['configName'], WG_CONF_PATH)
|
||||
|
||||
|
||||
"""
|
||||
Dashboard Tools Related
|
||||
"""
|
||||
|
@ -173,6 +173,10 @@ body {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
|
||||
.btn-control:hover{
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.btn-control:active,
|
||||
.btn-control:focus {
|
||||
background-color: transparent !important;
|
||||
@ -914,4 +918,8 @@ pre.index-alert {
|
||||
|
||||
.sb-update-url .dot-running{
|
||||
transform: translateX(10px);
|
||||
}
|
||||
|
||||
.list-group-item{
|
||||
transition: all 0.1s ease-in;
|
||||
}
|
123
src/static/css/theme/dark.css
Normal file
123
src/static/css/theme/dark.css
Normal file
@ -0,0 +1,123 @@
|
||||
:root{
|
||||
--blue: #3f9eff;
|
||||
--dark1: #1C1C1E;
|
||||
--dark2: #232323;
|
||||
--dark3: #3f3f3f;
|
||||
}
|
||||
|
||||
a{
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
body{
|
||||
background-color: var(--dark1);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
hr{
|
||||
border-top: 1px solid rgb(255 255 255 / 10%);
|
||||
}
|
||||
|
||||
/* Color */
|
||||
|
||||
.bg-dark{
|
||||
background-color: #232323!important;
|
||||
}
|
||||
|
||||
.text-primary{
|
||||
color: var(--blue) !important;
|
||||
}
|
||||
|
||||
/* Form Related */
|
||||
|
||||
.form-control{
|
||||
color: #ffffff;
|
||||
background-color: #232323;
|
||||
border: 1px solid #686868;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
color: #ffffff;
|
||||
background-color: #232323;
|
||||
border-color: #686868;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.50);
|
||||
}
|
||||
|
||||
.form-control:disabled, .form-control[readonly]{
|
||||
background-color: #525252;
|
||||
opacity: 1;
|
||||
color: #a5a5a5;
|
||||
}
|
||||
|
||||
.custom-control-label::before{
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Side Bar */
|
||||
|
||||
.sidebar{
|
||||
background-color: #232323 !important;
|
||||
}
|
||||
|
||||
.sidebar .nav-link, .bottomNavContainer .nav-link{
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active, .bottomNavContainer .nav-link.active{
|
||||
color: var(--blue) !important;
|
||||
}
|
||||
|
||||
.nav-link:hover{
|
||||
background-color: #3f3f3f;
|
||||
}
|
||||
|
||||
.card{
|
||||
background-color: #232323;
|
||||
}
|
||||
|
||||
|
||||
/* Button Related */
|
||||
|
||||
.btn-outline-primary{
|
||||
color: var(--blue);
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
color: #fff;
|
||||
background-color: var(--blue);
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
.btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active, .show>.btn-outline-primary.dropdown-toggle{
|
||||
background-color: var(--blue);
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
|
||||
/* Configuration Card (index.html) */
|
||||
.conf_card:hover{
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.modal-content{
|
||||
background-color: var(--dark1);
|
||||
}
|
||||
|
||||
.modal-header, .modal-footer{
|
||||
border-color:rgb(255 255 255 / 10%);;
|
||||
}
|
||||
|
||||
/* List Group Item */
|
||||
.list-group-item{
|
||||
background-color: var(--dark2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.list-group-item:hover{
|
||||
color: white;
|
||||
background-color: var(--dark3);
|
||||
border-color: var(--dark3);
|
||||
}
|
@ -8,7 +8,7 @@ let peers = [];
|
||||
/**
|
||||
* Definitions
|
||||
*/
|
||||
$(".bottomNavConfigs").addClass("active")
|
||||
$(".bottomNavConfigs").addClass("active");
|
||||
let configuration_name;
|
||||
let configuration_interval;
|
||||
let configuration_timeout = window.localStorage.getItem("configurationTimeout");
|
||||
@ -38,6 +38,7 @@ let peers = [];
|
||||
let settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), bootstrapModalConfig);
|
||||
let deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), bootstrapModalConfig);
|
||||
let configurationDeleteModal = new bootstrap.Modal(document.getElementById('configuration_delete_modal'), bootstrapModalConfig);
|
||||
let configurationEditModal = new bootstrap.Modal(document.getElementById('editConfigurationModal'), bootstrapModalConfig);
|
||||
let peerDataUsageModal = new bootstrap.Modal(document.getElementById('peerDataUsage'), bootstrapModalConfig);
|
||||
$("[data-toggle='tooltip']").tooltip();
|
||||
$("[data-toggle='popover']").popover();
|
||||
@ -977,6 +978,13 @@ let peers = [];
|
||||
});
|
||||
}
|
||||
|
||||
function getConfigurationDetails() {
|
||||
function done(res){
|
||||
console.log(res);
|
||||
}
|
||||
ajaxGetJSON(`/api/getConfigurationInfo?configName=${configuration_name}`, done)
|
||||
}
|
||||
|
||||
configurations = {
|
||||
peerDataUsageChartObj: () => { return peerDataUsageChartObj },
|
||||
peerDataUsageModal: () => { return peerDataUsageModal },
|
||||
@ -987,6 +995,7 @@ let peers = [];
|
||||
ipModal: () => { return ipModal; },
|
||||
qrcodeModal: () => { return qrcodeModal; },
|
||||
settingModal: () => { return settingModal; },
|
||||
configurationEditModal: () => { return configurationEditModal; },
|
||||
configurationTimeout: () => { return configuration_timeout; },
|
||||
updateDisplayMode: () => { display_mode = window.localStorage.getItem("displayMode"); },
|
||||
removeConfigurationInterval: () => { removeConfigurationInterval(); },
|
||||
@ -998,7 +1007,7 @@ let peers = [];
|
||||
parsePeers: (response) => { parsePeers(response); },
|
||||
toggleAccess: (peerID) => { toggleAccess(peerID); },
|
||||
|
||||
|
||||
getConfigurationDetails: () => { getConfigurationDetails() },
|
||||
setConfigurationName: (confName) => { configuration_name = confName; },
|
||||
getConfigurationName: () => { return configuration_name; },
|
||||
setActiveConfigurationName: () => { setActiveConfigurationName(); },
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
let $body = $("body");
|
||||
let available_ips = [];
|
||||
let $add_peer = document.getElementById("save_peer");
|
||||
@ -89,11 +87,6 @@ $body.on("click", ".btn-data-usage-peer", function(){
|
||||
ajaxPostJSON("/api/getPeerDataUsage", {"config": configurations.getConfigurationName(), "peerID": configurations.peerDataUsageChartObj().data.peerID, "interval": window.localStorage.getItem("peerTimePeriod")}, loadPeerDataUsageChartDone);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$('#peerDataUsage').on('shown.bs.modal', function() {
|
||||
configurations.peerDataUsageChartObj().resize();
|
||||
}).on('hidden.bs.modal', function() {
|
||||
@ -117,6 +110,17 @@ $(".switchTimePeriod").on("click", function(){
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Edit Configuration
|
||||
*/
|
||||
|
||||
$editConfiguration = $("#edit_configuration");
|
||||
$editConfiguration.on("click", function(){
|
||||
configurations.getConfigurationDetails();
|
||||
configurations.configurationEditModal().toggle();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* ==========
|
||||
* Add peers
|
||||
|
@ -170,7 +170,7 @@
|
||||
data-url="/download_all/{{conf_data['name']}}"><i
|
||||
class="bi bi-cloud-download-fill"></i> Download All Peers</a>
|
||||
<hr>
|
||||
<a class="text-primary" id="configuration_setting"><i class="bi bi-gear-fill"></i>
|
||||
<a class="text-primary" id="edit_configuration"><i class="bi bi-gear-fill"></i>
|
||||
Configration Settings</a>
|
||||
<a class="text-danger" id="configuration_delete"><i class="bi bi-trash3-fill"></i>
|
||||
Delete Configuration</a>
|
||||
|
@ -14,6 +14,7 @@
|
||||
<link rel="icon" href="{{ url_for('static',filename='img/logo.png') }}"/>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='css/dashboard.css') }}">
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='css/theme/dark.css') }}">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js" integrity="sha512-QSkVNOCYLtj73J4hbmVoOV6KVZuMluZlioC+trLpewV8qMjsWqlIQvkn1KGX2StWvPMdWGBqim1xlC8krl1EKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
|
||||
|
@ -123,7 +123,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="form-group">
|
||||
<label for="addConfigurationPreUp">PreUp</label>
|
||||
|
@ -354,4 +354,109 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="editConfigurationModal">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Edit Configuration</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="addCconfigurationAlert" class="alert alert-danger alert-dismissible fade show d-none"
|
||||
role="alert">
|
||||
<div class="alert-body"></div>
|
||||
</div>
|
||||
<pre id="addCconfigurationAlertMessage" class="index-alert d-none"></pre>
|
||||
<form id="add_configuration_form">
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<label for="editConfigurationPrivateKey">Private Key <code>*</code></label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control codeFont" id="editConfigurationPrivateKey"
|
||||
name="editConfigurationPrivateKey" required>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-danger" id="reGeneratePrivateKey"
|
||||
data-toggle="tooltip" data-placement="top" title="Regenerate Key"><i
|
||||
class="bi bi-arrow-repeat"></i></button>
|
||||
</div>
|
||||
<div id="editConfigurationPrivateKeyFeedback" class="input-feedback"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationName">Configuration Name <code>*</code></label>
|
||||
<input type="text" class="form-control" id="editConfigurationName"
|
||||
name="editConfigurationName" required>
|
||||
<div id="editConfigurationNameFeedback" class="input-feedback"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationListenPort">Listen Port <code>*</code></label>
|
||||
<input type="number" class="form-control codeFont" id="editConfigurationListenPort"
|
||||
name="editConfigurationListenPort" required>
|
||||
<div id="editConfigurationListenPortFeedback" class="input-feedback"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationAddress">Address <code>*</code>
|
||||
|
||||
</label>
|
||||
<input type="text" class="form-control codeFont" id="editConfigurationAddress"
|
||||
placeholder="Ex: 192.168.0.1/24" name="editConfigurationAddress" required>
|
||||
<div id="editConfigurationAddressFeedback" class="input-feedback"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for=""># of available IPs</label>
|
||||
<p class="editConfigurationAvailableIPs">N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationPreUp">PreUp</label>
|
||||
<input type="text" class="form-control codeFont" id="editConfigurationPreUp"
|
||||
name="editConfigurationPreUp">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationPreDown">PreDown</label>
|
||||
<input type="text" class="form-control codeFont" id="editConfigurationPreDown"
|
||||
name="editConfigurationPreDown">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationPostUp">PostUp</label>
|
||||
<input type="text" class="form-control codeFont" id="editConfigurationPostUp"
|
||||
name="editConfigurationPostUp">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editConfigurationPostDown">PostDown</label>
|
||||
<input type="text" class="form-control codeFont" id="editConfigurationPostDown"
|
||||
name="editConfigurationPostDown">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="editConfigurationBtn">Add</button>
|
||||
<div class="text-primary editConfigurationStatus editConfigurationAddStatus d-none">
|
||||
<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
Editing Configuration
|
||||
</div>
|
||||
<div class="text-primary editConfigurationStatus editConfigurationToggleStatus d-none waiting">
|
||||
<i class="bi bi-circle"></i> Toggle Configuration
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -62,7 +62,6 @@
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item"><a href="https://github.com/donaldzou/WGDashboard/releases/tag/{{ session['dashboard_version'] }}"><small class="nav-link text-muted">{{ session['dashboard_version'] }}</small></a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user