1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 23:27:45 +01:00

New darkmode theme

This commit is contained in:
Donald Cheng Hong Zou 2022-04-21 15:11:01 -04:00
parent a053504bb8
commit 13b9d15d8f
11 changed files with 297 additions and 28 deletions

View File

@ -2,10 +2,15 @@ import ipaddress, subprocess, datetime, os, util
from datetime import datetime, timedelta from datetime import datetime, timedelta
from flask import jsonify from flask import jsonify
from util import * from util import *
import configparser
notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."} notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."}
good = {"status": True, "reason": ""} good = {"status": True, "reason": ""}
def ret(status=True, reason="", data=""):
return {"status": status, "reason": reason, "data": data}
def togglePeerAccess(data, g): def togglePeerAccess(data, g):
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone() 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} return {"status": True, "reason": "", "data": chartData}
class addConfiguration: class manageConfiguration:
def AddressCheck(self, data): def AddressCheck(self, data):
address = data['address'] address = data['address']
address = address.replace(" ", "") address = address.replace(" ", "")
@ -166,3 +171,14 @@ class addConfiguration:
return {"status": False, "reason": "Can't delete peer", "data": str(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))

View File

@ -3,6 +3,7 @@
Under Apache-2.0 License Under Apache-2.0 License
""" """
from crypt import methods
import sqlite3 import sqlite3
import configparser import configparser
import hashlib import hashlib
@ -1599,7 +1600,7 @@ def addConfigurationAddressCheck():
returnData = {"status": True, "reason": ""} returnData = {"status": True, "reason": ""}
required = ['address'] required = ['address']
if checkJSONAllParameter(required, data): if checkJSONAllParameter(required, data):
returnData = api.addConfiguration.AddressCheck(api.addConfiguration, data) returnData = api.manageConfiguration.AddressCheck(api.manageConfiguration, data)
else: else:
return jsonify(api.notEnoughParameter) return jsonify(api.notEnoughParameter)
return jsonify(returnData) return jsonify(returnData)
@ -1610,7 +1611,7 @@ def addConfigurationPortCheck():
returnData = {"status": True, "reason": ""} returnData = {"status": True, "reason": ""}
required = ['port'] required = ['port']
if checkJSONAllParameter(required, data): 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: else:
return jsonify(api.notEnoughParameter) return jsonify(api.notEnoughParameter)
return jsonify(returnData) return jsonify(returnData)
@ -1621,7 +1622,7 @@ def addConfigurationNameCheck():
returnData = {"status": True, "reason": ""} returnData = {"status": True, "reason": ""}
required = ['name'] required = ['name']
if checkJSONAllParameter(required, data): 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: else:
return jsonify(api.notEnoughParameter) return jsonify(api.notEnoughParameter)
return jsonify(returnData) return jsonify(returnData)
@ -1641,36 +1642,40 @@ def addConfiguration():
if i not in data.keys(): if i not in data.keys():
return jsonify(api.notEnoughParameter) return jsonify(api.notEnoughParameter)
config = get_conf_list() 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']: if not nameCheck['status']:
return nameCheck 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']: if not portCheck['status']:
return portCheck return portCheck
addressCheck = api.addConfiguration.AddressCheck(api.addConfiguration, {"address": data['addConfigurationAddress']}) addressCheck = api.manageConfiguration.AddressCheck(api.manageConfiguration, {"address": data['addConfigurationAddress']})
if not addressCheck['status']: if not addressCheck['status']:
return addressCheck 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) return jsonify(returnData)
@app.route('/api/deleteConfiguration', methods=['POST']) @app.route('/api/deleteConfiguration', methods=['POST'])
def deleteConfiguration(): def deleteConfiguration():
data = request.get_json() data = request.get_json()
returnData = {"status": True, "reason": "", "data":""}
required = ['name'] required = ['name']
if not checkJSONAllParameter(required, data): if not checkJSONAllParameter(required, data):
return jsonify(api.notEnoughParameter) return jsonify(api.notEnoughParameter)
returnData = api.manageConfiguration.deleteConfiguration(api.manageConfiguration, data, get_conf_list(), g, WG_CONF_PATH)
returnData = api.addConfiguration.deleteConfiguration(api.addConfiguration, data, get_conf_list(), g, WG_CONF_PATH)
return returnData 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 Dashboard Tools Related
""" """

View File

