1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 07:10: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 json import JSONEncoder
from operator import itemgetter
from typing import Dict, Any
import flask
# PIP installed library
@ -114,6 +115,8 @@ class WireguardConfiguration:
if self.PrivateKey:
self.PublicKey = self.__getPublicKey()
self.Status = self.__getStatus()
# Create tables in database
inspector = inspect(engine)
existingTable = inspector.get_table_names()
@ -127,7 +130,11 @@ class WireguardConfiguration:
def __getPublicKey(self) -> str:
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):
self.Status = self.__getStatus()
return self.__dict__
@ -190,6 +197,14 @@ class DashboardConfig:
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:
response = Flask.make_response(app, {
@ -340,12 +355,13 @@ def API_AuthenticateLogin():
@app.route('/api/getWireguardConfigurations', methods=["GET"])
def API_getWireguardConfigurations():
pass
WireguardConfigurations = _getConfigurationList()
return ResponseObject(data=[wc.toJSON() for wc in WireguardConfigurations])
@app.route('/api/getDashboardConfiguration', methods=["GET"])
def API_getDashboardConfiguration():
pass
return ResponseObject(data=DashboardConfig.toJSON())
if __name__ == "__main__":

View File

@ -3,4 +3,5 @@ ifcfg
icmplib
flask-qrcode
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,34 +1,43 @@
<script>
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
export default {
name: "navbar"
name: "navbar",
setup(){
const store = wgdashboardStore()
return {store}
}
}
</script>
<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">
<ul class="nav flex-column">
<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">
<RouterLink class="nav-link" to="/settings">Settings</RouterLink></li>
<RouterLink class="nav-link" to="/settings" exact-active-class="active">Settings</RouterLink></li>
</ul>
<hr>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Configurations</span>
</h6>
<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>
<hr>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Tools</span>
</h6>
<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="#traceroute_modal" href="#">Traceroute</a></li>
</ul>
<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>
</ul>
<hr>
<ul class="nav flex-column">

View File

@ -2,8 +2,10 @@ import { createRouter, createWebHashHistory } from 'vue-router'
import {cookie} from "../utilities/cookie.js";
import Index from "@/views/index.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 {wgdashboardStore} from "@/stores/wgdashboardStore.js";
import Settings from "@/views/settings.vue";
const checkAuth = async () => {
let result = false
@ -17,6 +19,7 @@ const router = createRouter({
history: createWebHashHistory(),
routes: [
{
name: "Index",
path: '/',
component: Index,
meta: {
@ -24,8 +27,14 @@ const router = createRouter({
},
children: [
{
name: "Configuration List",
path: '',
component: ConfigurationList
},
{
name: "Settings",
path: '/settings',
component: Settings
}
]
},
@ -36,8 +45,18 @@ const router = createRouter({
});
router.beforeEach(async (to, from, next) => {
const store = wgdashboardStore();
if (to.meta.requiresAuth){
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()
}else{
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>
<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">
<Navbar></Navbar>
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4">
<RouterView></RouterView>
<Suspense>
<RouterView></RouterView>
</Suspense>
</main>
</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:{
proxy: {
'/api': 'http://127.0.0.1:10086/'
'/api': 'http://178.128.231.4:10086'
}
}
})

View File

@ -51,6 +51,10 @@
/* position: sticky;*/
/* }*/
/*}*/
[data-bs-theme="dark"].main{
background-color: #1b1e21;
}
.sidebar .nav-link, .bottomNavContainer .nav-link{
font-weight: 500;
@ -58,6 +62,18 @@
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 {
padding-left: 30px;
background-color: #dfdfdf;
@ -131,9 +147,10 @@
border-radius: 50px;
display: inline-block;
margin-left: auto !important;
background-color: #6c757d;
}
.dot-running {
.dot.active{
background-color: #28a745!important;
box-shadow: 0 0 0 0.2rem #28a74545;
}
@ -142,10 +159,6 @@
margin-left: 0.3rem;
}
.dot-stopped {
background-color: #6c757d!important;
}
.card-running {
border-color: #28a745;
}