This commit is contained in:
Donald Zou
2025-08-19 17:56:46 +08:00
parent 9c6d0b56c3
commit 574aff605f
8 changed files with 148 additions and 89 deletions

View File

@@ -76,7 +76,6 @@ const configurationModals = ref({
}
})
const peerSearchBar = ref(false)
// Fetch Peer =====================================
const fetchPeerList = async () => {
await fetchGet("/api/getWireguardConfigurationInfo", {
@@ -110,6 +109,7 @@ setFetchPeerListInterval()
onBeforeUnmount(() => {
clearInterval(fetchPeerListInterval.value);
fetchPeerListInterval.value = undefined;
wireguardConfigurationStore.Filter.HiddenTags = []
})
watch(() => {
@@ -155,13 +155,28 @@ const configurationSummary = computed(() => {
const showPeersCount = ref(10)
const showPeersThreshold = 20;
const hiddenPeers = computed(() => {
return wireguardConfigurationStore.Filter.HiddenTags.map(tag => {
return configurationInfo.value.Info.PeerGroups[tag].Peers
}).flat()
})
const taggedPeers = computed(() => {
return Object.values(configurationInfo.value.Info.PeerGroups).map(x => x.Peers).flat()
})
const searchPeers = computed(() => {
const result = wireguardConfigurationStore.searchString ?
configurationPeers.value.filter(x => {
return x.name.includes(wireguardConfigurationStore.searchString) ||
return (x.name.includes(wireguardConfigurationStore.searchString) ||
x.id.includes(wireguardConfigurationStore.searchString) ||
x.allowed_ip.includes(wireguardConfigurationStore.searchString)
}) : configurationPeers.value;
x.allowed_ip.includes(wireguardConfigurationStore.searchString))
&& !hiddenPeers.value.includes(x.id)
&& (
wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags || (!wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags && taggedPeers.value.includes(x.id))
)
}) : configurationPeers.value.filter(x => !hiddenPeers.value.includes(x.id) && (
wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags || (!wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags && taggedPeers.value.includes(x.id))
));
if (dashboardStore.Configuration.Server.dashboard_sort === "restricted"){
return result.sort((a, b) => {
@@ -201,6 +216,7 @@ watch(() => route.query.id, (newValue) => {
})
</script>
<template>
@@ -352,10 +368,10 @@ watch(() => route.query.id, (newValue) => {
:configurationInfo="configurationInfo"
></PeerDataUsageCharts>
<hr>
<div style="margin-bottom: 80px">
<div style="margin-bottom: 10rem">
<PeerSearch
v-if="configurationPeers.length > 0"
@search="peerSearchBar = true"
@search="peerSearchBar = !peerSearchBar"
@jobsAll="configurationModals.peerScheduleJobsAll.modalOpen = true"
@jobLogs="configurationModals.peerScheduleJobsLogs.modalOpen = true"
@editConfiguration="configurationModals.editConfiguration.modalOpen = true"
@@ -383,8 +399,11 @@ watch(() => route.query.id, (newValue) => {
</TransitionGroup>
</div>
<Transition name="slideUp">
<PeerSearchBar @close="peerSearchBar = false" v-if="peerSearchBar"></PeerSearchBar>
<Transition name="slide-fade">
<PeerSearchBar
v-if="peerSearchBar"
:ConfigurationInfo="configurationInfo"
@close="peerSearchBar = false"></PeerSearchBar>
</Transition>
<PeerListModals
:configurationModals="configurationModals"

View File

@@ -16,7 +16,7 @@ export default {
return {store, wireguardConfigurationStore}
},
props: {
configuration: Object
configuration: Object, displayTags: Array
},
data(){
return {
@@ -163,7 +163,7 @@ export default {
@click="tagManager = !tagManager"
class="btn btn-sm w-100 text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative">
<i class="bi me-2 bi-hash"></i>
<i class="bi me-2 bi-tag"></i>
<LocaleText t="Tags"></LocaleText>
</button>

View File

@@ -2,8 +2,7 @@
import {GetLocale} from "@/utilities/locale.js";
import {computed, onMounted, ref, useTemplateRef} from "vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import LocaleText from "@/components/text/localeText.vue";
import {useRoute, useRouter} from "vue-router";
import {onBeforeRouteUpdate, useRoute, useRouter} from "vue-router";
const searchBarPlaceholder = computed(() => {
return GetLocale("Search Peers...")
@@ -27,7 +26,7 @@ const debounce = () => {
const emits = defineEmits(['close'])
const input = useTemplateRef('searchBar')
const props = defineProps(["ConfigurationInfo"])
const route = useRoute()
const router = useRouter()
if (route.query.peer){
@@ -35,53 +34,42 @@ if (route.query.peer){
router.replace({ query: null })
}
const show = ref(true)
onMounted(() => {
input.value.focus();
document.querySelector("#searchPeers").focus()
})
onBeforeRouteUpdate(() => {
show.value = false
})
</script>
<template>
<Transition name="slideUp" appear type="animation" style="animation-delay: 1s">
<div class="fixed-bottom w-100 bottom-0 z-2" style="z-index: 1;">
<div class="container-fluid">
<div class="row g-0">
<div class="col-md-3 col-lg-2"></div>
<div class="col-md-9 col-lg-10 d-flex justify-content-center py-2">
<div class="rounded-3 p-2 border shadow searchPeersContainer bg-body-tertiary">
<div class="d-flex gap-1 align-items-center px-2">
<h6 class="mb-0 me-2">
<label for="searchPeers">
<i class="bi bi-search"></i>
</label>
</h6>
<div class="fixed-bottom w-100 bottom-0 z-2 p-3" style="z-index: 1;" v-if="show">
<div class="d-flex flex-column searchPeersContainer ms-auto p-2 rounded-5"
style="width: 300px;">
<div class="rounded-5 border border-white p-2 d-flex align-items-center gap-1 w-100">
<input
ref="searchBar"
class="flex-grow-1 form-control rounded-3 bg-secondary-subtle border-1 border-secondary-subtle "
class="flex-grow-1 form-control form-control-sm rounded-5 bg-transparent border-0 border-secondary-subtle "
:placeholder="searchBarPlaceholder"
id="searchPeers"
@keyup="debounce()"
v-model="searchString">
<button
@click="emits('close')"
style="white-space: nowrap"
class="btn bg-secondary-subtle text-secondary-emphasis border-secondary-subtle rounded-3 d-flex align-items-center">
<span>
<i class="bi bi-x-circle-fill me-2"></i><LocaleText t="Done"></LocaleText>
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</Transition>
</template>
<style scoped>
.searchPeersContainer{
backdrop-filter: blur(8px);
width: 100%;
background: linear-gradient(var(--degree), rgba(45, 173, 255, 0.4), rgba(255, 108, 109, 0.4), var(--brandColor2) 100%);
}
#searchPeers::placeholder{
color: white;
}
</style>

View File

@@ -162,7 +162,7 @@ export default {
data-bs-toggle="dropdown"
>
<i class="me-auto bi bi-diagram-2"></i> <LocaleText t="Tag Peer"></LocaleText>
<i class="me-auto bi bi-tag"></i> <LocaleText t="Tag Peer"></LocaleText>
</a>
<PeerTagSelectDropdown
@update="this.$emit('refresh')"

View File

@@ -106,7 +106,8 @@ const predefinedColors = {
"white": "#fff",
"black": "#000",
}
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js"
const store = WireguardConfigurationsStore()
const props = defineProps(['configuration'])
const groups = reactive({...props.configuration.Info.PeerGroups})
import { v4 } from "uuid"
@@ -154,10 +155,22 @@ watch(() => groups, (newVal) => {
}, {
deep: true
})
const edit = ref(false)
</script>
<template>
<div class="card shadow" id="peerTag">
<div class="card shadow rounded-3" id="peerTag">
<div class="card-header">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showAllPeers" v-model="store.Filter.ShowAllPeersWhenHiddenTags">
<label class="form-check-label" for="showAllPeers">
<small>
<LocaleText t="Show All Peers"></LocaleText>
</small>
</label>
</div>
</div>
<div class="card-body p-2" >
<Transition name="zoom" mode="out-in">
<div v-if="!iconPickerOpen && !colorPickerOpen">
@@ -165,12 +178,16 @@ watch(() => groups, (newVal) => {
<small><LocaleText t="No tag"></LocaleText></small>
</div>
<div class="d-flex flex-column gap-2" v-else>
<TransitionGroup name="slide-fade">
<PeerTagSetting v-for="(group, key) in groups"
@delete="delete groups[key]"
:groupId="key"
@delete="delete groups[key]; store.Filter.HiddenTags = store.Filter.HiddenTags.filter(x => x !== key)"
@colorPickerOpen="colorPickerOpen = true; selectedKey = key"
@iconPickerOpen="iconPickerOpen = true; selectedKey = key"
:key="key"
:edit="edit"
:group="group"></PeerTagSetting>
</TransitionGroup>
</div>
</div>
<PeerTagIconPicker
@@ -184,16 +201,31 @@ watch(() => groups, (newVal) => {
</Transition>
</div>
<div class="card-footer p-2 d-flex gap-2" >
<template v-if="!edit">
<button
@click="emits('close')"
class="btn btn-sm bg-secondary-subtle text-secondary-emphasis border-secondary-subtle rounded-3">
<small><LocaleText t="Close"></LocaleText></small>
</button>
<button
@click="addGroup"
@click="edit = true"
class="btn btn-sm bg-primary-subtle text-primary-emphasis border-primary-subtle rounded-3 ms-auto">
<small><i class="bi bi-pen me-2"></i><LocaleText t="Edit"></LocaleText></small>
</button>
</template>
<template v-else>
<button
@click="addGroup"
class="btn btn-sm bg-primary-subtle text-primary-emphasis border-primary-subtle rounded-3 ">
<small><i class="bi bi-plus-lg me-2"></i><LocaleText t="Tag"></LocaleText></small>
</button>
<button
@click="edit = false"
class="btn btn-sm bg-secondary-subtle text-secondary-emphasis border-secondary-subtle rounded-3 ms-auto">
<small><LocaleText t="Done"></LocaleText></small>
</button>
</template>
</div>
</div>
</template>

View File

@@ -16,14 +16,6 @@ onMounted(() => {
<template>
<div class="w-100 bg-body top-0 border rounded-2">
<div class="p-2 d-flex align-items-center gap-2 border-bottom">
<label>
<i class="bi bi-search"></i>
</label>
<input v-model="searchString"
placeholder="Search Icon"
class="form-control form-control-sm rounded-2">
</div>
<div class="p-2 d-grid icon-grid"
style="grid-template-columns: repeat(auto-fit, minmax(30px, 30px)); gap: 3px; max-height: 300px; overflow-y: scroll">
<div class="rounded-1 border icon d-flex"

View File

@@ -3,41 +3,65 @@ import LocaleText from "@/components/text/localeText.vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js"
import {ref} from "vue";
const store = WireguardConfigurationsStore();
const props = defineProps(['group'])
const emits = defineEmits(['delete', 'iconPickerOpen', 'colorPickerOpen'])
const props = defineProps(['group', 'edit', 'groupId'])
const emits = defineEmits(['delete', 'iconPickerOpen', 'colorPickerOpen', 'toggle'])
const groupName = ref(props.group.GroupName)
const toggleTag = () => {
if (store.Filter.HiddenTags.includes(props.groupId)){
store.Filter.HiddenTags = store.Filter.HiddenTags.filter(x => x !== props.groupId)
}else{
store.Filter.HiddenTags.push(props.groupId)
}
}
</script>
<template>
<div class="border rounded-3 p-2">
<div
class="rounded-3 align-items-center overflow-scroll d-flex gap-2 position-relative">
<div
class=" align-items-center overflow-scroll d-flex gap-2 position-relative">
<button
@click="emits('iconPickerOpen')"
aria-label="Pick icon button"
:class="{disabled: !edit}"
class="d-flex align-items-center p-2 btn btn-sm border rounded-2">
<i class="bi" :class="'bi-' + group.Icon" :aria-label="group.Icon" v-if="group.Icon"></i>
<span style="white-space: nowrap" v-else>
<LocaleText t="No Icon"></LocaleText>
</span>
</div>
<div
</button>
<button
:class="{disabled: !edit}"
aria-label="Pick color button"
@click="emits('colorPickerOpen')"
:style="{'background-color': group.BackgroundColor, 'color': store.colorText(group.BackgroundColor)}"
class="d-flex align-items-center p-2 btn btn-sm border rounded-2">
<i class="bi bi-eyedropper" ></i>
</div>
</button>
<input
:disabled="!edit"
v-model="groupName"
@change="group.GroupName = groupName"
placeholder="Tag Name"
class="form-control form-control-sm p-2 rounded-2 w-100">
<div
aria-label="Pick color button" @click="emits('delete')"
<button
v-if="edit"
aria-label="Delete Tag Button" @click="emits('delete')"
class="rounded-2 border p-2 btn btn-sm btn-outline-danger">
<i class="bi bi-trash-fill"></i>
</div>
</button>
<button
v-else
aria-label="Show / Hide Button"
style="white-space: nowrap"
:class="{active: !store.Filter.HiddenTags.includes(groupId)}"
@click="toggleTag()"
class="rounded-2 p-2 btn btn-sm btn-outline-primary">
<i class="bi"
:class="[!store.Filter.HiddenTags.includes(groupId) ? 'bi-eye-fill':'bi-eye-slash-fill']"
></i>
</button>
</div>
</div>
</template>

View File

@@ -10,6 +10,10 @@ export const WireguardConfigurationsStore = defineStore('WireguardConfigurations
ConfigurationLoaded: false,
searchString: "",
ConfigurationListInterval: undefined,
Filter: {
HiddenTags: [],
ShowAllPeersWhenHiddenTags: true
},
SortOptions: {
Name: GetLocale("Name"),
Status: GetLocale("Status"),
@@ -131,7 +135,7 @@ export const WireguardConfigurationsStore = defineStore('WireguardConfigurations
},
persist: {
pick: [
"CurrentSort", "CurrentDisplay"
"CurrentSort", "CurrentDisplay", "Filter.ShowAllPeersWhenHiddenTags"
]
}
});