2023-08-04 13:34:18 +02:00
< script setup >
import PeerViewModal from "../components/PeerViewModal.vue" ;
2024-02-29 07:17:17 +03:00
import { onMounted , ref } from "vue" ;
import { profileStore } from "@/stores/profile" ;
2025-01-26 11:35:24 +01:00
import UserPeerEditModal from "@/components/UserPeerEditModal.vue" ;
2024-02-29 07:17:17 +03:00
import { settingsStore } from "@/stores/settings" ;
2024-09-23 21:44:43 +02:00
import { humanFileSize } from "@/helpers/utils" ;
2023-08-04 13:34:18 +02:00
const settings = settingsStore ()
const profile = profileStore ()
const viewedPeerId = ref ( "" )
const editPeerId = ref ( "" )
2025-02-26 22:24:37 +01:00
const sortKey = ref ( "" )
const sortOrder = ref ( 1 )
const selectAll = ref ( false )
2024-09-23 21:44:43 +02:00
function sortBy ( key ) {
if ( sortKey . value === key ) {
sortOrder . value = sortOrder . value * - 1 ; // Toggle sort order
} else {
sortKey . value = key ;
sortOrder . value = 1 ; // Default to ascending
}
profile . sortKey = sortKey . value ;
profile . sortOrder = sortOrder . value ;
}
2025-01-26 11:35:24 +01:00
function friendlyInterfaceName ( id , name ) {
if ( name ) {
return name
}
return id
}
2025-02-26 22:24:37 +01:00
function toggleSelectAll () {
profile . FilteredAndPagedPeers . forEach ( peer => {
peer . IsSelected = selectAll . value ;
});
}
2023-08-04 13:34:18 +02:00
onMounted ( async () => {
await profile . LoadUser ()
await profile . LoadPeers ()
await profile . LoadStats ()
2025-01-26 11:35:24 +01:00
await profile . LoadInterfaces ()
2024-09-23 21:44:43 +02:00
await profile . calculatePages (); // Forces to show initial page number
2023-08-04 13:34:18 +02:00
})
2024-02-29 07:17:17 +03:00
2023-08-04 13:34:18 +02:00
</ script >
< template >
2024-02-29 07:17:17 +03:00
< PeerViewModal :peerId = "viewedPeerId" : visible = "viewedPeerId !== ''" @close ="viewedPeerId = ''" ></ PeerViewModal >
2025-01-26 11:35:24 +01:00
< UserPeerEditModal :peerId = "editPeerId" : visible = "editPeerId !== ''" @close ="editPeerId = ''; profile.LoadPeers()" ></ UserPeerEditModal >
2023-08-04 13:34:18 +02:00
<!-- Peer list -- >
< div class = "mt-4 row" >
< div class = "col-12 col-lg-5" >
< 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" >
2024-02-29 07:17:17 +03:00
< 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 >
2023-08-04 13:34:18 +02:00
</ div >
</ div >
</ div >
< div class = "col-12 col-lg-3 text-lg-end" >
2025-01-26 11:35:24 +01:00
< div class = "form-group" v-if = "settings.Setting('SelfProvisioning')" >
< div class = "input-group mb-3" >
< button class = "input-group-text btn btn-primary" :title = "$t('interfaces.button-add-peer')" @click.prevent ="editPeerId = '#NEW#'" >
< i class = "fa fa-plus me-1" ></ i >< i class = "fa fa-user" ></ i >
</ button >
< select v-model = "profile.selectedInterfaceId" :disabled="profile.CountInterfaces===0" class="form-select" >
< option v-if = "profile.CountInterfaces===0" value="nothing" >{{ $ t (' interfaces.no -interface .default -selection ') }}</ option >
< option v-for = "iface in profile.interfaces" :key="iface.Identifier" :value="iface.Identifier" >{{ friendlyInterfaceName ( iface.Identifier , iface.DisplayName ) }}</ option >
</ select >
</ div >
</ div >
2023-08-04 13:34:18 +02:00
</ div >
</ div >
< div class = "mt-2 table-responsive" >
2024-02-29 07:17:17 +03:00
< div v-if = "profile.CountPeers === 0" >
< h4 >{{ $t ( 'profile.no-peer.headline' ) }}</ h4 >
< p >{{ $t ( 'profile.no-peer.abstract' ) }}</ p >
2023-08-04 13:34:18 +02:00
</ div >
2024-02-29 07:17:17 +03:00
< table v-if = "profile.CountPeers !== 0" id="peerTable" class="table table-sm" >
2023-08-04 13:34:18 +02:00
< thead >
2024-02-29 07:17:17 +03:00
< tr >
< th scope = "col" >
2025-02-26 22:24:37 +01:00
< input class = "form-check-input" :title = "$t('general.select-all')" type = "checkbox" v-model = "selectAll" @change="toggleSelectAll" >
2024-02-29 07:17:17 +03:00
</ th > <!-- select -- >
< th scope = "col" ></ th > <!-- status -->
2024-09-23 21:44:43 +02:00
< th scope = "col" @click ="sortBy('DisplayName')" >
{{ $ t (" profile.table -heading .name ") }}
< i v-if = "sortKey === 'DisplayName'" :class="sortOrder === 1 ? 'asc' : 'desc'" ></ i >
</ th >
< th scope = "col" @click ="sortBy('Addresses')" >
{{ $ t (" profile.table -heading .ip ") }}
< i v-if = "sortKey === 'Addresses'" :class="sortOrder === 1 ? 'asc' : 'desc'" ></ i >
</ th >
< th v-if = "profile.hasStatistics" scope="col" @click="sortBy('IsConnected')" >
{{ $ t (" profile.table -heading .stats ") }}
< i v-if = "sortKey === 'IsConnected'" :class="sortOrder === 1 ? 'asc' : 'desc'" ></ i >
</ th >
< th v-if = "profile.hasStatistics" scope="col" @click="sortBy('Traffic')" > RX / TX
< i v-if = "sortKey === 'Traffic'" :class="sortOrder === 1 ? 'asc' : 'desc'" ></ i >
</ th >
2024-02-29 07:17:17 +03:00
< th scope = "col" >{{ $t ( 'profile.table-heading.interface' ) }}</ th >
< th scope = "col" ></ th > <!-- Actions -->
</ tr >
2023-08-04 13:34:18 +02:00
</ thead >
< tbody >
< tr v-for = "peer in profile.FilteredAndPagedPeers" :key="peer.Identifier" >
< th scope = "row" >
2025-02-26 22:24:37 +01:00
< input class = "form-check-input" type = "checkbox" v-model = "peer.IsSelected" >
2023-08-04 13:34:18 +02:00
</ th >
< td class = "text-center" >
2024-02-29 07:17:17 +03:00
< 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"
:title = "peer.ExpiresAt" ></ i ></ span >
2023-08-04 13:34:18 +02:00
</ td >
2024-02-29 07:17:17 +03:00
< 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 >
2023-08-04 13:34:18 +02:00
< td >
< span v-for = "ip in peer.Addresses" :key="ip" class="badge rounded-pill bg-light" >{{ ip }}</ span >
</ td >
< td v-if = "profile.hasStatistics" >
< div v-if = "profile.Statistics(peer.Identifier).IsConnected" >
2024-02-29 07:17:17 +03:00
< span class = "badge rounded-pill bg-success" >< i class = "fa-solid fa-link" ></ i ></ span >
< span :title = "profile.Statistics(peer.Identifier).LastHandshake" >{{ $t ( 'profile.peer-connected' ) }}</ span >
2023-08-04 13:34:18 +02:00
</ div >
< div v-else >
< span class = "badge rounded-pill bg-light" >< i class = "fa-solid fa-link-slash" ></ i ></ span >
</ div >
</ td >
2024-09-23 21:44:43 +02:00
< td v-if = "profile.hasStatistics" >
< span class = "text-center" >{{ humanFileSize ( profile . Statistics ( peer . Identifier ). BytesReceived ) }} / {{ humanFileSize ( profile . Statistics ( peer . Identifier ). BytesTransmitted ) }}</ span >
</ td >
2024-02-29 07:17:17 +03:00
< td >{{ peer . InterfaceIdentifier }}</ td >
2023-08-04 13:34:18 +02:00
< td class = "text-center" >
2024-02-29 07:17:17 +03:00
< 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 >
2023-08-04 13:34:18 +02:00
</ td >
</ tr >
</ tbody >
</ table >
</ div >
< hr >
< div class = "mt-3" >
< div class = "row" >
< div class = "col-6" >
< ul class = "pagination pagination-sm" >
2024-02-29 07:17:17 +03:00
< li : class = "{ disabled: profile.pageOffset === 0 }" class = "page-item" >
2023-08-04 13:34:18 +02:00
< a class = "page-link" @click ="profile.previousPage" > & laquo ; </ a >
</ li >
2024-02-29 07:17:17 +03:00
< li v-for = "page in profile.pages" :key="page" :class="{ active: profile.currentPage === page }" class="page-item" >
< a class = "page-link" @click ="profile.gotoPage(page)" >{{ page }}</ a >
2023-08-04 13:34:18 +02:00
</ li >
2024-02-29 07:17:17 +03:00
< li : class = "{ disabled: !profile.hasNextPage }" class = "page-item" >
2023-08-04 13:34:18 +02:00
< a class = "page-link" @click ="profile.nextPage" > & raquo ; </ a >
</ li >
</ ul >
</ div >
< div class = "col-6" >
< div class = "form-group row" >
2024-02-29 07:17:17 +03:00
< label class = "col-sm-6 col-form-label text-end" for = "paginationSelector" >
{{ $t ( 'general.pagination.size' )}} :
</ label >
2023-08-04 13:34:18 +02:00
< div class = "col-sm-6" >
< select v -model .number =" profile.pageSize " class = "form-select" @click ="profile.afterPageSizeChange()" >
< option value = "10" > 10 </ option >
< option value = "25" > 25 </ option >
< option value = "50" > 50 </ option >
2024-02-29 07:17:17 +03:00
< option value = "100" > 100 </ option >
< option value = "999999999" >{{ $t ( 'general.pagination.all' ) }}</ option >
</ select >
2023-08-04 13:34:18 +02:00
</ div >
</ div >
</ div >
</ div >
2024-02-29 07:17:17 +03:00
</ div ></ template >