diff --git a/package.json b/package.json
index e582edf..7f1426b 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"@solid-primitives/keyed": "^1.2.0",
"@solid-primitives/media": "^2.2.5",
"@solid-primitives/storage": "^2.1.1",
+ "@solid-primitives/timer": "^1.3.7",
"@solid-primitives/websocket": "^1.1.0",
"@solidjs/router": "^0.8.3",
"@tabler/icons-solidjs": "^2.32.0",
@@ -28,6 +29,7 @@
"@tanstack/solid-virtual": "3.0.0-beta.6",
"@thisbeyond/solid-dnd": "^0.7.4",
"@types/byte-size": "^8.1.0",
+ "@types/lodash": "^4.14.197",
"@types/node": "^20.5.8",
"@types/uuid": "^9.0.3",
"@typescript-eslint/eslint-plugin": "^6.5.0",
@@ -45,6 +47,7 @@
"is-ip": "^5.0.1",
"ky": "^1.0.0",
"lint-staged": "^14.0.1",
+ "lodash": "^4.17.21",
"prettier": "^3.0.3",
"prettier-plugin-organize-imports": "^3.2.3",
"prettier-plugin-tailwindcss": "^0.5.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4e40290..9deecc8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,6 +35,9 @@ dependencies:
'@solid-primitives/storage':
specifier: ^2.1.1
version: 2.1.1(solid-js@1.7.11)
+ '@solid-primitives/timer':
+ specifier: ^1.3.7
+ version: 1.3.7(solid-js@1.7.11)
'@solid-primitives/websocket':
specifier: ^1.1.0
version: 1.1.0(solid-js@1.7.11)
@@ -56,6 +59,9 @@ dependencies:
'@types/byte-size':
specifier: ^8.1.0
version: 8.1.0
+ '@types/lodash':
+ specifier: ^4.14.197
+ version: 4.14.197
'@types/node':
specifier: ^20.5.8
version: 20.5.8
@@ -107,6 +113,9 @@ dependencies:
lint-staged:
specifier: ^14.0.1
version: 14.0.1
+ lodash:
+ specifier: ^4.17.21
+ version: 4.17.21
prettier:
specifier: ^3.0.3
version: 3.0.3
@@ -2655,6 +2664,17 @@ packages:
solid-js: 1.7.11
dev: false
+ /@solid-primitives/timer@1.3.7(solid-js@1.7.11):
+ resolution:
+ {
+ integrity: sha512-zS3qA7WVZYsW7+iTdk2M4W1wpMvRhdcMnO23Tcd+nX3YD7eMvjOnO15Oz2mymyfl/OC2ZgM1L5ec66GayEvPwQ==,
+ }
+ peerDependencies:
+ solid-js: ^1.6.12
+ dependencies:
+ solid-js: 1.7.11
+ dev: false
+
/@solid-primitives/utils@6.2.1(solid-js@1.7.11):
resolution:
{
@@ -2851,6 +2871,13 @@ packages:
}
dev: false
+ /@types/lodash@4.14.197:
+ resolution:
+ {
+ integrity: sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==,
+ }
+ dev: false
+
/@types/minimist@1.2.2:
resolution:
{
diff --git a/src/constants/index.ts b/src/constants/index.ts
index a2545ee..c05cf15 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -1,3 +1,6 @@
+import { ApexOptions } from 'apexcharts'
+import byteSize from 'byte-size'
+
export const themes = [
'light',
'dark',
@@ -40,6 +43,38 @@ export enum ROUTES {
Config = '/config',
}
+export const CHART_MAX_XAXIS = 10
+
+export const DEFAULT_CHART_OPTIONS: ApexOptions = {
+ title: { align: 'center', style: { color: 'gray' } },
+ chart: {
+ toolbar: { show: false },
+ zoom: { enabled: false },
+ animations: { easing: 'linear' },
+ },
+ noData: { text: 'Loading...' },
+ legend: {
+ fontSize: '14px',
+ labels: { colors: 'gray' },
+ itemMargin: { horizontal: 64 },
+ },
+ dataLabels: { enabled: false },
+ grid: { yaxis: { lines: { show: false } } },
+ stroke: { curve: 'smooth' },
+ tooltip: { enabled: false },
+ xaxis: {
+ range: CHART_MAX_XAXIS,
+ labels: { show: false },
+ axisTicks: { show: false },
+ },
+ yaxis: {
+ labels: {
+ style: { colors: 'gray' },
+ formatter: (val) => byteSize(val).toString(),
+ },
+ },
+}
+
export enum LATENCY_QUALITY_MAP_HTTP {
NOT_CONNECTED = -1,
MEDIUM = 200,
diff --git a/src/pages/Connections.tsx b/src/pages/Connections.tsx
index e6d4215..56c2cce 100644
--- a/src/pages/Connections.tsx
+++ b/src/pages/Connections.tsx
@@ -1,3 +1,4 @@
+import { writeClipboard } from '@solid-primitives/clipboard'
import { createEventSignal } from '@solid-primitives/event-listener'
import { useI18n } from '@solid-primitives/i18n'
import { makePersisted } from '@solid-primitives/storage'
@@ -304,7 +305,12 @@ export default () => {
{(cell) => (
-
+ | {
+ e.preventDefault()
+ writeClipboard(cell.renderValue() as string)
+ }}
+ >
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
diff --git a/src/pages/Overview.tsx b/src/pages/Overview.tsx
index 5a4eb5f..bc81f85 100644
--- a/src/pages/Overview.tsx
+++ b/src/pages/Overview.tsx
@@ -1,8 +1,10 @@
import { createEventSignal } from '@solid-primitives/event-listener'
import { useI18n } from '@solid-primitives/i18n'
+import { makeTimer } from '@solid-primitives/timer'
import { createReconnectingWS } from '@solid-primitives/websocket'
import type { ApexOptions } from 'apexcharts'
import byteSize from 'byte-size'
+import { merge } from 'lodash'
import { SolidApexCharts } from 'solid-apexcharts'
import {
JSX,
@@ -11,13 +13,11 @@ import {
createEffect,
createMemo,
createSignal,
- onCleanup,
} from 'solid-js'
+import { CHART_MAX_XAXIS, DEFAULT_CHART_OPTIONS } from '~/constants'
import { secret, wsEndpointURL } from '~/signals'
import type { Connection } from '~/types'
-const CHART_MAX_XAXIS = 10
-
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
{props.label}
@@ -34,26 +34,24 @@ export default () => {
[],
)
const [memories, setMemories] = createSignal ([])
+
// https://github.com/apexcharts/apexcharts.js/blob/main/samples/source/line/realtime.xml
// TODO: need a better way
- const preventLeakTimer = setInterval(
+ makeTimer(
() => {
setTraffics((traffics) => traffics.slice(-CHART_MAX_XAXIS))
setMemories((memo) => memo.slice(-CHART_MAX_XAXIS))
},
- // we shrink the chart data array size down every 10 minutes
+ // we shrink the chart data array size down every 10 minutes to prevent memory leaks
10 * 60 * 1000,
+ setInterval,
)
- onCleanup(() => clearInterval(preventLeakTimer))
-
const trafficWS = createReconnectingWS(
`${wsEndpointURL()}/traffic?token=${secret()}`,
)
- const trafficWSMessageEvent = createEventSignal<{
- message: WebSocketEventMap['message']
- }>(trafficWS, 'message')
+ const trafficWSMessageEvent = createEventSignal(trafficWS, 'message')
const traffic = () => {
const data = trafficWSMessageEvent()?.data
@@ -64,50 +62,12 @@ export default () => {
createEffect(() => {
const t = traffic()
- if (t) {
- setTraffics((traffics) => [...traffics, t])
- }
+ if (t) setTraffics((traffics) => [...traffics, t])
})
- const defaultChartOptions: ApexOptions = {
- chart: {
- toolbar: { show: false },
- zoom: { enabled: false },
- animations: { easing: 'linear' },
- },
- noData: { text: 'Loading...' },
- legend: {
- fontSize: '14px',
- labels: { colors: 'gray' },
- itemMargin: { horizontal: 64 },
- },
- dataLabels: { enabled: false },
- grid: { yaxis: { lines: { show: false } } },
- stroke: { curve: 'smooth' },
- tooltip: { enabled: false },
- xaxis: {
- range: CHART_MAX_XAXIS,
- labels: { show: false },
- axisTicks: { show: false },
- },
- yaxis: {
- labels: {
- style: { colors: 'gray' },
- formatter(val) {
- return byteSize(val).toString()
- },
- },
- },
- }
-
- const trafficChartOptions = createMemo(() => ({
- title: {
- text: t('traffic'),
- align: 'center',
- style: { color: 'gray' },
- },
- ...defaultChartOptions,
- }))
+ const trafficChartOptions = createMemo(() =>
+ merge({ title: { text: t('traffic') } }, DEFAULT_CHART_OPTIONS),
+ )
const trafficChartSeries = createMemo(() => [
{
@@ -124,9 +84,7 @@ export default () => {
`${wsEndpointURL()}/memory?token=${secret()}`,
)
- const memoryWSMessageEvent = createEventSignal<{
- message: WebSocketEventMap['message']
- }>(memoryWS, 'message')
+ const memoryWSMessageEvent = createEventSignal(memoryWS, 'message')
const memory = () => {
const data = memoryWSMessageEvent()?.data
@@ -137,19 +95,12 @@ export default () => {
createEffect(() => {
const m = memory()
- if (m) {
- setMemories((memories) => [...memories, m])
- }
+ if (m) setMemories((memories) => [...memories, m])
})
- const memoryChartOptions = createMemo(() => ({
- title: {
- text: t('memory'),
- align: 'center',
- style: { color: 'gray' },
- },
- ...defaultChartOptions,
- }))
+ const memoryChartOptions = createMemo(() =>
+ merge({ title: { text: t('memory') } }, DEFAULT_CHART_OPTIONS),
+ )
const memoryChartSeries = createMemo(() => [{ data: memories() }])
|