1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 15:20:09 +01:00

Continue to refactor the UI and APIs :)

This commit is contained in:
Donald Zou 2024-01-11 01:10:26 -05:00
parent ba2bcaba07
commit e6e070d89e
11 changed files with 174 additions and 34 deletions

View File

@ -16,6 +16,7 @@ from dataclasses import dataclass
from datetime import datetime, timedelta from datetime import datetime, timedelta
from json import JSONEncoder from json import JSONEncoder
from operator import itemgetter from operator import itemgetter
from typing import Dict, Any
import flask import flask
# PIP installed library # PIP installed library
@ -114,6 +115,8 @@ class WireguardConfiguration:
if self.PrivateKey: if self.PrivateKey:
self.PublicKey = self.__getPublicKey() self.PublicKey = self.__getPublicKey()
self.Status = self.__getStatus()
# Create tables in database # Create tables in database
inspector = inspect(engine) inspector = inspect(engine)
existingTable = inspector.get_table_names() existingTable = inspector.get_table_names()
@ -127,7 +130,11 @@ class WireguardConfiguration:
def __getPublicKey(self) -> str: def __getPublicKey(self) -> str:
return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n') return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n')
def __getStatus(self) -> bool:
return self.Name in dict(ifcfg.interfaces().items()).keys()
def toJSON(self): def toJSON(self):
self.Status = self.__getStatus()
return self.__dict__ return self.__dict__
@ -190,6 +197,14 @@ class DashboardConfig:
return True, self.__config[section][key] return True, self.__config[section][key]
def toJSON(self) -> dict[str, dict[Any, Any]]:
the_dict = {}
for section in self.__config.sections():
the_dict[section] = {}
for key, val in self.__config.items(section):
the_dict[section][key] = val
return the_dict
def ResponseObject(status=True, message=None, data=None) -> Flask.response_class: def ResponseObject(status=True, message=None, data=None) -> Flask.response_class:
response = Flask.make_response(app, { response = Flask.make_response(app, {
@ -340,12 +355,13 @@ def API_AuthenticateLogin():
@app.route('/api/getWireguardConfigurations', methods=["GET"]) @app.route('/api/getWireguardConfigurations', methods=["GET"])
def API_getWireguardConfigurations(): def API_getWireguardConfigurations():
pass WireguardConfigurations = _getConfigurationList()
return ResponseObject(data=[wc.toJSON() for wc in WireguardConfigurations])
@app.route('/api/getDashboardConfiguration', methods=["GET"]) @app.route('/api/getDashboardConfiguration', methods=["GET"])
def API_getDashboardConfiguration(): def API_getDashboardConfiguration():
pass return ResponseObject(data=DashboardConfig.toJSON())
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -4,3 +4,4 @@ icmplib
flask-qrcode flask-qrcode
gunicorn gunicorn
certbot certbot
sqlalchemy

View File

@ -0,0 +1,51 @@
<script>
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
export default {
name: "configurationList",
async setup(){
const store = wgdashboardStore();
await store.getWireguardConfigurations();
return {store}
}
}
</script>
<template>
<div class="mt-4">
<h3 class="mb-3 text-body">Wireguard Configurations</h3>
<p class="text-muted" v-if="this.store.WireguardConfigurations.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="card conf_card rounded-3 shadow" v-else v-for="c in this.store.WireguardConfigurations" :key="c.Name">
<div class="card-body">
<div class="row">
<div class="row">
<div class="col card-col">
<small class="text-muted"><strong>CONFIGURATION</strong></small>
<h6 class="card-title" style="margin:0 !important;"><samp>{{c.Name}}</samp></h6>
</div>
<div class="col card-col">
<small class="text-muted"><strong>STATUS</strong></small>
<h6><span>{{c.Status ? "Running":"Stopped"}}</span>
<span class="dot" :class="{active: c.Status}"></span></h6>
</div>
<div class="col-sm card-col">
<small class="text-muted"><strong>PUBLIC KEY</strong></small>
<h6 style="margin:0 !important;"><samp>{{c.PublicKey}}</samp></h6>
</div>
<div class="col-sm index-switch">
<div class="switch-test">
<input type="checkbox" class="toggle--switch" checked :id="c.Name + '-switch'">
<label :for="c.Name + '-switch'" class="toggleLabel"></label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -1,35 +1,44 @@
<script> <script>
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
export default { export default {
name: "navbar" name: "navbar",
setup(){
const store = wgdashboardStore()
return {store}
}
} }
</script> </script>
<template> <template>
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar border border-right p-0"> <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-body-tertiary sidebar border border-right p-0">
<div class="sidebar-sticky pt-3"> <div class="sidebar-sticky pt-3">
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item"> <li class="nav-item">
<RouterLink class="nav-link" to="/">Home</RouterLink></li> <RouterLink class="nav-link" to="/" exact-active-class="active">Home</RouterLink></li>
<li class="nav-item"> <li class="nav-item">
<RouterLink class="nav-link" to="/settings">Settings</RouterLink></li> <RouterLink class="nav-link" to="/settings" exact-active-class="active">Settings</RouterLink></li>
</ul> </ul>
<hr> <hr>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted"> <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Configurations</span> <span>Configurations</span>
</h6> </h6>
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item">
<RouterLink :to="'/configuration/'+c.Name" class="nav-link nav-conf-link" v-for="c in this.store.WireguardConfigurations">
<samp>{{c.Name}}</samp>
</RouterLink>
</li>
</ul> </ul>
<hr> <hr>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted"> <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Tools</span> <span>Tools</span>
</h6> </h6>
<ul class="nav flex-column">
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#ping_modal" href="#">Ping</a></li> <li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#ping_modal" href="#">Ping</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#traceroute_modal" href="#">Traceroute</a></li> <li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#traceroute_modal" href="#">Traceroute</a></li>
</ul> </ul>
</ul>
<hr> <hr>
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item"><a href="https://github.com/donaldzou/WGDashboard/releases/tag/"><small class="nav-link text-muted"></small></a></li> <li class="nav-item"><a href="https://github.com/donaldzou/WGDashboard/releases/tag/"><small class="nav-link text-muted"></small></a></li>

View File

@ -2,8 +2,10 @@ import { createRouter, createWebHashHistory } from 'vue-router'
import {cookie} from "../utilities/cookie.js"; import {cookie} from "../utilities/cookie.js";
import Index from "@/views/index.vue" import Index from "@/views/index.vue"
import Signin from "@/views/signin.vue"; import Signin from "@/views/signin.vue";
import ConfigurationList from "@/views/configurationList.vue"; import ConfigurationList from "@/components/configurationList.vue";
import {fetchGet} from "@/utilities/fetch.js"; import {fetchGet} from "@/utilities/fetch.js";
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
import Settings from "@/views/settings.vue";
const checkAuth = async () => { const checkAuth = async () => {
let result = false let result = false
@ -17,6 +19,7 @@ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes: [ routes: [
{ {
name: "Index",
path: '/', path: '/',
component: Index, component: Index,
meta: { meta: {
@ -24,8 +27,14 @@ const router = createRouter({
}, },
children: [ children: [
{ {
name: "Configuration List",
path: '', path: '',
component: ConfigurationList component: ConfigurationList
},
{
name: "Settings",
path: '/settings',
component: Settings
} }
] ]
}, },
@ -36,8 +45,18 @@ const router = createRouter({
}); });
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const store = wgdashboardStore();
if (to.meta.requiresAuth){ if (to.meta.requiresAuth){
if (cookie.getCookie("authToken") && await checkAuth()){ if (cookie.getCookie("authToken") && await checkAuth()){
console.log(to.name)
if (!store.DashboardConfiguration){
await store.getDashboardConfiguration()
}
if (!store.WireguardConfigurations && to.name !== "Configuration List"){
await store.getWireguardConfigurations()
}
next() next()
}else{ }else{
next("/signin") next("/signin")

View File

@ -0,0 +1,23 @@
import {defineStore} from "pinia";
import {fetchGet} from "@/utilities/fetch.js";
export const wgdashboardStore = defineStore('WGDashboardStore', {
state: () => ({
WireguardConfigurations: undefined,
DashboardConfiguration: undefined
}),
actions: {
async getWireguardConfigurations(){
await fetchGet("/api/getWireguardConfigurations", {}, (res) => {
console.log(res.status)
if (res.status) this.WireguardConfigurations = res.data
})
},
async getDashboardConfiguration(){
await fetchGet("/api/getDashboardConfiguration", {}, (res) => {
console.log(res.status)
if (res.status) this.DashboardConfiguration = res.data
})
}
},
})

View File

@ -1,13 +0,0 @@
<script>
export default {
name: "configurationList"
}
</script>
<template>
</template>
<style scoped>
</style>

View File

@ -8,11 +8,13 @@ export default {
</script> </script>
<template> <template>
<div class="container-fluid flex-grow-1"> <div class="container-fluid flex-grow-1 main" data-bs-theme="dark">
<div class="row h-100"> <div class="row h-100">
<Navbar></Navbar> <Navbar></Navbar>
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4"> <main class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4">
<Suspense>
<RouterView></RouterView> <RouterView></RouterView>
</Suspense>
</main> </main>
</div> </div>
</div> </div>

View File

@ -0,0 +1,19 @@
<script>
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
export default {
name: "settings",
setup(){
const store = wgdashboardStore();
return {store}
}
}
</script>
<template>
</template>
<style scoped>
</style>

View File

@ -15,7 +15,7 @@ export default defineConfig({
}, },
server:{ server:{
proxy: { proxy: {
'/api': 'http://127.0.0.1:10086/' '/api': 'http://178.128.231.4:10086'
} }
} }
}) })

View File

@ -51,6 +51,10 @@
/* position: sticky;*/ /* position: sticky;*/
/* }*/ /* }*/
/*}*/ /*}*/
[data-bs-theme="dark"].main{
background-color: #1b1e21;
}
.sidebar .nav-link, .bottomNavContainer .nav-link{ .sidebar .nav-link, .bottomNavContainer .nav-link{
font-weight: 500; font-weight: 500;
@ -58,6 +62,18 @@
transition: 0.2s cubic-bezier(0.82, -0.07, 0, 1.01); transition: 0.2s cubic-bezier(0.82, -0.07, 0, 1.01);
} }
[data-bs-theme="dark"] .sidebar .nav-link{
color: white;
}
[data-bs-theme="dark"] .sidebar .nav-link.active{
color: #74b7ff;
}
[data-bs-theme="dark"] .nav-link:hover{
background-color: #323844;
}
.nav-link:hover { .nav-link:hover {
padding-left: 30px; padding-left: 30px;
background-color: #dfdfdf; background-color: #dfdfdf;
@ -131,9 +147,10 @@
border-radius: 50px; border-radius: 50px;
display: inline-block; display: inline-block;
margin-left: auto !important; margin-left: auto !important;
background-color: #6c757d;
} }
.dot-running { .dot.active{
background-color: #28a745!important; background-color: #28a745!important;
box-shadow: 0 0 0 0.2rem #28a74545; box-shadow: 0 0 0 0.2rem #28a74545;
} }
@ -142,10 +159,6 @@
margin-left: 0.3rem; margin-left: 0.3rem;
} }
.dot-stopped {
background-color: #6c757d!important;
}
.card-running { .card-running {
border-color: #28a745; border-color: #28a745;
} }