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:
parent
a950b80d5a
commit
0aa4c8af6f
99
src/static/app/package-lock.json
generated
99
src/static/app/package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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>
|
@ -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>
|
@ -3,7 +3,8 @@ import {fetchGet} from "@/utilities/fetch.js";
|
||||
|
||||
export const WireguardConfigurationsStore = defineStore('WireguardConfigurationsStore', {
|
||||
state: () => ({
|
||||
Configurations: undefined
|
||||
Configurations: undefined,
|
||||
searchString: ""
|
||||
}),
|
||||
actions: {
|
||||
async getConfigurations(){
|
||||
|
@ -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,7 +183,13 @@ 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: {
|
||||
configurationSummary(){
|
||||
@ -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>
|
Loading…
Reference in New Issue
Block a user