Perf/optimize details (#106)

* 🎈 perf: details
* 🎈 perf: optimize Style
This commit is contained in:
m1m1sha 2024-05-11 16:26:44 +08:00 committed by GitHub
parent 65ac991d1c
commit a5637003ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 94 additions and 52 deletions

View File

@ -13,6 +13,7 @@ enable_vpn_portal: 启用VPN门户
vpn_portal_listen_port: 监听端口
vpn_portal_client_network: 客户端子网
advanced_settings: 高级设置
basic_settings: 基础设置
listener_urls: 监听地址
rpc_port: RPC端口
config_network: 配置网络
@ -43,7 +44,9 @@ peer_count: 已连接
upload: 上传
download: 下载
show_vpn_portal_config: 显示VPN门户配置
vpn_portal_config: VPN门户配置
show_event_log: 显示事件日志
event_log: 事件日志
peer_info: 节点信息
hostname: 主机名
route_cost: 路由
@ -54,3 +57,5 @@ loss_rate: 丢包率
run_network: 运行网络
stop_network: 停止网络
network_running: 运行中
network_stopped: 已停止

View File

@ -13,6 +13,7 @@ enable_vpn_portal: Enable VPN Portal
vpn_portal_listen_port: VPN Portal Listen Port
vpn_portal_client_network: Client Sub Network
advanced_settings: Advanced Settings
basic_settings: Basic Settings
listener_urls: Listener URLs
rpc_port: RPC Port
config_network: Config Network
@ -43,7 +44,9 @@ peer_count: Connected
upload: Upload
download: Download
show_vpn_portal_config: Show VPN Portal Config
vpn_portal_config: VPN Portal Config
show_event_log: Show Event Log
event_log: Event Log
peer_info: Peer Info
route_cost: Route Cost
hostname: Hostname
@ -54,3 +57,5 @@ loss_rate: Loss Rate
run_network: Run Network
stop_network: Stop Network
network_running: running
network_stopped: stopped

View File

@ -56,8 +56,8 @@ onMounted(async () => {
<template>
<div class="flex flex-column h-full">
<div class="flex flex-column">
<div class="w-10/12 max-w-fit self-center ">
<Panel header="Basic Settings">
<div class="w-7/12 self-center ">
<Panel :header="$t('basic_settings')">
<div class="flex flex-column gap-y-2">
<div class="flex flex-row gap-x-9 flex-wrap">
<div class="flex flex-column gap-2 basis-5/12 grow">
@ -107,6 +107,22 @@ onMounted(async () => {
</div>
</div>
</div>
</div>
</Panel>
<Divider />
<Panel :header="$t('advanced_settings')" toggleable>
<div class="flex flex-column gap-y-2">
<div class="flex flex-row gap-x-9 flex-wrap">
<div class="flex flex-column gap-2 basis-5/12 grow">
<label for="hostname">{{ $t('hostname') }}</label>
<InputText
id="hostname" v-model="curNetwork.hostname" aria-describedby="hostname-help" :format="true"
:placeholder="$t('hostname_placeholder', [osHostname])" @blur="validateHostname"
/>
</div>
</div>
<div class="flex flex-row gap-x-9 flex-wrap w-full">
<div class="flex flex-column gap-2 grow p-fluid">
@ -144,14 +160,8 @@ onMounted(async () => {
</div>
</div>
</div>
</div>
</Panel>
<Divider />
<Panel :header="$t('advanced_settings')" toggleable>
<div class="flex flex-column gap-y-2">
<div class="flex flex-row gap-x-9 flex-wrap w-full">
<div class="flex flex-row gap-x-9 flex-wrap">
<div class="flex flex-column gap-2 grow p-fluid">
<label for="listener_urls">{{ $t('listener_urls') }}</label>
<Chips
@ -170,20 +180,9 @@ onMounted(async () => {
/>
</div>
</div>
<div class="flex flex-row gap-x-9 flex-wrap">
<div class="flex flex-column gap-2 basis-5/12 grow">
<label for="hostname">{{ $t('hostname') }}</label>
<InputText
id="hostname" v-model="curNetwork.hostname" aria-describedby="hostname-help" :format="true"
:placeholder="$t('hostname_placeholder', [osHostname])" @blur="validateHostname"
/>
</div>
</div>
</div>
</Panel>
<Divider />
<div class="flex pt-4 justify-content-center">
<Button
:label="$t('run_network')" icon="pi pi-arrow-right" icon-pos="right" :disabled="configInvalid"

View File

@ -42,7 +42,7 @@ function resolveObjPath(path: string, obj = globalThis, separator = '.') {
return properties.reduce((prev, curr) => prev?.[curr], obj)
}
function statsCommon(info: any, field: string) {
function statsCommon(info: any, field: string): number | undefined {
if (!info.peer)
return undefined
@ -73,8 +73,11 @@ function humanFileSize(bytes: number, si = false, dp = 1) {
}
function latencyMs(info: any) {
const lat_us_sum = statsCommon(info, 'stats.latency_us')
return lat_us_sum ? `${lat_us_sum / 1000 / info.peer.conns.length}ms` : ''
let lat_us_sum = statsCommon(info, 'stats.latency_us')
if (lat_us_sum === undefined)
return ''
lat_us_sum = lat_us_sum / 1000 / info.peer.conns.length
return `${lat_us_sum % 1 > 0 ? Math.round(lat_us_sum) + 1 : Math.round(lat_us_sum)}ms`
}
function txBytes(info: any) {
@ -236,6 +239,7 @@ onUnmounted(() => {
const dialogVisible = ref(false)
const dialogContent = ref<any>('')
const dialogHeader = ref('event_log')
function showVpnPortalConfig() {
const my_node_info = myNodeInfo.value
@ -244,6 +248,7 @@ function showVpnPortalConfig() {
const url = 'https://www.wireguardconfig.com/qrcode'
dialogContent.value = `${my_node_info.vpn_portal_cfg}\n\n # can generate QR code: ${url}`
dialogHeader.value = 'vpn_portal_config'
dialogVisible.value = true
}
@ -253,13 +258,14 @@ function showEventLogs() {
return
dialogContent.value = detail.events
dialogHeader.value = 'event_log'
dialogVisible.value = true
}
</script>
<template>
<div>
<Dialog v-model:visible="dialogVisible" modal header="Dialog" :style="{ width: '70%' }">
<Dialog v-model:visible="dialogVisible" modal :header="$t(dialogHeader)" :style="{ width: '70%' }">
<Panel>
<ScrollPanel style="width: 100%; height: 400px">
<pre>{{ dialogContent }}</pre>
@ -267,7 +273,7 @@ function showEventLogs() {
</Panel>
<Divider />
<div class="flex justify-content-end gap-2">
<Button type="button" label="Close" @click="dialogVisible = false" />
<Button type="button" :label="$t('close')" @click="dialogVisible = false" />
</div>
</Dialog>
@ -292,7 +298,7 @@ function showEventLogs() {
<div class="flex w-full flex-column gap-y-5">
<div class="m-0 flex flex-row justify-center gap-x-5">
<div
class="rounded-full w-36 h-36 flex flex-column align-items-center pt-4"
class="rounded-full w-32 h-32 flex flex-column align-items-center pt-4"
style="border: 1px solid green"
>
<div class="font-bold">
@ -304,7 +310,7 @@ function showEventLogs() {
</div>
<div
class="rounded-full w-36 h-36 flex flex-column align-items-center pt-4"
class="rounded-full w-32 h-32 flex flex-column align-items-center pt-4"
style="border: 1px solid purple"
>
<div class="font-bold">
@ -316,7 +322,7 @@ function showEventLogs() {
</div>
<div
class="rounded-full w-36 h-36 flex flex-column align-items-center pt-4"
class="rounded-full w-32 h-32 flex flex-column align-items-center pt-4"
style="border: 1px solid fuchsia"
>
<div class="font-bold">
@ -353,11 +359,11 @@ function showEventLogs() {
<DataTable :value="peerRouteInfos" column-resize-mode="fit" table-style="width: 100%">
<Column field="route.ipv4_addr" style="width: 100px;" :header="$t('virtual_ipv4')" />
<Column field="route.hostname" style="max-width: 250px;" :header="$t('hostname')" />
<Column :field="routeCost" style="width: 60px;" :header="$t('route_cost')" />
<Column :field="routeCost" style="width: 100px;" :header="$t('route_cost')" />
<Column :field="latencyMs" style="width: 80px;" :header="$t('latency')" />
<Column :field="txBytes" style="width: 80px;" :header="$t('upload_bytes')" />
<Column :field="rxBytes" style="width: 80px;" :header="$t('download_bytes')" />
<Column :field="lossRate" style="width: 60px;" :header="$t('loss_rate')" />
<Column :field="lossRate" style="width: 100px;" :header="$t('loss_rate')" />
</DataTable>
</template>
</Card>

View File

@ -62,10 +62,6 @@ function addNewNetwork() {
networkStore.curNetwork = networkStore.lastNetwork
}
function networkMenuName(network: NetworkConfig) {
return `${network.network_name} (${network.instance_id})`
}
networkStore.$subscribe(async () => {
networkStore.saveToLocalStorage()
try {
@ -150,6 +146,10 @@ function toggle_setting_menu(event: any) {
onMounted(async () => {
networkStore.loadFromLocalStorage()
})
function isRunning(id: string) {
return networkStore.networkInstanceIds.includes(id)
}
</script>
<script lang="ts">
@ -183,10 +183,38 @@ onMounted(async () => {
<template #center>
<div class="min-w-80 mr-20">
<Dropdown
v-model="networkStore.curNetwork" :options="networkStore.networkList"
:option-label="networkMenuName" :placeholder="$t('select_network')" :highlight-on-select="true"
:checkmark="true" class="w-full md:w-32rem"
/>
v-model="networkStore.curNetwork" :options="networkStore.networkList" :highlight-on-select="false"
:placeholder="$t('select_network')" class="w-full"
>
<template #value="slotProps">
<div class="flex items-start content-center">
<div class="mr-3">
<span>{{ slotProps.value.network_name }}</span>
<span v-if="isRunning(slotProps.value.instance_id)" class="ml-3">
{{ slotProps.value.virtual_ipv4 }}
</span>
</div>
<Tag
class="my-auto" :severity="isRunning(slotProps.value.instance_id) ? 'success' : 'info'"
:value="$t(isRunning(slotProps.value.instance_id) ? 'network_running' : 'network_stopped')"
/>
</div>
</template>
<template #option="slotProps">
<div class="flex flex-col items-start content-center">
<div class="flex">
<div class="mr-3">
{{ $t('network_name') }}: {{ slotProps.option.network_name }}
</div>
<Tag
class="my-auto" :severity="isRunning(slotProps.option.instance_id) ? 'success' : 'info'"
:value="$t(isRunning(slotProps.option.instance_id) ? 'network_running' : 'network_stopped')"
/>
</div>
<div>{{ slotProps.option.public_server_url }}</div>
</div>
</template>
</Dropdown>
</div>
</template>
@ -201,7 +229,7 @@ onMounted(async () => {
</div>
<Stepper class="h-full overflow-y-auto" :active-step="activeStep">
<StepperPanel :header="$t('config_network')" class="w">
<StepperPanel :header="$t('config_network')">
<template #content="{ nextCallback }">
<Config
:instance-id="networkStore.curNetworkId" :config-invalid="messageBarSeverity !== Severity.None"
@ -233,11 +261,15 @@ onMounted(async () => {
</div>
</template>
<style scoped>
<style scoped lang="postcss">
#root {
height: 100vh;
width: 100vw;
}
.p-dropdown :deep(.p-dropdown-panel .p-dropdown-items .p-dropdown-item) {
padding: 0 0.5rem;
}
</style>
<style>

View File

@ -75,20 +75,15 @@ export const useNetworkStore = defineStore('networkStore', {
loadFromLocalStorage() {
let networkList: NetworkConfig[]
try {
networkList = JSON.parse(localStorage.getItem('networkList') || '[{}]')
networkList = networkList.map((cfg) => {
return { ...DEFAULT_NETWORK_CONFIG(), ...cfg } as NetworkConfig
})
// if localStorage default is [{}], instanceId will be undefined
networkList = JSON.parse(localStorage.getItem('networkList') || '[]')
networkList = networkList.map((cfg) => {
return { ...DEFAULT_NETWORK_CONFIG(), ...cfg } as NetworkConfig
})
// prevent a empty list from localStorage, should not happen
if (networkList.length === 0) {
networkList = [DEFAULT_NETWORK_CONFIG()]
}
}
catch {
// prevent a empty list from localStorage, should not happen
if (networkList.length === 0)
networkList = [DEFAULT_NETWORK_CONFIG()]
}
this.networkList = networkList
this.curNetwork = this.networkList[0]