mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 16:00:28 +01:00
Made some progress ;)
This commit is contained in:
parent
41e05ddf9c
commit
c7ca20b45a
@ -35,9 +35,6 @@ from icmplib import ping, traceroute
|
||||
# Import other python files
|
||||
import threading
|
||||
|
||||
from sqlalchemy.orm import mapped_column, declarative_base, Session
|
||||
from sqlalchemy import FLOAT, INT, VARCHAR, select, MetaData, DATETIME
|
||||
from sqlalchemy import create_engine, inspect
|
||||
from flask.json.provider import DefaultJSONProvider
|
||||
|
||||
DASHBOARD_VERSION = 'v4.0'
|
||||
@ -141,7 +138,6 @@ class WireguardConfiguration:
|
||||
|
||||
self.Status = self.getStatus()
|
||||
|
||||
|
||||
else:
|
||||
self.Name = data["ConfigurationName"]
|
||||
for i in dir(self):
|
||||
@ -168,7 +164,7 @@ class WireguardConfiguration:
|
||||
# print(self.__parser.sections())
|
||||
self.__parser.write(configFile)
|
||||
|
||||
self.Peers = []
|
||||
self.Peers: list[Peer] = []
|
||||
|
||||
# Create tables in database
|
||||
self.__createDatabase()
|
||||
@ -313,6 +309,30 @@ class WireguardConfiguration:
|
||||
return True, i
|
||||
return False, None
|
||||
|
||||
def deletePeers(self, listOfPublicKeys):
|
||||
numOfDeletedPeers = 0
|
||||
numOfFailedToDeletePeers = 0
|
||||
for p in listOfPublicKeys:
|
||||
found, pf = self.searchPeer(p)
|
||||
if found:
|
||||
try:
|
||||
subprocess.check_output(f"wg set {self.Name} peer {pf.id} remove",
|
||||
shell=True, stderr=subprocess.STDOUT)
|
||||
cursor.execute("DELETE FROM %s WHERE id = ?" % self.Name, (pf.id,))
|
||||
numOfDeletedPeers += 1
|
||||
except Exception as e:
|
||||
numOfFailedToDeletePeers += 1
|
||||
|
||||
if not self.__wgSave():
|
||||
return ResponseObject(False, "Failed to save configuration through WireGuard")
|
||||
|
||||
self.__getPeers()
|
||||
|
||||
if numOfDeletedPeers == len(listOfPublicKeys):
|
||||
return ResponseObject(True, f"Deleted {numOfDeletedPeers} peer(s)")
|
||||
return ResponseObject(False,
|
||||
f"Deleted {numOfDeletedPeers} peer(s) successfully. Failed to delete {numOfFailedToDeletePeers} peer(s)")
|
||||
|
||||
def __savePeers(self):
|
||||
for i in self.Peers:
|
||||
d = i.toJson()
|
||||
@ -329,6 +349,13 @@ class WireguardConfiguration:
|
||||
)
|
||||
sqldb.commit()
|
||||
|
||||
def __wgSave(self) -> tuple[bool, str] | tuple[bool, None]:
|
||||
try:
|
||||
subprocess.check_output(f"wg-quick save {self.Name}", shell=True, stderr=subprocess.STDOUT)
|
||||
return True, None
|
||||
except subprocess.CalledProcessError as e:
|
||||
return False, str(e)
|
||||
|
||||
def getPeersLatestHandshake(self):
|
||||
try:
|
||||
latestHandshake = subprocess.check_output(f"wg show {self.Name} latest-handshakes",
|
||||
@ -383,22 +410,25 @@ class WireguardConfiguration:
|
||||
data_usage[i][0],))
|
||||
total_sent = 0
|
||||
total_receive = 0
|
||||
cursor.execute(
|
||||
"UPDATE %s SET total_receive = ?, total_sent = ?, total_data = ? WHERE id = ?"
|
||||
% self.Name, (round(total_receive, 4), round(total_sent, 4),
|
||||
round(total_receive + total_sent, 4), data_usage[i][0],))
|
||||
|
||||
_, p = self.searchPeer(data_usage[i][0])
|
||||
if p.total_receive != round(total_receive, 4) or p.total_sent != round(total_sent, 4):
|
||||
cursor.execute(
|
||||
"UPDATE %s SET total_receive = ?, total_sent = ?, total_data = ? WHERE id = ?"
|
||||
% self.Name, (round(total_receive, 4), round(total_sent, 4),
|
||||
round(total_receive + total_sent, 4), data_usage[i][0],))
|
||||
now = datetime.now()
|
||||
now_string = now.strftime("%d/%m/%Y %H:%M:%S")
|
||||
cursor.execute(f'''
|
||||
INSERT INTO %s_transfer
|
||||
(id, total_receive, total_sent, total_data,
|
||||
cumu_receive, cumu_sent, cumu_data, time)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''' % self.Name, (data_usage[i][0], round(total_receive, 4), round(total_sent, 4),
|
||||
round(total_receive + total_sent, 4), round(cumulative_receive, 4),
|
||||
round(cumulative_sent, 4),
|
||||
round(cumulative_sent + cumulative_receive, 4), now_string,))
|
||||
sqldb.commit()
|
||||
# cursor.execute(f'''
|
||||
# INSERT INTO %s_transfer
|
||||
# (id, total_receive, total_sent, total_data,
|
||||
# cumu_receive, cumu_sent, cumu_data, time)
|
||||
# VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
# ''' % self.Name, (data_usage[i][0], round(total_receive, 4), round(total_sent, 4),
|
||||
# round(total_receive + total_sent, 4), round(cumulative_receive, 4),
|
||||
# round(cumulative_sent, 4),
|
||||
# round(cumulative_sent + cumulative_receive, 4), now_string,))
|
||||
# sqldb.commit()
|
||||
except Exception as e:
|
||||
print("Error" + str(e))
|
||||
|
||||
@ -837,9 +867,14 @@ def auth_req():
|
||||
and "getDashboardConfiguration" not in request.path and "getDashboardTheme" not in request.path
|
||||
and "isTotpEnabled" not in request.path
|
||||
):
|
||||
resp = Flask.make_response(app, "Not Authorized" + request.path)
|
||||
resp.status_code = 401
|
||||
return resp
|
||||
response = Flask.make_response(app, {
|
||||
"status": False,
|
||||
"message": None,
|
||||
"data": None
|
||||
})
|
||||
response.content_type = "application/json"
|
||||
response.status_code = 401
|
||||
return response
|
||||
|
||||
|
||||
@app.route('/api/validateAuthentication', methods=["GET"])
|
||||
@ -999,6 +1034,19 @@ def API_updatePeerSettings(configName):
|
||||
return ResponseObject(False, "Peer does not exist")
|
||||
|
||||
|
||||
@app.route('/api/deletePeers/<configName>', methods=['POST'])
|
||||
def API_deletePeers(configName: str) -> ResponseObject:
|
||||
data = request.get_json()
|
||||
peers = data['peers']
|
||||
if configName in WireguardConfigurations.keys():
|
||||
if len(peers) == 0:
|
||||
return ResponseObject(False, "Please specify more than one peer")
|
||||
configuration = WireguardConfigurations.get(configName)
|
||||
return configuration.deletePeers(peers)
|
||||
|
||||
return ResponseObject(False, "Configuration does not exist")
|
||||
|
||||
|
||||
@app.route('/api/addPeers/<configName>', methods=['POST'])
|
||||
def API_addPeers(configName):
|
||||
data = request.get_json()
|
||||
@ -1055,8 +1103,6 @@ def API_addPeers(configName):
|
||||
|
||||
return ResponseObject()
|
||||
|
||||
|
||||
|
||||
else:
|
||||
if config.searchPeer(public_key)[0] is True:
|
||||
return ResponseObject(False, f"This peer already exist.")
|
||||
@ -1231,7 +1277,7 @@ def backGroundThread():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
engine = create_engine("sqlite:///" + os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard.db'))
|
||||
# engine = create_engine("sqlite:///" + os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard.db'))
|
||||
sqldb = sqlite3.connect(os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard.db'), check_same_thread=False)
|
||||
sqldb.row_factory = sqlite3.Row
|
||||
cursor = sqldb.cursor()
|
||||
|
@ -4,4 +4,6 @@ psutil
|
||||
pyotp
|
||||
flask
|
||||
icmplib
|
||||
sqlalchemy
|
||||
sqlalchemy
|
||||
flask[async]
|
||||
aiosqlite
|
@ -935,4 +935,8 @@ pre.index-alert {
|
||||
|
||||
.theme-switch-btn{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-item.disabled, .dropdown-item:disabled{
|
||||
opacity: 0.7;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { ref } from 'vue'
|
||||
import { onClickOutside } from '@vueuse/core'
|
||||
import "animate.css"
|
||||
import PeerSettingsDropdown from "@/components/configurationComponents/peerSettingsDropdown.vue";
|
||||
export default {
|
||||
name: "peer",
|
||||
@ -76,6 +77,7 @@ export default {
|
||||
<PeerSettingsDropdown
|
||||
@qrcode="(file) => this.$emit('qrcode', file)"
|
||||
@setting="this.$emit('setting')"
|
||||
@refresh="this.$emit('refresh')"
|
||||
:Peer="Peer"
|
||||
v-if="this.subMenuOpened"
|
||||
ref="target"
|
||||
|
@ -100,13 +100,14 @@ export default {
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="mb-4 d-flex align-items-center gap-4">
|
||||
<RouterLink to="peers">
|
||||
<div class="mb-4">
|
||||
<RouterLink to="peers" is="div" class="d-flex align-items-center gap-4 text-decoration-none">
|
||||
<h3 class="mb-0 text-body">
|
||||
<i class="bi bi-chevron-left"></i>
|
||||
</h3>
|
||||
<h3 class="text-body mb-0">Add Peers</h3>
|
||||
</RouterLink>
|
||||
<h3 class="text-body mb-0">New Configuration</h3>
|
||||
|
||||
</div>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<BulkAdd :saving="saving" :data="this.data" :availableIp="this.availableIp"></BulkAdd>
|
||||
|
@ -73,6 +73,7 @@ export default {
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
configurationToggling: false,
|
||||
loading: false,
|
||||
error: null,
|
||||
configurationInfo: [],
|
||||
@ -151,7 +152,24 @@ export default {
|
||||
clearInterval(this.interval)
|
||||
},
|
||||
methods:{
|
||||
getPeers(id){
|
||||
toggle(){
|
||||
this.configurationToggling = true;
|
||||
fetchGet("/api/toggleWireguardConfiguration/", {
|
||||
configurationName: this.configurationInfo.Name
|
||||
}, (res) => {
|
||||
if (res.status){
|
||||
this.dashboardConfigurationStore.newMessage("Server",
|
||||
`${this.configurationInfo.Name} is
|
||||
${res.data ? 'is on':'is off'}`, "Success")
|
||||
}else{
|
||||
this.dashboardConfigurationStore.newMessage("Server",
|
||||
res.message, 'danger')
|
||||
}
|
||||
this.configurationInfo.Status = res.data
|
||||
this.configurationToggling = false;
|
||||
})
|
||||
},
|
||||
getPeers(id = this.$route.params.id){
|
||||
fetchGet("/api/getWireguardConfigurationInfo",
|
||||
{
|
||||
configurationName: id
|
||||
@ -207,7 +225,7 @@ export default {
|
||||
},
|
||||
setInterval(){
|
||||
this.interval = setInterval(() => {
|
||||
this.getPeers(this.$route.params.id)
|
||||
this.getPeers()
|
||||
}, parseInt(this.dashboardConfigurationStore.Configuration.Server.dashboard_refresh_interval))
|
||||
}
|
||||
},
|
||||
@ -338,14 +356,39 @@ export default {
|
||||
|
||||
<template>
|
||||
<div v-if="!this.loading">
|
||||
<div>
|
||||
<small CLASS="text-muted">CONFIGURATION</small>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<h1 class="mb-0"><samp>{{this.configurationInfo.Name}}</samp></h1>
|
||||
<div class="dot active ms-0"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<small CLASS="text-muted">CONFIGURATION</small>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<h1 class="mb-0"><samp>{{this.configurationInfo.Name}}</samp></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card rounded-3 bg-transparent shadow-sm ms-auto">
|
||||
<div class="card-body py-2 d-flex align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-muted"><small>Status</small></p>
|
||||
<div class="form-check form-switch ms-auto">
|
||||
<label class="form-check-label" style="cursor: pointer" :for="'switch' + this.configurationInfo.id">
|
||||
{{this.configurationToggling ? 'Turning ':''}}
|
||||
{{this.configurationInfo.Status ? "On":"Off"}}
|
||||
<span v-if="this.configurationToggling"
|
||||
class="spinner-border spinner-border-sm" aria-hidden="true"></span>
|
||||
</label>
|
||||
<input class="form-check-input"
|
||||
style="cursor: pointer"
|
||||
:disabled="this.configurationToggling"
|
||||
type="checkbox" role="switch" :id="'switch' + this.configurationInfo.id"
|
||||
@change="this.toggle()"
|
||||
v-model="this.configurationInfo.Status"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dot ms-5" :class="{active: this.configurationInfo.Status}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3 gy-2 gx-2 mb-2">
|
||||
|
||||
<div class="col-6 col-lg-3">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm">
|
||||
<div class="card-body py-2">
|
||||
@ -419,36 +462,36 @@ export default {
|
||||
</div>
|
||||
<div class="row gx-2 gy-2 mb-5">
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
|
||||
<div class="card-header bg-transparent border-0"><small class="text-muted">Peers Total Data Usage</small></div>
|
||||
<div class="card-body pt-1">
|
||||
<Bar
|
||||
:data="individualDataUsage"
|
||||
:options="individualDataUsageChartOption"
|
||||
style="height: 200px; width: 100%"></Bar>
|
||||
style="width: 100%; height: 200px; max-height: 200px"></Bar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm col-lg-3">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
|
||||
<div class="card-header bg-transparent border-0"><small class="text-muted">Real Time Received Data Usage</small></div>
|
||||
<div class="card-body pt-1">
|
||||
<Line
|
||||
:options="chartOptions"
|
||||
:data="receiveData"
|
||||
style="width: 100%; height: 200px"
|
||||
style="width: 100%; height: 200px; max-height: 200px"
|
||||
></Line>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm col-lg-3">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm">
|
||||
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
|
||||
<div class="card-header bg-transparent border-0"><small class="text-muted">Real Time Sent Data Usage</small></div>
|
||||
<div class="card-body pt-1">
|
||||
<Line
|
||||
:options="chartOptions"
|
||||
:data="sentData"
|
||||
style="width: 100%; height: 200px"
|
||||
style="width: 100%; height: 200px; max-height: 200px"
|
||||
></Line>
|
||||
</div>
|
||||
</div>
|
||||
@ -457,17 +500,19 @@ export default {
|
||||
<div class="mb-4">
|
||||
<div class="d-flex align-items-center gap-3 mb-2 ">
|
||||
<h3>Peers</h3>
|
||||
|
||||
<RouterLink
|
||||
to="create"
|
||||
class="text-decoration-none ms-auto">
|
||||
<i class="bi bi-plus-circle-fill me-2"></i>Add Peer</RouterLink>
|
||||
class="text-decoration-none ms-auto btn btn-primary rounded-3">
|
||||
<i class="bi bi-plus-circle-fill me-2"></i>Peers</RouterLink>
|
||||
</div>
|
||||
<PeerSearch></PeerSearch>
|
||||
<TransitionGroup name="list" tag="div" class="row gx-2 gy-2 z-0">
|
||||
<div class="col-12 col-lg-6 col-xl-4"
|
||||
:key="peer.id"
|
||||
v-for="peer in this.searchPeers">
|
||||
<Peer :Peer="peer"
|
||||
<Peer :Peer="peer"
|
||||
@refresh="this.getPeers()"
|
||||
@setting="peerSetting.modalOpen = true; peerSetting.selectedPeer = this.configurationPeers.find(x => x.id === peer.id)"
|
||||
@qrcode="(file) => {this.peerQRCode.peerConfigData = file; this.peerQRCode.modalOpen = true;}"
|
||||
></Peer>
|
||||
@ -477,7 +522,7 @@ export default {
|
||||
<Transition name="fade">
|
||||
<PeerSettings v-if="this.peerSetting.modalOpen"
|
||||
:selectedPeer="this.peerSetting.selectedPeer"
|
||||
@refresh="this.getPeers(this.$route.params.id)"
|
||||
@refresh="this.getPeers()"
|
||||
@close="this.peerSetting.modalOpen = false">
|
||||
</PeerSettings>
|
||||
|
||||
@ -487,10 +532,6 @@ export default {
|
||||
@close="this.peerQRCode.modalOpen = false"
|
||||
v-if="peerQRCode.modalOpen"></PeerQRCode>
|
||||
</Transition>
|
||||
<!-- <Transition name="fade">-->
|
||||
<!-- -->
|
||||
<!-- </Transition>-->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -53,15 +53,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let fadeIn = "animate__fadeInUp";
|
||||
let fadeOut = "animate__fadeOutDown"
|
||||
|
||||
this.$el.querySelectorAll(".dropdown").forEach(x => {
|
||||
x.addEventListener('show.bs.dropdown', (e) => {
|
||||
console.log(e.target.parentNode.children)
|
||||
console.log(e.target.closest("ul.dropdown-menu"))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -73,34 +65,43 @@ export default {
|
||||
<i class="bi bi-filter-circle me-2"></i>
|
||||
Sort
|
||||
</button>
|
||||
<ul class="dropdown-menu mt-2 shadow">
|
||||
<ul class="dropdown-menu mt-2 shadow rounded-3">
|
||||
<li v-for="(value, key) in this.sort">
|
||||
<a class="dropdown-item d-flex" role="button" @click="this.updateSort(key)">
|
||||
<span class="me-auto">{{value}}</span>
|
||||
<i class="bi bi-check"
|
||||
<i class="bi bi-check text-primary"
|
||||
v-if="store.Configuration.Server.dashboard_sort === key"></i>
|
||||
</a></li>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm dropdown-toggle rounded-3" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<button class="btn btn-outline-secondary btn-sm dropdown-toggle rounded-3" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-arrow-repeat me-2"></i>Refresh Interval
|
||||
</button>
|
||||
<ul class="dropdown-menu shadow mt-2">
|
||||
<ul class="dropdown-menu shadow mt-2 rounded-3">
|
||||
<li v-for="(value, key) in this.interval">
|
||||
<a class="dropdown-item d-flex" role="button" @click="updateRefreshInterval(key)">
|
||||
<span class="me-auto">{{value}}</span>
|
||||
<i class="bi bi-check"
|
||||
<i class="bi bi-check text-primary"
|
||||
v-if="store.Configuration.Server.dashboard_refresh_interval === key"></i>
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- <button class="btn btn-outline-secondary btn-sm rounded-3" type="button"-->
|
||||
<!-- @click="this.store.Peers.Selecting = !this.store.Peers.Selecting"-->
|
||||
<!-- >-->
|
||||
<!-- <i class="bi bi-app-indicator me-2"></i>-->
|
||||
<!-- Select-->
|
||||
<!-- </button>-->
|
||||
|
||||
<div class="ms-auto d-flex align-items-center">
|
||||
<label class="d-flex me-2 text-muted" for="searchPeers"><i class="bi bi-search me-1"></i></label>
|
||||
<input class="form-control form-control-sm rounded-3"
|
||||
id="searchPeers"
|
||||
v-model="this.wireguardConfigurationStore.searchString">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import {fetchGet} from "@/utilities/fetch.js";
|
||||
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
|
||||
export default {
|
||||
@ -11,6 +11,11 @@ export default {
|
||||
props: {
|
||||
Peer: Object
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
deleteBtnDisabled: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
downloadPeer(){
|
||||
fetchGet("/api/downloadPeer/"+this.$route.params.id, {
|
||||
@ -40,6 +45,16 @@ export default {
|
||||
this.dashboardStore.newMessage("Server", res.message, "danger")
|
||||
}
|
||||
})
|
||||
},
|
||||
deletePeer(){
|
||||
this.deleteBtnDisabled = true
|
||||
fetchPost(`/api/deletePeers/${this.$route.params.id}`, {
|
||||
peers: [this.Peer.id]
|
||||
}, (res) => {
|
||||
this.dashboardStore.newMessage("Server", res.message, res.status ? "success":"danger")
|
||||
this.$emit("refresh")
|
||||
this.deleteBtnDisabled = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,9 +105,10 @@ export default {
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex fw-bold text-danger"
|
||||
|
||||
@click="this.deletePeer()"
|
||||
:class="{disabled: this.deleteBtnDisabled}"
|
||||
role="button">
|
||||
<i class="me-auto bi bi-trash"></i> Delete
|
||||
<i class="me-auto bi bi-trash"></i> {{!this.deleteBtnDisabled ? "Delete":"Deleting..."}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@ -102,4 +118,8 @@ export default {
|
||||
.dropdown-menu{
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
.dropdown-item.disabled, .dropdown-item:disabled{
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
@ -8,13 +8,23 @@ export default {
|
||||
components: {ConfigurationCard},
|
||||
async setup(){
|
||||
const wireguardConfigurationsStore = WireguardConfigurationsStore();
|
||||
await wireguardConfigurationsStore.getConfigurations();
|
||||
|
||||
return {wireguardConfigurationsStore}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
configurationLoaded: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.wireguardConfigurationsStore.getConfigurations();
|
||||
this.configurationLoaded = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="mt-4">
|
||||
<div class="container">
|
||||
<div class="d-flex mb-4 ">
|
||||
@ -24,13 +34,21 @@ export default {
|
||||
<i class="bi bi-plus-circle-fill ms-2"></i>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.length === 0">You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".</p>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div v-if="this.configurationLoaded">
|
||||
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.length === 0">
|
||||
You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".
|
||||
</p>
|
||||
|
||||
<div class="d-flex gap-3 flex-column" v-else >
|
||||
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard>
|
||||
</div>
|
||||
<div class="d-flex gap-3 flex-column" v-else>
|
||||
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
@ -13,12 +13,18 @@ export default {
|
||||
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
configurationToggling: false
|
||||
}
|
||||
},
|
||||
setup(){
|
||||
const dashboardConfigurationStore = DashboardConfigurationStore();
|
||||
return {dashboardConfigurationStore}
|
||||
},
|
||||
methods: {
|
||||
toggle(){
|
||||
this.configurationToggling = true;
|
||||
fetchGet("/api/toggleWireguardConfiguration/", {
|
||||
configurationName: this.c.Name
|
||||
}, (res) => {
|
||||
@ -30,6 +36,7 @@ export default {
|
||||
res.message, 'danger')
|
||||
}
|
||||
this.c.Status = res.data
|
||||
this.configurationToggling = false;
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -53,10 +60,15 @@ export default {
|
||||
<samp style="line-break: anywhere">{{c.PublicKey}}</samp>
|
||||
</small>
|
||||
<div class="form-check form-switch ms-auto">
|
||||
<label class="form-check-label" :for="'switch' + c.PrivateKey">
|
||||
<label class="form-check-label" style="cursor: pointer" :for="'switch' + c.PrivateKey">
|
||||
{{this.configurationToggling ? 'Turning ':''}}
|
||||
{{c.Status ? "On":"Off"}}
|
||||
<span v-if="this.configurationToggling"
|
||||
class="spinner-border spinner-border-sm" aria-hidden="true"></span>
|
||||
</label>
|
||||
<input class="form-check-input"
|
||||
<input class="form-check-input"
|
||||
style="cursor: pointer"
|
||||
:disabled="this.configurationToggling"
|
||||
type="checkbox" role="switch" :id="'switch' + c.PrivateKey"
|
||||
@change="this.toggle()"
|
||||
v-model="c.Status"
|
||||
|
@ -117,8 +117,10 @@ router.beforeEach(async (to, from, next) => {
|
||||
if (!wireguardConfigurationsStore.Configurations && to.name !== "Configuration List"){
|
||||
await wireguardConfigurationsStore.getConfigurations();
|
||||
}
|
||||
dashboardConfigurationStore.Redirect = undefined;
|
||||
next()
|
||||
}else{
|
||||
dashboardConfigurationStore.Redirect = to;
|
||||
next("/signin")
|
||||
}
|
||||
}else {
|
||||
|
@ -4,8 +4,12 @@ import {v4} from "uuid";
|
||||
|
||||
export const DashboardConfigurationStore = defineStore('DashboardConfigurationStore', {
|
||||
state: () => ({
|
||||
Redirect: undefined,
|
||||
Configuration: undefined,
|
||||
Messages: []
|
||||
Messages: [],
|
||||
Peers: {
|
||||
Selecting: false
|
||||
}
|
||||
}),
|
||||
actions: {
|
||||
async getConfiguration(){
|
||||
|
@ -19,6 +19,7 @@ export const WireguardConfigurationsStore = defineStore('WireguardConfigurations
|
||||
},
|
||||
checkCIDR(ip){
|
||||
return isCidr(ip) !== 0
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
});
|
@ -7,7 +7,12 @@ export const fetchGet = async (url, params=undefined, callback=undefined) => {
|
||||
})
|
||||
.then(x => x.json())
|
||||
.then(x => callback ? callback(x) : undefined)
|
||||
|
||||
.catch(x => {
|
||||
// let router = useRouter()
|
||||
// if (x.status === 401){
|
||||
// router.push('/signin')
|
||||
// }
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchPost = async (url, body, callback) => {
|
||||
|
@ -8,7 +8,9 @@ export default {
|
||||
<div class="mt-5 text-body">
|
||||
<RouterView v-slot="{ Component, route }">
|
||||
<Transition name="fade2" mode="out-in">
|
||||
<Component :is="Component" :key="route.path"></Component>
|
||||
<Suspense>
|
||||
<Component :is="Component" :key="route.path"></Component>
|
||||
</Suspense>
|
||||
</Transition>
|
||||
</RouterView>
|
||||
</div>
|
||||
|
@ -41,7 +41,11 @@ export default {
|
||||
if (response.message){
|
||||
this.$router.push('/welcome')
|
||||
}else{
|
||||
this.$router.push('/')
|
||||
if (this.store.Redirect !== undefined){
|
||||
this.$router.push(this.store.Redirect)
|
||||
}else{
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
}else{
|
||||
this.loginError = true;
|
||||
@ -71,7 +75,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container-fluid login-container-fluid d-flex main" :data-bs-theme="this.theme">
|
||||
<div class="container-fluid login-container-fluid d-flex main flex-column" :data-bs-theme="this.theme">
|
||||
<div class="login-box m-auto" style="width: 500px;">
|
||||
<h4 class="mb-0 text-body">Welcome to</h4>
|
||||
<span class="dashboardLogo display-3">WGDashboard</span>
|
||||
@ -117,6 +121,10 @@ export default {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted pb-3 d-block w-100 text-center">
|
||||
WGDashboard v4.0 | Developed with ❤️ by
|
||||
<a href="https://github.com/donaldzou" target="_blank"><strong>Donald Zou</strong></a>
|
||||
</small>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user