mirror of
https://github.com/h44z/wg-portal.git
synced 2025-09-15 07:11:15 +00:00
Mikrotik integration (#467)
Allow MikroTik routes as WireGuard backends
This commit is contained in:
@@ -10,11 +10,13 @@ import isCidr from "is-cidr";
|
||||
import {isIP} from 'is-ip';
|
||||
import { freshInterface } from '@/helpers/models';
|
||||
import {peerStore} from "@/stores/peers";
|
||||
import {settingsStore} from "@/stores/settings";
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const interfaces = interfaceStore()
|
||||
const peers = peerStore()
|
||||
const settings = settingsStore()
|
||||
|
||||
const props = defineProps({
|
||||
interfaceId: String,
|
||||
@@ -48,6 +50,26 @@ const currentTags = ref({
|
||||
PeerDefDnsSearch: ""
|
||||
})
|
||||
const formData = ref(freshInterface())
|
||||
const isSaving = ref(false)
|
||||
const isDeleting = ref(false)
|
||||
const isApplyingDefaults = ref(false)
|
||||
|
||||
const isBackendValid = computed(() => {
|
||||
if (!props.visible || !selectedInterface.value) {
|
||||
return true // if modal is not visible or no interface is selected, we don't care about backend validity
|
||||
}
|
||||
|
||||
let backendId = selectedInterface.value.Backend
|
||||
|
||||
let valid = false
|
||||
let availableBackends = settings.Setting('AvailableBackends') || []
|
||||
availableBackends.forEach(backend => {
|
||||
if (backend.Id === backendId) {
|
||||
valid = true
|
||||
}
|
||||
})
|
||||
return valid
|
||||
})
|
||||
|
||||
// functions
|
||||
|
||||
@@ -61,6 +83,7 @@ watch(() => props.visible, async (newValue, oldValue) => {
|
||||
formData.value.Identifier = interfaces.Prepared.Identifier
|
||||
formData.value.DisplayName = interfaces.Prepared.DisplayName
|
||||
formData.value.Mode = interfaces.Prepared.Mode
|
||||
formData.value.Backend = interfaces.Prepared.Backend
|
||||
|
||||
formData.value.PublicKey = interfaces.Prepared.PublicKey
|
||||
formData.value.PrivateKey = interfaces.Prepared.PrivateKey
|
||||
@@ -99,6 +122,7 @@ watch(() => props.visible, async (newValue, oldValue) => {
|
||||
formData.value.Identifier = selectedInterface.value.Identifier
|
||||
formData.value.DisplayName = selectedInterface.value.DisplayName
|
||||
formData.value.Mode = selectedInterface.value.Mode
|
||||
formData.value.Backend = selectedInterface.value.Backend
|
||||
|
||||
formData.value.PublicKey = selectedInterface.value.PublicKey
|
||||
formData.value.PrivateKey = selectedInterface.value.PrivateKey
|
||||
@@ -237,6 +261,8 @@ function handleChangePeerDefDnsSearch(tags) {
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (isSaving.value) return
|
||||
isSaving.value = true
|
||||
try {
|
||||
if (props.interfaceId!=='#NEW#') {
|
||||
await interfaces.UpdateInterface(selectedInterface.value.Identifier, formData.value)
|
||||
@@ -251,6 +277,8 @@ async function save() {
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +287,8 @@ async function applyPeerDefaults() {
|
||||
return; // do nothing for new interfaces
|
||||
}
|
||||
|
||||
if (isApplyingDefaults.value) return
|
||||
isApplyingDefaults.value = true
|
||||
try {
|
||||
await interfaces.ApplyPeerDefaults(selectedInterface.value.Identifier, formData.value)
|
||||
|
||||
@@ -276,10 +306,14 @@ async function applyPeerDefaults() {
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isApplyingDefaults.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function del() {
|
||||
if (isDeleting.value) return
|
||||
isDeleting.value = true
|
||||
try {
|
||||
await interfaces.DeleteInterface(selectedInterface.value.Identifier)
|
||||
close()
|
||||
@@ -290,6 +324,8 @@ async function del() {
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isDeleting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,13 +350,22 @@ async function del() {
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.identifier.label') }}</label>
|
||||
<input v-model="formData.Identifier" class="form-control" :placeholder="$t('modals.interface-edit.identifier.placeholder')" type="text">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.mode.label') }}</label>
|
||||
<select v-model="formData.Mode" class="form-select">
|
||||
<option value="server">{{ $t('modals.interface-edit.mode.server') }}</option>
|
||||
<option value="client">{{ $t('modals.interface-edit.mode.client') }}</option>
|
||||
<option value="any">{{ $t('modals.interface-edit.mode.any') }}</option>
|
||||
</select>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.mode.label') }}</label>
|
||||
<select v-model="formData.Mode" class="form-select">
|
||||
<option value="server">{{ $t('modals.interface-edit.mode.server') }}</option>
|
||||
<option value="client">{{ $t('modals.interface-edit.mode.client') }}</option>
|
||||
<option value="any">{{ $t('modals.interface-edit.mode.any') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4" for="ifaceBackendSelector">{{ $t('modals.interface-edit.backend.label') }}</label>
|
||||
<select id="ifaceBackendSelector" v-model="formData.Backend" class="form-select" aria-describedby="backendHelp">
|
||||
<option v-for="backend in settings.Setting('AvailableBackends')" :value="backend.Id">{{ backend.Id === 'local' ? $t(backend.Name) : backend.Name }}</option>
|
||||
</select>
|
||||
<small v-if="!isBackendValid" id="backendHelp" class="form-text text-warning">{{ $t('modals.interface-edit.backend.invalid-label') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.display-name.label') }}</label>
|
||||
@@ -385,12 +430,14 @@ async function del() {
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.mtu.label') }}</label>
|
||||
<input v-model="formData.Mtu" class="form-control" :placeholder="$t('modals.interface-edit.mtu.placeholder')" type="number">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<div class="form-group col-md-6" v-if="formData.Backend==='local'">
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.firewall-mark.label') }}</label>
|
||||
<input v-model="formData.FirewallMark" class="form-control" :placeholder="$t('modals.interface-edit.firewall-mark.placeholder')" type="number">
|
||||
</div>
|
||||
<div class="form-group col-md-6" v-else>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row" v-if="formData.Backend==='local'">
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4">{{ $t('modals.interface-edit.routing-table.label') }}</label>
|
||||
<input v-model="formData.RoutingTable" aria-describedby="routingTableHelp" class="form-control" :placeholder="$t('modals.interface-edit.routing-table.placeholder')" type="text">
|
||||
@@ -530,16 +577,25 @@ async function del() {
|
||||
</fieldset>
|
||||
<fieldset v-if="props.interfaceId!=='#NEW#'" class="text-end">
|
||||
<hr class="mt-4">
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="applyPeerDefaults">{{ $t('modals.interface-edit.button-apply-defaults') }}</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="applyPeerDefaults" :disabled="isApplyingDefaults">
|
||||
<span v-if="isApplyingDefaults" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('modals.interface-edit.button-apply-defaults') }}
|
||||
</button>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex-fill text-start">
|
||||
<button v-if="props.interfaceId!=='#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del">{{ $t('general.delete') }}</button>
|
||||
<button v-if="props.interfaceId!=='#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del" :disabled="isDeleting">
|
||||
<span v-if="isDeleting" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">{{ $t('general.save') }}</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save" :disabled="isSaving">
|
||||
<span v-if="isSaving" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.save') }}
|
||||
</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
@@ -73,6 +73,8 @@ const currentTags = ref({
|
||||
DnsSearch: ""
|
||||
})
|
||||
const formData = ref(freshPeer())
|
||||
const isSaving = ref(false)
|
||||
const isDeleting = ref(false)
|
||||
|
||||
// functions
|
||||
|
||||
@@ -270,6 +272,8 @@ function handleChangeDnsSearch(tags) {
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (isSaving.value) return
|
||||
isSaving.value = true
|
||||
try {
|
||||
if (props.peerId !== '#NEW#') {
|
||||
await peers.UpdatePeer(selectedPeer.value.Identifier, formData.value)
|
||||
@@ -278,26 +282,30 @@ async function save() {
|
||||
}
|
||||
close()
|
||||
} catch (e) {
|
||||
// console.log(e)
|
||||
notify({
|
||||
title: "Failed to save peer!",
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function del() {
|
||||
if (isDeleting.value) return
|
||||
isDeleting.value = true
|
||||
try {
|
||||
await peers.DeletePeer(selectedPeer.value.Identifier)
|
||||
close()
|
||||
} catch (e) {
|
||||
// console.log(e)
|
||||
notify({
|
||||
title: "Failed to delete peer!",
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isDeleting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,10 +478,15 @@ async function del() {
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex-fill text-start">
|
||||
<button v-if="props.peerId !== '#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del">{{
|
||||
$t('general.delete') }}</button>
|
||||
<button v-if="props.peerId !== '#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del" :disabled="isDeleting">
|
||||
<span v-if="isDeleting" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">{{ $t('general.save') }}</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save" :disabled="isSaving">
|
||||
<span v-if="isSaving" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.save') }}
|
||||
</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
@@ -38,6 +38,7 @@ function freshForm() {
|
||||
|
||||
const currentTag = ref("")
|
||||
const formData = ref(freshForm())
|
||||
const isSaving = ref(false)
|
||||
|
||||
const title = computed(() => {
|
||||
if (!props.visible) {
|
||||
@@ -60,12 +61,15 @@ function handleChangeUserIdentifiers(tags) {
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (isSaving.value) return
|
||||
isSaving.value = true
|
||||
if (formData.value.Identifiers.length === 0) {
|
||||
notify({
|
||||
title: "Missing Identifiers",
|
||||
text: "At least one identifier is required to create a new peer.",
|
||||
type: 'error',
|
||||
})
|
||||
isSaving.value = false
|
||||
return
|
||||
}
|
||||
|
||||
@@ -79,6 +83,8 @@ async function save() {
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +114,10 @@ async function save() {
|
||||
</fieldset>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">{{ $t('general.save') }}</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save" :disabled="isSaving">
|
||||
<span v-if="isSaving" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.save') }}
|
||||
</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
@@ -34,6 +34,8 @@ const title = computed(() => {
|
||||
})
|
||||
|
||||
const formData = ref(freshUser())
|
||||
const isSaving = ref(false)
|
||||
const isDeleting = ref(false)
|
||||
|
||||
const passwordWeak = computed(() => {
|
||||
return formData.value.Password && formData.value.Password.length > 0 && formData.value.Password.length < settings.Setting('MinPasswordLength')
|
||||
@@ -89,6 +91,8 @@ function close() {
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (isSaving.value) return
|
||||
isSaving.value = true
|
||||
try {
|
||||
if (props.userId!=='#NEW#') {
|
||||
await users.UpdateUser(selectedUser.value.Identifier, formData.value)
|
||||
@@ -102,10 +106,14 @@ async function save() {
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function del() {
|
||||
if (isDeleting.value) return
|
||||
isDeleting.value = true
|
||||
try {
|
||||
await users.DeleteUser(selectedUser.value.Identifier)
|
||||
close()
|
||||
@@ -115,6 +123,8 @@ async function del() {
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isDeleting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,9 +203,15 @@ async function del() {
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex-fill text-start">
|
||||
<button v-if="props.userId!=='#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del">{{ $t('general.delete') }}</button>
|
||||
<button v-if="props.userId!=='#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del" :disabled="isDeleting">
|
||||
<span v-if="isDeleting" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save" :disabled="!formValid">{{ $t('general.save') }}</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save" :disabled="!formValid || isSaving">
|
||||
<span v-if="isSaving" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.save') }}
|
||||
</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
@@ -55,6 +55,8 @@ const title = computed(() => {
|
||||
})
|
||||
|
||||
const formData = ref(freshPeer())
|
||||
const isSaving = ref(false)
|
||||
const isDeleting = ref(false)
|
||||
|
||||
// functions
|
||||
|
||||
@@ -163,6 +165,8 @@ function close() {
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (isSaving.value) return
|
||||
isSaving.value = true
|
||||
try {
|
||||
if (props.peerId !== '#NEW#') {
|
||||
await peers.UpdatePeer(selectedPeer.value.Identifier, formData.value)
|
||||
@@ -171,26 +175,30 @@ async function save() {
|
||||
}
|
||||
close()
|
||||
} catch (e) {
|
||||
// console.log(e)
|
||||
notify({
|
||||
title: "Failed to save peer!",
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function del() {
|
||||
if (isDeleting.value) return
|
||||
isDeleting.value = true
|
||||
try {
|
||||
await peers.DeletePeer(selectedPeer.value.Identifier)
|
||||
close()
|
||||
} catch (e) {
|
||||
// console.log(e)
|
||||
notify({
|
||||
title: "Failed to delete peer!",
|
||||
text: e.toString(),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
isDeleting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,10 +291,15 @@ async function del() {
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex-fill text-start">
|
||||
<button v-if="props.peerId !== '#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del">{{
|
||||
$t('general.delete') }}</button>
|
||||
<button v-if="props.peerId !== '#NEW#'" class="btn btn-danger me-1" type="button" @click.prevent="del" :disabled="isDeleting">
|
||||
<span v-if="isDeleting" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">{{ $t('general.save') }}</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save" :disabled="isSaving">
|
||||
<span v-if="isSaving" class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
{{ $t('general.save') }}
|
||||
</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
@@ -5,6 +5,7 @@ export function freshInterface() {
|
||||
DisplayName: "",
|
||||
Identifier: "",
|
||||
Mode: "server",
|
||||
Backend: "local",
|
||||
|
||||
PublicKey: "",
|
||||
PrivateKey: "",
|
||||
|
@@ -102,7 +102,9 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Schnittstellenstatus für",
|
||||
"mode": "Modus",
|
||||
"backend": "Backend",
|
||||
"unknown-backend": "Unbekannt",
|
||||
"wrong-backend": "Ungültiges Backend, das lokale WireGuard Backend wird stattdessen verwendet!",
|
||||
"key": "Öffentlicher Schlüssel",
|
||||
"endpoint": "Öffentlicher Endpunkt",
|
||||
"port": "Port",
|
||||
@@ -357,6 +359,11 @@
|
||||
"client": "Client-Modus",
|
||||
"any": "Unbekannter Modus"
|
||||
},
|
||||
"backend": {
|
||||
"label": "Schnittstellenbackend",
|
||||
"invalid-label": "Ursprüngliches Backend ist ungültig, das lokale WireGuard Backend wird stattdessen verwendet!",
|
||||
"local": "Lokales WireGuard Backend"
|
||||
},
|
||||
"display-name": {
|
||||
"label": "Anzeigename",
|
||||
"placeholder": "Der beschreibende Name für die Schnittstelle"
|
||||
|
@@ -102,7 +102,9 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Interface status for",
|
||||
"mode": "mode",
|
||||
"backend": "Backend",
|
||||
"unknown-backend": "Unknown",
|
||||
"wrong-backend": "Invalid backend, using local WireGuard backend instead!",
|
||||
"key": "Public Key",
|
||||
"endpoint": "Public Endpoint",
|
||||
"port": "Listening Port",
|
||||
@@ -357,6 +359,11 @@
|
||||
"client": "Client Mode",
|
||||
"any": "Unknown Mode"
|
||||
},
|
||||
"backend": {
|
||||
"label": "Interface Backend",
|
||||
"invalid-label": "Original backend is no longer available, using local WireGuard backend instead!",
|
||||
"local": "Local WireGuard Backend"
|
||||
},
|
||||
"display-name": {
|
||||
"label": "Display Name",
|
||||
"placeholder": "The descriptive name for the interface"
|
||||
|
@@ -99,7 +99,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "État de l'interface pour",
|
||||
"mode": "mode",
|
||||
"backend": "backend",
|
||||
"key": "Clé publique",
|
||||
"endpoint": "Point de terminaison public",
|
||||
"port": "Port d'écoute",
|
||||
|
@@ -100,7 +100,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "인터페이스 상태:",
|
||||
"mode": "모드",
|
||||
"backend": "백엔드",
|
||||
"key": "공개 키",
|
||||
"endpoint": "공개 엔드포인트",
|
||||
"port": "수신 포트",
|
||||
|
@@ -101,7 +101,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Status da interface para",
|
||||
"mode": "modo",
|
||||
"mode": "backend",
|
||||
"key": "Chave Pública",
|
||||
"endpoint": "Endpoint Público",
|
||||
"port": "Porta de Escuta",
|
||||
|
@@ -99,7 +99,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Статус интерфейса для",
|
||||
"mode": "режим",
|
||||
"backend": "бэкэнд",
|
||||
"key": "Публичный ключ",
|
||||
"endpoint": "Публичная конечная точка",
|
||||
"port": "Порт прослушивания",
|
||||
|
@@ -99,7 +99,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Статус інтерфейсу для",
|
||||
"mode": "режим",
|
||||
"backend": "бекенд",
|
||||
"key": "Публічний ключ",
|
||||
"endpoint": "Публічна кінцева точка",
|
||||
"port": "Порт прослуховування",
|
||||
|
@@ -98,7 +98,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "Trạng thái giao diện cho",
|
||||
"mode": "chế độ",
|
||||
"backend": "phần sau",
|
||||
"key": "Khóa Công khai",
|
||||
"endpoint": "Điểm cuối Công khai",
|
||||
"port": "Cổng Nghe",
|
||||
|
@@ -98,7 +98,7 @@
|
||||
},
|
||||
"interface": {
|
||||
"headline": "接口状态",
|
||||
"mode": "模式",
|
||||
"backend": "后端",
|
||||
"key": "公钥",
|
||||
"endpoint": "公开节点",
|
||||
"port": "监听端口",
|
||||
|
@@ -5,17 +5,20 @@ import PeerMultiCreateModal from "../components/PeerMultiCreateModal.vue";
|
||||
import InterfaceEditModal from "../components/InterfaceEditModal.vue";
|
||||
import InterfaceViewModal from "../components/InterfaceViewModal.vue";
|
||||
|
||||
import {onMounted, ref} from "vue";
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import {peerStore} from "@/stores/peers";
|
||||
import {interfaceStore} from "@/stores/interfaces";
|
||||
import {notify} from "@kyvg/vue3-notification";
|
||||
import {settingsStore} from "@/stores/settings";
|
||||
import {humanFileSize} from '@/helpers/utils';
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const settings = settingsStore()
|
||||
const interfaces = interfaceStore()
|
||||
const peers = peerStore()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const viewedPeerId = ref("")
|
||||
const editPeerId = ref("")
|
||||
const multiCreatePeerId = ref("")
|
||||
@@ -45,6 +48,33 @@ function calculateInterfaceName(id, name) {
|
||||
return result
|
||||
}
|
||||
|
||||
const calculateBackendName = computed(() => {
|
||||
let backendId = interfaces.GetSelected.Backend
|
||||
|
||||
let backendName = t('interfaces.interface.unknown-backend')
|
||||
let availableBackends = settings.Setting('AvailableBackends') || []
|
||||
availableBackends.forEach(backend => {
|
||||
if (backend.Id === backendId) {
|
||||
backendName = backend.Id === 'local' ? t(backend.Name) : backend.Name
|
||||
}
|
||||
})
|
||||
return backendName
|
||||
})
|
||||
|
||||
const isBackendValid = computed(() => {
|
||||
let backendId = interfaces.GetSelected.Backend
|
||||
|
||||
let valid = false
|
||||
let availableBackends = settings.Setting('AvailableBackends') || []
|
||||
availableBackends.forEach(backend => {
|
||||
if (backend.Id === backendId) {
|
||||
valid = true
|
||||
}
|
||||
})
|
||||
return valid
|
||||
})
|
||||
|
||||
|
||||
async function download() {
|
||||
await interfaces.LoadInterfaceConfig(interfaces.GetSelected.Identifier)
|
||||
|
||||
@@ -141,7 +171,7 @@ onMounted(async () => {
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-8">
|
||||
{{ $t('interfaces.interface.headline') }} <strong>{{interfaces.GetSelected.Identifier}}</strong> ({{interfaces.GetSelected.Mode}} {{ $t('interfaces.interface.mode') }})
|
||||
{{ $t('interfaces.interface.headline') }} <strong>{{interfaces.GetSelected.Identifier}}</strong> ({{ $t('modals.interface-edit.mode.' + interfaces.GetSelected.Mode )}} | {{ $t('interfaces.interface.backend') + ": " + calculateBackendName }}<span v-if="!isBackendValid" :title="t('interfaces.interface.wrong-backend')" class="ms-1 me-1"><i class="fa-solid fa-triangle-exclamation"></i></span>)
|
||||
<span v-if="interfaces.GetSelected.Disabled" class="text-danger"><i class="fa fa-circle-xmark" :title="interfaces.GetSelected.DisabledReason"></i></span>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 text-lg-end">
|
||||
|
Reference in New Issue
Block a user