mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-06-28 09:16:55 +00:00
Reconstruct Client App UI
This commit is contained in:
parent
e69e7ff3c1
commit
79ad3c0a84
@ -1,3 +1,5 @@
|
|||||||
|
from tzlocal import get_localzone
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from flask import Blueprint, render_template, abort, request, Flask, current_app, session
|
from flask import Blueprint, render_template, abort, request, Flask, current_app, session
|
||||||
@ -91,6 +93,12 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
|
|||||||
def ClientIndex():
|
def ClientIndex():
|
||||||
return render_template('client.html')
|
return render_template('client.html')
|
||||||
|
|
||||||
|
@client.get(f'{prefix}/api/serverInformation')
|
||||||
|
def ClientAPI_ServerInformation():
|
||||||
|
return ResponseObject(data={
|
||||||
|
"ServerTimezone": str(get_localzone())
|
||||||
|
})
|
||||||
|
|
||||||
@client.get(f'{prefix}/api/validateAuthentication')
|
@client.get(f'{prefix}/api/validateAuthentication')
|
||||||
@login_required
|
@login_required
|
||||||
def ClientAPI_ValidateAuthentication():
|
def ClientAPI_ValidateAuthentication():
|
||||||
|
@ -3,7 +3,6 @@ import uuid
|
|||||||
from .ConnectionString import ConnectionString
|
from .ConnectionString import ConnectionString
|
||||||
from .DashboardLogger import DashboardLogger
|
from .DashboardLogger import DashboardLogger
|
||||||
import sqlalchemy as db
|
import sqlalchemy as db
|
||||||
|
|
||||||
from .WireguardConfiguration import WireguardConfiguration
|
from .WireguardConfiguration import WireguardConfiguration
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,3 +12,4 @@ sqlalchemy
|
|||||||
sqlalchemy_utils
|
sqlalchemy_utils
|
||||||
psycopg2
|
psycopg2
|
||||||
mysqlclient
|
mysqlclient
|
||||||
|
tzlocal
|
@ -6,6 +6,7 @@ import PeerSettingsDropdown from "@/components/configurationComponents/peerSetti
|
|||||||
import LocaleText from "@/components/text/localeText.vue";
|
import LocaleText from "@/components/text/localeText.vue";
|
||||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
import {GetLocale} from "../../utilities/locale.js";
|
import {GetLocale} from "../../utilities/locale.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "peer",
|
name: "peer",
|
||||||
methods: {GetLocale},
|
methods: {GetLocale},
|
||||||
|
@ -1,12 +1,50 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import ConfigurationQRCode from "@/components/Configuration/configurationQRCode.vue";
|
import ConfigurationQRCode from "@/components/Configuration/configurationQRCode.vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import Duration from 'dayjs/plugin/Duration'
|
||||||
|
dayjs.extend(Duration);
|
||||||
const props = defineProps([
|
const props = defineProps([
|
||||||
'config'
|
'config'
|
||||||
])
|
])
|
||||||
|
|
||||||
const showQRCode = ref(false)
|
const showQRCode = ref(false)
|
||||||
|
|
||||||
|
const dateJobs = computed(() => {
|
||||||
|
return props.config.jobs.filter(x => x.Field === 'date').sort((x, y) => {
|
||||||
|
if (dayjs(x.Value).isBefore(y.Value)){
|
||||||
|
return -1
|
||||||
|
}else if (dayjs(x.Value).isAfter(y.Value)){
|
||||||
|
return 1
|
||||||
|
}else{
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalDataJobs = computed(() => {
|
||||||
|
return props.config.jobs.filter(x => x.Field === "total_data").sort((x, y) => {
|
||||||
|
return parseFloat(y.Value) - parseFloat(x.Value)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const dateLimit = computed(() => {
|
||||||
|
if (dateJobs.value.length > 0){
|
||||||
|
return dateJobs.value[0].Value
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
const totalDataLimit = computed(() => {
|
||||||
|
if (totalDataJobs.value.length > 0){
|
||||||
|
return totalDataJobs.value[0].Value
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const totalDataPercentage = computed(() => {
|
||||||
|
if (!totalDataLimit.value) return 100
|
||||||
|
return ( props.config.data / totalDataLimit.value ) * 100
|
||||||
|
})
|
||||||
|
window.dayjs = dayjs
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -21,25 +59,32 @@ const showQRCode = ref(false)
|
|||||||
{{ props.config.protocol === 'wg' ? 'WireGuard': 'AmneziaWG' }}
|
{{ props.config.protocol === 'wg' ? 'WireGuard': 'AmneziaWG' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-3">
|
<div class="card-body p-3 d-flex gap-3 flex-column">
|
||||||
<div class="row gy-2 mb-2">
|
<div>
|
||||||
<div class="col-sm text-center">
|
<div class="mb-1 d-flex align-items-center">
|
||||||
<small class="text-muted mb-2">
|
<small class="text-muted ">
|
||||||
<i class="bi bi-bar-chart-fill me-1"></i> Data Usage
|
<i class="bi bi-bar-chart-fill me-1"></i> Data Usage
|
||||||
</small>
|
</small>
|
||||||
<h6 class="fw-bold ">
|
<small class="fw-bold ms-sm-auto">
|
||||||
3.42 / 4.00 GB
|
{{ props.config.data.toFixed(4) }} / {{ totalDataLimit ? parseFloat(totalDataLimit).toFixed(4) : 'Unlimited'}} GB
|
||||||
</h6>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm text-center">
|
<div class="progress" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="height: 6px">
|
||||||
<small class="text-muted mb-2">
|
<div class="progress-bar bg-primary"
|
||||||
|
:style="{'width': '' + totalDataPercentage + '%'}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="mb-1 d-flex align-items-center">
|
||||||
|
<small class="text-muted">
|
||||||
<i class="bi bi-calendar me-1"></i> Valid Until
|
<i class="bi bi-calendar me-1"></i> Valid Until
|
||||||
</small>
|
</small>
|
||||||
<h6 class="fw-bold ">
|
<small class="fw-bold ms-auto">
|
||||||
3.42 / 4.00 GB
|
{{ dateLimit ? dateLimit : 'Unlimited Time' }}
|
||||||
</h6>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-outline-body rounded-3 flex-grow-1 fw-bold w-100" @click="showQRCode = true">
|
<button class="btn btn-outline-body rounded-3 flex-grow-1 fw-bold w-100" @click="showQRCode = true">
|
||||||
<i class="bi bi-link-45deg me-2"></i><small>Connect</small>
|
<i class="bi bi-link-45deg me-2"></i><small>Connect</small>
|
||||||
</button>
|
</button>
|
||||||
|
@ -6,8 +6,14 @@ import router from "@/router/router.js";
|
|||||||
import {createPinia} from "pinia";
|
import {createPinia} from "pinia";
|
||||||
|
|
||||||
import 'bootstrap/dist/js/bootstrap.bundle.js'
|
import 'bootstrap/dist/js/bootstrap.bundle.js'
|
||||||
|
import {clientStore} from "@/stores/clientStore.js";
|
||||||
|
|
||||||
createApp(App)
|
const app = createApp(App)
|
||||||
.use(createPinia())
|
|
||||||
.use(router)
|
app.use(createPinia())
|
||||||
.mount('#app')
|
const store = clientStore()
|
||||||
|
await fetch("/client/api/serverInformation").then(res => res.json()).then(res => store.serverInformation = res.data)
|
||||||
|
|
||||||
|
|
||||||
|
app.use(router)
|
||||||
|
app.mount("#app")
|
@ -7,6 +7,7 @@ import {axiosGet} from "@/utilities/request.js";
|
|||||||
|
|
||||||
export const clientStore = defineStore('clientStore', {
|
export const clientStore = defineStore('clientStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
serverInformation: {},
|
||||||
notifications: [],
|
notifications: [],
|
||||||
configurations: [],
|
configurations: [],
|
||||||
clientProfile: {
|
clientProfile: {
|
||||||
@ -36,21 +37,6 @@ export const clientStore = defineStore('clientStore', {
|
|||||||
const data = await axiosGet("/api/configurations")
|
const data = await axiosGet("/api/configurations")
|
||||||
if (data){
|
if (data){
|
||||||
this.configurations = data.data
|
this.configurations = data.data
|
||||||
this.configurations.forEach(c => {
|
|
||||||
console.log(
|
|
||||||
c.jobs.sort((x, y) => {
|
|
||||||
if (dayjs(x.CreationDate).isBefore(y.CreationDate)){
|
|
||||||
return 1
|
|
||||||
}else if (dayjs(x.CreationDate).isAfter(y.CreationDate)){
|
|
||||||
return -1
|
|
||||||
}else{
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
)
|
|
||||||
console.log(c.jobs.find(x => x.Field === 'date'))
|
|
||||||
})
|
|
||||||
}else{
|
}else{
|
||||||
this.newNotification("Failed to fetch configurations", "danger")
|
this.newNotification("Failed to fetch configurations", "danger")
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,10 @@ const configurations = computed(() => {
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await store.getConfigurations()
|
await store.getConfigurations()
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
await store.getConfigurations()
|
||||||
|
}, 5000)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user