wg-portal/frontend/src/views/InterfaceView.vue

353 lines
15 KiB
Vue
Raw Normal View History

2023-02-12 23:13:04 +01:00
<script setup>
import PeerViewModal from "../components/PeerViewModal.vue";
import PeerEditModal from "../components/PeerEditModal.vue";
import InterfaceEditModal from "../components/InterfaceEditModal.vue";
2023-06-14 23:03:24 +02:00
import InterfaceViewModal from "../components/InterfaceViewModal.vue";
2023-02-12 23:13:04 +01:00
import {onMounted, ref} from "vue";
import {peerStore} from "../stores/peers";
import {interfaceStore} from "../stores/interfaces";
const interfaces = interfaceStore()
const peers = peerStore()
const viewedPeerId = ref("")
const editPeerId = ref("")
const editInterfaceId = ref("")
2023-06-14 23:03:24 +02:00
const viewedInterfaceId = ref("")
function calculateInterfaceName(id, name) {
let result = id
if (name) {
result += ' (' + name + ')'
}
return result
}
2023-02-12 23:13:04 +01:00
2023-07-04 22:55:11 +02:00
async function download() {
await interfaces.LoadInterfaceConfig(interfaces.GetSelected.Identifier)
// credit: https://www.bitdegree.org/learn/javascript-download
let filename = interfaces.GetSelected.Identifier + ".conf"
let text = interfaces.configuration
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
2023-02-12 23:13:04 +01:00
onMounted(async () => {
await interfaces.LoadInterfaces()
await peers.LoadPeers()
})
</script>
<template>
<PeerViewModal :peerId="viewedPeerId" :visible="viewedPeerId!==''" @close="viewedPeerId=''"></PeerViewModal>
<PeerEditModal :peerId="editPeerId" :visible="editPeerId!==''" @close="editPeerId=''"></PeerEditModal>
<InterfaceEditModal :interfaceId="editInterfaceId" :visible="editInterfaceId!==''" @close="editInterfaceId=''"></InterfaceEditModal>
2023-06-14 23:03:24 +02:00
<InterfaceViewModal :interfaceId="viewedInterfaceId" :visible="viewedInterfaceId!==''" @close="viewedInterfaceId=''"></InterfaceViewModal>
2023-02-12 23:13:04 +01:00
<!-- Headline and interface selector -->
<div class="page-header row">
<div class="col-12 col-lg-8">
<h1>{{ $t('interfaces.h1') }}</h1>
</div>
<div class="col-12 col-lg-4 text-end">
<div class="form-group">
</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#'">
<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>
2023-06-14 23:03:24 +02:00
<option v-for="iface in interfaces.All" :key="iface.Identifier" :value="iface.Identifier">{{ calculateInterfaceName(iface.Identifier,iface.DisplayName) }}</option>
2023-02-12 23:13:04 +01:00
</select>
</div>
</div>
</div>
</div>
<!-- No interfaces information -->
<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>
</div>
</div>
</div>
<!-- Interface overview -->
<div v-if="interfaces.Count!==0" class="row">
<div class="col-lg-12">
<div class="card border-secondary mb-4" style="min-height: 15rem;">
<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') }})
</div>
<div class="col-12 col-lg-4 text-lg-end">
2023-06-14 23:03:24 +02:00
<a class="btn-link" href="#" title="Show interface configuration" @click.prevent="viewedInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-eye"></i></a>
2023-07-04 22:55:11 +02:00
<a class="ms-5 btn-link" href="#" title="Download interface configuration" @click.prevent="download"><i class="fas fa-download"></i></a>
2023-02-12 23:13:04 +01:00
<a class="ms-5 btn-link" href="#" title="Write interface configuration file"><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>
</div>
</div>
</div>
<div class="card-body d-flex flex-column">
<div v-if="interfaces.GetSelected.Mode==='server'" class="row">
<div class="col-sm-6">
<table class="table table-sm table-borderless device-status-table">
<tbody>
<tr>
<td>{{ $t('interfaces.statusBox.key') }}:</td>
<td>{{interfaces.GetSelected.PublicKey}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.endpoint') }}:</td>
<td>{{interfaces.GetSelected.PeerDefEndpoint}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.port') }}:</td>
<td>{{interfaces.GetSelected.ListenPort}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.peers') }}:</td>
<td>{{interfaces.GetSelected.EnabledPeers}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.totalPeers') }}:</td>
<td>{{interfaces.GetSelected.TotalPeers}}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6">
<table class="table table-sm table-borderless device-status-table">
<tbody>
<tr>
<td>{{ $t('interfaces.statusBox.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><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>{{interfaces.GetSelected.Mtu}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.intervall') }}:</td>
<td>{{interfaces.GetSelected.PeerDefPersistentKeepalive}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.allowedIP') }}:</td>
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.PeerDefAllowedIPs" :key="addr">{{addr}}</span></td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-if="interfaces.GetSelected.Mode==='client'" class="row">
<div class="col-sm-6">
<table class="table table-sm table-borderless device-status-table">
<tbody>
<tr>
<td>{{ $t('interfaces.statusBox.key') }}:</td>
<td>{{interfaces.GetSelected.PublicKey}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.endpoint') }}:</td>
<td>{{interfaces.GetSelected.InterfacePeers}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.totalPeers') }}:</td>
<td>{{interfaces.GetSelected.TotalPeers}}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6">
<table class="table table-sm table-borderless device-status-table">
<tbody>
<tr>
<td>{{ $t('interfaces.statusBox.ip') }}:</td>
2023-06-14 23:03:24 +02:00
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Addresses" :key="addr">{{addr}}</span></td>
2023-02-12 23:13:04 +01:00
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.dnsServers') }}:</td>
2023-06-14 23:03:24 +02:00
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Dns" :key="addr">{{addr}}</span></td>
2023-02-12 23:13:04 +01:00
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.mtu') }}:</td>
<td>{{interfaces.GetSelected.Mtu}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-if="interfaces.GetSelected.Mode==='any'" class="row">
<div class="col-sm-6">
<table class="table table-sm table-borderless device-status-table">
<tbody>
<tr>
<td>{{ $t('interfaces.statusBox.key') }}:</td>
<td>{{interfaces.GetSelected.PublicKey}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.endpoint') }}:</td>
<td>{{interfaces.GetSelected.PeerDefEndpoint}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.port') }}:</td>
<td>{{interfaces.GetSelected.ListenPort}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.peers') }}:</td>
<td>{{interfaces.GetSelected.EnabledPeers}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.totalPeers') }}:</td>
<td>{{interfaces.GetSelected.TotalPeers}}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6">
<table class="table table-sm table-borderless device-status-table">
<tbody>
<tr>
<td>{{ $t('interfaces.statusBox.ip') }}:</td>
2023-06-14 23:03:24 +02:00
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.Addresses" :key="addr">{{addr}}</span></td>
2023-02-12 23:13:04 +01:00
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.allowedIP') }}:</td>
2023-06-14 23:03:24 +02:00
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.PeerDefAllowedIPs" :key="addr">{{addr}}</span></td>
2023-02-12 23:13:04 +01:00
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.dnsServers') }}:</td>
2023-06-14 23:03:24 +02:00
<td><span class="badge bg-light me-1" v-for="addr in interfaces.GetSelected.PeerDefDns" :key="addr">{{addr}}</span></td>
2023-02-12 23:13:04 +01:00
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.mtu') }}:</td>
<td>{{interfaces.GetSelected.Mtu}}</td>
</tr>
<tr>
<td>{{ $t('interfaces.statusBox.intervall') }}:</td>
<td>{{interfaces.GetSelected.PeerDefPersistentKeepalive}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 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>
</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>
</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"><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>
</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>
</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="">
</th><!-- select -->
<th scope="col">{{ $t('interfaces.tableHeadings[0]') }}</th>
<th scope="col">{{ $t('interfaces.tableHeadings[1]') }}</th>
<th scope="col">{{ $t('interfaces.tableHeadings[2]') }}</th>
2023-06-24 01:35:25 +02:00
<th v-if="interfaces.GetSelected.Mode==='client'" scope="col">{{ $t('interfaces.tableHeadings[3]') }}</th>
<th scope="col">{{ $t('interfaces.tableHeadings[4]') }}</th>
2023-02-12 23:13:04 +01:00
<th scope="col"></th><!-- Actions -->
</tr>
</thead>
<tbody>
<tr v-for="peer in peers.FilteredAndPaged" :key="peer.Identifier">
<th scope="row">
<input id="flexCheckDefault" class="form-check-input" type="checkbox" value="">
</th>
<td>{{peer.DisplayName}}</td>
<td>{{peer.UserIdentifier}}</td>
<td>
2023-06-24 01:35:25 +02:00
<span v-for="ip in peer.Addresses" :key="ip" class="badge bg-light me-1">{{ ip }}</span>
2023-02-12 23:13:04 +01:00
</td>
2023-06-23 19:24:59 +02:00
<td v-if="interfaces.GetSelected.Mode==='client'">{{peer.Endpoint.Value}}</td>
2023-02-12 23:13:04 +01:00
<td>{{peer.LastConnected}}</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>
</td>
</tr>
</tbody>
</table>
</div>
<hr v-if="interfaces.Count!==0">
<div v-if="interfaces.Count!==0" class="mt-3">
<div class="row">
<div class="col-6">
<ul class="pagination pagination-sm">
<li :class="{disabled:peers.pageOffset===0}" class="page-item">
<a class="page-link" @click="peers.previousPage">&laquo;</a>
</li>
<li v-for="page in peers.pages" :key="page" :class="{active:peers.currentPage===page}" class="page-item">
<a class="page-link" @click="peers.gotoPage(page)">{{page}}</a>
</li>
<li :class="{disabled:!peers.hasNextPage}" class="page-item">
<a class="page-link" @click="peers.nextPage">&raquo;</a>
</li>
</ul>
</div>
<div class="col-6">
<div class="form-group row">
<label class="col-sm-6 col-form-label text-end" for="paginationSelector">{{ $t('interfaces.pagination.size') }}:</label>
<div class="col-sm-6">
<select v-model.number="peers.pageSize" class="form-select" @click="peers.afterPageSizeChange()">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="999999999">{{ $t('interfaces.pagination.all') }}</option>
</select>
</div>
</div>
</div>
</div>
</div>
</template>