feat: Added peers sorting on views (#302)

* Added peers sorting for Interface and Profile views

* Use ip-address package to sort with IPv6 addresses only

* Add RX/TX column and fix add-peer button title
This commit is contained in:
Dmytro Bondar
2024-09-23 21:44:43 +02:00
committed by GitHub
parent 6ffe1a90ae
commit 3196010a58
8 changed files with 186 additions and 15 deletions

View File

@@ -10,6 +10,7 @@ import {peerStore} from "@/stores/peers";
import {interfaceStore} from "@/stores/interfaces";
import {notify} from "@kyvg/vue3-notification";
import {settingsStore} from "@/stores/settings";
import {humanFileSize} from '@/helpers/utils';
const settings = settingsStore()
const interfaces = interfaceStore()
@@ -21,6 +22,20 @@ const multiCreatePeerId = ref("")
const editInterfaceId = ref("")
const viewedInterfaceId = ref("")
const sortKey = ref("");
const sortOrder = ref(1);
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
}
peers.sortKey = sortKey.value;
peers.sortOrder = sortOrder.value;
}
function calculateInterfaceName(id, name) {
let result = id
if (name) {
@@ -314,11 +329,28 @@ onMounted(async () => {
<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.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" @click="sortBy('DisplayName')">
{{ $t("interfaces.table-heading.name") }}
<i v-if="sortKey === 'DisplayName'" :class="sortOrder === 1 ? 'asc' : 'desc'"></i>
</th>
<th scope="col" @click="sortBy('UserIdentifier')">
{{ $t("interfaces.table-heading.user") }}
<i v-if="sortKey === 'UserIdentifier'" :class="sortOrder === 1 ? 'asc' : 'desc'"></i>
</th>
<th scope="col" @click="sortBy('Addresses')">
{{ $t("interfaces.table-heading.ip") }}
<i v-if="sortKey === 'Addresses'" :class="sortOrder === 1 ? 'asc' : 'desc'"></i>
</th>
<th v-if="interfaces.GetSelected.Mode === 'client'" scope="col">
{{ $t("interfaces.table-heading.endpoint") }}
</th>
<th v-if="peers.hasStatistics" scope="col" @click="sortBy('IsConnected')">
{{ $t("interfaces.table-heading.status") }}
<i v-if="sortKey === 'IsConnected'" :class="sortOrder === 1 ? 'asc' : 'desc'"></i>
</th>
<th v-if="peers.hasStatistics" scope="col" @click="sortBy('Traffic')">RX/TX
<i v-if="sortKey === 'Traffic'" :class="sortOrder === 1 ? 'asc' : 'desc'"></i>
</th>
<th scope="col"></th><!-- Actions -->
</tr>
</thead>
@@ -345,6 +377,9 @@ onMounted(async () => {
<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 v-if="peers.hasStatistics" >
<span class="text-center" >{{ humanFileSize(peers.Statistics(peer.Identifier).BytesReceived) }} / {{ humanFileSize(peers.Statistics(peer.Identifier).BytesTransmitted) }}</span>
</td>
<td class="text-center">
<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>

View File

@@ -5,6 +5,7 @@ import { onMounted, ref } from "vue";
import { profileStore } from "@/stores/profile";
import PeerEditModal from "@/components/PeerEditModal.vue";
import { settingsStore } from "@/stores/settings";
import { humanFileSize } from "@/helpers/utils";
const settings = settingsStore()
const profile = profileStore()
@@ -12,10 +13,25 @@ const profile = profileStore()
const viewedPeerId = ref("")
const editPeerId = ref("")
const sortKey = ref("");
const sortOrder = ref(1);
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;
}
onMounted(async () => {
await profile.LoadUser()
await profile.LoadPeers()
await profile.LoadStats()
await profile.calculatePages(); // Forces to show initial page number
})
</script>
@@ -41,7 +57,7 @@ onMounted(async () => {
</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="$t('general.search.button-add-peer')" @click.prevent="editPeerId = '#NEW#'"><i
: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>
@@ -58,9 +74,21 @@ onMounted(async () => {
value="">
</th><!-- select -->
<th scope="col"></th><!-- status -->
<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" @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>
<th scope="col">{{ $t('profile.table-heading.interface') }}</th>
<th scope="col"></th><!-- Actions -->
</tr>
@@ -90,6 +118,9 @@ onMounted(async () => {
<span class="badge rounded-pill bg-light"><i class="fa-solid fa-link-slash"></i></span>
</div>
</td>
<td v-if="profile.hasStatistics" >
<span class="text-center" >{{ humanFileSize(profile.Statistics(peer.Identifier).BytesReceived) }} / {{ humanFileSize(profile.Statistics(peer.Identifier).BytesTransmitted) }}</span>
</td>
<td>{{ peer.InterfaceIdentifier }}</td>
<td class="text-center">
<a href="#" :title="$t('profile.button-show-peer')" @click.prevent="viewedPeerId = peer.Identifier"><i