@ -173,6 +173,10 @@ body {
margin: 0 1rem 0 0; margin: 0 1rem 0 0;
} }
.btn-control:hover{
background-color: transparent !important;
}
.btn-control:active, .btn-control:active,
.btn-control:focus { .btn-control:focus {
background-color: transparent !important; background-color: transparent !important;
@ -915,3 +919,7 @@ pre.index-alert {
.sb-update-url .dot-running{ .sb-update-url .dot-running{
transform: translateX(10px); transform: translateX(10px);
} }
.list-group-item{
transition: all 0.1s ease-in;
}

View 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);
}

View File

@ -8,7 +8,7 @@ let peers = [];
/** /**
* Definitions * Definitions
*/ */
$(".bottomNavConfigs").addClass("active") $(".bottomNavConfigs").addClass("active");
let configuration_name; let configuration_name;
let configuration_interval; let configuration_interval;
let configuration_timeout = window.localStorage.getItem("configurationTimeout"); let configuration_timeout = window.localStorage.getItem("configurationTimeout");
@ -38,6 +38,7 @@ let peers = [];
let settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), bootstrapModalConfig); let settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), bootstrapModalConfig);
let deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), bootstrapModalConfig); let deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), bootstrapModalConfig);
let configurationDeleteModal = new bootstrap.Modal(document.getElementById('configuration_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); let peerDataUsageModal = new bootstrap.Modal(document.getElementById('peerDataUsage'), bootstrapModalConfig);
$("[data-toggle='tooltip']").tooltip(); $("[data-toggle='tooltip']").tooltip();
$("[data-toggle='popover']").popover(); $("[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 = { configurations = {
peerDataUsageChartObj: () => { return peerDataUsageChartObj }, peerDataUsageChartObj: () => { return peerDataUsageChartObj },
peerDataUsageModal: () => { return peerDataUsageModal }, peerDataUsageModal: () => { return peerDataUsageModal },
@ -987,6 +995,7 @@ let peers = [];
ipModal: () => { return ipModal; }, ipModal: () => { return ipModal; },
qrcodeModal: () => { return qrcodeModal; }, qrcodeModal: () => { return qrcodeModal; },
settingModal: () => { return settingModal; }, settingModal: () => { return settingModal; },
configurationEditModal: () => { return configurationEditModal; },
configurationTimeout: () => { return configuration_timeout; }, configurationTimeout: () => { return configuration_timeout; },
updateDisplayMode: () => { display_mode = window.localStorage.getItem("displayMode"); }, updateDisplayMode: () => { display_mode = window.localStorage.getItem("displayMode"); },
removeConfigurationInterval: () => { removeConfigurationInterval(); }, removeConfigurationInterval: () => { removeConfigurationInterval(); },
@ -998,7 +1007,7 @@ let peers = [];
parsePeers: (response) => { parsePeers(response); }, parsePeers: (response) => { parsePeers(response); },
toggleAccess: (peerID) => { toggleAccess(peerID); }, toggleAccess: (peerID) => { toggleAccess(peerID); },
getConfigurationDetails: () => { getConfigurationDetails() },
setConfigurationName: (confName) => { configuration_name = confName; }, setConfigurationName: (confName) => { configuration_name = confName; },
getConfigurationName: () => { return configuration_name; }, getConfigurationName: () => { return configuration_name; },
setActiveConfigurationName: () => { setActiveConfigurationName(); }, setActiveConfigurationName: () => { setActiveConfigurationName(); },

View File

@ -1,5 +1,3 @@
let $body = $("body"); let $body = $("body");
let available_ips = []; let available_ips = [];
let $add_peer = document.getElementById("save_peer"); 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); ajaxPostJSON("/api/getPeerDataUsage", {"config": configurations.getConfigurationName(), "peerID": configurations.peerDataUsageChartObj().data.peerID, "interval": window.localStorage.getItem("peerTimePeriod")}, loadPeerDataUsageChartDone);
}); });
$('#peerDataUsage').on('shown.bs.modal', function() { $('#peerDataUsage').on('shown.bs.modal', function() {
configurations.peerDataUsageChartObj().resize(); configurations.peerDataUsageChartObj().resize();
}).on('hidden.bs.modal', function() { }).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 * Add peers

View File

@ -170,7 +170,7 @@
data-url="/download_all/{{conf_data['name']}}"><i data-url="/download_all/{{conf_data['name']}}"><i
class="bi bi-cloud-download-fill"></i> Download All Peers</a> class="bi bi-cloud-download-fill"></i> Download All Peers</a>
<hr> <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> Configration Settings</a>
<a class="text-danger" id="configuration_delete"><i class="bi bi-trash3-fill"></i> <a class="text-danger" id="configuration_delete"><i class="bi bi-trash3-fill"></i>
Delete Configuration</a> Delete Configuration</a>

View File

@ -14,6 +14,7 @@
<link rel="icon" href="{{ url_for('static',filename='img/logo.png') }}"/> <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" 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/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"> <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> <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"/> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>

View File

@ -123,7 +123,6 @@
</div> </div>
</div> </div>
</div> </div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<label for="addConfigurationPreUp">PreUp</label> <label for="addConfigurationPreUp">PreUp</label>

View File

@ -355,3 +355,108 @@
</div> </div>
</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">&times;</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>

View File

@ -62,7 +62,6 @@
<ul class="nav flex-column"> <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> <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> </ul>
</div> </div>
</div> </div>
</div> </div>