Skip to content

Commit

Permalink
feat: charts in settings & fix websocket reactive
Browse files Browse the repository at this point in the history
  • Loading branch information
Zephyruso committed Dec 8, 2024
1 parent 94e2433 commit e406e14
Show file tree
Hide file tree
Showing 16 changed files with 293 additions and 111 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@heroicons/vue": "^2.2.0",
"@tanstack/vue-table": "^8.20.5",
"@types/echarts": "^4.9.22",
"@types/reconnectingwebsocket": "^1.0.10",
"@vueuse/core": "^12.0.0",
"axios": "^1.7.8",
"dayjs": "^1.11.13",
Expand All @@ -28,6 +29,7 @@
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-tailwindcss": "^0.6.9",
"pretty-bytes": "^6.1.1",
"reconnectingwebsocket": "^1.0.0",
"subsetted-fonts": "^1.0.4",
"theme-change": "^2.5.0",
"uuid": "^11.0.3",
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 16 additions & 5 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { activeBackend } from '@/store/setup'
import type { Config, Proxy, ProxyProvider, Rule, RuleProvider } from '@/types'
import { useWebSocket } from '@vueuse/core'
import axios from 'axios'
import ReconnectingWebSocket from 'reconnectingwebsocket'
import { computed, ref, watch } from 'vue'

axios.interceptors.request.use((config) => {
Expand Down Expand Up @@ -136,10 +136,21 @@ const createWebSocket = <T>(url: string, searchParams?: Record<string, string>)
})
}

return useWebSocket<T>(resurl, {
autoClose: false,
autoReconnect: true,
})
const data = ref<T>()
const websocket = new ReconnectingWebSocket(resurl.toString())

const close = () => {
websocket.close()
}

websocket.onmessage = ({ data: message }) => {
data.value = JSON.parse(message)
}

return {
data,
close,
}
}

