mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-14 06:25:35 +08:00
feat(connections): copy to clipboard on right click
This commit is contained in:
parent
3f90a81615
commit
58afb5fce2
@ -21,6 +21,7 @@
|
|||||||
"@solid-primitives/keyed": "^1.2.0",
|
"@solid-primitives/keyed": "^1.2.0",
|
||||||
"@solid-primitives/media": "^2.2.5",
|
"@solid-primitives/media": "^2.2.5",
|
||||||
"@solid-primitives/storage": "^2.1.1",
|
"@solid-primitives/storage": "^2.1.1",
|
||||||
|
"@solid-primitives/timer": "^1.3.7",
|
||||||
"@solid-primitives/websocket": "^1.1.0",
|
"@solid-primitives/websocket": "^1.1.0",
|
||||||
"@solidjs/router": "^0.8.3",
|
"@solidjs/router": "^0.8.3",
|
||||||
"@tabler/icons-solidjs": "^2.32.0",
|
"@tabler/icons-solidjs": "^2.32.0",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"@tanstack/solid-virtual": "3.0.0-beta.6",
|
"@tanstack/solid-virtual": "3.0.0-beta.6",
|
||||||
"@thisbeyond/solid-dnd": "^0.7.4",
|
"@thisbeyond/solid-dnd": "^0.7.4",
|
||||||
"@types/byte-size": "^8.1.0",
|
"@types/byte-size": "^8.1.0",
|
||||||
|
"@types/lodash": "^4.14.197",
|
||||||
"@types/node": "^20.5.8",
|
"@types/node": "^20.5.8",
|
||||||
"@types/uuid": "^9.0.3",
|
"@types/uuid": "^9.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
||||||
@ -45,6 +47,7 @@
|
|||||||
"is-ip": "^5.0.1",
|
"is-ip": "^5.0.1",
|
||||||
"ky": "^1.0.0",
|
"ky": "^1.0.0",
|
||||||
"lint-staged": "^14.0.1",
|
"lint-staged": "^14.0.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"prettier-plugin-organize-imports": "^3.2.3",
|
"prettier-plugin-organize-imports": "^3.2.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.4",
|
"prettier-plugin-tailwindcss": "^0.5.4",
|
||||||
|
@ -35,6 +35,9 @@ dependencies:
|
|||||||
'@solid-primitives/storage':
|
'@solid-primitives/storage':
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1(solid-js@1.7.11)
|
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':
|
'@solid-primitives/websocket':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(solid-js@1.7.11)
|
version: 1.1.0(solid-js@1.7.11)
|
||||||
@ -56,6 +59,9 @@ dependencies:
|
|||||||
'@types/byte-size':
|
'@types/byte-size':
|
||||||
specifier: ^8.1.0
|
specifier: ^8.1.0
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
|
'@types/lodash':
|
||||||
|
specifier: ^4.14.197
|
||||||
|
version: 4.14.197
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.5.8
|
specifier: ^20.5.8
|
||||||
version: 20.5.8
|
version: 20.5.8
|
||||||
@ -107,6 +113,9 @@ dependencies:
|
|||||||
lint-staged:
|
lint-staged:
|
||||||
specifier: ^14.0.1
|
specifier: ^14.0.1
|
||||||
version: 14.0.1
|
version: 14.0.1
|
||||||
|
lodash:
|
||||||
|
specifier: ^4.17.21
|
||||||
|
version: 4.17.21
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.0.3
|
specifier: ^3.0.3
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
@ -2655,6 +2664,17 @@ packages:
|
|||||||
solid-js: 1.7.11
|
solid-js: 1.7.11
|
||||||
dev: false
|
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):
|
/@solid-primitives/utils@6.2.1(solid-js@1.7.11):
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -2851,6 +2871,13 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/lodash@4.14.197:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==,
|
||||||
|
}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/minimist@1.2.2:
|
/@types/minimist@1.2.2:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { ApexOptions } from 'apexcharts'
|
||||||
|
import byteSize from 'byte-size'
|
||||||
|
|
||||||
export const themes = [
|
export const themes = [
|
||||||
'light',
|
'light',
|
||||||
'dark',
|
'dark',
|
||||||
@ -40,6 +43,38 @@ export enum ROUTES {
|
|||||||
Config = '/config',
|
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 {
|
export enum LATENCY_QUALITY_MAP_HTTP {
|
||||||
NOT_CONNECTED = -1,
|
NOT_CONNECTED = -1,
|
||||||
MEDIUM = 200,
|
MEDIUM = 200,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { writeClipboard } from '@solid-primitives/clipboard'
|
||||||
import { createEventSignal } from '@solid-primitives/event-listener'
|
import { createEventSignal } from '@solid-primitives/event-listener'
|
||||||
import { useI18n } from '@solid-primitives/i18n'
|
import { useI18n } from '@solid-primitives/i18n'
|
||||||
import { makePersisted } from '@solid-primitives/storage'
|
import { makePersisted } from '@solid-primitives/storage'
|
||||||
@ -304,7 +305,12 @@ export default () => {
|
|||||||
<tr class="hover">
|
<tr class="hover">
|
||||||
<For each={row.getVisibleCells()}>
|
<For each={row.getVisibleCells()}>
|
||||||
{(cell) => (
|
{(cell) => (
|
||||||
<td>
|
<td
|
||||||
|
onContextMenu={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
writeClipboard(cell.renderValue() as string)
|
||||||
|
}}
|
||||||
|
>
|
||||||
{flexRender(
|
{flexRender(
|
||||||
cell.column.columnDef.cell,
|
cell.column.columnDef.cell,
|
||||||
cell.getContext(),
|
cell.getContext(),
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { createEventSignal } from '@solid-primitives/event-listener'
|
import { createEventSignal } from '@solid-primitives/event-listener'
|
||||||
import { useI18n } from '@solid-primitives/i18n'
|
import { useI18n } from '@solid-primitives/i18n'
|
||||||
|
import { makeTimer } from '@solid-primitives/timer'
|
||||||
import { createReconnectingWS } from '@solid-primitives/websocket'
|
import { createReconnectingWS } from '@solid-primitives/websocket'
|
||||||
import type { ApexOptions } from 'apexcharts'
|
import type { ApexOptions } from 'apexcharts'
|
||||||
import byteSize from 'byte-size'
|
import byteSize from 'byte-size'
|
||||||
|
import { merge } from 'lodash'
|
||||||
import { SolidApexCharts } from 'solid-apexcharts'
|
import { SolidApexCharts } from 'solid-apexcharts'
|
||||||
import {
|
import {
|
||||||
JSX,
|
JSX,
|
||||||
@ -11,13 +13,11 @@ import {
|
|||||||
createEffect,
|
createEffect,
|
||||||
createMemo,
|
createMemo,
|
||||||
createSignal,
|
createSignal,
|
||||||
onCleanup,
|
|
||||||
} from 'solid-js'
|
} from 'solid-js'
|
||||||
|
import { CHART_MAX_XAXIS, DEFAULT_CHART_OPTIONS } from '~/constants'
|
||||||
import { secret, wsEndpointURL } from '~/signals'
|
import { secret, wsEndpointURL } from '~/signals'
|
||||||
import type { Connection } from '~/types'
|
import type { Connection } from '~/types'
|
||||||
|
|
||||||
const CHART_MAX_XAXIS = 10
|
|
||||||
|
|
||||||
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
|
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
|
||||||
<div class="stat flex-1">
|
<div class="stat flex-1">
|
||||||
<div class="stat-title text-primary-content">{props.label}</div>
|
<div class="stat-title text-primary-content">{props.label}</div>
|
||||||
@ -34,26 +34,24 @@ export default () => {
|
|||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
const [memories, setMemories] = createSignal<number[]>([])
|
const [memories, setMemories] = createSignal<number[]>([])
|
||||||
|
|
||||||
// https://github.com/apexcharts/apexcharts.js/blob/main/samples/source/line/realtime.xml
|
// https://github.com/apexcharts/apexcharts.js/blob/main/samples/source/line/realtime.xml
|
||||||
// TODO: need a better way
|
// TODO: need a better way
|
||||||
const preventLeakTimer = setInterval(
|
makeTimer(
|
||||||
() => {
|
() => {
|
||||||
setTraffics((traffics) => traffics.slice(-CHART_MAX_XAXIS))
|
setTraffics((traffics) => traffics.slice(-CHART_MAX_XAXIS))
|
||||||
setMemories((memo) => memo.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,
|
10 * 60 * 1000,
|
||||||
|
setInterval,
|
||||||
)
|
)
|
||||||
|
|
||||||
onCleanup(() => clearInterval(preventLeakTimer))
|
|
||||||
|
|
||||||
const trafficWS = createReconnectingWS(
|
const trafficWS = createReconnectingWS(
|
||||||
`${wsEndpointURL()}/traffic?token=${secret()}`,
|
`${wsEndpointURL()}/traffic?token=${secret()}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const trafficWSMessageEvent = createEventSignal<{
|
const trafficWSMessageEvent = createEventSignal(trafficWS, 'message')
|
||||||
message: WebSocketEventMap['message']
|
|
||||||
}>(trafficWS, 'message')
|
|
||||||
|
|
||||||
const traffic = () => {
|
const traffic = () => {
|
||||||
const data = trafficWSMessageEvent()?.data
|
const data = trafficWSMessageEvent()?.data
|
||||||
@ -64,50 +62,12 @@ export default () => {
|
|||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const t = traffic()
|
const t = traffic()
|
||||||
|
|
||||||
if (t) {
|
if (t) setTraffics((traffics) => [...traffics, t])
|
||||||
setTraffics((traffics) => [...traffics, t])
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const defaultChartOptions: ApexOptions = {
|
const trafficChartOptions = createMemo<ApexOptions>(() =>
|
||||||
chart: {
|
merge({ title: { text: t('traffic') } }, DEFAULT_CHART_OPTIONS),
|
||||||
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<ApexOptions>(() => ({
|
|
||||||
title: {
|
|
||||||
text: t('traffic'),
|
|
||||||
align: 'center',
|
|
||||||
style: { color: 'gray' },
|
|
||||||
},
|
|
||||||
...defaultChartOptions,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const trafficChartSeries = createMemo(() => [
|
const trafficChartSeries = createMemo(() => [
|
||||||
{
|
{
|
||||||
@ -124,9 +84,7 @@ export default () => {
|
|||||||
`${wsEndpointURL()}/memory?token=${secret()}`,
|
`${wsEndpointURL()}/memory?token=${secret()}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const memoryWSMessageEvent = createEventSignal<{
|
const memoryWSMessageEvent = createEventSignal(memoryWS, 'message')
|
||||||
message: WebSocketEventMap['message']
|
|
||||||
}>(memoryWS, 'message')
|
|
||||||
|
|
||||||
const memory = () => {
|
const memory = () => {
|
||||||
const data = memoryWSMessageEvent()?.data
|
const data = memoryWSMessageEvent()?.data
|
||||||
@ -137,19 +95,12 @@ export default () => {
|
|||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const m = memory()
|
const m = memory()
|
||||||
|
|
||||||
if (m) {
|
if (m) setMemories((memories) => [...memories, m])
|
||||||
setMemories((memories) => [...memories, m])
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const memoryChartOptions = createMemo<ApexOptions>(() => ({
|
const memoryChartOptions = createMemo<ApexOptions>(() =>
|
||||||
title: {
|
merge({ title: { text: t('memory') } }, DEFAULT_CHART_OPTIONS),
|
||||||
text: t('memory'),
|
)
|
||||||
align: 'center',
|
|
||||||
style: { color: 'gray' },
|
|
||||||
},
|
|
||||||
...defaultChartOptions,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const memoryChartSeries = createMemo(() => [{ data: memories() }])
|
const memoryChartSeries = createMemo(() => [{ data: memories() }])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user