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

Continue to work on v4 ;0

This commit is contained in:
Donald Zou 2024-03-11 00:11:07 -04:00
parent a950b80d5a
commit 0aa4c8af6f
6 changed files with 328 additions and 31 deletions

View File

@ -8,10 +8,13 @@
"name": "app",
"version": "0.0.0",
"dependencies": {
"@vueuse/core": "^10.9.0",
"@vueuse/shared": "^10.9.0",
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.10",
"fuse.js": "^7.0.0",
"pinia": "^2.1.7",
"qrcode": "^1.5.3",
"uuid": "^9.0.1",
@ -593,6 +596,11 @@
"win32"
]
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.20",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
},
"node_modules/@vitejs/plugin-vue": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz",
@ -701,6 +709,89 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.3.tgz",
"integrity": "sha512-rIwlkkP1n4uKrRzivAKPZIEkHiuwY5mmhMJ2nZKCBLz8lTUlE73rQh4n1OnnMurXt1vcUNyH4ZPfdh8QweTjpQ=="
},
"node_modules/@vueuse/core": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz",
"integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==",
"dependencies": {
"@types/web-bluetooth": "^0.0.20",
"@vueuse/metadata": "10.9.0",
"@vueuse/shared": "10.9.0",
"vue-demi": ">=0.14.7"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz",
"integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz",
"integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==",
"dependencies": {
"vue-demi": ">=0.14.7"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@ -926,6 +1017,14 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/fuse.js": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz",
"integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==",
"engines": {
"node": ">=10"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",

View File

@ -9,10 +9,13 @@
"preview": "vite preview"
},
"dependencies": {
"@vueuse/core": "^10.9.0",
"@vueuse/shared": "^10.9.0",
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.10",
"fuse.js": "^7.0.0",
"pinia": "^2.1.7",
"qrcode": "^1.5.3",
"uuid": "^9.0.1",

View File

@ -1,8 +1,26 @@
<script>
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
export default {
name: "peer",
props: {
Peer: Object
},
data(){
return {
}
},
setup(){
const target = ref(null);
const subMenuOpened = ref(false)
onClickOutside(target, event => {
subMenuOpened.value = false;
});
return {target, subMenuOpened}
},
mounted() {
}
}
</script>
@ -34,9 +52,24 @@ export default {
<small class="text-muted">Public Key</small>
<p class="mb-0"><samp>{{Peer.id}}</samp></p>
</div>
<div>
<small class="text-muted">Allowed IP</small>
<p class="mb-0"><samp>{{Peer.allowed_ip}}</samp></p>
<div class="d-flex align-items-end">
<div>
<small class="text-muted">Allowed IP</small>
<p class="mb-0"><samp>{{Peer.allowed_ip}}</samp></p>
</div>
<div class="ms-auto px-2">
<a role="button" class="text-body" @click="this.subMenuOpened = true">
<h5 class="mb-0"><i class="bi bi-three-dots"></i></h5>
</a>
<Transition name="slide-fade">
<ul class="dropdown-menu mt-2 shadow-lg dropdown-menu-left d-block"
v-if="this.subMenuOpened"
ref="target">
<li>
<a class="dropdown-item d-flex" role="button" ></a></li>
</ul>
</Transition>
</div>
</div>
</div>
</div>
@ -44,4 +77,13 @@ export default {
<style scoped>
.slide-fade-leave-active, .slide-fade-enter-active {
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateY(20px);
opacity: 0;
}
</style>

View File

@ -0,0 +1,98 @@
<script>
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {fetchPost} from "@/utilities/fetch.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
export default {
name: "peerSearch",
setup(){
const store = DashboardConfigurationStore();
const wireguardConfigurationStore = WireguardConfigurationsStore()
return {store, wireguardConfigurationStore}
},
props: {
searchString: String
},
data(){
return {
sort: {
status: "Status",
name: "Name",
allowed_ip: "Allowed IP"
},
interval: {
'5000': '5 Seconds',
'10000': '10 Seconds',
'30000': '30 Seconds',
'60000': '1 Minutes'
}
}
},
methods: {
updateSort(sort){
fetchPost("/api/updateDashboardConfigurationItem", {
section: "Server",
key: "dashboard_sort",
value: sort
}, (res) => {
if (res.status){
this.store.getConfiguration();
}
})
},
updateRefreshInterval(refreshInterval){
fetchPost("/api/updateDashboardConfigurationItem", {
section: "Server",
key: "dashboard_refresh_interval",
value: refreshInterval
}, (res) => {
if (res.status){
this.store.getConfiguration();
}
})
}
}
}
</script>
<template>
<div class="d-flex gap-2 mb-3 z-3">
<div class="dropdown">
<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-filter-circle me-2"></i>
Sort
</button>
<ul class="dropdown-menu mt-2 shadow-lg">
<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"
v-if="store.Configuration.Server.dashboard_sort === key"></i>
</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">
<i class="bi bi-arrow-repeat me-2"></i>Refresh Interval
</button>
<ul class="dropdown-menu">
<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"
v-if="store.Configuration.Server.dashboard_refresh_interval === key"></i>
</a></li>
</ul>
</div>
<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"
v-model="this.wireguardConfigurationStore.searchString">
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -3,7 +3,8 @@ import {fetchGet} from "@/utilities/fetch.js";
export const WireguardConfigurationsStore = defineStore('WireguardConfigurationsStore', {
state: () => ({
Configurations: undefined
Configurations: undefined,
searchString: ""
}),
actions: {
async getConfigurations(){

View File

@ -2,6 +2,7 @@
import {fetchGet} from "@/utilities/fetch.js";
import Peer from "@/components/configurationComponents/peer.vue";
import { Line, Bar } from 'vue-chartjs'
import Fuse from "fuse.js";
import {
Chart,
ArcElement,
@ -56,10 +57,19 @@ Chart.register(
);
import dayjs from "dayjs";
import PeerSearch from "@/components/configurationComponents/peerSearch.vue";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {ref} from "vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
export default {
name: "configuration",
components: {Peer, Line, Bar},
setup(){
const dashboardConfigurationStore = DashboardConfigurationStore();
const wireguardConfigurationStore = WireguardConfigurationsStore();
return {dashboardConfigurationStore, wireguardConfigurationStore}
},
components: {PeerSearch, Peer, Line, Bar},
data(){
return {
loading: false,
@ -69,6 +79,7 @@ export default {
historyDataSentDifference: [],
historyDataReceivedDifference: [],
historySentData: {
labels: [],
datasets: [
@ -106,11 +117,13 @@ export default {
this.configurationPeers = [];
if (id){
this.getPeers(id)
// this.interval = setInterval(() => {
// this.getPeers(id)
// }, 2000)
this.setInterval();
}
}
},
'dashboardConfigurationStore.Configuration.Server.dashboard_refresh_interval'(){
clearInterval(this.interval);
this.setInterval();
}
},
beforeRouteLeave(){
@ -170,6 +183,12 @@ export default {
}
}
});
},
setInterval(){
console.log('Set Interval');
this.interval = setInterval(() => {
this.getPeers(this.$route.params.id)
}, parseInt(this.dashboardConfigurationStore.Configuration.Server.dashboard_refresh_interval))
}
},
computed: {
@ -275,6 +294,25 @@ export default {
}
}
}
},
searchPeers(){
const fuse = new Fuse(this.configurationPeers, {
keys: ["name", "id", "allowed_ip"]
});
const result = this.wireguardConfigurationStore.searchString ? fuse.search(this.wireguardConfigurationStore.searchString).map(x => x.item) : this.configurationPeers;
return result.slice().sort((a, b) => {
if ( a[this.dashboardConfigurationStore.Configuration.Server.dashboard_sort]
< b[this.dashboardConfigurationStore.Configuration.Server.dashboard_sort] ){
return -1;
}
if ( a[this.dashboardConfigurationStore.Configuration.Server.dashboard_sort]
> b[this.dashboardConfigurationStore.Configuration.Server.dashboard_sort]){
return 1;
}
return 0;
});
}
}
}
@ -398,29 +436,22 @@ export default {
</div>
</div>
</div>
<div>
<nav class="navbar navbar-expand-lg bg-body mb-3 rounded-3 shadow-sm border">
<div class="container-fluid w-100">
<ul class="navbar-nav peerNav gap-1">
<li class="nav-item">
<a class="nav-link active rounded-3 px-3 w-100" aria-current="page" href="#">Peers</a>
</li>
<li class="nav-item">
<a class="nav-link rounded-3 px-3" href="#">Manage Peers</a>
</li>
<li class="nav-item">
<a class="nav-link rounded-3 px-3" href="#">Configuration Settings</a>
</li>
</ul>
</div>
</nav>
<div class="row gx-2 gy-2">
<div class="col-12 col-lg-6 col-xl-4" v-for="peer in this.configurationPeers">
<div class="d-flex align-items-center gap-3 mb-2 ">
<h3>Peers</h3>
<a href="#"
class="ms-auto text-secondary text-decoration-none"><i class="bi bi-sliders2 me-2"></i>Peer Settings</a>
<a href="#" class="text-decoration-none"><i class="bi bi-plus-circle-fill me-2"></i>Add Peer</a>
</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>
</div>
</div>
</TransitionGroup>
</div>
</div>
</template>
@ -428,8 +459,31 @@ export default {
<style scoped>
.peerNav .nav-link{
&.active{
background: linear-gradient(var(--degree), var(--brandColor1) var(--distance2), var(--brandColor2) 100%);
color: white;
//background: linear-gradient(var(--degree), var(--brandColor1) var(--distance2), var(--brandColor2) 100%);
//color: white;
background-color: #efefef;
}
}
.list-move, /* apply transition to moving elements */
.list-enter-active,
.list-leave-active {
transition: all 0.4s cubic-bezier(0.82, 0.58, 0.17, 0.9);
}
.list-leave-active{
position: absolute;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
/* ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.list-leave-active {
position: absolute;
}
</style>