export const fetchConnectionsAPI = <T>() => {
Expand Down
116 changes: 116 additions & 0 deletions src/components/charts/MemoryCharts.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<template>
<div
ref="chart"
class="card h-28 w-full bg-base-100 p-0 shadow-lg"
></div>
<span
class="hidden text-base-content"
ref="text"
></span>
</template>

<script setup lang="ts">
import { prettyBytesHelper } from '@/helper'
import { theme } from '@/store/settings'
import { memoryHistory } from '@/store/statistics'
import { useElementSize } from '@vueuse/core'
import { LineChart } from 'echarts/charts'
import { GridComponent, LegendComponent } from 'echarts/components'
import * as echarts from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { debounce } from 'lodash'
import { computed, onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
echarts.use([LineChart, GridComponent, LegendComponent, CanvasRenderer])
const text = ref()
const t = useI18n().t
const chart = ref()
onMounted(() => {
let color = getComputedStyle(text.value)?.color
watch(
() => theme.value,
() => {
color = getComputedStyle(text.value)?.color
},
)
const options = computed(() => {
return {
legend: {
bottom: 0,
data: [t('memoryUsage')],
textStyle: {
color: color,
},
},
grid: {
left: 60,
top: 15,
right: 10,
bottom: 25,
},
xAxis: {
type: 'category',
axisLine: { show: false },
axisLabel: { show: false },
splitLine: { show: false },
axisTick: { show: false },
},
yAxis: {
type: 'value',
splitNumber: 4,
max: (value: { max: number }) => {
return Math.max(value.max, 100 * 1024)
},
axisLine: { show: false },
axisLabel: {
align: 'left',
padding: [0, 0, 0, -45],
formatter: (value: number) => {
return `${prettyBytesHelper(value, {
maximumFractionDigits: 1,
binary: true,
})}`
},
color: color,
},
splitLine: { show: false },
},
series: [
{
name: t('memoryUsage'),
data: memoryHistory.value,
symbol: 'none',
emphasis: {
disabled: true,
},
type: 'line',
color: color,
smooth: true,
},
],
}
})
const myChart = echarts.init(chart.value)
myChart.setOption(options.value)
watch(options, () => {
myChart?.setOption(options.value)
})
const { width } = useElementSize(chart)
const resize = debounce(() => {
myChart.resize()
}, 100)
watch(
() => width.value,
() => {
resize()
},
)
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

<script setup lang="ts">
import { prettyBytesHelper } from '@/helper'
import { theme } from '@/store/settings'
import { downloadSpeedHistory, uploadSpeedHistory } from '@/store/statistics'
import { useElementSize } from '@vueuse/core'
import { LineChart } from 'echarts/charts'
Expand All @@ -39,17 +40,28 @@ const t = useI18n().t
const chart = ref()
onMounted(() => {
const options = computed(() => {
const color = getComputedStyle(text.value)?.color
const primaryColor = getComputedStyle(primaryText.value)?.color
const secondaryColor = getComputedStyle(secondaryText.value)?.color
const colorMap = {
color: getComputedStyle(text.value)?.color,
primaryColor: getComputedStyle(primaryText.value)?.color,
secondaryColor: getComputedStyle(secondaryText.value)?.color,
}
watch(
() => theme.value,
() => {
colorMap.color = getComputedStyle(text.value)?.color
colorMap.primaryColor = getComputedStyle(primaryText.value)?.color
colorMap.secondaryColor = getComputedStyle(secondaryText.value)?.color
},
)
const options = computed(() => {
return {
legend: {
bottom: 0,
data: [t('download'), t('upload')],
textStyle: {
color: color,
color: colorMap.color,
},
},
grid: {
Expand Down Expand Up @@ -80,7 +92,7 @@ onMounted(() => {
maximumFractionDigits: 1,
})}/s`
},
color: color,
color: colorMap.color,
},
splitLine: { show: false },
},
Expand All @@ -93,7 +105,7 @@ onMounted(() => {
disabled: true,
},
type: 'line',
color: secondaryColor,
color: colorMap.secondaryColor,
smooth: true,
},
{
Expand All @@ -104,7 +116,7 @@ onMounted(() => {
disabled: true,
},
type: 'line',
color: primaryColor,
color: colorMap.primaryColor,
smooth: true,
},
],
Expand All @@ -115,7 +127,7 @@ onMounted(() => {
myChart.setOption(options.value)
watch(options, () => {
myChart.setOption(options.value)
myChart?.setOption(options.value)
})
const { width } = useElementSize(chart)
Expand Down
14 changes: 2 additions & 12 deletions src/components/sidebar/CommonCtrl.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
<template>
<div class="flex flex-col gap-2 p-2 text-xs">
<div class="grid grid-cols-2 gap-2">
<div>{{ $t('connections') }}: {{ activeConnections.length }}</div>
<div>{{ $t('memoryUsage') }}: {{ prettyBytesHelper(memory, { binary: true }) }}</div>
<div>{{ $t('download') }}: {{ prettyBytesHelper(downloadTotal) }}</div>
<div>{{ $t('dlSpeed') }}: {{ prettyBytesHelper(downloadSpeed) }}/s</div>
<div>{{ $t('upload') }}: {{ prettyBytesHelper(uploadTotal) }}</div>
<div>{{ $t('ulSpeed') }}: {{ prettyBytesHelper(uploadSpeed) }}/s</div>
</div>

<StatisticsInfo />
<div class="flex gap-1">
{{ $t('version') }}:
<img
Expand All @@ -34,10 +26,8 @@
import { isSingBox, version } from '@/api'
import MetacubexLogo from '@/assets/metacubex.jpeg'
import SingBoxLogo from '@/assets/sing-box.svg'
import { prettyBytesHelper } from '@/helper'
import { activeConnections, downloadTotal, uploadTotal } from '@/store/connections'
import { isSiderbarCollapsed } from '@/store/settings'
import { downloadSpeed, memory, uploadSpeed } from '@/store/statistics'
import { ArrowLeftCircleIcon } from '@heroicons/vue/24/outline'
import BackendSwitch from '../settings/BackendSwitch.vue'
import StatisticsInfo from './StatisticsInfo.vue'
</script>
23 changes: 4 additions & 19 deletions src/components/sidebar/SideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@click="() => router.push({ name: r })"
>
<component
:is="routeIconMap[r]"
:is="ROUTE_ICON_MAP[r]"
class="h-5 w-5"
/>
<template v-if="!isSiderbarCollapsed">
Expand All @@ -43,29 +43,22 @@
/>
<CommonSidebar />
</div>
<SpeedCharts />
<SpeedCharts v-if="route.name !== ROUTE_NAME.settings" />
</template>
</div>
</div>
</template>

<script setup lang="ts">
import SpeedCharts from '@/components/charts/SpeedCharts.vue'
import CommonSidebar from '@/components/sidebar/CommonCtrl.vue'
import ConnectionCtrl from '@/components/sidebar/ConnectionCtrl.vue'
import LogsCtrl from '@/components/sidebar/LogsCtrl.vue'
import ProxiesCtrl from '@/components/sidebar/ProxiesCtrl.vue'
import RulesCtrl from '@/components/sidebar/RulesCtrl.vue'
import SpeedCharts from '@/components/sidebar/SpeedCharts.vue'
import { ROUTE_NAME } from '@/config'
import { ROUTE_ICON_MAP, ROUTE_NAME } from '@/config'
import router from '@/router'
import { isSiderbarCollapsed } from '@/store/settings'
import {
ArrowsRightLeftIcon,
Cog6ToothIcon,
DocumentTextIcon,
GlobeAltIcon,
WrenchScrewdriverIcon,
} from '@heroicons/vue/24/outline'
import { twMerge } from 'tailwind-merge'
import { computed } from 'vue'
import { useRoute } from 'vue-router'
Expand All @@ -78,14 +71,6 @@ const sidebarCompMap = {
[ROUTE_NAME.rules]: RulesCtrl,
}
const routeIconMap = {
[ROUTE_NAME.proxies]: GlobeAltIcon,
[ROUTE_NAME.connections]: ArrowsRightLeftIcon,
[ROUTE_NAME.rules]: WrenchScrewdriverIcon,
[ROUTE_NAME.logs]: DocumentTextIcon,
[ROUTE_NAME.settings]: Cog6ToothIcon,
}
const sidebarComp = computed(() => {
if (route.name) {
return sidebarCompMap[route.name as keyof typeof sidebarCompMap]
Expand Down
Loading

0 comments on commit e406e14

Please sign in to comment.