mirror of
https://github.com/h44z/wg-portal.git
synced 2025-08-10 07:22:24 +00:00
wip: english translation
This commit is contained in:
parent
984818c393
commit
c934d7ecd3
@ -109,13 +109,12 @@ const currentYear = ref(new Date().getFullYear())
|
||||
<div class="row align-items-center">
|
||||
<div class="col-6">Copyright © {{ companyName }} {{ currentYear }} <span v-if="auth.IsAuthenticated"> - version {{ wgVersion }}</span></div>
|
||||
<div class="col-6 text-end">
|
||||
<div aria-label="{{ $t('menu.lang') }}" class="btn-group" role="group">
|
||||
<div :aria-label="$t('menu.lang')" class="btn-group" role="group">
|
||||
<div class="btn-group" role="group">
|
||||
<button aria-expanded="false" aria-haspopup="true" class="btn btn btn-secondary pe-0" data-bs-toggle="dropdown" type="button"><span :class="languageFlag" class="fi"></span></button>
|
||||
<div aria-labelledby="btnGroupDrop3" class="dropdown-menu" style="">
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('en')"><span class="fi fi-us"></span> English</a>
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('de')"><span class="fi fi-de"></span> Deutsch</a>
|
||||
<a class="dropdown-item" href="#" @click.prevent="switchLanguage('es')"><span class="fi fi-es"></span> Español</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,31 +1,8 @@
|
||||
<template>
|
||||
<Teleport to="#dialogs">
|
||||
<div v-if="visible" class="modal-backdrop fade show">
|
||||
<div class="modal fade show" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-scrollable" @click.stop="">
|
||||
<div class="modal-content" ref="body">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ title }}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ question }}
|
||||
</div>
|
||||
<div class="modal-footer pt-0 border-top-0">
|
||||
<button type="button" class="btn btn-primary" @click="no">No</button>
|
||||
<button type="button" class="btn btn-success" @click="yes">Yes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const title = ref("Default Title")
|
||||
const question = ref("Default Question")
|
||||
@ -41,13 +18,37 @@ function showDialog(titleStr, questionStr) {
|
||||
|
||||
function yes() {
|
||||
visible.value = false
|
||||
console.log("Chosen yes")
|
||||
emit('yes')
|
||||
}
|
||||
|
||||
function no() {
|
||||
visible.value = false
|
||||
console.log("Chosen no")
|
||||
emit('no')
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="#dialogs">
|
||||
<div v-if="visible" class="modal-backdrop fade show">
|
||||
<div class="modal fade show" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-scrollable" @click.stop="">
|
||||
<div class="modal-content" ref="body">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ title }}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ question }}
|
||||
</div>
|
||||
<div class="modal-footer pt-0 border-top-0">
|
||||
<button type="button" class="btn btn-primary" @click="no">{{ $t('general.no') }}</button>
|
||||
<button type="button" class="btn btn-success" @click="yes">{{ $t('general.yes') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
@ -28,7 +28,7 @@ const title = computed(() => {
|
||||
return "" // otherwise interfaces.GetSelected will die...
|
||||
}
|
||||
|
||||
return t("interfaces.interface.show") + ": " + selectedInterface.value.Identifier
|
||||
return t("modals.interface-view.headline") + " " + selectedInterface.value.Identifier
|
||||
})
|
||||
|
||||
// functions
|
||||
@ -54,7 +54,7 @@ function close() {
|
||||
<Prism language="ini" :code="configString"></Prism>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button class="btn btn-primary" type="button" @click.prevent="close">Close</button>
|
||||
<button class="btn btn-primary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Teleport to="#modals">
|
||||
<div v-show="visible" class="modal-backdrop fade show" @click="closeBackdrop">
|
||||
<div class="modal fade show" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable" @click.stop="">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable" @click.stop="">
|
||||
<div class="modal-content" ref="body">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ title }}</h5>
|
||||
|
@ -63,16 +63,14 @@ const title = computed(() => {
|
||||
return "" // otherwise interfaces.GetSelected will die...
|
||||
}
|
||||
if (selectedInterface.value.Mode === "server") {
|
||||
return t("interfaces.peer.view") + ": " + selectedPeer.value.DisplayName
|
||||
return t("modals.peer-view.headline-peer") + " " + selectedPeer.value.DisplayName
|
||||
} else {
|
||||
return t("interfaces.endpoint.view") + ": " + selectedPeer.value.DisplayName
|
||||
return t("modals.peer-view.headline-endpoint") + " " + selectedPeer.value.DisplayName
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.visible, async (newValue, oldValue) => {
|
||||
if (oldValue === false && newValue === true) { // if modal is shown
|
||||
console.log(selectedInterface.value)
|
||||
console.log(selectedPeer.value)
|
||||
await peers.LoadPeerConfig(selectedPeer.value.Identifier)
|
||||
configString.value = peers.configuration
|
||||
}
|
||||
@ -121,21 +119,20 @@ function email() {
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDetails" aria-expanded="true" aria-controls="collapseDetails">
|
||||
Peer Information
|
||||
{{ $t('modals.peer-view.section-info') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseDetails" class="accordion-collapse collapse show" aria-labelledby="headingDetails" data-bs-parent="#peerInformation" style="">
|
||||
<div class="accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h4>Details</h4>
|
||||
<ul>
|
||||
<li>Identifier: {{ selectedPeer.PublicKey }}</li>
|
||||
<li>IP Addresses: <span v-for="ip in selectedPeer.Addresses" :key="ip" class="badge rounded-pill bg-light">{{ ip }}</span></li>
|
||||
<li>Linked User: {{ selectedPeer.UserIdentifier }}</li>
|
||||
<li v-if="selectedPeer.Notes">Notes: {{ selectedPeer.Notes }}</li>
|
||||
<li v-if="selectedPeer.ExpiresAt">Expires At: {{ selectedPeer.ExpiresAt }}</li>
|
||||
<li v-if="selectedPeer.Disabled">Disabled Reason: {{ selectedPeer.DisabledReason }}</li>
|
||||
<li>{{ $t('modals.peer-view.identifier') }}: {{ selectedPeer.PublicKey }}</li>
|
||||
<li>{{ $t('modals.peer-view.ip') }}: <span v-for="ip in selectedPeer.Addresses" :key="ip" class="badge rounded-pill bg-light">{{ ip }}</span></li>
|
||||
<li>{{ $t('modals.peer-view.user') }}: {{ selectedPeer.UserIdentifier }}</li>
|
||||
<li v-if="selectedPeer.Notes">{{ $t('modals.peer-view.notes') }}: {{ selectedPeer.Notes }}</li>
|
||||
<li v-if="selectedPeer.ExpiresAt">{{ $t('modals.peer-view.expiry-status') }}: {{ selectedPeer.ExpiresAt }}</li>
|
||||
<li v-if="selectedPeer.Disabled">{{ $t('modals.peer-view.disabled-status') }}: {{ selectedPeer.DisabledReason }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
@ -148,21 +145,21 @@ function email() {
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingStatus">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStatus" aria-expanded="false" aria-controls="collapseStatus">
|
||||
Current Status
|
||||
{{ $t('modals.peer-view.section-status') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseStatus" class="accordion-collapse collapse" aria-labelledby="headingStatus" data-bs-parent="#peerInformation" style="">
|
||||
<div class="accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4>Traffic</h4>
|
||||
<p><i class="fas fa-long-arrow-alt-down"></i> {{ selectedStats.BytesReceived }} Bytes / <i class="fas fa-long-arrow-alt-up"></i> {{ selectedStats.BytesTransmitted }} Bytes</p>
|
||||
<h4>Connection Stats</h4>
|
||||
<h4>{{ $t('modals.peer-view.traffic') }}</h4>
|
||||
<p><i class="fas fa-long-arrow-alt-down" :title="$t('modals.peer-view.download')"></i> {{ selectedStats.BytesReceived }} Bytes / <i class="fas fa-long-arrow-alt-up" :title="$t('modals.peer-view.upload')"></i> {{ selectedStats.BytesTransmitted }} Bytes</p>
|
||||
<h4>{{ $t('modals.peer-view.connection-status') }}</h4>
|
||||
<ul>
|
||||
<li>Pingable: {{ selectedStats.IsPingable }}</li>
|
||||
<li>Last Handshake: {{ selectedStats.LastHandshake }}</li>
|
||||
<li>Connected Since: {{ selectedStats.LastSessionStart }}</li>
|
||||
<li>Endpoint: {{ selectedStats.EndpointAddress }}</li>
|
||||
<li>{{ $t('modals.peer-view.pingable') }}: {{ selectedStats.IsPingable }}</li>
|
||||
<li>{{ $t('modals.peer-view.handshake') }}: {{ selectedStats.LastHandshake }}</li>
|
||||
<li>{{ $t('modals.peer-view.connected-since') }}: {{ selectedStats.LastSessionStart }}</li>
|
||||
<li>{{ $t('modals.peer-view.endpoint') }}: {{ selectedStats.EndpointAddress }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -172,7 +169,7 @@ function email() {
|
||||
<div v-if="selectedInterface.Mode==='server'" class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingConfig">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseConfig" aria-expanded="false" aria-controls="collapseConfig">
|
||||
Peer Configuration
|
||||
{{ $t('modals.peer-view.section-config') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseConfig" class="accordion-collapse collapse" aria-labelledby="headingConfig" data-bs-parent="#peerInformation" style="">
|
||||
@ -185,10 +182,10 @@ function email() {
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex-fill text-start">
|
||||
<button @click.prevent="download" type="button" class="btn btn-primary me-1">Download</button>
|
||||
<button @click.prevent="email" type="button" class="btn btn-primary me-1">Email</button>
|
||||
<button @click.prevent="download" type="button" class="btn btn-primary me-1">{{ $t('modals.peer-view.button-download') }}</button>
|
||||
<button @click.prevent="email" type="button" class="btn btn-primary me-1">{{ $t('modals.peer-view.button-email') }}</button>
|
||||
</div>
|
||||
<button @click.prevent="close" type="button" class="btn btn-secondary">Close</button>
|
||||
<button @click.prevent="close" type="button" class="btn btn-secondary">{{ $t('general.close') }}</button>
|
||||
|
||||
|
||||
</template>
|
||||
|
@ -26,9 +26,9 @@ const title = computed(() => {
|
||||
return "" // otherwise interfaces.GetSelected will die...
|
||||
}
|
||||
if (selectedUser.value) {
|
||||
return t("users.edit") + ": " + selectedUser.value.Identifier
|
||||
return t("modals.user-edit.headline-edit") + " " + selectedUser.value.Identifier
|
||||
}
|
||||
return t("users.new")
|
||||
return t("modals.user-edit.headline-new")
|
||||
})
|
||||
|
||||
const formData = ref(freshUser())
|
||||
@ -97,78 +97,78 @@ async function del() {
|
||||
<Modal :title="title" :visible="visible" @close="close">
|
||||
<template #default>
|
||||
<fieldset v-if="formData.Source==='db'">
|
||||
<legend class="mt-4">General</legend>
|
||||
<legend class="mt-4">{{ $t('modals.user-edit.header-general') }}</legend>
|
||||
<div v-if="props.userId==='#NEW#'" class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.identifier') }}</label>
|
||||
<input v-model="formData.Identifier" class="form-control" placeholder="The user id" type="text">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.identifier.label') }}</label>
|
||||
<input v-model="formData.Identifier" class="form-control" :placeholder="$t('modals.user-edit.identifier.placeholder')" type="text">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.source') }}</label>
|
||||
<input v-model="formData.Source" class="form-control" disabled="disabled" placeholder="The user source" type="text">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.source.label') }}</label>
|
||||
<input v-model="formData.Source" class="form-control" disabled="disabled" :placeholder="$t('modals.user-edit.source.placeholder')" type="text">
|
||||
</div>
|
||||
<div v-if="formData.Source==='db'" class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.password') }}</label>
|
||||
<input v-model="formData.Password" aria-describedby="passwordHelp" class="form-control" placeholder="Password" type="text">
|
||||
<small v-if="props.userId!=='#NEW#'" id="passwordHelp" class="form-text text-muted">Leave this field blank to keep current password.</small>
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.password.label') }}</label>
|
||||
<input v-model="formData.Password" aria-describedby="passwordHelp" class="form-control" :placeholder="$t('modals.user-edit.password.placeholder')" type="text">
|
||||
<small v-if="props.userId!=='#NEW#'" id="passwordHelp" class="form-text text-muted">{{ $t('modals.user-edit.password.description') }}</small>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset v-if="formData.Source==='db'">
|
||||
<legend class="mt-4">User Information</legend>
|
||||
<legend class="mt-4">{{ $t('modals.user-edit.header-personal') }}</legend>
|
||||
<div class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.email') }}</label>
|
||||
<input v-model="formData.Email" class="form-control" placeholder="Email" type="email">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.email.label') }}</label>
|
||||
<input v-model="formData.Email" class="form-control" :placeholder="$t('modals.user-edit.email.placeholder')" type="email">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.firstname') }}</label>
|
||||
<input v-model="formData.Firstname" class="form-control" placeholder="Firstname" type="text">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.firstname.label') }}</label>
|
||||
<input v-model="formData.Firstname" class="form-control" :placeholder="$t('modals.user-edit.firstname.placeholder')" type="text">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.lastname') }}</label>
|
||||
<input v-model="formData.Lastname" class="form-control" placeholder="Lastname" type="text">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.lastname.label') }}</label>
|
||||
<input v-model="formData.Lastname" class="form-control" :placeholder="$t('modals.user-edit.lastname.placeholder')" type="text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.phone') }}</label>
|
||||
<input v-model="formData.Phone" class="form-control" placeholder="Phone" type="text">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.phone.label') }}</label>
|
||||
<input v-model="formData.Phone" class="form-control" :placeholder="$t('modals.user-edit.phone.placeholder')" type="text">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.department') }}</label>
|
||||
<input v-model="formData.Department" class="form-control" placeholder="Department" type="text">
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.department.label') }}</label>
|
||||
<input v-model="formData.Department" class="form-control" :placeholder="$t('modals.user-edit.department.placeholder')" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend class="mt-4">Notes</legend>
|
||||
<legend class="mt-4">{{ $t('modals.user-edit.header-notes') }}</legend>
|
||||
<div class="form-group">
|
||||
<label class="form-label mt-4">{{ $t('modals.useredit.notes') }}</label>
|
||||
<label class="form-label mt-4">{{ $t('modals.user-edit.notes.label') }}</label>
|
||||
<textarea v-model="formData.Notes" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend class="mt-4">State</legend>
|
||||
<legend class="mt-4">{{ $t('modals.user-edit.header-state') }}</legend>
|
||||
<div class="form-check form-switch">
|
||||
<input v-model="formData.Disabled" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label" >Disabled (no WireGuard connection and no login possible)</label>
|
||||
<label class="form-check-label" >{{ $t('modals.user-edit.disabled.label') }}</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input v-model="formData.Locked" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label" >Locked (no login possible, WireGuard connections still work)</label>
|
||||
<label class="form-check-label" >{{ $t('modals.user-edit.locked.label') }}</label>
|
||||
</div>
|
||||
<div class="form-check form-switch" v-if="formData.Source==='db'">
|
||||
<input v-model="formData.IsAdmin" checked="" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label">Is Admin</label>
|
||||
<label class="form-check-label">{{ $t('modals.user-edit.admin.label') }}</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex-fill text-start">
|
||||
<button v-if="props.userId!=='#NEW#'&&formData.Source==='db'" class="btn btn-danger me-1" type="button" @click.prevent="del">Delete</button>
|
||||
<button v-if="props.userId!=='#NEW#'&&formData.Source==='db'" class="btn btn-danger me-1" type="button" @click.prevent="del">{{ $t('general.delete') }}</button>
|
||||
</div>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">Save</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">Discard</button>
|
||||
<button class="btn btn-primary me-1" type="button" @click.prevent="save">{{ $t('general.save') }}</button>
|
||||
<button class="btn btn-secondary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
@ -3,7 +3,6 @@ import Modal from "./Modal.vue";
|
||||
import {userStore} from "../stores/users";
|
||||
import {computed, ref, watch} from "vue";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { notify } from "@kyvg/vue3-notification";
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -29,7 +28,7 @@ const title = computed(() => {
|
||||
if (!props.visible) {
|
||||
return "" // otherwise interfaces.GetSelected will die...
|
||||
}
|
||||
return t("users.view") + ": " + selectedUser.value.Identifier
|
||||
return t("modals.user-view.headline") + " " + selectedUser.value.Identifier
|
||||
})
|
||||
|
||||
const userPeers = computed(() => {
|
||||
@ -56,52 +55,52 @@ function close() {
|
||||
<template #default>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-bs-toggle="tab" href="#user">User</a>
|
||||
<a class="nav-link active" data-bs-toggle="tab" href="#user">{{ $t('modals.user-view.tab-user') }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#peers">Peers</a>
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#peers">{{ $t('modals.user-view.tab-peers') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="interfaceTabs" class="tab-content">
|
||||
<div id="user" class="tab-pane fade active show">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<h4>User Information:</h4>
|
||||
<h4>{{ $t('modals.user-view.headline-info') }}</h4>
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('users.label.email') }}:</td>
|
||||
<td>{{ $t('modals.user-view.email') }}:</td>
|
||||
<td>{{selectedUser.Email}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('users.label.firstname') }}:</td>
|
||||
<td>{{ $t('modals.user-view.firstname') }}:</td>
|
||||
<td>{{selectedUser.Firstname}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('users.label.lastname') }}:</td>
|
||||
<td>{{ $t('modals.user-view.lastname') }}:</td>
|
||||
<td>{{selectedUser.Lastname}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('users.label.phone') }}:</td>
|
||||
<td>{{ $t('modals.user-view.phone') }}:</td>
|
||||
<td>{{selectedUser.Phone}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('users.label.department') }}:</td>
|
||||
<td>{{ $t('modals.user-view.department') }}:</td>
|
||||
<td>{{selectedUser.Department}}</td>
|
||||
</tr>
|
||||
<tr v-if="selectedUser.Disabled">
|
||||
<td>{{ $t('users.label.disabled') }}:</td>
|
||||
<td>{{ $t('modals.user-view.disabled') }}:</td>
|
||||
<td>{{selectedUser.DisabledReason}}</td>
|
||||
</tr>
|
||||
<tr v-if="selectedUser.Locked">
|
||||
<td>{{ $t('users.label.locked') }}:</td>
|
||||
<td>{{ $t('modals.user-view.locked') }}:</td>
|
||||
<td>{{selectedUser.LockedReason}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
<li class="list-group-item" v-if="selectedUser.Notes">
|
||||
<h4>Notes:</h4>
|
||||
<h4>{{ $t('modals.user-view.headline-notes') }}</h4>
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr><td>{{selectedUser.Notes}}</td></tr>
|
||||
@ -112,15 +111,15 @@ function close() {
|
||||
</div>
|
||||
<div id="peers" class="tab-pane fade">
|
||||
<ul v-if="userPeers.length===0" class="list-group list-group-flush">
|
||||
<li class="list-group-item">{{ $t('users.nopeers.message') }}</li>
|
||||
<li class="list-group-item">{{ $t('modals.user-view.no-peers') }}</li>
|
||||
</ul>
|
||||
|
||||
<table v-if="userPeers.length!==0" id="peerTable" class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{ $t('user.peers.name') }}</th>
|
||||
<th scope="col">{{ $t('user.peers.interface') }}</th>
|
||||
<th scope="col">{{ $t('user.peers.ips') }}</th>
|
||||
<th scope="col">{{ $t('modals.user-view.peers.name') }}</th>
|
||||
<th scope="col">{{ $t('modals.user-view.peers.interface') }}</th>
|
||||
<th scope="col">{{ $t('modals.user-view.peers.ip') }}</th>
|
||||
<th scope="col"></th><!-- Actions -->
|
||||
</tr>
|
||||
</thead>
|
||||
@ -129,7 +128,7 @@ function close() {
|
||||
<td>{{peer.DisplayName}}</td>
|
||||
<td>{{peer.InterfaceIdentifier}}</td>
|
||||
<td>
|
||||
<span v-for="ip in peer.Addresses" :key="ip" class="badge rounded-pill bg-light">{{ ip }}</span>
|
||||
<span v-for="ip in peer.Addresses" :key="ip" class="badge pill bg-light">{{ ip }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -138,7 +137,7 @@ function close() {
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button class="btn btn-primary" type="button" @click.prevent="close">Close</button>
|
||||
<button class="btn btn-primary" type="button" @click.prevent="close">{{ $t('general.close') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
@ -39,7 +39,10 @@ export function freshInterface() {
|
||||
PeerDefPreUp: "",
|
||||
PeerDefPostUp: "",
|
||||
PeerDefPreDown: "",
|
||||
PeerDefPostDown: ""
|
||||
PeerDefPostDown: "",
|
||||
|
||||
TotalPeers: 0,
|
||||
EnabledPeers: 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,7 +144,9 @@ export function freshUser() {
|
||||
Disabled: false,
|
||||
DisabledReason: "",
|
||||
Locked: false,
|
||||
LockedReason: ""
|
||||
LockedReason: "",
|
||||
|
||||
PeerCount: 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// src/lang/index.js
|
||||
import de from './translations/de.json';
|
||||
import en from './translations/en.json';
|
||||
import es from './translations/es.json';
|
||||
import {createI18n} from "vue-i18n";
|
||||
|
||||
function getStoredLanguage() {
|
||||
@ -21,8 +20,7 @@ const i18n = createI18n({
|
||||
fallbackLocale: "en", // set fallback locale
|
||||
messages: {
|
||||
"de": de,
|
||||
"en": en,
|
||||
"es": es
|
||||
"en": en
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,137 +1,278 @@
|
||||
{
|
||||
"hello": "Hello World!",
|
||||
"general": {
|
||||
"pagination": {
|
||||
"size": "Number of Elements",
|
||||
"all": "All (slow)"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Search...",
|
||||
"button": "Search"
|
||||
},
|
||||
"select-all": "Select all",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"save": "Save",
|
||||
"delete": "Delete"
|
||||
},
|
||||
"login": {
|
||||
"headline": "Please sign in",
|
||||
"username": {
|
||||
"label": "Username",
|
||||
"placeholder": "Please enter your username"
|
||||
},
|
||||
"password": {
|
||||
"label": "Password",
|
||||
"placeholder": "Please enter your password"
|
||||
},
|
||||
"button": "Sign in"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Home",
|
||||
"interfaces": "Interfaces",
|
||||
"users": "Users",
|
||||
"firstname": "Firstname",
|
||||
"lastname": "Lastname",
|
||||
"login": "Login",
|
||||
"lang": "Toggle Language",
|
||||
"profile": "My Profile",
|
||||
"login": "Login",
|
||||
"logout": "Logout"
|
||||
},
|
||||
"home": {
|
||||
"h1": "WireGuard® VPN Portal",
|
||||
"info": "More Information",
|
||||
"headline": "WireGuard® VPN Portal",
|
||||
"info-headline": "More Information",
|
||||
"abstract": "WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.",
|
||||
"installation": {
|
||||
"instruct": "Installation instructions for client software can be found on the official WireGuard website.",
|
||||
"h1": "WireGuard Installation",
|
||||
"h2": "Installation",
|
||||
"box-header": "WireGuard Installation",
|
||||
"headline": "Installation",
|
||||
"content": "Installation instructions for client software can be found on the official WireGuard website.",
|
||||
"btn": "Open Instructions"
|
||||
},
|
||||
"about-wg": {
|
||||
"instruct": "WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.",
|
||||
"h1": "About WireGuard",
|
||||
"h2": "About",
|
||||
"btn": "More"
|
||||
"box-header": "About WireGuard",
|
||||
"headline": "About",
|
||||
"content": "WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.",
|
||||
"button": "More"
|
||||
},
|
||||
"about-portal": {
|
||||
"instruct": "WireGuard Portal is a simple, web based configuration portal for WireGuard.",
|
||||
"h1": "About WireGuard Portal",
|
||||
"h2": "WireGuard Portal",
|
||||
"btn": "More"
|
||||
"box-header": "About WireGuard Portal",
|
||||
"headline": "WireGuard Portal",
|
||||
"content": "WireGuard Portal is a simple, web based configuration portal for WireGuard.",
|
||||
"button": "More"
|
||||
},
|
||||
"profiles": {
|
||||
"h1": "VPN Profiles",
|
||||
"headline": "VPN Profiles",
|
||||
"abstract": "You can access and download your personal VPN configurations via your Userprofile.",
|
||||
"instruct": "To find all your configured profiles click on the button below.",
|
||||
"btn": "Open my profile"
|
||||
"content": "To find all your configured profiles click on the button below.",
|
||||
"button": "Open my profile"
|
||||
},
|
||||
"admin": {
|
||||
"h1": "Administration Area",
|
||||
"headline": "Administration Area",
|
||||
"abstract": "In the administration area you can manage WireGuard peers and the server interface as well as users that are allowed to log in to the WireGuard Portal.",
|
||||
"instruct": "To find all your configured profiles click on the button below.",
|
||||
"btn-1": "Open Server Administration",
|
||||
"btn-2": "Open User Administration"
|
||||
"content": "To find all your configured profiles click on the button below.",
|
||||
"button-admin": "Open Server Administration",
|
||||
"button-user": "Open User Administration"
|
||||
}
|
||||
},
|
||||
"interfaces": {
|
||||
"h1": "Interface Administration",
|
||||
"h2": "Current VPN Peers",
|
||||
"h2-client": "Current Endpoints",
|
||||
"tableHeadings": {
|
||||
"headline": "Interface Administration",
|
||||
"headline-peers": "Current VPN Peers",
|
||||
"headline-endpoints": "Current Endpoints",
|
||||
"no-interface": {
|
||||
"default-selection": "No Interface available",
|
||||
"headline": "No interfaces found...",
|
||||
"abstract": "Click the plus button above to create a new WireGuard interface."
|
||||
},
|
||||
"no-peer": {
|
||||
"headline": "No peers available",
|
||||
"abstract": "Currently, there are no peers available for the selected WireGuard interface."
|
||||
},
|
||||
"table-heading": {
|
||||
"name": "Name",
|
||||
"user": "User",
|
||||
"ip": "IP's",
|
||||
"endpoint": "Endpoint",
|
||||
"stats": "Status"
|
||||
"status": "Status"
|
||||
},
|
||||
"noInterface": {
|
||||
"h1": "No interfaces found...",
|
||||
"message": "Click the plus button above to create a new WireGuard interface."
|
||||
},
|
||||
"notAvailable": "No Interface available",
|
||||
"statusBox": {
|
||||
"h1": "Interface status for",
|
||||
"interface": {
|
||||
"headline": "Interface status for",
|
||||
"mode": "mode",
|
||||
"key": "Public Key",
|
||||
"endpoint": "Public Endpoint",
|
||||
"port": "Listening Port",
|
||||
"peers": "Enabled Peers",
|
||||
"totalPeers": "Total Peers",
|
||||
"total-peers": "Total Peers",
|
||||
"endpoints": "Enabled Endpoints",
|
||||
"total-endpoints": "Total Endpoints",
|
||||
"ip": "IP Address",
|
||||
"allowedIP": "Default allowed IPs",
|
||||
"dnsServers": "DNS Servers",
|
||||
"mtu": "Default MTU",
|
||||
"interval": "Default Keepalive Interval"
|
||||
"default-allowed-ip": "Default allowed IPs",
|
||||
"dns": "DNS Servers",
|
||||
"mtu": "MTU",
|
||||
"default-keep-alive": "Default Keepalive Interval",
|
||||
"button-show-config": "Show configuration",
|
||||
"button-download-config": "Download configuration",
|
||||
"button-store-config": "Store configuration for wg-quick",
|
||||
"button-edit": "Edit interface"
|
||||
},
|
||||
"noPeerSelect": {
|
||||
"h4": "No peers for the selected interface...",
|
||||
"message": "Click the plus button above to create a new WireGuard interface."
|
||||
},
|
||||
"peer": {
|
||||
"new": "Create new peer",
|
||||
"edit": "Edit peer"
|
||||
},
|
||||
"interface": {
|
||||
"new": "Create new interface",
|
||||
"edit": "Edit interface"
|
||||
},
|
||||
"endpoint": {
|
||||
"new": "Create new endpoint",
|
||||
"edit": "Edit endpoint"
|
||||
}
|
||||
"button-add-interface": "Add Interface",
|
||||
"button-add-peer": "Add Peer",
|
||||
"button-add-peers": "Add Multiple Peers",
|
||||
"button-show-peer": "Show Peer",
|
||||
"button-edit-peer": "Edit Peer",
|
||||
"peer-disabled": "Peer is disabled, reason:",
|
||||
"peer-expiring": "Peer is expiring at",
|
||||
"peer-connected": "Connected",
|
||||
"peer-not-connected": "Not Connected",
|
||||
"peer-handshake": "Last handshake:"
|
||||
},
|
||||
"login": {
|
||||
"please": "Please sign in",
|
||||
"username": "Username",
|
||||
"userMessage": "Please enter your username",
|
||||
"pass": "Password",
|
||||
"passMessage": "Please enter your password",
|
||||
"btn": "Sign in"
|
||||
},
|
||||
"user": {
|
||||
"h1": "User Administration",
|
||||
"id": "ID",
|
||||
"email": "eMail",
|
||||
"firstname": "Firstname",
|
||||
"lastname": "Lastname",
|
||||
"source": "Source",
|
||||
"peers": "Peers",
|
||||
"admin": "Admin",
|
||||
"addUser": "Add User",
|
||||
"addMulti": "Add Multiple Users"
|
||||
"users": {
|
||||
"headline": "User Administration",
|
||||
"table-heading": {
|
||||
"id": "ID",
|
||||
"email": "E-Mail",
|
||||
"firstname": "Firstname",
|
||||
"lastname": "Lastname",
|
||||
"source": "Source",
|
||||
"peers": "Peers",
|
||||
"admin": "Admin"
|
||||
},
|
||||
"no-user": {
|
||||
"headline": "No users available",
|
||||
"abstract": "Currently, there are no users registered with WireGuard Portal."
|
||||
},
|
||||
"button-add-user": "Add User",
|
||||
"button-show-user": "Show User",
|
||||
"button-edit-user": "Edit User",
|
||||
"user-disabled": "User is disabled, reason:",
|
||||
"user-locked": "Account is locked, reason:",
|
||||
"admin": "User has administrator privileges",
|
||||
"no-admin": "User has no administrator privileges"
|
||||
},
|
||||
"profile": {
|
||||
"h2-clients": "My VPN Peers",
|
||||
"tableHeadings": {
|
||||
"headline": "My VPN Peers",
|
||||
"table-heading": {
|
||||
"name": "Name",
|
||||
"ip": "IP's",
|
||||
"stats": "Status",
|
||||
"interface": "Server Interface"
|
||||
}
|
||||
},
|
||||
"no-peer": {
|
||||
"headline": "No peers available",
|
||||
"abstract": "Currently, there are no peers associated with your user profile."
|
||||
},
|
||||
"peer-connected": "Connected",
|
||||
"button-add-peer": "Add Peer",
|
||||
"button-show-peer": "Show Peer",
|
||||
"button-edit-peer": "Edit Peer"
|
||||
},
|
||||
"modals": {
|
||||
"peeredit": {
|
||||
"user-view": {
|
||||
"headline": "User Account:",
|
||||
"tab-user": "Information",
|
||||
"tab-peers": "Peers",
|
||||
"headline-info": "User Information:",
|
||||
"headline-notes": "Notes:",
|
||||
"email": "E-Mail",
|
||||
"firstname": "Firstname",
|
||||
"lastname": "Lastname",
|
||||
"phone": "Phone number",
|
||||
"department": "Department",
|
||||
"disabled": "Account Disabled",
|
||||
"locked": "Account Locked",
|
||||
"no-peers": "User has no associated peers.",
|
||||
"peers": {
|
||||
"name": "Name",
|
||||
"interface": "Interface",
|
||||
"ip": "IP's"
|
||||
}
|
||||
},
|
||||
"user-edit": {
|
||||
"headline-edit": "Edit user:",
|
||||
"headline-new": "New user",
|
||||
"header-general": "General",
|
||||
"header-personal": "User Information",
|
||||
"header-notes": "Notes",
|
||||
"header-state": "State",
|
||||
"identifier": {
|
||||
"label": "Identifier",
|
||||
"placeholder": "The unique user identifier"
|
||||
},
|
||||
"source": {
|
||||
"label": "Source",
|
||||
"placeholder": "The user source"
|
||||
},
|
||||
"password": {
|
||||
"label": "Password",
|
||||
"placeholder": "A super secret password",
|
||||
"description": "Leave this field blank to keep current password."
|
||||
},
|
||||
"email": {
|
||||
"label": "Email",
|
||||
"placeholder": "The email address"
|
||||
},
|
||||
"phone": {
|
||||
"label": "Phone",
|
||||
"placeholder": "The phone number"
|
||||
},
|
||||
"department": {
|
||||
"label": "Department",
|
||||
"placeholder": "The department"
|
||||
},
|
||||
"firstname": {
|
||||
"label": "Firstname",
|
||||
"placeholder": "Firstname"
|
||||
},
|
||||
"lastname": {
|
||||
"label": "Lastname",
|
||||
"placeholder": "Lastname"
|
||||
},
|
||||
"notes": {
|
||||
"label": "Notes",
|
||||
"placeholder": ""
|
||||
},
|
||||
"disabled": {
|
||||
"label": "Disabled (no WireGuard connection and no login possible)"
|
||||
},
|
||||
"locked": {
|
||||
"label": "Locked (no login possible, WireGuard connections still work)"
|
||||
},
|
||||
"admin": {
|
||||
"label": "Is Admin"
|
||||
}
|
||||
},
|
||||
"interface-view": {
|
||||
"headline": "Config for Interface:"
|
||||
},
|
||||
"interface-edit": {
|
||||
"privatekey": "Private Key"
|
||||
},
|
||||
"peer-view": {
|
||||
"headline-peer": "Peer:",
|
||||
"headline-endpoint": "Endpoint:",
|
||||
"section-info": "Peer Information",
|
||||
"section-status": "Current Status",
|
||||
"section-config": "Configuration",
|
||||
"identifier": "Identifier",
|
||||
"ip": "IP Addresses",
|
||||
"user": "Associated User",
|
||||
"notes": "Notes",
|
||||
"expiry-status": "Expires At",
|
||||
"disabled-status": "Disabled At",
|
||||
"traffic": "Traffic",
|
||||
"connection-status": "Connection Stats",
|
||||
"upload": "Uploaded Bytes (from Server to Peer)",
|
||||
"download": "Downloaded Bytes (from Peer to Server)",
|
||||
"pingable": "Is Pingable",
|
||||
"handshake": "Last Handshake",
|
||||
"connected-since": "Connected since",
|
||||
"endpoint": "Endpoint",
|
||||
"button-download": "Download configuration",
|
||||
"button-email": "Send configuration via E-Mail"
|
||||
},
|
||||
"peer-edit": {
|
||||
"privatekey": "Private Key"
|
||||
},
|
||||
"peer-multi-create": {
|
||||
"privatekey": "Private Key"
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"pagination": {
|
||||
"size": "Number of Elements",
|
||||
"all": "All (slow)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"hello": "Hola mundo!"
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1024px) {
|
||||
.about {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -7,65 +7,65 @@
|
||||
|
||||
<template>
|
||||
<div class="page-header">
|
||||
<h1>{{ $t('home.h1') }}</h1>
|
||||
<h1>{{ $t('home.headline') }}</h1>
|
||||
</div>
|
||||
|
||||
<p class="lead">{{ $t('home.abstract') }}</p>
|
||||
|
||||
|
||||
<div class="bg-light p-5" v-if="auth.IsAuthenticated">
|
||||
<h2 class="display-5">{{ $t('home.profiles.h1') }}</h2>
|
||||
<h2 class="display-5">{{ $t('home.profiles.headline') }}</h2>
|
||||
<p class="lead">{{ $t('home.profiles.abstract') }}</p>
|
||||
<hr class="my-4">
|
||||
<p>{{ $t('home.profiles.instruct') }}</p>
|
||||
<p>{{ $t('home.profiles.content') }}</p>
|
||||
<p class="lead">
|
||||
<RouterLink :to="{ name: 'profile' }" class="btn btn-primary btn-lg">{{ $t('home.profiles.btn') }}</RouterLink>
|
||||
<RouterLink :to="{ name: 'profile' }" class="btn btn-primary btn-lg">{{ $t('home.profiles.button') }}</RouterLink>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-light p-5 mt-4" v-if="auth.IsAuthenticated && auth.IsAdmin">
|
||||
<h2 class="display-5">{{ $t('home.admin.h1') }}</h2>
|
||||
<h2 class="display-5">{{ $t('home.admin.headline') }}</h2>
|
||||
<p class="lead">{{ $t('home.admin.abstract') }}</p>
|
||||
<hr class="my-4">
|
||||
<p>{{ $t('home.admin.instruct') }}</p>
|
||||
<p>{{ $t('home.admin.content') }}</p>
|
||||
<p class="lead">
|
||||
<RouterLink :to="{ name: 'interfaces' }" class="btn btn-primary btn-lg me-2">{{ $t('home.admin.btn-1') }}</RouterLink>
|
||||
<RouterLink :to="{ name: 'users' }" class="btn btn-primary btn-lg">{{ $t('home.admin.btn-2') }}</RouterLink>
|
||||
<RouterLink :to="{ name: 'interfaces' }" class="btn btn-primary btn-lg me-2">{{ $t('home.admin.button-admin') }}</RouterLink>
|
||||
<RouterLink :to="{ name: 'users' }" class="btn btn-primary btn-lg">{{ $t('home.admin.button-user') }}</RouterLink>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-5">{{ $t('home.info') }}</h3>
|
||||
<h3 class="mt-5">{{ $t('home.info-headline') }}</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="card border-secondary mb-4" style="min-height: 15rem;">
|
||||
<div class="card-header">{{ $t('home.installation.h1') }}</div>
|
||||
<div class="card-header">{{ $t('home.installation.box-header') }}</div>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h4 class="card-title">{{ $t('home.installation.h2') }}</h4>
|
||||
<p class="card-text">{{ $t('home.installation.instruct') }}</p>
|
||||
<h4 class="card-title">{{ $t('home.installation.headline') }}</h4>
|
||||
<p class="card-text">{{ $t('home.installation.content') }}</p>
|
||||
<a href="https://www.wireguard.com/install/" title="WireGuard Installation" target="_blank"
|
||||
rel="noopener noreferrer" class="mt-auto btn btn-primary btn-sm">{{ $t('home.installation.btn') }}</a>
|
||||
rel="noopener noreferrer" class="mt-auto btn btn-primary btn-sm">{{ $t('home.installation.button') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card border-secondary mb-4" style="min-height: 15rem;">
|
||||
<div class="card-header">{{ $t('home.about-wg.h1') }}</div>
|
||||
<div class="card-header">{{ $t('home.about-wg.box-header') }}</div>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h4 class="card-title">{{ $t('home.about-wg.h2') }}</h4>
|
||||
<p class="card-text">{{ $t('home.about-wg.instruct') }}</p>
|
||||
<h4 class="card-title">{{ $t('home.about-wg.headline') }}</h4>
|
||||
<p class="card-text">{{ $t('home.about-wg.content') }}</p>
|
||||
<a href="https://www.wireguard.com/" title="WireGuard" target="_blank" rel="noopener noreferrer"
|
||||
class="mt-auto btn btn-primary btn-sm">{{ $t('home.about-wg.btn') }}</a>
|
||||
class="mt-auto btn btn-primary btn-sm">{{ $t('home.about-wg.button') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card border-secondary mb-4" style="min-height: 15rem;">
|
||||
<div class="card-header">{{ $t('home.about-portal.h1') }}</div>
|
||||
<div class="card-header">{{ $t('home.about-portal.box-header') }}</div>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h4 class="card-title">{{ $t('home.about-portal.h2') }}</h4>
|
||||
<p class="card-text">{{ $t('home.about-portal.instruct') }}</p>
|
||||
<h4 class="card-title">{{ $t('home.about-portal.headline') }}</h4>
|
||||
<p class="card-text">{{ $t('home.about-portal.content') }}</p>
|
||||
<a href="https://github.com/h44z/wg-portal/" title="WireGuard Portal" target="_blank"
|
||||
rel="noopener noreferrer" class="mt-auto btn btn-primary btn-sm">{{ $t('home.about-portal.btn') }}</a>
|
||||
rel="noopener noreferrer" class="mt-auto btn btn-primary btn-sm">{{ $t('home.about-portal.button') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,7 +83,7 @@ onMounted(async () => {
|
||||
<!-- Headline and interface selector -->
|
||||
<div class="page-header row">
|
||||
<div class="col-12 col-lg-8">
|
||||
<h1>{{ $t('interfaces.h1') }}</h1>
|
||||
<h1>{{ $t('interfaces.headline') }}</h1>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 text-end">
|
||||
<div class="form-group">
|
||||
@ -91,11 +91,11 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="input-group mb-3">
|
||||
<button class="input-group-text btn btn-primary" title="Add new interface" @click.prevent="editInterfaceId='#NEW#'">
|
||||
<button class="input-group-text btn btn-primary" :title="$t('interfaces.button-add-interface')" @click.prevent="editInterfaceId='#NEW#'">
|
||||
<i class="fa-solid fa-plus-circle"></i>
|
||||
</button>
|
||||
<select v-model="interfaces.selected" :disabled="interfaces.Count===0" class="form-select" @change="peers.LoadPeers()">
|
||||
<option v-if="interfaces.Count===0" value="nothing">{{ $t('interfaces.notAvailable') }}</option>
|
||||
<option v-if="interfaces.Count===0" value="nothing">{{ $t('interfaces.no-interface.default-selection') }}</option>
|
||||
<option v-for="iface in interfaces.All" :key="iface.Identifier" :value="iface.Identifier">{{ calculateInterfaceName(iface.Identifier,iface.DisplayName) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -107,8 +107,8 @@ onMounted(async () => {
|
||||
<div v-if="interfaces.Count===0" class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="mt-5">
|
||||
<h4>{{ $t('interfaces.noInterface.h1') }}</h4>
|
||||
<p>{{ $t('interfaces.noInterface.message') }}</p>
|
||||
<h4>{{ $t('interfaces.no-interface.headline') }}</h4>
|
||||
<p>{{ $t('interfaces.no-interface.abstract') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -120,14 +120,14 @@ onMounted(async () => {
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-8">
|
||||
{{ $t('interfaces.statusBox.h1') }} <strong>{{interfaces.GetSelected.Identifier}}</strong> ({{interfaces.GetSelected.Mode}} {{ $t('interfaces.statusBox.mode') }})
|
||||
{{ $t('interfaces.interface.headline') }} <strong>{{interfaces.GetSelected.Identifier}}</strong> ({{interfaces.GetSelected.Mode}} {{ $t('interfaces.interface.mode') }})
|
||||
<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">
|
||||
<a class="btn-link" href="#" title="Show interface configuration" @click.prevent="viewedInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-eye"></i></a>
|
||||
<a class="ms-5 btn-link" href="#" title="Download interface configuration" @click.prevent="download"><i class="fas fa-download"></i></a>
|
||||
<a v-if="settings.Setting('PersistentConfigSupported')" class="ms-5 btn-link" href="#" title="Write interface configuration file" @click.prevent="saveConfig"><i class="fas fa-save"></i></a>
|
||||
<a class="ms-5 btn-link" href="#" title="Edit interface settings" @click.prevent="editInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-cog"></i></a>
|
||||
<a class="btn-link" href="#" :title="$t('interfaces.interface.button-show-config')" @click.prevent="viewedInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-eye"></i></a>
|
||||
<a class="ms-5 btn-link" href="#" :title="$t('interfaces.interface.button-download-config')" @click.prevent="download"><i class="fas fa-download"></i></a>
|
||||
<a v-if="settings.Setting('PersistentConfigSupported')" class="ms-5 btn-link" href="#" :title="$t('interfaces.interface.button-store-config')" @click.prevent="saveConfig"><i class="fas fa-save"></i></a>
|
||||
<a class="ms-5 btn-link" href="#" :title="$t('interfaces.interface.button-edit')" @click.prevent="editInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-cog"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -137,23 +137,23 @@ onMounted(async () => {
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.key') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.key') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PublicKey}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.endpoint') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.endpoint') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PeerDefEndpoint}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.port') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.port') }}:</td>
|
||||
<td>{{interfaces.GetSelected.ListenPort}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.peers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.peers') }}:</td>
|
||||
<td>{{interfaces.GetSelected.EnabledPeers}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.totalPeers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.total-peers') }}:</td>
|
||||
<td>{{interfaces.GetSelected.TotalPeers}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -163,23 +163,23 @@ onMounted(async () => {
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.ip') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.ip') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Addresses" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.dnsServers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.dns') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Dns" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.mtu') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.mtu') }}:</td>
|
||||
<td>{{interfaces.GetSelected.Mtu}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.interval') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.default-keep-alive') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PeerDefPersistentKeepalive}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.allowedIP') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.default-allowed-ip') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.PeerDefAllowedIPs" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -191,15 +191,15 @@ onMounted(async () => {
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.key') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.key') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PublicKey}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.endpoint') }}:</td>
|
||||
<td>{{interfaces.GetSelected.InterfacePeers}}</td>
|
||||
<td>{{ $t('interfaces.interface.endpoints') }}:</td>
|
||||
<td>{{interfaces.GetSelected.EnabledPeers}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.totalPeers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.total-endpoints') }}:</td>
|
||||
<td>{{interfaces.GetSelected.TotalPeers}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -209,15 +209,15 @@ onMounted(async () => {
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.ip') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.ip') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Addresses" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.dnsServers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.dns') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Dns" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.mtu') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.mtu') }}:</td>
|
||||
<td>{{interfaces.GetSelected.Mtu}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -229,23 +229,23 @@ onMounted(async () => {
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.key') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.key') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PublicKey}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.endpoint') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.endpoint') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PeerDefEndpoint}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.port') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.port') }}:</td>
|
||||
<td>{{interfaces.GetSelected.ListenPort}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.peers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.peers') }}:</td>
|
||||
<td>{{interfaces.GetSelected.EnabledPeers}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.totalPeers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.total-peers') }}:</td>
|
||||
<td>{{interfaces.GetSelected.TotalPeers}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -255,23 +255,23 @@ onMounted(async () => {
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.ip') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.ip') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Addresses" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.allowedIP') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.default-allowed-ip') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.PeerDefAllowedIPs" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.dnsServers') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.dns') }}:</td>
|
||||
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.PeerDefDns" :key="addr">{{addr}}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.mtu') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.mtu') }}:</td>
|
||||
<td>{{interfaces.GetSelected.Mtu}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t('interfaces.statusBox.interval') }}:</td>
|
||||
<td>{{ $t('interfaces.interface.default-keep-alive') }}:</td>
|
||||
<td>{{interfaces.GetSelected.PeerDefPersistentKeepalive}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -286,40 +286,39 @@ onMounted(async () => {
|
||||
<!-- Peer list -->
|
||||
<div v-if="interfaces.Count!==0" class="mt-4 row">
|
||||
<div class="col-12 col-lg-5">
|
||||
<h2 v-if="interfaces.GetSelected.Mode==='server'" class="mt-2">{{ $t('interfaces.h2') }}</h2>
|
||||
<h2 v-else class="mt-2">{{ $t('interfaces.h2-client') }}</h2>
|
||||
<h2 v-if="interfaces.GetSelected.Mode==='server'" class="mt-2">{{ $t('interfaces.headline-peers') }}</h2>
|
||||
<h2 v-else class="mt-2">{{ $t('interfaces.headline-endpoints') }}</h2>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 text-lg-end">
|
||||
<div class="form-group d-inline">
|
||||
<div class="input-group mb-3">
|
||||
<input v-model="peers.filter" class="form-control" placeholder="Search..." type="text" @keyup="peers.afterPageSizeChange">
|
||||
<button class="input-group-text btn btn-primary" title="Search"><i class="fa-solid fa-search"></i></button>
|
||||
<input v-model="peers.filter" class="form-control" :placeholder="$t('general.search.placeholder')" type="text" @keyup="peers.afterPageSizeChange">
|
||||
<button class="input-group-text btn btn-primary" :title="$t('general.search.button')"><i class="fa-solid fa-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-3 text-lg-end">
|
||||
<!--a v-if="interfaces.GetSelected.Mode==='server' && peers.Count!==0" class="btn btn-primary" href="#" title="Send mail to all peers"><i class="fa fa-paper-plane"></i></a-->
|
||||
<a class="btn btn-primary ms-2" href="#" title="Add multiple peers" @click.prevent="multiCreatePeerId='#NEW#'"><i class="fa fa-plus me-1"></i><i class="fa fa-users"></i></a>
|
||||
<a class="btn btn-primary ms-2" href="#" title="Add a peer" @click.prevent="editPeerId='#NEW#'"><i class="fa fa-plus me-1"></i><i class="fa fa-user"></i></a>
|
||||
<a class="btn btn-primary ms-2" href="#" :title="$t('interfaces.button-add-peers')" @click.prevent="multiCreatePeerId='#NEW#'"><i class="fa fa-plus me-1"></i><i class="fa fa-users"></i></a>
|
||||
<a class="btn btn-primary ms-2" href="#" :title="$t('interfaces.button-add-peer')" @click.prevent="editPeerId='#NEW#'"><i class="fa fa-plus me-1"></i><i class="fa fa-user"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="interfaces.Count!==0" class="mt-2 table-responsive">
|
||||
<div v-if="peers.Count===0">
|
||||
<h4>{{ $t('interfaces.noPeerSelect.h4') }}</h4>
|
||||
<p>{{ $t('interfaces.noPeerSelect.message') }}</p>
|
||||
<h4>{{ $t('interfaces.no-peer.headline') }}</h4>
|
||||
<p>{{ $t('interfaces.no-peer.abstract') }}</p>
|
||||
</div>
|
||||
<table v-if="peers.Count!==0" id="peerTable" class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<input id="flexCheckDefault" class="form-check-input" title="Select all" type="checkbox" value="">
|
||||
<input id="flexCheckDefault" class="form-check-input" :title="$t('general.select-all')" type="checkbox" value="">
|
||||
</th><!-- select -->
|
||||
<th scope="col"></th><!-- status -->
|
||||
<th scope="col">{{ $t('interfaces.tableHeadings.name') }}</th>
|
||||
<th scope="col">{{ $t('interfaces.tableHeadings.user') }}</th>
|
||||
<th scope="col">{{ $t('interfaces.tableHeadings.ip') }}</th>
|
||||
<th v-if="interfaces.GetSelected.Mode==='client'" scope="col">{{ $t('interfaces.tableHeadings.endpoint') }}</th>
|
||||
<th v-if="peers.hasStatistics" scope="col">{{ $t('interfaces.tableHeadings.stats') }}</th>
|
||||
<th scope="col">{{ $t('interfaces.table-heading.name') }}</th>
|
||||
<th scope="col">{{ $t('interfaces.table-heading.user') }}</th>
|
||||
<th scope="col">{{ $t('interfaces.table-heading.ip') }}</th>
|
||||
<th v-if="interfaces.GetSelected.Mode==='client'" scope="col">{{ $t('interfaces.table-heading.endpoint') }}</th>
|
||||
<th v-if="peers.hasStatistics" scope="col">{{ $t('interfaces.table-heading.status') }}</th>
|
||||
<th scope="col"></th><!-- Actions -->
|
||||
</tr>
|
||||
</thead>
|
||||
@ -329,8 +328,8 @@ onMounted(async () => {
|
||||
<input id="flexCheckDefault" class="form-check-input" type="checkbox" value="">
|
||||
</th>
|
||||
<td class="text-center">
|
||||
<span v-if="peer.Disabled" class="text-danger"><i class="fa fa-circle-xmark" :title="peer.DisabledReason"></i></span>
|
||||
<span v-if="!peer.Disabled && peer.ExpiresAt" class="text-warning"><i class="fas fa-hourglass-end expiring-peer" :title="peer.ExpiresAt"></i></span>
|
||||
<span v-if="peer.Disabled" class="text-danger" :title="$t('interfaces.peer-disabled') + ' ' + peer.DisabledReason"><i class="fa fa-circle-xmark"></i></span>
|
||||
<span v-if="!peer.Disabled && peer.ExpiresAt" class="text-warning" :title="$t('interfaces.peer-expiring') + ' ' + peer.ExpiresAt"><i class="fas fa-hourglass-end expiring-peer"></i></span>
|
||||
</td>
|
||||
<td><span v-if="peer.DisplayName" :title="peer.Identifier">{{peer.DisplayName}}</span><span v-else :title="peer.Identifier">{{ $filters.truncate(peer.Identifier, 10)}}</span></td>
|
||||
<td>{{peer.UserIdentifier}}</td>
|
||||
@ -340,15 +339,15 @@ onMounted(async () => {
|
||||
<td v-if="interfaces.GetSelected.Mode==='client'">{{peer.Endpoint.Value}}</td>
|
||||
<td v-if="peers.hasStatistics">
|
||||
<div v-if="peers.Statistics(peer.Identifier).IsConnected">
|
||||
<span class="badge rounded-pill bg-success"><i class="fa-solid fa-link"></i></span> <span :title="peers.Statistics(peer.Identifier).LastHandshake">Connected</span>
|
||||
<span class="badge rounded-pill bg-success" :title="$t('interfaces.peer-connected')"><i class="fa-solid fa-link"></i></span> <span :title="$t('interfaces.peer-handshake') + ' ' + peers.Statistics(peer.Identifier).LastHandshake">{{ $t('interfaces.peer-connected') }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="badge rounded-pill bg-light"><i class="fa-solid fa-link-slash"></i></span>
|
||||
<span class="badge rounded-pill bg-light" :title="$t('interfaces.peer-not-connected')"><i class="fa-solid fa-link-slash"></i></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="#" title="Show peer" @click.prevent="viewedPeerId=peer.Identifier"><i class="fas fa-eye me-2"></i></a>
|
||||
<a href="#" title="Edit peer" @click.prevent="editPeerId=peer.Identifier"><i class="fas fa-cog"></i></a>
|
||||
<a href="#" :title="$t('interfaces.button-show-peer')" @click.prevent="viewedPeerId=peer.Identifier"><i class="fas fa-eye me-2"></i></a>
|
||||
<a href="#" :title="$t('interfaces.button-edit-peer')" @click.prevent="editPeerId=peer.Identifier"><i class="fas fa-cog"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -61,26 +61,26 @@ const externalLogin = function (provider) {
|
||||
<div class="col-lg-3"></div><!-- left spacer -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card mt-5">
|
||||
<div class="card-header">Please sign in <div class="float-end">
|
||||
<RouterLink :to="{ name: 'home' }" class="nav-link" title="Home"><i class="fas fa-times-circle"></i></RouterLink>
|
||||
<div class="card-header">{{ $t('login.headline') }}<div class="float-end">
|
||||
<RouterLink :to="{ name: 'home' }" class="nav-link" :title="$t('menu.home')"><i class="fas fa-times-circle"></i></RouterLink>
|
||||
</div></div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="inputUsername">{{ $t('login.username') }}</label>
|
||||
<label class="form-label" for="inputUsername">{{ $t('login.username.label') }}</label>
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text"><span class="far fa-user p-2"></span></span>
|
||||
<input id="inputUsername" v-model="username" :class="{'is-invalid':usernameInvalid, 'is-valid':!usernameInvalid}" :placeholder="$t('login.userMessage')" aria-describedby="usernameHelp"
|
||||
<input id="inputUsername" v-model="username" :class="{'is-invalid':usernameInvalid, 'is-valid':!usernameInvalid}" :placeholder="$t('login.username.placeholder')" aria-describedby="usernameHelp"
|
||||
class="form-control"
|
||||
name="username" type="text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="inputPassword">{{ $t('login.pass') }}</label>
|
||||
<label class="form-label" for="inputPassword">{{ $t('login.password.label') }}</label>
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text"><span class="fas fa-lock p-2"></span></span>
|
||||
<input id="inputPassword" v-model="password" :class="{'is-invalid':passwordInvalid, 'is-valid':!passwordInvalid}" :placeholder="$t('login.passMessage')" class="form-control"
|
||||
<input id="inputPassword" v-model="password" :class="{'is-invalid':passwordInvalid, 'is-valid':!passwordInvalid}" :placeholder="$t('login.password.placeholder')" class="form-control"
|
||||
name="password" type="password">
|
||||
</div>
|
||||
</div>
|
||||
@ -88,7 +88,7 @@ const externalLogin = function (provider) {
|
||||
<div class="row mt-5 d-flex">
|
||||
<div :class="{'col-lg-4':auth.LoginProviders.length < 3, 'col-lg-12':auth.LoginProviders.length >= 3}" class="d-flex mb-2">
|
||||
<button :disabled="disableLoginBtn" class="btn btn-primary flex-fill" type="submit" @click.prevent="login">
|
||||
{{ $t('login.btn') }} <div v-if="loggingIn" class="d-inline"><i class="ms-2 fa-solid fa-circle-notch fa-spin"></i></div>
|
||||
{{ $t('login.button') }} <div v-if="loggingIn" class="d-inline"><i class="ms-2 fa-solid fa-circle-notch fa-spin"></i></div>
|
||||
</button>
|
||||
</div>
|
||||
<div :class="{'col-lg-8':auth.LoginProviders.length < 3, 'col-lg-12':auth.LoginProviders.length >= 3}" class="d-flex mb-2">
|
||||
|
@ -26,36 +26,36 @@ onMounted(async () => {
|
||||
<!-- Peer list -->
|
||||
<div class="mt-4 row">
|
||||
<div class="col-12 col-lg-5">
|
||||
<h2 class="mt-2">{{ $t('profile.h2-clients') }}</h2>
|
||||
<h2 class="mt-2">{{ $t('profile.headline') }}</h2>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 text-lg-end">
|
||||
<div class="form-group d-inline">
|
||||
<div class="input-group mb-3">
|
||||
<input v-model="profile.filter" class="form-control" placeholder="Search..." type="text" @keyup="profile.afterPageSizeChange">
|
||||
<button class="input-group-text btn btn-primary" title="Search"><i class="fa-solid fa-search"></i></button>
|
||||
<input v-model="profile.filter" class="form-control" :placeholder="$t('general.search.placeholder')" type="text" @keyup="profile.afterPageSizeChange">
|
||||
<button class="input-group-text btn btn-primary" :title="$t('general.search.button')"><i class="fa-solid fa-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-3 text-lg-end">
|
||||
<a v-if="settings.Setting('SelfProvisioning')" class="btn btn-primary ms-2" href="#" title="Add a peer" @click.prevent="editPeerId='#NEW#'"><i class="fa fa-plus me-1"></i><i class="fa fa-user"></i></a>
|
||||
<a v-if="settings.Setting('SelfProvisioning')" class="btn btn-primary ms-2" href="#" :title="$t('general.search.button-add-peer')" @click.prevent="editPeerId='#NEW#'"><i class="fa fa-plus me-1"></i><i class="fa fa-user"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 table-responsive">
|
||||
<div v-if="profile.CountPeers===0">
|
||||
<h4>{{ $t('profile.noPeerSelect.h4') }}</h4>
|
||||
<p>{{ $t('profile.noPeerSelect.message') }}</p>
|
||||
<h4>{{ $t('profile.no-peer.headline') }}</h4>
|
||||
<p>{{ $t('profile.no-peer.abstract') }}</p>
|
||||
</div>
|
||||
<table v-if="profile.CountPeers!==0" id="peerTable" class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<input id="flexCheckDefault" class="form-check-input" title="Select all" type="checkbox" value="">
|
||||
<input id="flexCheckDefault" class="form-check-input" :title="$t('general.select-all')" type="checkbox" value="">
|
||||
</th><!-- select -->
|
||||
<th scope="col"></th><!-- status -->
|
||||
<th scope="col">{{ $t('profile.tableHeadings.name') }}</th>
|
||||
<th scope="col">{{ $t('profile.tableHeadings.ip') }}</th>
|
||||
<th v-if="profile.hasStatistics" scope="col">{{ $t('profile.tableHeadings.stats') }}</th>
|
||||
<th scope="col">{{ $t('profile.tableHeadings.interface') }}</th>
|
||||
<th scope="col">{{ $t('profile.table-heading.name') }}</th>
|
||||
<th scope="col">{{ $t('profile.table-heading.ip') }}</th>
|
||||
<th v-if="profile.hasStatistics" scope="col">{{ $t('profile.table-heading.stats') }}</th>
|
||||
<th scope="col">{{ $t('profile.table-heading.interface') }}</th>
|
||||
<th scope="col"></th><!-- Actions -->
|
||||
</tr>
|
||||
</thead>
|
||||
@ -74,7 +74,7 @@ onMounted(async () => {
|
||||
</td>
|
||||
<td v-if="profile.hasStatistics">
|
||||
<div v-if="profile.Statistics(peer.Identifier).IsConnected">
|
||||
<span class="badge rounded-pill bg-success"><i class="fa-solid fa-link"></i></span> <span :title="peers.Statistics(peer.Identifier).LastHandshake">Connected</span>
|
||||
<span class="badge rounded-pill bg-success"><i class="fa-solid fa-link"></i></span> <span :title="peers.Statistics(peer.Identifier).LastHandshake">{{ $t('profile.peer-connected') }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="badge rounded-pill bg-light"><i class="fa-solid fa-link-slash"></i></span>
|
||||
@ -82,8 +82,8 @@ onMounted(async () => {
|
||||
</td>
|
||||
<td>{{peer.InterfaceIdentifier}}</td>
|
||||
<td class="text-center">
|
||||
<a href="#" title="Show peer" @click.prevent="viewedPeerId=peer.Identifier"><i class="fas fa-eye me-2"></i></a>
|
||||
<a href="#" title="Edit peer" @click.prevent="editPeerId=peer.Identifier"><i class="fas fa-cog"></i></a>
|
||||
<a href="#" :title="$t('profile.button-show-peer')" @click.prevent="viewedPeerId=peer.Identifier"><i class="fas fa-eye me-2"></i></a>
|
||||
<a href="#" :title="$t('profile.button-edit-peer')" @click.prevent="editPeerId=peer.Identifier"><i class="fas fa-cog"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -24,40 +24,41 @@ onMounted(() => {
|
||||
<!-- User list -->
|
||||
<div class="mt-4 row">
|
||||
<div class="col-12 col-lg-5">
|
||||
<h1>{{ $t('user.h1') }}</h1>
|
||||
<h1>{{ $t('users.headline') }}</h1>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 text-lg-end">
|
||||
<div class="form-group d-inline">
|
||||
<div class="input-group mb-3">
|
||||
<input v-model="users.filter" class="form-control" placeholder="Search..." type="text" @keyup="users.afterPageSizeChange">
|
||||
<button class="input-group-text btn btn-primary" title="Search"><i class="fa-solid fa-search"></i></button>
|
||||
<input v-model="users.filter" class="form-control" :placeholder="$t('general.search.placeholder')" type="text" @keyup="users.afterPageSizeChange">
|
||||
<button class="input-group-text btn btn-primary" :title="$t('general.search.button')"><i class="fa-solid fa-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-3 text-lg-end">
|
||||
<a class="btn btn-primary ms-2" href="#" title="Add a user" @click.prevent="editUserId='#NEW#'"><i class="fa fa-plus me-1"></i><i
|
||||
class="fa fa-user"></i></a>
|
||||
<a class="btn btn-primary ms-2" href="#" :title="$t('users.button-add-user')" @click.prevent="editUserId='#NEW#'">
|
||||
<i class="fa fa-plus me-1"></i><i class="fa fa-user"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 table-responsive">
|
||||
<div v-if="users.Count===0">
|
||||
<h4>{{ $t('users.noUsers.h4') }}</h4>
|
||||
<p>{{ $t('users.noUsers.message') }}</p>
|
||||
<h4>{{ $t('users.no-user.headline') }}</h4>
|
||||
<p>{{ $t('users.no-user.abstract') }}</p>
|
||||
</div>
|
||||
<table v-if="users.Count!==0" id="userTable" class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<input id="flexCheckDefault" class="form-check-input" title="Select all" type="checkbox" value="">
|
||||
<input id="flexCheckDefault" class="form-check-input" :title="$t('general.select-all')" type="checkbox" value="">
|
||||
</th><!-- select -->
|
||||
<th scope="col"></th><!-- status -->
|
||||
<th scope="col">{{ $t('user.id') }}</th>
|
||||
<th scope="col">{{ $t('user.email') }}</th>
|
||||
<th scope="col">{{ $t('user.firstname') }}</th>
|
||||
<th scope="col">{{ $t('user.lastname') }}</th>
|
||||
<th class="text-center" scope="col">{{ $t('user.source') }}</th>
|
||||
<th class="text-center" scope="col">{{ $t('user.peers') }}</th>
|
||||
<th class="text-center" scope="col">{{ $t('user.admin') }}</th>
|
||||
<th scope="col">{{ $t('users.table-heading.id') }}</th>
|
||||
<th scope="col">{{ $t('users.table-heading.email') }}</th>
|
||||
<th scope="col">{{ $t('users.table-heading.firstname') }}</th>
|
||||
<th scope="col">{{ $t('users.table-heading.lastname') }}</th>
|
||||
<th class="text-center" scope="col">{{ $t('users.table-heading.source') }}</th>
|
||||
<th class="text-center" scope="col">{{ $t('users.table-heading.peers') }}</th>
|
||||
<th class="text-center" scope="col">{{ $t('users.table-heading.admin') }}</th>
|
||||
<th scope="col"></th><!-- Actions -->
|
||||
</tr>
|
||||
</thead>
|
||||
@ -67,8 +68,8 @@ onMounted(() => {
|
||||
<input id="flexCheckDefault" class="form-check-input" type="checkbox" value="">
|
||||
</th>
|
||||
<td class="text-center">
|
||||
<span v-if="user.Disabled" class="text-danger"><i class="fa fa-circle-xmark" :title="user.DisabledReason"></i></span>
|
||||
<span v-if="user.Locked" class="text-danger"><i class="fas fa-lock" :title="user.LockedReason"></i></span>
|
||||
<span v-if="user.Disabled" class="text-danger" :title="$t('users.user-disabled') + ' ' + user.DisabledReason"><i class="fa fa-circle-xmark"></i></span>
|
||||
<span v-if="user.Locked" class="text-danger" :title="$t('users.user-locked') + ' ' + user.LockedReason"><i class="fas fa-lock"></i></span>
|
||||
</td>
|
||||
<td>{{user.Identifier}}</td>
|
||||
<td>{{user.Email}}</td>
|
||||
@ -77,12 +78,12 @@ onMounted(() => {
|
||||
<td class="text-center"><span class="badge rounded-pill bg-light">{{user.Source}}</span></td>
|
||||
<td class="text-center">{{user.PeerCount}}</td>
|
||||
<td class="text-center">
|
||||
<span v-if="user.IsAdmin" class="text-danger"><i class="fa fa-check-circle"></i></span>
|
||||
<span v-else><i class="fa fa-circle-xmark"></i></span>
|
||||
<span v-if="user.IsAdmin" class="text-danger" :title="$t('users.admin')"><i class="fa fa-check-circle"></i></span>
|
||||
<span v-else><i class="fa fa-circle-xmark" :title="$t('users.no-admin')"></i></span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="#" title="Show user" @click.prevent="viewedUserId=user.Identifier"><i class="fas fa-eye me-2"></i></a>
|
||||
<a href="#" title="Edit user" @click.prevent="editUserId=user.Identifier"><i class="fas fa-cog me-2"></i></a>
|
||||
<a href="#" :title="$t('users.button-show-user')" @click.prevent="viewedUserId=user.Identifier"><i class="fas fa-eye me-2"></i></a>
|
||||
<a href="#" :title="$t('users.button-edit-user')" @click.prevent="editUserId=user.Identifier"><i class="fas fa-cog me-2"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
Loading…
x
Reference in New Issue
Block a user