Merge branch 'v4.1-dev' into v4.0.3-fix

This commit is contained in:
Donald Zou
2024-09-14 16:23:08 +08:00
committed by GitHub
46 changed files with 896 additions and 364 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,19 +1,19 @@
{
"name": "app",
"version": "4.0.0",
"version": "4.0.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "app",
"version": "4.0.0",
"version": "4.0.2",
"dependencies": {
"@vuepic/vue-datepicker": "^9.0.1",
"@vueuse/core": "^10.9.0",
"@vueuse/shared": "^10.9.0",
"animate.css": "^4.1.1",
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"bootstrap-icons": "^1.11.3",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.12",
"electron-builder": "^24.13.3",
@@ -1486,9 +1486,9 @@
}
},
"node_modules/bootstrap-icons": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.2.tgz",
"integrity": "sha512-TgdiPv+IM9tgDb+dsxrnGIyocsk85d2M7T0qIgkvPedZeoZfyeG/j+yiAE4uHCEayKef2RP05ahQ0/e9Sv75Wg==",
"version": "1.11.3",
"resolved": "https://registry.npmmirror.com/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz",
"integrity": "sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==",
"funding": [
{
"type": "github",

View File

@@ -15,7 +15,7 @@
"@vueuse/shared": "^10.9.0",
"animate.css": "^4.1.1",
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"bootstrap-icons": "^1.11.3",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.12",
"electron-builder": "^24.13.3",

View File

@@ -1,4 +1,4 @@
<script setup>
<script setup async>
import { RouterView } from 'vue-router'
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {computed, watch} from "vue";
@@ -21,7 +21,6 @@ const getActiveCrossServer = computed(() => {
}
return undefined
})
</script>
<template>

View File

@@ -4,17 +4,38 @@ export default {
props: {
data: Object,
saving: Boolean
},
data(){
return{
enable: false
}
},
watch:{
enable(){
if (this.enable){
this.data.preshared_key = window.wireguard.generateKeypair().presharedKey
}else {
this.data.preshared_key = ""
}
}
}
}
</script>
<template>
<div>
<label for="peer_preshared_key_textbox" class="form-label">
<small class="text-muted">Pre-Shared Key</small>
</label>
<div class="d-flex align-items-start">
<label for="peer_preshared_key_textbox" class="form-label">
<small class="text-muted">Pre-Shared Key</small>
</label>
<div class="form-check form-switch ms-auto">
<input class="form-check-input" type="checkbox" role="switch"
v-model="this.enable"
id="peer_preshared_key_switch">
</div>
</div>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
:disabled="this.saving || !this.enable"
v-model="this.data.preshared_key"
id="peer_preshared_key_textbox">
</div>

View File

@@ -3,9 +3,10 @@ import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
import "animate.css"
import PeerSettingsDropdown from "@/components/configurationComponents/peerSettingsDropdown.vue";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peer",
components: {PeerSettingsDropdown},
components: {LocaleText, PeerSettingsDropdown},
props: {
Peer: Object
},
@@ -57,7 +58,7 @@ export default {
<div v-else class="border-0 card-header bg-transparent text-warning fw-bold"
style="font-size: 0.8rem">
<i class="bi-lock-fill me-2"></i>
Access Restricted
<LocaleText t="Access Restricted"></LocaleText>
</div>
</div>
<div class="card-body pt-1" style="font-size: 0.9rem">
@@ -65,12 +66,16 @@ export default {
{{Peer.name ? Peer.name : 'Untitled Peer'}}
</h6>
<div class="mb-2">
<small class="text-muted">Public Key</small>
<small class="text-muted">
<LocaleText t="Public Key"></LocaleText>
</small>
<p class="mb-0"><samp>{{Peer.id}}</samp></p>
</div>
<div class="d-flex align-items-end">
<div>
<small class="text-muted">Allowed IP</small>
<small class="text-muted">
<LocaleText t="Allowed IPs"></LocaleText>
</small>
<p class="mb-0"><samp>{{Peer.allowed_ip}}</samp></p>
</div>
<div class="ms-auto px-2 rounded-3 subMenuBtn"

View File

@@ -33,7 +33,8 @@ export default {
endpoint_allowed_ip: this.dashboardStore.Configuration.Peers.peer_endpoint_allowed_ip,
keepalive: parseInt(this.dashboardStore.Configuration.Peers.peer_keep_alive),
mtu: parseInt(this.dashboardStore.Configuration.Peers.peer_mtu),
preshared_key: ""
preshared_key: "",
preshared_key_bulkAdd: false
},
availableIp: undefined,
availableIpSearchString: "",
@@ -119,16 +120,28 @@ export default {
<DnsInput :saving="saving" :data="data"></DnsInput>
<hr class="mb-0 mt-2">
<div class="row">
<div class="row gy-3">
<div class="col-sm" v-if="!this.data.bulkAdd">
<PresharedKeyInput :saving="saving" :data="data" :bulk="this.data.bulkAdd"></PresharedKeyInput>
</div>
<div class="col-sm">
<MtuInput :saving="saving" :data="data"></MtuInput>
</div>
<div class="col-sm">
<PersistentKeepAliveInput :saving="saving" :data="data"></PersistentKeepAliveInput>
</div>
<div class="col-12" v-if="this.data.bulkAdd">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch"
v-model="this.data.preshared_key_bulkAdd"
id="bullAdd_PresharedKey_Switch" checked>
<label class="form-check-label" for="bullAdd_PresharedKey_Switch">
Pre-Share Key
{{this.data.preshared_key_bulkAdd ? "Enabled":"Disabled"}}
</label>
</div>
</div>
</div>
<div class="d-flex mt-2">
<button class="ms-auto btn btn-dark btn-brand rounded-3 px-3 py-2 shadow"

View File

@@ -3,6 +3,7 @@ import ScheduleDropdown from "@/components/configurationComponents/peerScheduleJ
import SchedulePeerJob from "@/components/configurationComponents/peerScheduleJobsComponents/schedulePeerJob.vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {v4} from "uuid";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peerJobs",
setup(){
@@ -13,6 +14,7 @@ export default {
selectedPeer: Object
},
components:{
LocaleText,
SchedulePeerJob,
ScheduleDropdown,
},
@@ -50,8 +52,8 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow" style="width: 700px">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0 fw-normal">Schedule Jobs
<strong></strong>
<h4 class="mb-0 fw-normal">
<LocaleText t="Schedule Jobs"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
@@ -60,7 +62,8 @@ export default {
<button class="btn bg-primary-subtle border-1 border-primary-subtle text-primary-emphasis rounded-3 shadow"
@click="this.addJob()">
<i class="bi bi-plus-lg me-2"></i> Job
<i class="bi bi-plus-lg me-2"></i>
<LocaleText t="Job"></LocaleText>
</button>
</div>
<TransitionGroup name="schedulePeerJobTransition" tag="div" class="position-relative">
@@ -76,7 +79,9 @@ export default {
style="height: 153px"
v-if="this.selectedPeer.jobs.length === 0">
<div class="card-body text-muted text-center d-flex">
<h6 class="m-auto">This peer does not have any job yet.</h6>
<h6 class="m-auto">
<LocaleText t="This peer does not have any job yet."></LocaleText>
</h6>
</div>
</div>
</TransitionGroup>

View File

@@ -2,6 +2,7 @@
import SchedulePeerJob from "@/components/configurationComponents/peerScheduleJobsComponents/schedulePeerJob.vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {v4} from "uuid";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peerJobsAllModal",
@@ -9,7 +10,7 @@ export default {
const store = WireguardConfigurationsStore();
return {store}
},
components: {SchedulePeerJob},
components: {LocaleText, SchedulePeerJob},
props: {
configurationPeers: Array[Object]
},
@@ -32,7 +33,8 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow" style="width: 700px">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0 fw-normal">All Active Jobs
<h4 class="mb-0 fw-normal">
<LocaleText t="All Active Jobs"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
@@ -71,7 +73,9 @@ export default {
style="height: 153px"
v-else>
<div class="card-body text-muted text-center d-flex">
<h6 class="m-auto">No active job at the moment.</h6>
<span class="m-auto">
<LocaleText t="No active job at the moment."></LocaleText>
</span>
</div>
</div>
</div>

View File

@@ -1,8 +1,10 @@
<script>
import dayjs from "dayjs";
import {fetchGet} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peerJobsLogsModal",
components: {LocaleText},
props: {
configurationInfo: Object
},
@@ -51,44 +53,56 @@ export default {
<div class="m-auto mt-0 modal-dialog-centered dashboardModal" style="width: 100%">
<div class="card rounded-3 shadow w-100" >
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h4 class="mb-0">Jobs Logs</h4>
<h4 class="mb-0">
<LocaleText t="Jobs Logs"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4 pt-2">
<div v-if="!this.dataLoading">
<p>Updated at: {{this.logFetchTime}}</p>
<p>
<LocaleText t="Updated at"></LocaleText>
: {{this.logFetchTime}}</p>
<div class="mb-2 d-flex gap-3">
<button @click="this.fetchLog()"
class="btn btn-sm rounded-3 shadow-sm
text-info-emphasis bg-info-subtle border-1 border-info-subtle me-1">
<i class="bi bi-arrow-clockwise me-2"></i>
Refresh
<LocaleText t="Refresh"></LocaleText>
</button>
<div class="d-flex gap-3 align-items-center">
<span class="text-muted">Filter</span>
<span class="text-muted">
<LocaleText t="Filter"></LocaleText>
</span>
<div class="form-check">
<input class="form-check-input" type="checkbox" v-model="this.showSuccessJob"
id="jobLogsShowSuccessCheck">
<label class="form-check-label" for="jobLogsShowSuccessCheck">
<span class="badge text-success-emphasis bg-success-subtle">Success</span>
<span class="badge text-success-emphasis bg-success-subtle">
<LocaleText t="Success"></LocaleText>
</span>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" v-model="this.showFailedJob"
id="jobLogsShowFailedCheck">
<label class="form-check-label" for="jobLogsShowFailedCheck">
<span class="badge text-danger-emphasis bg-danger-subtle">Failed</span>
<span class="badge text-danger-emphasis bg-danger-subtle">
<LocaleText t="Failed"></LocaleText>
</span>
</label>
</div>
</div>
<div class="d-flex gap-3 align-items-center ms-auto">
<span class="text-muted">Display</span>
<span class="text-muted">
<LocaleText t="Display"></LocaleText>
</span>
<div class="form-check">
<input class="form-check-input" type="checkbox"
v-model="showJobID"
id="jobLogsShowJobIDCheck">
<label class="form-check-label" for="jobLogsShowJobIDCheck">
Job ID
<LocaleText t="Job ID"></LocaleText>
</label>
</div>
<div class="form-check">
@@ -96,7 +110,7 @@ export default {
v-model="showLogID"
id="jobLogsShowLogIDCheck">
<label class="form-check-label" for="jobLogsShowLogIDCheck">
Log ID
<LocaleText t="Log ID"></LocaleText>
</label>
</div>
@@ -106,11 +120,21 @@ export default {
<table class="table">
<thead>
<tr>
<th scope="col">Date</th>
<th scope="col" v-if="showLogID">Log ID</th>
<th scope="col" v-if="showJobID">Job ID</th>
<th scope="col">Status</th>
<th scope="col">Message</th>
<th scope="col">
<LocaleText t="Date"></LocaleText>
</th>
<th scope="col" v-if="showLogID">
<LocaleText t="Log ID"></LocaleText>
</th>
<th scope="col" v-if="showJobID">
<LocaleText t="Job ID"></LocaleText>
</th>
<th scope="col">
<LocaleText t="Status"></LocaleText>
</th>
<th scope="col">
<LocaleText t="Message"></LocaleText>
</th>
</tr>
</thead>
<tbody>

View File

@@ -41,6 +41,7 @@ import PeerJobsAllModal from "@/components/configurationComponents/peerJobsAllMo
import PeerJobsLogsModal from "@/components/configurationComponents/peerJobsLogsModal.vue";
import {ref} from "vue";
import PeerShareLinkModal from "@/components/configurationComponents/peerShareLinkModal.vue";
import LocaleText from "@/components/text/localeText.vue";
Chart.register(
ArcElement,
@@ -71,6 +72,7 @@ Chart.register(
export default {
name: "peerList",
components: {
LocaleText,
PeerShareLinkModal,
PeerJobsLogsModal,
PeerJobsAllModal, PeerJobs, PeerCreate, PeerQRCode, PeerSettings, PeerSearch, Peer, Line, Bar},
@@ -369,8 +371,12 @@ export default {
keys: ["name", "id", "allowed_ip"]
});
const result = this.wireguardConfigurationStore.searchString ?
fuse.search(this.wireguardConfigurationStore.searchString).map(x => x.item) : this.configurationPeers;
const result = this.wireguardConfigurationStore.searchString ?
this.configurationPeers.filter(x => {
return x.name.includes(this.wireguardConfigurationStore.searchString) ||
x.id.includes(this.wireguardConfigurationStore.searchString) ||
x.allowed_ip.includes(this.wireguardConfigurationStore.searchString)
}) : this.configurationPeers;
if (this.dashboardConfigurationStore.Configuration.Server.dashboard_sort === "restricted"){
return result.slice().sort((a, b) => {
@@ -406,7 +412,9 @@ export default {
<div v-if="!this.loading" class="container-md">
<div class="d-flex align-items-center">
<div>
<small CLASS="text-muted">CONFIGURATION</small>
<small CLASS="text-muted">
<LocaleText t="CONFIGURATION"></LocaleText>
</small>
<div class="d-flex align-items-center gap-3">
<h1 class="mb-0"><samp>{{this.configurationInfo.Name}}</samp></h1>
</div>
@@ -414,13 +422,15 @@ export default {
<div class="card rounded-3 bg-transparent shadow-sm ms-auto">
<div class="card-body py-2 d-flex align-items-center">
<div>
<p class="mb-0 text-muted"><small>Status</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Status"></LocaleText>
</small></p>
<div class="form-check form-switch ms-auto">
<label class="form-check-label" style="cursor: pointer" :for="'switch' + this.configurationInfo.id">
{{this.configurationToggling ? 'Turning ':''}}
{{this.configurationInfo.Status ? "On":"Off"}}
<LocaleText t="On" v-if="this.configurationInfo.Status"></LocaleText>
<LocaleText t="Off" v-else></LocaleText>
<span v-if="this.configurationToggling"
class="spinner-border spinner-border-sm" aria-hidden="true"></span>
class="spinner-border spinner-border-sm ms-2" aria-hidden="true"></span>
</label>
<input class="form-check-input"
style="cursor: pointer"
@@ -440,7 +450,9 @@ export default {
<div class="col-6 col-lg-3">
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body py-2">
<p class="mb-0 text-muted"><small>Address</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Address"></LocaleText>
</small></p>
{{this.configurationInfo.Address}}
</div>
</div>
@@ -448,7 +460,9 @@ export default {
<div class="col-6 col-lg-3">
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body py-2">
<p class="mb-0 text-muted"><small>Listen Port</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Listen Port"></LocaleText>
</small></p>
{{this.configurationInfo.ListenPort}}
</div>
</div>
@@ -456,7 +470,9 @@ export default {
<div style="word-break: break-all" class="col-12 col-lg-6">
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body py-2">
<p class="mb-0 text-muted"><small>Public Key</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Public Key"></LocaleText>
</small></p>
<samp>{{this.configurationInfo.PublicKey}}</samp>
</div>
</div>
@@ -467,7 +483,9 @@ export default {
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body d-flex">
<div>
<p class="mb-0 text-muted"><small>Connected Peers</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Connected Peers"></LocaleText>
</small></p>
<strong class="h4">{{configurationSummary.connectedPeers}}</strong>
</div>
<i class="bi bi-ethernet ms-auto h2 text-muted"></i>
@@ -478,7 +496,9 @@ export default {
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body d-flex">
<div>
<p class="mb-0 text-muted"><small>Total Usage</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Total Usage"></LocaleText>
</small></p>
<strong class="h4">{{configurationSummary.totalUsage}} GB</strong>
</div>
<i class="bi bi-arrow-down-up ms-auto h2 text-muted"></i>
@@ -489,7 +509,9 @@ export default {
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body d-flex">
<div>
<p class="mb-0 text-muted"><small>Total Received</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Total Received"></LocaleText>
</small></p>
<strong class="h4 text-primary">{{configurationSummary.totalReceive}} GB</strong>
</div>
<i class="bi bi-arrow-down ms-auto h2 text-muted"></i>
@@ -500,7 +522,9 @@ export default {
<div class="card rounded-3 bg-transparent shadow-sm">
<div class="card-body d-flex">
<div>
<p class="mb-0 text-muted"><small>Total Sent</small></p>
<p class="mb-0 text-muted"><small>
<LocaleText t="Total Sent"></LocaleText>
</small></p>
<strong class="h4 text-success">{{configurationSummary.totalSent}} GB</strong>
</div>
<i class="bi bi-arrow-up ms-auto h2 text-muted"></i>
@@ -512,7 +536,9 @@ export default {
<div class="col-12 col-lg-6">
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
<div class="card-header bg-transparent border-0">
<small class="text-muted">Peers Total Data Usage</small></div>
<small class="text-muted">
<LocaleText t="Peers Data Usage"></LocaleText>
</small></div>
<div class="card-body pt-1">
<Bar
:data="individualDataUsage"
@@ -523,7 +549,9 @@ export default {
</div>
<div class="col-sm col-lg-3">
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
<div class="card-header bg-transparent border-0"><small class="text-muted">Real Time Received Data Usage</small></div>
<div class="card-header bg-transparent border-0"><small class="text-muted">
<LocaleText t="Real Time Received Data Usage"></LocaleText>
</small></div>
<div class="card-body pt-1">
<Line
:options="chartOptions"
@@ -535,7 +563,9 @@ export default {
</div>
<div class="col-sm col-lg-3">
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
<div class="card-header bg-transparent border-0"><small class="text-muted">Real Time Sent Data Usage</small></div>
<div class="card-header bg-transparent border-0"><small class="text-muted">
<LocaleText t="Real Time Sent Data Usage"></LocaleText>
</small></div>
<div class="card-body pt-1">
<Line
:options="chartOptions"

View File

@@ -1,7 +1,9 @@
<script>
import QRCode from "qrcode";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peerQRCode",
components: {LocaleText},
props: {
peerConfigData: String
},
@@ -19,7 +21,9 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal justify-content-center">
<div class="card rounded-3 shadow">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h4 class="mb-0">QR Code</h4>
<h4 class="mb-0">
<LocaleText t="QR Code"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body">

View File

@@ -5,10 +5,11 @@ import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.
import {fetchPost} from "@/utilities/fetch.js";
import VueDatePicker from "@vuepic/vue-datepicker";
import dayjs from "dayjs";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "schedulePeerJob",
components: {VueDatePicker, ScheduleDropdown},
components: {LocaleText, VueDatePicker, ScheduleDropdown},
props: {
dropdowns: Array[Object],
pjob: Object,
@@ -110,15 +111,19 @@ export default {
<div class="card shadow-sm rounded-3 mb-2" :class="{'border-warning-subtle': this.newJob}">
<div class="card-header bg-transparent text-muted border-0">
<small class="d-flex" v-if="!this.newJob">
<strong class="me-auto">Job ID</strong>
<strong class="me-auto">
<LocaleText t="Job ID"></LocaleText>
</strong>
<samp>{{this.job.JobID}}</samp>
</small>
<small v-else><span class="badge text-bg-warning">Unsaved Job</span></small>
<small v-else><span class="badge text-bg-warning">
<LocaleText t="Unsaved Job"></LocaleText>
</span></small>
</div>
<div class="card-body pt-1" style="font-family: var(--bs-font-monospace)">
<div class="d-flex gap-2 align-items-center mb-2">
<samp>
if
<LocaleText t="if"></LocaleText>
</samp>
<ScheduleDropdown
:edit="edit"
@@ -127,7 +132,7 @@ export default {
@update="(value) => {this.job.Field = value}"
></ScheduleDropdown>
<samp>
is
<LocaleText t="is"></LocaleText>
</samp>
<ScheduleDropdown
:edit="edit"
@@ -149,12 +154,6 @@ export default {
:dark="this.store.Configuration.Server.dashboard_theme === 'dark'"
/>
<!-- <input class="form-control form-control-sm form-control-dark rounded-3 flex-grow-1"-->
<!-- :disabled="!edit"-->
<!-- type="datetime-local"-->
<!-- v-if="this.job.Field === 'date'"-->
<!-- v-model="this.job.Value"-->
<!-- style="width: auto">-->
<input class="form-control form-control-sm form-control-dark rounded-3 flex-grow-1"
:disabled="!edit"
v-else
@@ -165,7 +164,7 @@ export default {
</samp>
</div>
<div class="px-5 d-flex gap-2 align-items-center">
<samp>then</samp>
<samp><LocaleText t="then"></LocaleText></samp>
<ScheduleDropdown
:edit="edit"
:options="this.dropdowns.Action"
@@ -178,18 +177,18 @@ export default {
<div class="ms-auto d-flex gap-3" v-if="!this.edit">
<a role="button"
class="ms-auto text-decoration-none"
@click="this.edit = true">[E] Edit</a>
@click="this.edit = true">[E] <LocaleText t="Edit"></LocaleText></a>
<a role="button"
@click="this.delete()"
class=" text-danger text-decoration-none">[D] Delete</a>
class=" text-danger text-decoration-none">[D] <LocaleText t="Delete"></LocaleText></a>
</div>
<div class="ms-auto d-flex gap-3" v-else>
<a role="button"
class="text-secondary text-decoration-none"
@click="this.reset()">[C] Cancel</a>
@click="this.reset()">[C] <LocaleText t="Cancel"></LocaleText></a>
<a role="button"
class="text-primary ms-auto text-decoration-none"
@click="this.save()">[S] Save</a>
@click="this.save()">[S] <LocaleText t="Save"></LocaleText></a>
</div>
</div>
</div>

View File

@@ -2,10 +2,13 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import LocaleText from "@/components/text/localeText.vue";
import {GetLocale} from "@/utilities/locale.js";
export default {
name: "peerSearch",
components: {LocaleText},
setup(){
const store = DashboardConfigurationStore();
const wireguardConfigurationStore = WireguardConfigurationsStore()
@@ -18,16 +21,16 @@ export default {
data(){
return {
sort: {
status: "Status",
name: "Name",
allowed_ip: "Allowed IP",
restricted: "Restricted"
status: GetLocale("Status"),
name: GetLocale("Name"),
allowed_ip: GetLocale("Allowed IPs"),
restricted: GetLocale("Restricted")
},
interval: {
'5000': '5 Seconds',
'10000': '10 Seconds',
'30000': '30 Seconds',
'60000': '1 Minutes'
'5000': GetLocale('5 Seconds'),
'10000': GetLocale('10 Seconds'),
'30000': GetLocale('30 Seconds'),
'60000': GetLocale('1 Minutes')
},
searchString: "",
searchStringTimeout: undefined,
@@ -77,8 +80,10 @@ export default {
})
}
},
mounted() {
computed: {
searchBarPlaceholder(){
return GetLocale("Search Peers...")
}
}
}
</script>
@@ -89,25 +94,28 @@ export default {
<RouterLink
to="create"
class="text-decoration-none btn text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle shadow-sm">
<i class="bi bi-plus-lg me-2"></i>Peer
<i class="bi bi-plus-lg me-2"></i>
<LocaleText t="Peer"></LocaleText>
</RouterLink>
<button class="btn text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle shadow-sm"
@click="this.downloadAllPeer()">
<i class="bi bi-download me-2"></i> Download All
<i class="bi bi-download me-2"></i>
<LocaleText t="Download All"></LocaleText>
</button>
<div class="flex-grow-1 mt-3 mt-md-0">
<div class="mt-3 mt-md-0 flex-grow-1">
<input class="form-control rounded-3 bg-secondary-subtle border-1 border-secondary-subtle shadow-sm w-100"
placeholder="Search..."
:placeholder="searchBarPlaceholder"
id="searchPeers"
@keyup="this.debounce()"
v-model="this.searchString">
</div>
<button
<button
@click="this.showDisplaySettings = true"
class="btn text-secondary-emphasis bg-secondary-subtle rounded-3 border-1 border-secondary-subtle shadow-sm"
type="button" aria-expanded="false">
type="button" aria-expanded="false">
<i class="bi bi-filter-circle me-2"></i>
Display
<LocaleText t="Display"></LocaleText>
</button>
<button class="btn text-secondary-emphasis bg-secondary-subtle rounded-3 border-1 border-secondary-subtle shadow-sm"
@click="this.showMoreSettings = true"
@@ -122,13 +130,15 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow w-100">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0 fw-normal">Display
<h4 class="mb-0 fw-normal"><LocaleText t="Display"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.showDisplaySettings = false"></button>
</div>
<div class="card-body px-4 pb-4 d-flex gap-3 flex-column">
<div>
<p class="text-muted fw-bold mb-2"><small>Sort by</small></p>
<p class="text-muted fw-bold mb-2"><small>
<LocaleText t="Sort by"></LocaleText>
</small></p>
<div class="list-group">
<a v-for="(value, key) in this.sort" class="list-group-item list-group-item-action d-flex" role="button" @click="this.updateSort(key)">
<span class="me-auto">{{value}}</span>
@@ -138,7 +148,9 @@ export default {
</div>
</div>
<div>
<p class="text-muted fw-bold mb-2"><small>Refresh interval</small></p>
<p class="text-muted fw-bold mb-2"><small>
<LocaleText t="Refresh Interval"></LocaleText>
</small></p>
<div class="list-group">
<a v-for="(value, key) in this.interval"
class="list-group-item list-group-item-action d-flex" role="button"
@@ -163,21 +175,24 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow w-100">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0 fw-normal">Configuration Settings
<h4 class="mb-0 fw-normal">
<LocaleText t="Configuration Settings"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.showMoreSettings = false"></button>
</div>
<div class="card-body px-4 pb-4 d-flex gap-3 flex-column">
<div>
<p class="text-muted fw-bold mb-2"><small>Peer Jobs</small></p>
<p class="text-muted fw-bold mb-2"><small>
<LocaleText t="Peer Jobs"></LocaleText>
</small></p>
<div class="list-group">
<a class="list-group-item list-group-item-action d-flex" role="button"
@click="this.$emit('jobsAll')">
Active Jobs
<LocaleText t="Active Jobs"></LocaleText>
</a>
<a class="list-group-item list-group-item-action d-flex" role="button"
@click="this.$emit('jobLogs')">
Logs
<LocaleText t="Logs"></LocaleText>
</a>
</div>
</div>

View File

@@ -1,9 +1,11 @@
<script>
import {fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peerSettings",
components: {LocaleText},
props: {
selectedPeer: Object
},
@@ -73,18 +75,24 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow flex-grow-1">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0">Peer Settings</h4>
<h4 class="mb-0">
<LocaleText t="Peer Settings"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4" v-if="this.data">
<div class="d-flex flex-column gap-2 mb-4">
<div class="d-flex align-items-center">
<small class="text-muted">Public Key</small>
<small class="text-muted">
<LocaleText t="Public Key"></LocaleText>
</small>
<small class="ms-auto"><samp>{{this.data.id}}</samp></small>
</div>
<div>
<label for="peer_name_textbox" class="form-label">
<small class="text-muted">Name</small>
<small class="text-muted">
<LocaleText t="Name"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
@@ -94,7 +102,10 @@ export default {
<div>
<div class="d-flex position-relative">
<label for="peer_private_key_textbox" class="form-label">
<small class="text-muted">Private Key <code>(Required for QR Code and Download)</code></small>
<small class="text-muted"><LocaleText t="Private Key"></LocaleText>
<code>
<LocaleText t="(Required for QR Code and Download)"></LocaleText>
</code></small>
</label>
<a role="button" class="ms-auto text-decoration-none toggleShowKey"
@click="this.showKey = !this.showKey"
@@ -110,7 +121,11 @@ export default {
</div>
<div>
<label for="peer_allowed_ip_textbox" class="form-label">
<small class="text-muted">Allowed IPs <code>(Required)</code></small>
<small class="text-muted">
<LocaleText t="Allowed IPs"></LocaleText>
<code>
<LocaleText t="(Required)"></LocaleText>
</code></small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
@@ -120,7 +135,11 @@ export default {
<div>
<label for="peer_endpoint_allowed_ips" class="form-label">
<small class="text-muted">Endpoint Allowed IPs <code>(Required)</code></small>
<small class="text-muted">
<LocaleText t="Endpoint Allowed IPs"></LocaleText>
<code>
<LocaleText t="(Required)"></LocaleText>
</code></small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
@@ -129,7 +148,9 @@ export default {
</div>
<div>
<label for="peer_DNS_textbox" class="form-label">
<small class="text-muted">DNS</small>
<small class="text-muted">
<LocaleText t="DNS"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
@@ -141,7 +162,7 @@ export default {
<h2 class="accordion-header">
<button class="accordion-button rounded-3 collapsed" type="button"
data-bs-toggle="collapse" data-bs-target="#peerSettingsAccordionOptional">
Optional Settings
<LocaleText t="Optional Settings"></LocaleText>
</button>
</h2>
<div id="peerSettingsAccordionOptional" class="accordion-collapse collapse"
@@ -149,7 +170,8 @@ export default {
<div class="accordion-body d-flex flex-column gap-2 mb-2">
<div>
<label for="peer_preshared_key_textbox" class="form-label">
<small class="text-muted">Pre-Shared Key</small>
<small class="text-muted">
<LocaleText t="Pre-Shared Key"></LocaleText></small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
@@ -157,7 +179,9 @@ export default {
id="peer_preshared_key_textbox">
</div>
<div>
<label for="peer_mtu" class="form-label"><small class="text-muted">MTU</small></label>
<label for="peer_mtu" class="form-label"><small class="text-muted">
<LocaleText t="MTU"></LocaleText>
</small></label>
<input type="number" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
v-model="this.data.mtu"
@@ -165,7 +189,9 @@ export default {
</div>
<div>
<label for="peer_keep_alive" class="form-label">
<small class="text-muted">Persistent Keepalive</small>
<small class="text-muted">
<LocaleText t="Persistent Keepalive"></LocaleText>
</small>
</label>
<input type="number" class="form-control form-control-sm rounded-3"
:disabled="this.saving"
@@ -178,25 +204,27 @@ export default {
</div>
<hr>
<div class="d-flex gap-2 align-items-center">
<strong>Reset Data Usage</strong>
<strong>
<LocaleText t="Reset Data Usage"></LocaleText>
</strong>
<div class="d-flex gap-2 ms-auto">
<button class="btn bg-primary-subtle text-primary-emphasis rounded-3 flex-grow-1 shadow-sm"
@click="this.resetPeerData('total')"
>
<i class="bi bi-arrow-down-up me-2"></i>
Total
<LocaleText t="Total"></LocaleText>
</button>
<button class="btn bg-primary-subtle text-primary-emphasis rounded-3 flex-grow-1 shadow-sm"
@click="this.resetPeerData('receive')"
>
<i class="bi bi-arrow-down me-2"></i>
Received
<LocaleText t="Received"></LocaleText>
</button>
<button class="btn bg-primary-subtle text-primary-emphasis rounded-3 flex-grow-1 shadow-sm"
@click="this.resetPeerData('sent')"
>
<i class="bi bi-arrow-up me-2"></i>
Sent
<LocaleText t="Sent"></LocaleText>
</button>
</div>
@@ -206,14 +234,16 @@ export default {
<button class="btn btn-secondary rounded-3 shadow"
@click="this.reset()"
:disabled="!this.dataChanged || this.saving">
Revert <i class="bi bi-arrow-clockwise ms-2"></i>
<LocaleText t="Revert"></LocaleText>
<i class="bi bi-arrow-clockwise ms-2"></i>
</button>
<button class="ms-auto btn btn-dark btn-brand rounded-3 px-3 py-2 shadow"
:disabled="!this.dataChanged || this.saving"
@click="this.savePeer()"
>
Save Peer<i class="bi bi-save-fill ms-2"></i></button>
<LocaleText t="Save Peer"></LocaleText>
<i class="bi bi-save-fill ms-2"></i></button>
</div>
</div>
</div>

View File

@@ -1,9 +1,11 @@
<script>
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "peerSettingsDropdown",
components: {LocaleText},
setup(){
const dashboardStore = DashboardConfigurationStore()
return {dashboardStore}
@@ -88,9 +90,8 @@ export default {
<template v-if="!this.Peer.private_key">
<li>
<small class="w-100 dropdown-item text-muted"
style="white-space: break-spaces; font-size: 0.7rem"
>Download & QR Code is not available due to no <code>private key</code>
set for this peer
style="white-space: break-spaces; font-size: 0.7rem">
<LocaleText t="Download & QR Code is not available due to no private key set for this peer"></LocaleText>
</small>
</li>
@@ -114,7 +115,7 @@ export default {
<a class="dropdown-item d-flex" role="button"
@click="this.$emit('setting')"
>
<i class="me-auto bi bi-pen"></i> Edit
<i class="me-auto bi bi-pen"></i> <LocaleText t="Peer Settings"></LocaleText>
</a>
</li>
<li>

View File

@@ -4,6 +4,7 @@ import {fetchPost} from "@/utilities/fetch.js";
import dayjs from "dayjs";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import VueDatePicker from '@vuepic/vue-datepicker';
import LocaleText from "@/components/text/localeText.vue";
export default {
@@ -12,6 +13,7 @@ export default {
peer: Object
},
components: {
LocaleText,
VueDatePicker
},
data(){
@@ -49,11 +51,9 @@ export default {
if (res.status){
this.peer.ShareLink = res.data;
this.dataCopy = res.data.at(0);
this.store.newMessage("Server", "Share link created successfully", "success")
}else{
this.store.newMessage("Server",
"Share link failed to create. Reason: " + res.message, "danger")
}
this.loading = false;
})
@@ -108,13 +108,15 @@ export default {
<div class="m-auto modal-dialog-centered dashboardModal" style="width: 500px">
<div class="card rounded-3 shadow flex-grow-1">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4">
<h4 class="mb-0">Share Peer</h4>
<h4 class="mb-0">
<LocaleText t="Share Peer"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4" v-if="this.peer.ShareLink">
<div v-if="!this.dataCopy">
<h6 class="mb-3 text-muted">
Currently the peer is not sharing
<LocaleText t="Currently the peer is not sharing"></LocaleText>
</h6>
<button
@click="this.startSharing()"
@@ -123,7 +125,8 @@ export default {
<span :class="{'animate__animated animate__flash animate__infinite animate__slower': this.loading}">
<i class="bi bi-send-fill me-2" ></i>
</span>
{{this.loading ? "Sharing...":"Start Sharing"}}
<LocaleText t="Sharing..." v-if="this.loading"></LocaleText>
<LocaleText t="Start Sharing" v-else></LocaleText>
</button>
</div>
<div v-else>
@@ -137,7 +140,7 @@ export default {
<div class="d-flex flex-column gap-2 mb-3">
<small>
<i class="bi bi-calendar me-2"></i>
Expire Date
<LocaleText t="Expire At"></LocaleText>
</small>
<VueDatePicker
:is24="true"
@@ -157,7 +160,8 @@ export default {
<span :class="{'animate__animated animate__flash animate__infinite animate__slower': this.loading}">
<i class="bi bi-send-slash-fill me-2" ></i>
</span>
{{this.loading ? "Stop Sharing...":"Stop Sharing"}}
<LocaleText t="Stop Sharing..." v-if="this.loading"></LocaleText>
<LocaleText t="Stop Sharing" v-else></LocaleText>
</button>
</div>
</div>

View File

@@ -2,10 +2,11 @@
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import ConfigurationCard from "@/components/configurationListComponents/configurationCard.vue";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "configurationList",
components: {ConfigurationCard},
components: {LocaleText, ConfigurationCard},
async setup(){
const wireguardConfigurationsStore = WireguardConfigurationsStore();
return {wireguardConfigurationsStore}
@@ -36,16 +37,18 @@ export default {
<div class="d-flex mb-4 configurationListTitle">
<h3 class="text-body d-flex">
<i class="bi bi-body-text me-2"></i>
<span>WireGuard Configurations</span></h3>
<span>
<LocaleText t="WireGuard Configurations"></LocaleText>
</span></h3>
<RouterLink to="/new_configuration" class="btn btn-dark btn-brand rounded-3 px-3 py-2 shadow ms-auto rounded-3">
<i class="bi bi-plus-circle-fill me-2"></i>
Configuration
<LocaleText t="Configuration"></LocaleText>
</RouterLink>
</div>
<Transition name="fade" mode="out-in">
<div v-if="this.configurationLoaded">
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.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".
<LocaleText t="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."></LocaleText>
</p>
<div class="d-flex gap-3 flex-column mb-3" v-else>
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard>

View File

@@ -3,9 +3,11 @@ import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {fetchGet} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "navbar",
components: {LocaleText},
setup(){
const wireguardConfigurationsStore = WireguardConfigurationsStore();
const dashboardConfigurationStore = DashboardConfigurationStore();
@@ -47,17 +49,19 @@ export default {
<RouterLink class="nav-link rounded-3"
to="/" exact-active-class="active">
<i class="bi bi-house me-2"></i>
Home</RouterLink></li>
<LocaleText t="Home"></LocaleText>
</RouterLink></li>
<li class="nav-item">
<RouterLink class="nav-link rounded-3" to="/settings"
exact-active-class="active">
<i class="bi bi-gear me-2"></i>
Settings</RouterLink></li>
<LocaleText t="Settings"></LocaleText>
</RouterLink></li>
</ul>
<hr class="text-body">
<h6 class="sidebar-heading px-3 mt-4 mb-1 text-muted text-center">
<i class="bi bi-body-text me-2"></i>
Configurations
<LocaleText t="WireGuard Configurations"></LocaleText>
</h6>
<ul class="nav flex-column px-2">
<li class="nav-item">
@@ -72,7 +76,7 @@ export default {
<hr class="text-body">
<h6 class="sidebar-heading px-3 mt-4 mb-1 text-muted text-center">
<i class="bi bi-tools me-2"></i>
Tools
<LocaleText t="Tools"></LocaleText>
</h6>
<ul class="nav flex-column px-2">
<li class="nav-item">
@@ -87,16 +91,18 @@ export default {
@click="this.dashboardConfigurationStore.signOut()"
role="button" style="font-weight: bold">
<i class="bi bi-box-arrow-left me-2"></i>
Sign Out</a>
<LocaleText t="Sign Out"></LocaleText>
</a>
</li>
<li class="nav-item" style="font-size: 0.8rem">
<a :href="this.updateUrl" v-if="this.updateAvailable" class="text-decoration-none" target="_blank">
<small class="nav-link text-muted rounded-3" >
{{ this.updateMessage }}
<LocaleText :t="this.updateMessage"></LocaleText>
</small>
</a>
<small class="nav-link text-muted" v-else>
{{ this.updateMessage }}
<LocaleText :t="this.updateMessage"></LocaleText>
({{ dashboardConfigurationStore.Configuration.Server.version}})
</small>
</li>
</ul>

View File

@@ -2,9 +2,11 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "accountSettingsInputPassword",
components: {LocaleText},
props:{
targetData: String,
warning: false,
@@ -66,6 +68,11 @@ export default {
this.invalidFeedback = "Please fill in all required fields."
}
}
},
computed: {
passwordValid(){
return Object.values(this.value).find(x => x.length === 0) === undefined && this.value.newPassword === this.value.repeatNewPassword
}
}
}
</script>
@@ -76,7 +83,9 @@ export default {
<div class="col-sm">
<div class="form-group mb-2">
<label :for="'currentPassword_' + this.uuid" class="text-muted mb-1">
<strong><small>Current Password</small></strong>
<strong><small>
<LocaleText t="Current Password"></LocaleText>
</small></strong>
</label>
<input type="password" class="form-control mb-2"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@@ -88,7 +97,9 @@ export default {
<div class="col-sm">
<div class="form-group mb-2">
<label :for="'newPassword_' + this.uuid" class="text-muted mb-1">
<strong><small>New Password</small></strong>
<strong><small>
<LocaleText t="New Password"></LocaleText>
</small></strong>
</label>
<input type="password" class="form-control mb-2"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@@ -100,7 +111,9 @@ export default {
<div class="col-sm">
<div class="form-group mb-2">
<label :for="'repeatNewPassword_' + this.uuid" class="text-muted mb-1">
<strong><small>Repeat New Password</small></strong>
<strong><small>
<LocaleText t="Repeat New Password"></LocaleText>
</small></strong>
</label>
<input type="password" class="form-control mb-2"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@@ -109,8 +122,11 @@ export default {
</div>
</div>
</div>
<button class="ms-auto btn bg-success-subtle text-success-emphasis border-1 border-success-subtle rounded-3 shadow-sm" @click="this.useValidation()">
<i class="bi bi-save2-fill me-2"></i>Update Password
<button
:disabled="!this.passwordValid"
class="ms-auto btn bg-success-subtle text-success-emphasis border-1 border-success-subtle rounded-3 shadow-sm" @click="this.useValidation()">
<i class="bi bi-save2-fill me-2"></i>
<LocaleText t="Update Password"></LocaleText>
</button>
</div>
</template>

View File

@@ -2,14 +2,14 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "accountSettingsInputUsername",
components: {LocaleText},
props:{
targetData: String,
title: String,
warning: false,
warningText: ""
},
setup(){
const store = DashboardConfigurationStore();
@@ -62,7 +62,9 @@ export default {
<template>
<div class="form-group mb-2">
<label :for="this.uuid" class="text-muted mb-1">
<strong><small>{{this.title}}</small></strong>
<strong><small>
<LocaleText :t="this.title"></LocaleText>
</small></strong>
</label>
<input type="text" class="form-control"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@@ -73,11 +75,6 @@ export default {
:disabled="this.updating"
>
<div class="invalid-feedback">{{this.invalidFeedback}}</div>
<div class="px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1"
v-if="warning"
>
<small><i class="bi bi-exclamation-triangle-fill me-2"></i><span v-html="warningText"></span></small>
</div>
</div>
</template>

View File

@@ -2,9 +2,11 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "accountSettingsMFA",
components: {LocaleText},
setup(){
const store = DashboardConfigurationStore();
const uuid = `input_${v4()}`;
@@ -43,7 +45,9 @@ export default {
<template>
<div>
<div class="d-flex align-items-center">
<strong>Multi-Factor Authentication</strong>
<strong>
<LocaleText t="Multi-Factor Authentication (MFA)"></LocaleText>
</strong>
<div class="form-check form-switch ms-3">
<input class="form-check-input" type="checkbox"
v-model="this.status"
@@ -52,7 +56,9 @@ export default {
<button class="btn bg-warning-subtle text-warning-emphasis border-1 border-warning-subtle ms-auto rounded-3 shadow-sm"
v-if="this.status" @click="this.resetMFA()">
<i class="bi bi-shield-lock-fill me-2"></i>
{{this.store.Configuration.Account["totp_verified"] ? "Reset" : "Setup" }} MFA
<LocaleText t="Reset" v-if='this.store.Configuration.Account["totp_verified"]'></LocaleText>
<LocaleText t="Setup" v-else></LocaleText>
MFA
</button>
</div>
</div>

View File

@@ -4,10 +4,11 @@ import {v4} from "uuid";
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import NewDashboardAPIKey from "@/components/settingsComponent/dashboardAPIKeysComponents/newDashboardAPIKey.vue";
import DashboardAPIKey from "@/components/settingsComponent/dashboardAPIKeysComponents/dashboardAPIKey.vue";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "dashboardAPIKeys",
components: {DashboardAPIKey, NewDashboardAPIKey},
components: {LocaleText, DashboardAPIKey, NewDashboardAPIKey},
setup(){
const store = DashboardConfigurationStore();
return {store};
@@ -64,14 +65,17 @@ export default {
<template>
<div class="card mb-4 shadow rounded-3">
<div class="card-header d-flex">
API Keys
<LocaleText t="API Keys"></LocaleText>
<div class="form-check form-switch ms-auto" v-if="!this.store.getActiveCrossServer()">
<input class="form-check-input" type="checkbox"
v-model="this.value"
@change="this.toggleDashboardAPIKeys()"
role="switch" id="allowAPIKeysSwitch">
<label class="form-check-label" for="allowAPIKeysSwitch">
{{this.value ? 'Enabled':'Disabled'}}
<LocaleText t="Enabled" v-if="this.value"></LocaleText>
<LocaleText t="Disabled" v-else></LocaleText>
</label>
</div>
</div>
@@ -80,12 +84,13 @@ export default {
@click="this.newDashboardAPIKey = true"
v-if="!this.store.getActiveCrossServer()"
>
<i class="bi bi-key me-2"></i> Create
<i class="bi bi-plus-circle-fill me-2"></i>
<LocaleText t="API Key"></LocaleText>
</button>
<div class="card" style="height: 300px" v-if="this.apiKeys.length === 0">
<div class="card-body d-flex text-muted">
<span class="m-auto">
No Dashboard API Key
<LocaleText t="No WGDashboard API Key"></LocaleText>
</span>
</div>
</div>

View File

@@ -1,9 +1,11 @@
<script>
import {fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "dashboardAPIKey",
components: {LocaleText},
props: {
apiKey: Object
},
@@ -37,12 +39,18 @@ export default {
<div class="card rounded-3 shadow-sm">
<div class="card-body d-flex gap-3 align-items-center apiKey-card-body" v-if="!this.confirmDelete">
<div class="d-flex align-items-center gap-2">
<small class="text-muted">Key</small>
<small class="text-muted">
<LocaleText t="Key"></LocaleText>
</small>
<span style="word-break: break-all">{{this.apiKey.Key}}</span>
</div>
<div class="d-flex align-items-center gap-2 ms-auto">
<small class="text-muted">Expire At</small>
{{this.apiKey.ExpiredAt ? this.apiKey.ExpiredAt : 'Never'}}
<small class="text-muted">
<LocaleText t="Expire At"></LocaleText>
</small>
<LocaleText t="Never Expire" v-if="!this.apiKey.ExpiredAt"></LocaleText>
<span>{{ this.apiKey.ExpiredAt }}</span>
</div>
<a role="button" class="btn btn-sm bg-danger-subtle text-danger-emphasis rounded-3"
v-if="!this.store.getActiveCrossServer()"
@@ -52,7 +60,7 @@ export default {
</div>
<div v-else class="card-body d-flex gap-3 align-items-center justify-content-end"
v-if="!this.store.getActiveCrossServer()">
Are you sure to delete this API key?
<LocaleText t="Are you sure to delete this API key?"></LocaleText>
<a role="button" class="btn btn-sm bg-success-subtle text-success-emphasis rounded-3"
@click="this.deleteAPIKey()"
>

View File

@@ -3,10 +3,11 @@ import dayjs from "dayjs";
import {fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import VueDatePicker from "@vuepic/vue-datepicker";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "newDashboardAPIKey",
components: {VueDatePicker},
components: {LocaleText, VueDatePicker},
data(){
return{
newKeyData:{
@@ -58,11 +59,15 @@ export default {
style="background-color: #00000060; backdrop-filter: blur(3px)">
<div class="card m-auto rounded-3 mt-5">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h6 class="mb-0">Create API Key</h6>
<h6 class="mb-0">
<LocaleText t="Create API Key"></LocaleText>
</h6>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body d-flex gap-2 p-4 flex-column">
<small class="text-muted">When should this API Key expire?</small>
<small class="text-muted">
<LocaleText t="When should this API Key expire?"></LocaleText>
</small>
<div class="d-flex align-items-center gap-2">
<VueDatePicker
:is24="true"
@@ -80,7 +85,8 @@ export default {
<input class="form-check-input" type="checkbox"
v-model="this.newKeyData.neverExpire" id="neverExpire" :disabled="this.submitting">
<label class="form-check-label" for="neverExpire">
Never Expire (<i class="bi bi-emoji-grimace-fill"></i> Don't think that's a good idea)
<LocaleText t="Never Expire"></LocaleText> (<i class="bi bi-emoji-grimace-fill me-2"></i>
<LocaleText t="Don't think that's a good idea"></LocaleText>)
</label>
</div>
<button class="ms-auto btn bg-success-subtle text-success-emphasis border-1 border-success-subtle rounded-3 shadow-sm"
@@ -88,7 +94,8 @@ export default {
@click="this.submitNewAPIKey()"
>
<i class="bi bi-check-lg me-2" v-if="!this.submitting"></i>
{{this.submitting ? 'Creating...':'Done'}}
<LocaleText t="Creating..." v-if="this.submitting"></LocaleText>
<LocaleText t="Create" v-else></LocaleText>
</button>
</div>
</div>

View File

@@ -2,9 +2,12 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "dashboardSettingsInputWireguardConfigurationPath",
components: {LocaleText},
props:{
targetData: String,
title: String,
@@ -13,8 +16,9 @@ export default {
},
setup(){
const store = DashboardConfigurationStore();
const WireguardConfigurationStore = WireguardConfigurationsStore()
const uuid = `input_${v4()}`;
return {store, uuid};
return {store, uuid, WireguardConfigurationStore};
},
data(){
return{
@@ -33,6 +37,7 @@ export default {
methods:{
async useValidation(){
if(this.changed){
this.updating = true;
await fetchPost("/api/updateDashboardConfigurationItem", {
section: "Server",
key: this.targetData,
@@ -44,6 +49,8 @@ export default {
this.store.Configuration.Account[this.targetData] = this.value
clearTimeout(this.timeout)
this.timeout = setTimeout(() => this.isValid = false, 5000);
this.WireguardConfigurationStore.getConfigurations()
this.store.newMessage("Server", "WireGuard configuration path saved", "success")
}else{
this.isValid = false;
this.showInvalidFeedback = true;
@@ -59,24 +66,39 @@ export default {
</script>
<template>
<div class="form-group mb-2">
<div class="form-group">
<label :for="this.uuid" class="text-muted mb-1">
<strong><small>{{this.title}}</small></strong>
<strong><small>
<LocaleText :t="this.title"></LocaleText>
</small></strong>
</label>
<input type="text" class="form-control"
:class="{'is-invalid': this.showInvalidFeedback, 'is-valid': this.isValid}"
:id="this.uuid"
v-model="this.value"
@keydown="this.changed = true"
@blur="this.useValidation()"
:disabled="this.updating"
>
<div class="invalid-feedback">{{this.invalidFeedback}}</div>
<div class="px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1"
<div class="d-flex gap-2 align-items-start">
<div class="flex-grow-1">
<input type="text" class="form-control rounded-3"
:class="{'is-invalid': this.showInvalidFeedback, 'is-valid': this.isValid}"
:id="this.uuid"
v-model="this.value"
@keydown="this.changed = true"
:disabled="this.updating"
>
<div class="invalid-feedback fw-bold">{{this.invalidFeedback}}</div>
</div>
<button
@click="this.useValidation()"
:disabled="!this.changed"
class="ms-auto btn rounded-3 border-success-subtle bg-success-subtle text-success-emphasis">
<i class="bi bi-save2-fill" v-if="!this.updating"></i>
<span class="spinner-border spinner-border-sm" v-else></span>
</button>
</div>
<div class="px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1 mb-2"
v-if="warning"
>
<small><i class="bi bi-exclamation-triangle-fill me-2"></i><span v-html="warningText"></span></small>
<small><i class="bi bi-exclamation-triangle-fill me-2"></i>
<LocaleText :t="warningText"></LocaleText>
</small>
</div>
</div>
</template>

View File

@@ -1,9 +1,11 @@
<script>
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "dashboardTheme",
components: {LocaleText},
setup(){
const dashboardConfigurationStore = DashboardConfigurationStore();
return {dashboardConfigurationStore}
@@ -26,19 +28,21 @@ export default {
<template>
<div class="card mb-4 shadow rounded-3">
<p class="card-header">Dashboard Theme</p>
<p class="card-header">
<LocaleText t="Dashboard Theme"></LocaleText>
</p>
<div class="card-body d-flex gap-2">
<button class="btn bg-primary-subtle text-primary-emphasis flex-grow-1"
@click="this.switchTheme('light')"
:class="{active: this.dashboardConfigurationStore.Configuration.Server.dashboard_theme === 'light'}">
<i class="bi bi-sun-fill"></i>
Light
<i class="bi bi-sun-fill me-2"></i>
<LocaleText t="Light"></LocaleText>
</button>
<button class="btn bg-primary-subtle text-primary-emphasis flex-grow-1"
@click="this.switchTheme('dark')"
:class="{active: this.dashboardConfigurationStore.Configuration.Server.dashboard_theme === 'dark'}">
<i class="bi bi-moon-fill"></i>
Dark
<i class="bi bi-moon-fill me-2"></i>
<LocaleText t="Dark"></LocaleText>
</button>
</div>
</div>

View File

@@ -2,8 +2,10 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
components: {LocaleText},
props:{
targetData: String,
title: String,
@@ -61,7 +63,9 @@ export default {
<template>
<div class="form-group mb-2">
<label :for="this.uuid" class="text-muted mb-1">
<strong><small>{{this.title}}</small></strong>
<strong><small>
<LocaleText :t="this.title"></LocaleText>
</small></strong>
</label>
<input type="text" class="form-control"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@@ -75,7 +79,9 @@ export default {
<div class="px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1"
v-if="warning"
>
<small><i class="bi bi-exclamation-triangle-fill me-2"></i><span v-html="warningText"></span></small>
<small><i class="bi bi-exclamation-triangle-fill me-2"></i>
<LocaleText :t="warningText"></LocaleText>
</small>
</div>
</div>
</template>

View File

@@ -0,0 +1,30 @@
<script>
import {GetLocale} from "@/utilities/locale.js";
export default {
name: "signInInput",
methods: {GetLocale},
props: {
id: "",
data: "",
type: "",
placeholder: ""
},
computed: {
getLocaleText(){
return GetLocale(this.placeholder)
}
}
}
</script>
<template>
<input :type="type" v-model="this.data[this.id]" class="form-control"
:id="this.id" :name="this.id"
autocomplete="on"
:placeholder="this.getLocaleText" required>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,29 @@
<script>
import {GetLocale} from "@/utilities/locale.js";
export default {
name: "signInTOTP",
methods: {GetLocale},
props: {
data: "",
},
computed: {
getLocaleText(){
return GetLocale(this.placeholder)
}
}
}
</script>
<template>
<input class="form-control totp"
required
id="totp" maxlength="6" type="text" inputmode="numeric" autocomplete="one-time-code"
:placeholder="this.getLocaleText('OTP from your authenticator')"
v-model="this.data.totp"
>
</template>
<style scoped>
</style>

View File

@@ -1,5 +1,6 @@
<script>
import dayjs from "dayjs";
import {GetLocale} from "@/utilities/locale.js";
export default {
name: "RemoteServer",
@@ -73,7 +74,7 @@ export default {
return `${dayjs().subtract(this.startTime).millisecond()}ms`
}else{
if (this.refreshing){
return `Pinging...`
return GetLocale(`Pinging...`)
}
return this.errorMsg ? this.errorMsg : "N/A"
}

View File

@@ -1,6 +1,7 @@
<script>
import RemoteServer from "@/components/signInComponents/RemoteServer.vue";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "RemoteServerList",
@@ -8,18 +9,21 @@ export default {
const store = DashboardConfigurationStore();
return {store}
},
components: {RemoteServer}
components: {LocaleText, RemoteServer}
}
</script>
<template>
<div class="w-100 mt-3">
<div class="d-flex align-items-center mb-3">
<h5 class="mb-0">Server List</h5>
<h5 class="mb-0">
<LocaleText t="Server List"></LocaleText>
</h5>
<button
@click="this.store.addCrossServerConfiguration()"
class="btn bg-primary-subtle text-primary-emphasis border-1 border-primary-subtle shadow-sm ms-auto">
<i class="bi bi-plus-circle-fill me-2"></i>Server
<i class="bi bi-plus-circle-fill me-2"></i>
<LocaleText t="Server"></LocaleText>
</button>
</div>
<div class="w-100 d-flex gap-3 flex-column p-3 border border-1 border-secondary-subtle rounded-3"
@@ -30,7 +34,10 @@ export default {
:key="key"
:server="server"></RemoteServer>
<h6 class="text-muted m-auto" v-if="Object.keys(this.store.CrossServerConfiguration.ServerList).length === 0">
Click<i class="bi bi-plus-circle-fill mx-1"></i>to add your server</h6>
<LocaleText t="Click"></LocaleText>
<i class="bi bi-plus-circle-fill mx-1"></i>
<LocaleText t="to add your server"></LocaleText>
</h6>
</div>
</div>
</template>

View File

@@ -0,0 +1,23 @@
<script>
import {GetLocale} from "@/utilities/locale.js";
export default {
name: "localeText",
props: {
t: ""
},
computed: {
getLocaleText(){
return GetLocale(this.t)
}
}
}
</script>
<template>
{{ this.getLocaleText }}
</template>
<style scoped>
</style>

View File

@@ -10,17 +10,24 @@ import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {fetchGet} from "@/utilities/fetch.js";
let Locale;
await fetch("/api/locale").then(res => res.json()).then(res => Locale = JSON.parse(res.data))
const app = createApp(App)
app.use(router)
const pinia = createPinia();
app.use(router)
const pinia = createPinia();
pinia.use(({ store }) => {
store.$router = markRaw(router)
})
app.use(pinia)
app.mount('#app')
const store = DashboardConfigurationStore()
window.Locale = Locale;
app.mount('#app')

View File

@@ -28,7 +28,6 @@ const checkAuth = async () => {
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
name: "Index",
path: '/',

View File

@@ -1,6 +1,7 @@
import {defineStore} from "pinia";
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {v4} from "uuid";
import {GetLocale} from "@/utilities/locale.js";
export const DashboardConfigurationStore = defineStore('DashboardConfigurationStore', {
state: () => ({
@@ -17,7 +18,8 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
},
ActiveServerConfiguration: undefined,
IsElectronApp: false,
ShowNavBar: false
ShowNavBar: false,
Locale: undefined
}),
actions: {
initCrossServerConfiguration(){
@@ -57,19 +59,11 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
this.ActiveServerConfiguration = undefined;
localStorage.removeItem('ActiveCrossServerConfiguration')
},
async getConfiguration(){
await fetchGet("/api/getDashboardConfiguration", {}, (res) => {
if (res.status) this.Configuration = res.data
});
},
// async updateConfiguration(){
// await fetchPost("/api/updateDashboardConfiguration", {
// DashboardConfiguration: this.Configuration
// }, (res) => {
// console.log(res)
// })
// },
async signOut(){
await fetchGet("/api/signout", {}, (res) => {
this.removeActiveCrossServer();
@@ -79,11 +73,25 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
newMessage(from, content, type){
this.Messages.push({
id: v4(),
from: from,
content: content,
from: GetLocale(from),
content: GetLocale(content),
type: type,
show: true
})
},
applyLocale(key){
if (this.Locale === null)
return key
const reg = Object.keys(this.Locale)
const match = reg.filter(x => {
return key.match(new RegExp('^' + x + '$', 'g')) !== null
})
console.log(match)
if (match.length === 0 || match.length > 1){
return key
}
return this.Locale[match[0]]
}
}
});

View File

@@ -1,6 +1,7 @@
import {defineStore} from "pinia";
import {fetchGet} from "@/utilities/fetch.js";
import isCidr from "is-cidr";
import {GetLocale} from "@/utilities/locale.js";
export const WireguardConfigurationsStore = defineStore('WireguardConfigurationsStore', {
state: () => ({
@@ -11,54 +12,54 @@ export const WireguardConfigurationsStore = defineStore('WireguardConfigurations
dropdowns: {
Field: [
{
display: "Total Received",
display: GetLocale("Total Received"),
value: "total_receive",
unit: "GB",
type: 'number'
},
{
display: "Total Sent",
display: GetLocale("Total Sent"),
value: "total_sent",
unit: "GB",
type: 'number'
},
{
display: "Total Data",
display: GetLocale("Total Usage"),
value: "total_data",
unit: "GB",
type: 'number'
},
{
display: "Date",
display: GetLocale("Date"),
value: "date",
type: 'date'
}
],
Operator: [
// {
// display: "equal",
// value: "eq"
// },
// {
// display: "not equal",
// value: "neq"
// },
{
display: "equal",
value: "eq"
},
{
display: "not equal",
value: "neq"
},
{
display: "larger than",
display: GetLocale("larger than"),
value: "lgt"
},
{
display: "less than",
value: "lst"
},
// {
// display: "less than",
// value: "lst"
// },
],
Action: [
{
display: "Restrict Peer",
display: GetLocale("Restrict Peer"),
value: "restrict"
},
{
display: "Delete Peer",
display: GetLocale("Delete Peer"),
value: "delete"
}
]

View File

@@ -0,0 +1,12 @@
export const GetLocale = (key) => {
if (window.Locale === null)
return key
const reg = Object.keys(window.Locale)
const match = reg.filter(x => {
return key.match(new RegExp('^' + x + '$', 'gi')) !== null
})
if (match.length === 0 || match.length > 1){
return key
}
return key.replace(new RegExp(match[0], 'gi'), window.Locale[match[0]])
}

View File

@@ -12,11 +12,13 @@ import DashboardSettingsInputIPAddressAndPort
from "@/components/settingsComponent/dashboardSettingsInputIPAddressAndPort.vue";
import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue";
import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue";
import LocaleText from "@/components/text/localeText.vue";
export default {
name: "settings",
methods: {ipV46RegexCheck},
components: {
LocaleText,
AccountSettingsMFA,
DashboardAPIKeys,
DashboardSettingsInputIPAddressAndPort,
@@ -27,24 +29,20 @@ export default {
const dashboardConfigurationStore = DashboardConfigurationStore()
return {dashboardConfigurationStore}
},
watch: {
// 'dashboardConfigurationStore.Configuration': {
// deep: true,
// handler(){
// this.dashboardConfigurationStore.updateConfiguration();
// }
// }
}
}
</script>
<template>
<div class="mt-md-5 mt-3">
<div class="container-md">
<h3 class="mb-3 text-body">Settings</h3>
<h3 class="mb-3 text-body">
<LocaleText t="Settings"></LocaleText>
</h3>
<DashboardTheme></DashboardTheme>
<div class="card mb-4 shadow rounded-3">
<p class="card-header">Peers Default Settings</p>
<p class="card-header">
<LocaleText t="Peers Default Settings"></LocaleText>
</p>
<div class="card-body">
<PeersDefaultSettingsInput targetData="peer_global_dns" title="DNS"></PeersDefaultSettingsInput>
<PeersDefaultSettingsInput targetData="peer_endpoint_allowed_ip" title="Peer Endpoint Allowed IPs"></PeersDefaultSettingsInput>
@@ -56,19 +54,23 @@ export default {
</div>
</div>
<div class="card mb-4 shadow rounded-3">
<p class="card-header">WireGuard Configurations Settings</p>
<p class="card-header">
<LocaleText t="WireGuard Configurations Settings"></LocaleText>
</p>
<div class="card-body">
<DashboardSettingsInputWireguardConfigurationPath
targetData="wg_conf_path"
title="Configurations Directory"
:warning="true"
warning-text="Remember to remove <code>/</code> at the end of your path. e.g <code>/etc/wireguard</code>"
warning-text="Remember to remove / at the end of your path. e.g /etc/wireguard"
>
</DashboardSettingsInputWireguardConfigurationPath>
</div>
</div>
<div class="card mb-4 shadow rounded-3">
<p class="card-header">Account Settings</p>
<p class="card-header">
<LocaleText t="WGDashboard Account Settings"></LocaleText>
</p>
<div class="card-body d-flex gap-4 flex-column">
<AccountSettingsInputUsername targetData="username"
title="Username"

View File

@@ -3,10 +3,14 @@ import {fetchGet, fetchPost} from "../utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import Message from "@/components/messageCentreComponent/message.vue";
import RemoteServerList from "@/components/signInComponents/RemoteServerList.vue";
import {GetLocale} from "@/utilities/locale.js";
import LocaleText from "@/components/text/localeText.vue";
import SignInInput from "@/components/signIn/signInInput.vue";
import SignInTOTP from "@/components/signIn/signInTOTP.vue";
export default {
name: "signin",
components: {RemoteServerList, Message},
components: {SignInTOTP, SignInInput, LocaleText, RemoteServerList, Message},
async setup(){
const store = DashboardConfigurationStore()
let theme = "dark"
@@ -22,6 +26,7 @@ export default {
}),
fetchGet("/api/getDashboardVersion", {}, (res) => {
version = res.data
})
]);
}
@@ -30,9 +35,11 @@ export default {
},
data(){
return {
username: "",
password: "",
totp: "",
data: {
username: "",
password: "",
totp: "",
},
loginError: false,
loginErrorMessage: "",
loading: false
@@ -41,17 +48,17 @@ export default {
computed: {
getMessages(){
return this.store.Messages.filter(x => x.show)
},
applyLocale(key){
return GetLocale(key)
}
},
methods: {
GetLocale,
async auth(){
if (this.username && this.password && ((this.totpEnabled && this.totp) || !this.totpEnabled)){
if (this.data.username && this.data.password && ((this.totpEnabled && this.data.totp) || !this.totpEnabled)){
this.loading = true
await fetchPost("/api/authenticate", {
username: this.username,
password: this.password,
totp: this.totp
}, (response) => {
await fetchPost("/api/authenticate", this.data, (response) => {
if (response.status){
this.loginError = false;
this.$refs["signInBtn"].classList.add("signedIn")
@@ -97,45 +104,38 @@ export default {
:data-bs-theme="this.theme">
<div class="login-box m-auto" >
<div class="m-auto" style="width: 700px;">
<h4 class="mb-0 text-body">Welcome to</h4>
<h4 class="mb-0 text-body">
<LocaleText t="Welcome to"></LocaleText>
</h4>
<span class="dashboardLogo display-3"><strong>WGDashboard</strong></span>
<div class="alert alert-danger mt-2 mb-0" role="alert" v-if="loginError">
{{this.loginErrorMessage}}
<LocaleText :t="this.loginErrorMessage"></LocaleText>
</div>
<form @submit="(e) => {e.preventDefault(); this.auth();}"
v-if="!this.store.CrossServerConfiguration.Enable">
<div class="form-group text-body">
<label for="username" class="text-left" style="font-size: 1rem">
<i class="bi bi-person-circle"></i></label>
<input type="text" v-model="username" class="form-control" id="username" name="username"
autocomplete="on"
placeholder="Username" required>
<SignInInput id="username" :data="this.data"
type="text" placeholder="Username"></SignInInput>
</div>
<div class="form-group text-body">
<label for="password" class="text-left" style="font-size: 1rem"><i class="bi bi-key-fill"></i></label>
<input type="password"
v-model="password" class="form-control" id="password" name="password"
autocomplete="on"
placeholder="Password" required>
<SignInInput id="password" :data="this.data"
type="password" placeholder="Password"></SignInInput>
</div>
<div class="form-group text-body" v-if="totpEnabled">
<label for="totp" class="text-left" style="font-size: 1rem"><i class="bi bi-lock-fill"></i></label>
<input class="form-control totp"
required
id="totp" maxlength="6" type="text" inputmode="numeric" autocomplete="one-time-code"
placeholder="OTP from your authenticator"
v-model="this.totp"
>
<SignInTOTP :data="this.data"></SignInTOTP>
</div>
<button class="btn btn-lg btn-dark ms-auto mt-4 w-100 d-flex btn-brand signInBtn" ref="signInBtn">
<span v-if="!this.loading" class="d-flex w-100">
Sign In<i class="ms-auto bi bi-chevron-right"></i>
<LocaleText t="Sign In"></LocaleText>
<i class="ms-auto bi bi-chevron-right"></i>
</span>
<span v-else class="d-flex w-100 align-items-center">
Signing In...
<span class="spinner-border ms-auto spinner-border-sm" role="status">
<span class="visually-hidden">Loading...</span>
</span>
<LocaleText t="Signing In..."></LocaleText>
<span class="spinner-border ms-auto spinner-border-sm" role="status"></span>
</span>
</button>
</form>
@@ -146,7 +146,9 @@ export default {
<input
v-model="this.store.CrossServerConfiguration.Enable"
class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckChecked">
<label class="form-check-label" for="flexSwitchCheckChecked">Access Remote Server</label>
<label class="form-check-label" for="flexSwitchCheckChecked">
<LocaleText t="Access Remote Server"></LocaleText>
</label>
</div>
</div>
</div>

View File

@@ -21,6 +21,7 @@ export default defineConfig(({mode}) => {
}
},
build: {
target: "es2022",
outDir: '../../../../WGDashboard-Desktop',
rollupOptions: {
output: {
@@ -50,6 +51,7 @@ export default defineConfig(({mode}) => {
host: '0.0.0.0'
},
build: {
target: "es2022",
outDir: 'dist',
rollupOptions: {
output: {

View File

@@ -0,0 +1,14 @@
[
{
"lang_id": "en",
"lang_name": "English"
},
{
"lang_id": "zh-CN",
"lang_name": "Chinese (Simplified)"
},
{
"lang_id": "zh-HK",
"lang_name": "Chinese (Traditional)"
}
]

View File

@@ -0,0 +1,10 @@
{
"WireGuard Configurations": {
"zh-CN": "WireGuard 配置",
"zh-HK": "WireGuard 配置"
},
"Configuration": {
"zh-CN": "配置",
"zh-HK": "配置"
}
}

View File

@@ -0,0 +1,134 @@
{
"Welcome to": "欢迎来到",
"Username": "用户名",
"Password": "密码",
"OTP from your authenticator": "您双因素身份验证的一次性验证码",
"Sign In": "登录",
"Signing In\\.\\.\\.": "正在登录...",
"Access Remote Server": "访问远程服务器",
"Server": "服务器",
"Click": "点击",
"Pinging...": "尝试连接中...",
"to add your server": "添加您的服务器",
"Server List": "服务器列表",
"Sorry, your username or password is incorrect.": "对不起,您的用户名或密码不正确",
"Home": "主页",
"Settings": "设定",
"Tools": "工具箱",
"Sign Out": "退出登录",
"Checking for update...": "正在检查是否有新版本...",
"You're on the latest version": "已经是最新版本",
"WireGuard Configurations": "WireGuard 配置",
"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.": "您还没有任何WireGuard配置。请检查您的配置文件夹或前往设置更改路径。默认文件夹是 /etc/wireguard",
"Configuration": "配置",
"Configurations": "配置",
"Peers Default Settings": "端点默认设置",
"Dashboard Theme": "面板主题",
"Light": "简约白",
"Dark": "简约黑",
"This will be changed globally, and will be apply to all peer's QR code and configuration file.": "更改这个设定会应用到所有端点的配置文件和配置二维码",
"WireGuard Configurations Settings": "WireGuard 配置设定",
"Configurations Directory": "配置文件路径",
"Remember to remove / at the end of your path. e.g /etc/wireguard": "请把路径最后的 /(左斜杠)移除,例如:/etc/wireguard",
"WGDashboard Account Settings": "WGDashboard 账户设定",
"Current Password": "当前密码",
"New Password": "新密码",
"Repeat New Password": "重复新密码",
"Update Password": "更新密码",
"Multi-Factor Authentication \\(MFA\\)": "多重身份验证MFA)",
"Reset": "重置",
"Setup": "设置",
"API Keys": "API 秘钥",
"API Key": "API 秘钥",
"Key": "秘钥",
"Enabled": "已启用",
"Disabled": "已停用",
"No WGDashboard API Key": "没有 WGDashboard API 秘钥",
"Expire At": "过期于",
"Are you sure to delete this API key\\?": "确定删除此 API 秘钥?",
"Create API Key": "创建 API 秘钥",
"When should this API Key expire\\?": "这个 API 秘钥什么时候过期呢?",
"Never Expire": "从不过期",
"Don't think that's a good idea": "我不觉得这是一个好主意",
"Creating\\.\\.\\.": "创建中...",
"Create": "创建",
"Status": "状态",
"On": "已启用",
"Off": "已停用",
"Address": "网络地址",
"Listen Port": "监听端口",
"Public Key": "公钥",
"Connected Peers": "已连接端点",
"Total Usage": "总数据用量",
"Total Received": "总接收数据用量",
"Total Sent": "总发送数据用量",
"Peers Data Usage": "端点的数据用量",
"Real Time Received Data Usage": "实时接收数据量",
"Real Time Sent Data Usage": "实时发送数据量",
"Peer": "端点",
"Peer Settings": "端点设定",
"Download All": "全部下载",
"Search Peers\\.\\.\\.": "搜索端点...",
"Display": "显示设置",
"Sort By": "排列方式",
"Refresh Interval": "刷新间隔",
"Name": "名字",
"Allowed IPs": "允许的 IP 地址",
"Restricted": "已限制端点",
"(.*) Seconds": "$1 秒",
"(.*) Minutes": "$1 分钟",
"Configuration Settings": "配置设定",
"Peer Jobs": "端点任务",
"Active Jobs": "未运行任务",
"All Active Jobs": "所有未运行任务",
"Logs": "日志",
"Private Key": "秘钥",
"\\(Required for QR Code and Download\\)": "(二维码以及下载功能需要填写秘钥)",
"\\(Required\\)": "(必填项)",
"Endpoint Allowed IPs": "终结点允许的 IP 地址",
"DNS": "域名系统DNS",
"Optional Settings": "可选设定",
"Pre-Shared Key": "共享秘钥",
"MTU": "最大传输单元",
"Persistent Keepalive": "持久保持活动",
"Reset Data Usage": "重置数据用量",
"Total": "总数据",
"Sent": "发送数据",
"Received": "接收数据",
"Revert": "撤销更改",
"Save Peer": "保存端点",
"QR Code": "二维码",
"Schedule Jobs": "计划任务",
"Job": "任务",
"Job ID": "任务 ID",
"Unsaved Job": "未保存任务",
"This peer does not have any job yet\\.": "此端点还没有任何任务",
"if": "如果",
"is": "是",
"then": "那就",
"larger than": "大于",
"Date": "日期",
"Restrict Peer": "限制端点",
"Delete Peer": "删除端点",
"Edit": "编辑",
"Delete": "删除",
"Cancel": "取消",
"Save": "保存",
"No active job at the moment\\.": "没有未运行的任务",
"Jobs Logs": "任务日志",
"Updated at": "更新于",
"Refresh": "刷新",
"Filter": "筛选",
"Success": "成功",
"Failed": "失败",
"Log ID": "任务 ID",
"Message": "消息",
"Share Peer": "分享端点",
"Currently the peer is not sharing": "此端点未被共享",
"Sharing\\.\\.\\.": "分享中...",
"Start Sharing": "开始分享",
"Stop Sharing\\.\\.\\.": "停止分享中...",
"Stop Sharing": "停止分享",
"Access Restricted": "已限制访问",
"Download \\& QR Code is not available due to no private key set for this peer": "下载以及二维码功能不可用,需要填写此端点的秘钥"
}