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

Still working on translation...

This commit is contained in:
Donald Zou 2024-09-09 23:43:55 +08:00
parent d458a28337
commit a3a312e3db
32 changed files with 399 additions and 171 deletions

View File

@ -399,7 +399,6 @@ class PeerShareLinks:
""" """
) )
self.__getSharedLinks() self.__getSharedLinks()
# print(self.Links)
def __getSharedLinks(self): def __getSharedLinks(self):
self.Links.clear() self.Links.clear()
allLinks = sqlSelect("SELECT * FROM PeerShareLinks WHERE ExpireDate IS NULL OR ExpireDate > datetime('now', 'localtime')").fetchall() allLinks = sqlSelect("SELECT * FROM PeerShareLinks WHERE ExpireDate IS NULL OR ExpireDate > datetime('now', 'localtime')").fetchall()
@ -503,7 +502,6 @@ class WireguardConfiguration:
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1],
f"{self.Name}.conf"), "w+") as configFile: f"{self.Name}.conf"), "w+") as configFile:
# print(self.__parser.sections())
self.__parser.write(configFile) self.__parser.write(configFile)
self.Peers: list[Peer] = [] self.Peers: list[Peer] = []
@ -613,7 +611,6 @@ class WireguardConfiguration:
if regex_match("#Name# = (.*)", i): if regex_match("#Name# = (.*)", i):
split = re.split(r'\s*=\s*', i, 1) split = re.split(r'\s*=\s*', i, 1)
print(split)
if len(split) == 2: if len(split) == 2:
p[pCounter]["name"] = split[1] p[pCounter]["name"] = split[1]
@ -1283,8 +1280,6 @@ def _regexMatch(regex, text):
def _getConfigurationList(): def _getConfigurationList():
# configurations = {}
print(DashboardConfig.GetConfig("Server", "wg_conf_path")[1])
for i in os.listdir(DashboardConfig.GetConfig("Server", "wg_conf_path")[1]): for i in os.listdir(DashboardConfig.GetConfig("Server", "wg_conf_path")[1]):
if _regexMatch("^(.{1,}).(conf)$", i): if _regexMatch("^(.{1,}).(conf)$", i):
i = i.replace('.conf', '') i = i.replace('.conf', '')
@ -1478,6 +1473,7 @@ def auth_req():
and "getDashboardVersion" not in request.path and "getDashboardVersion" not in request.path
and "sharePeer/get" not in request.path and "sharePeer/get" not in request.path
and "isTotpEnabled" not in request.path and "isTotpEnabled" not in request.path
and "locale" not in request.path
): ):
response = Flask.make_response(app, { response = Flask.make_response(app, {
"status": False, "status": False,
@ -2132,6 +2128,24 @@ def API_Welcome_Finish():
DashboardConfig.SetConfig("Other", "welcome_session", False) DashboardConfig.SetConfig("Other", "welcome_session", False)
return ResponseObject() return ResponseObject()
@app.get(f'{APP_PREFIX}/api/locale')
def API_Local_CurrentLang():
# if param is None or len(param) == 0:
# with open(os.path.join("./static/locale/active_languages.json"), "r") as f:
# return ResponseObject(data=''.join(f.readlines()))
_, param = DashboardConfig.GetConfig("Server", "dashboard_language")
if param == "en":
return ResponseObject()
if os.path.exists(os.path.join(f"./static/locale/{param}.json")):
with open(os.path.join(f"./static/locale/{param}.json"), "r") as f:
return ResponseObject(data=''.join(f.readlines()))
@app.route(f'{APP_PREFIX}/', methods=['GET']) @app.route(f'{APP_PREFIX}/', methods=['GET'])
def index(): def index():
@ -2148,8 +2162,6 @@ def backGroundThread():
time.sleep(10) time.sleep(10)
while True: while True:
with app.app_context(): with app.app_context():
print(DashboardConfig.GetConfig("Server", "wg_conf_path")[1])
print(id(WireguardConfigurations))
for c in WireguardConfigurations.values(): for c in WireguardConfigurations.values():
if c.getStatus(): if c.getStatus():
try: try:
@ -2176,11 +2188,6 @@ def gunicornConfig():
_, app_port = DashboardConfig.GetConfig("Server", "app_port") _, app_port = DashboardConfig.GetConfig("Server", "app_port")
return app_ip, app_port return app_ip, app_port
def clearWireguardConfigurations():
WireguardConfigurations = {}
WireguardConfigurations.clear()
print(WireguardConfigurations.keys())
AllPeerShareLinks: PeerShareLinks = PeerShareLinks() AllPeerShareLinks: PeerShareLinks = PeerShareLinks()
AllPeerJobs: PeerJobs = PeerJobs() AllPeerJobs: PeerJobs = PeerJobs()

Binary file not shown.

Binary file not shown.

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

View File

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

View File

@ -2,9 +2,11 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid"; import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
name: "accountSettingsInputPassword", name: "accountSettingsInputPassword",
components: {LocaleText},
props:{ props:{
targetData: String, targetData: String,
warning: false, warning: false,
@ -81,7 +83,9 @@ export default {
<div class="col-sm"> <div class="col-sm">
<div class="form-group mb-2"> <div class="form-group mb-2">
<label :for="'currentPassword_' + this.uuid" class="text-muted mb-1"> <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> </label>
<input type="password" class="form-control mb-2" <input type="password" class="form-control mb-2"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}" :class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@ -93,7 +97,9 @@ export default {
<div class="col-sm"> <div class="col-sm">
<div class="form-group mb-2"> <div class="form-group mb-2">
<label :for="'newPassword_' + this.uuid" class="text-muted mb-1"> <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> </label>
<input type="password" class="form-control mb-2" <input type="password" class="form-control mb-2"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}" :class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@ -105,7 +111,9 @@ export default {
<div class="col-sm"> <div class="col-sm">
<div class="form-group mb-2"> <div class="form-group mb-2">
<label :for="'repeatNewPassword_' + this.uuid" class="text-muted mb-1"> <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> </label>
<input type="password" class="form-control mb-2" <input type="password" class="form-control mb-2"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}" :class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@ -117,7 +125,8 @@ export default {
<button <button
:disabled="!this.passwordValid" :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()"> 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 <i class="bi bi-save2-fill me-2"></i>
<LocaleText t="Update Password"></LocaleText>
</button> </button>
</div> </div>
</template> </template>

View File

@ -2,14 +2,14 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid"; import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
name: "accountSettingsInputUsername", name: "accountSettingsInputUsername",
components: {LocaleText},
props:{ props:{
targetData: String, targetData: String,
title: String, title: String,
warning: false,
warningText: ""
}, },
setup(){ setup(){
const store = DashboardConfigurationStore(); const store = DashboardConfigurationStore();
@ -62,7 +62,9 @@ export default {
<template> <template>
<div class="form-group mb-2"> <div class="form-group mb-2">
<label :for="this.uuid" class="text-muted mb-1"> <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> </label>
<input type="text" class="form-control" <input type="text" class="form-control"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}" :class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
@ -73,11 +75,6 @@ export default {
:disabled="this.updating" :disabled="this.updating"
> >
<div class="invalid-feedback">{{this.invalidFeedback}}</div> <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> </div>
</template> </template>

View File

@ -2,9 +2,11 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid"; import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
name: "accountSettingsMFA", name: "accountSettingsMFA",
components: {LocaleText},
setup(){ setup(){
const store = DashboardConfigurationStore(); const store = DashboardConfigurationStore();
const uuid = `input_${v4()}`; const uuid = `input_${v4()}`;
@ -43,7 +45,9 @@ export default {
<template> <template>
<div> <div>
<div class="d-flex align-items-center"> <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"> <div class="form-check form-switch ms-3">
<input class="form-check-input" type="checkbox" <input class="form-check-input" type="checkbox"
v-model="this.status" 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" <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()"> v-if="this.status" @click="this.resetMFA()">
<i class="bi bi-shield-lock-fill me-2"></i> <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> </button>
</div> </div>
</div> </div>

View File

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

View File

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

View File

@ -3,9 +3,11 @@ import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.
import {v4} from "uuid"; import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js"; import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
name: "dashboardSettingsInputWireguardConfigurationPath", name: "dashboardSettingsInputWireguardConfigurationPath",
components: {LocaleText},
props:{ props:{
targetData: String, targetData: String,
title: String, title: String,
@ -66,7 +68,9 @@ export default {
<template> <template>
<div class="form-group"> <div class="form-group">
<label :for="this.uuid" class="text-muted mb-1"> <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> </label>
<div class="d-flex gap-2 align-items-start mb-2"> <div class="d-flex gap-2 align-items-start mb-2">
<div class="flex-grow-1"> <div class="flex-grow-1">
@ -90,7 +94,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 mb-2" <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" 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>
</div> </div>

View File

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

View File

@ -2,8 +2,10 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {v4} from "uuid"; import {v4} from "uuid";
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
components: {LocaleText},
props:{ props:{
targetData: String, targetData: String,
title: String, title: String,
@ -61,7 +63,9 @@ export default {
<template> <template>
<div class="form-group mb-2"> <div class="form-group mb-2">
<label :for="this.uuid" class="text-muted mb-1"> <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> </label>
<input type="text" class="form-control" <input type="text" class="form-control"
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}" :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" <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" 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>
</div> </div>
</template> </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> <script>
import dayjs from "dayjs"; import dayjs from "dayjs";
import {GetLocale} from "@/utilities/locale.js";
export default { export default {
name: "RemoteServer", name: "RemoteServer",
@ -73,7 +74,7 @@ export default {
return `${dayjs().subtract(this.startTime).millisecond()}ms` return `${dayjs().subtract(this.startTime).millisecond()}ms`
}else{ }else{
if (this.refreshing){ if (this.refreshing){
return `Pinging...` return GetLocale(`Pinging...`)
} }
return this.errorMsg ? this.errorMsg : "N/A" return this.errorMsg ? this.errorMsg : "N/A"
} }

View File

@ -1,6 +1,7 @@
<script> <script>
import RemoteServer from "@/components/signInComponents/RemoteServer.vue"; import RemoteServer from "@/components/signInComponents/RemoteServer.vue";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
name: "RemoteServerList", name: "RemoteServerList",
@ -8,18 +9,21 @@ export default {
const store = DashboardConfigurationStore(); const store = DashboardConfigurationStore();
return {store} return {store}
}, },
components: {RemoteServer} components: {LocaleText, RemoteServer}
} }
</script> </script>
<template> <template>
<div class="w-100 mt-3"> <div class="w-100 mt-3">
<div class="d-flex align-items-center mb-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 <button
@click="this.store.addCrossServerConfiguration()" @click="this.store.addCrossServerConfiguration()"
class="btn bg-primary-subtle text-primary-emphasis border-1 border-primary-subtle shadow-sm ms-auto"> 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> </button>
</div> </div>
<div class="w-100 d-flex gap-3 flex-column p-3 border border-1 border-secondary-subtle rounded-3" <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" :key="key"
:server="server"></RemoteServer> :server="server"></RemoteServer>
<h6 class="text-muted m-auto" v-if="Object.keys(this.store.CrossServerConfiguration.ServerList).length === 0"> <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>
</div> </div>
</template> </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 App from './App.vue'
import router from './router' 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) const app = createApp(App)
app.use(router)
const pinia = createPinia();
app.use(router)
const pinia = createPinia();
pinia.use(({ store }) => { pinia.use(({ store }) => {
store.$router = markRaw(router) store.$router = markRaw(router)
}) })
app.use(pinia) app.use(pinia)
const store = DashboardConfigurationStore()
app.mount('#app') window.Locale = Locale;
app.mount('#app')

View File

@ -1,6 +1,7 @@
import {defineStore} from "pinia"; import {defineStore} from "pinia";
import {fetchGet, fetchPost} from "@/utilities/fetch.js"; import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {v4} from "uuid"; import {v4} from "uuid";
import {GetLocale} from "@/utilities/locale.js";
export const DashboardConfigurationStore = defineStore('DashboardConfigurationStore', { export const DashboardConfigurationStore = defineStore('DashboardConfigurationStore', {
state: () => ({ state: () => ({
@ -17,7 +18,8 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
}, },
ActiveServerConfiguration: undefined, ActiveServerConfiguration: undefined,
IsElectronApp: false, IsElectronApp: false,
ShowNavBar: false ShowNavBar: false,
Locale: undefined
}), }),
actions: { actions: {
initCrossServerConfiguration(){ initCrossServerConfiguration(){
@ -57,19 +59,11 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
this.ActiveServerConfiguration = undefined; this.ActiveServerConfiguration = undefined;
localStorage.removeItem('ActiveCrossServerConfiguration') localStorage.removeItem('ActiveCrossServerConfiguration')
}, },
async getConfiguration(){ async getConfiguration(){
await fetchGet("/api/getDashboardConfiguration", {}, (res) => { await fetchGet("/api/getDashboardConfiguration", {}, (res) => {
if (res.status) this.Configuration = res.data if (res.status) this.Configuration = res.data
}); });
}, },
// async updateConfiguration(){
// await fetchPost("/api/updateDashboardConfiguration", {
// DashboardConfiguration: this.Configuration
// }, (res) => {
// console.log(res)
// })
// },
async signOut(){ async signOut(){
await fetchGet("/api/signout", {}, (res) => { await fetchGet("/api/signout", {}, (res) => {
this.removeActiveCrossServer(); this.removeActiveCrossServer();
@ -79,11 +73,25 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
newMessage(from, content, type){ newMessage(from, content, type){
this.Messages.push({ this.Messages.push({
id: v4(), id: v4(),
from: from, from: GetLocale(from),
content: content, content: GetLocale(content),
type: type, type: type,
show: true 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

@ -0,0 +1,16 @@
export const GetLocale = (key) => {
console.log(key)
if (window.Locale === null)
return key
const reg = Object.keys(window.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 window.Locale[match[0]]
}

View File

@ -12,11 +12,13 @@ import DashboardSettingsInputIPAddressAndPort
from "@/components/settingsComponent/dashboardSettingsInputIPAddressAndPort.vue"; from "@/components/settingsComponent/dashboardSettingsInputIPAddressAndPort.vue";
import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue"; import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue";
import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue"; import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue";
import LocaleText from "@/components/text/localeText.vue";
export default { export default {
name: "settings", name: "settings",
methods: {ipV46RegexCheck}, methods: {ipV46RegexCheck},
components: { components: {
LocaleText,
AccountSettingsMFA, AccountSettingsMFA,
DashboardAPIKeys, DashboardAPIKeys,
DashboardSettingsInputIPAddressAndPort, DashboardSettingsInputIPAddressAndPort,
@ -27,24 +29,20 @@ export default {
const dashboardConfigurationStore = DashboardConfigurationStore() const dashboardConfigurationStore = DashboardConfigurationStore()
return {dashboardConfigurationStore} return {dashboardConfigurationStore}
}, },
watch: {
// 'dashboardConfigurationStore.Configuration': {
// deep: true,
// handler(){
// this.dashboardConfigurationStore.updateConfiguration();
// }
// }
}
} }
</script> </script>
<template> <template>
<div class="mt-md-5 mt-3"> <div class="mt-md-5 mt-3">
<div class="container-md"> <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> <DashboardTheme></DashboardTheme>
<div class="card mb-4 shadow rounded-3"> <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"> <div class="card-body">
<PeersDefaultSettingsInput targetData="peer_global_dns" title="DNS"></PeersDefaultSettingsInput> <PeersDefaultSettingsInput targetData="peer_global_dns" title="DNS"></PeersDefaultSettingsInput>
<PeersDefaultSettingsInput targetData="peer_endpoint_allowed_ip" title="Peer Endpoint Allowed IPs"></PeersDefaultSettingsInput> <PeersDefaultSettingsInput targetData="peer_endpoint_allowed_ip" title="Peer Endpoint Allowed IPs"></PeersDefaultSettingsInput>
@ -56,19 +54,23 @@ export default {
</div> </div>
</div> </div>
<div class="card mb-4 shadow rounded-3"> <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"> <div class="card-body">
<DashboardSettingsInputWireguardConfigurationPath <DashboardSettingsInputWireguardConfigurationPath
targetData="wg_conf_path" targetData="wg_conf_path"
title="Configurations Directory" title="Configurations Directory"
:warning="true" :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> </DashboardSettingsInputWireguardConfigurationPath>
</div> </div>
</div> </div>
<div class="card mb-4 shadow rounded-3"> <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"> <div class="card-body d-flex gap-4 flex-column">
<AccountSettingsInputUsername targetData="username" <AccountSettingsInputUsername targetData="username"
title="Username" title="Username"

View File

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

View File

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

View File

@ -1,8 +0,0 @@
{
"Index": {
"configurationList": {
"mainTitle": "WireGuard Configurations",
"addConfigurationBtn": "Configuration"
}
}
}

View File

@ -1,8 +0,0 @@
{
"Index": {
"configurationList": {
"mainTitle": "WireGuard 配置",
"addConfigurationBtn": "配置"
}
}
}

View File

@ -4,7 +4,11 @@
"lang_name": "English" "lang_name": "English"
}, },
{ {
"lang_id": "zh-cn", "lang_id": "zh-CN",
"lang_name": "Chinese (Simplified)" "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,49 @@
{
"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 秘钥?"
}