mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 14:01:56 +08:00
Feature: show process name and path in connections page (#95)
Co-authored-by: MetaCubeX <maze.y2b@github.com>
This commit is contained in:
parent
542aa21330
commit
5ba5058c70
@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { formatTraffic } from '@lib/helper'
|
||||
import { basePath, formatTraffic } from '@lib/helper'
|
||||
import { BaseComponentProps } from '@models'
|
||||
import { useI18n } from '@stores'
|
||||
|
||||
@ -18,21 +18,21 @@ export function ConnectionInfo (props: ConnectionsInfoProps) {
|
||||
return (
|
||||
<div className={classnames(props.className, 'text-sm flex flex-col')}>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.id')}</span>
|
||||
<span className="font-bold w-20">{t('info.id')}</span>
|
||||
<span className="font-mono">{props.connection.id}</span>
|
||||
</div>
|
||||
<div className="flex my-3 justify-between">
|
||||
<div className="flex flex-1">
|
||||
<span className="font-bold w-16">{t('info.network')}</span>
|
||||
<span className="font-bold w-20">{t('info.network')}</span>
|
||||
<span className="font-mono">{props.connection.metadata?.network}</span>
|
||||
</div>
|
||||
<div className="flex flex-1">
|
||||
<span className="font-bold w-16">{t('info.inbound')}</span>
|
||||
<span className="font-bold w-20">{t('info.inbound')}</span>
|
||||
<span className="font-mono">{props.connection.metadata?.type}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.host')}</span>
|
||||
<span className="font-bold w-20">{t('info.host')}</span>
|
||||
<span className="font-mono flex-1 break-all">{
|
||||
props.connection.metadata?.host
|
||||
? `${props.connection.metadata.host}:${props.connection.metadata?.destinationPort}`
|
||||
@ -40,7 +40,7 @@ export function ConnectionInfo (props: ConnectionsInfoProps) {
|
||||
}</span>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.dstIP')}</span>
|
||||
<span className="font-bold w-20">{t('info.dstIP')}</span>
|
||||
<span className="font-mono">{
|
||||
props.connection.metadata?.destinationIP
|
||||
? `${props.connection.metadata.destinationIP}:${props.connection.metadata?.destinationPort}`
|
||||
@ -48,35 +48,51 @@ export function ConnectionInfo (props: ConnectionsInfoProps) {
|
||||
}</span>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.srcIP')}</span>
|
||||
<span className="font-bold w-20">{t('info.srcIP')}</span>
|
||||
<span className="font-mono">{
|
||||
`${props.connection.metadata?.sourceIP}:${props.connection.metadata?.sourcePort}`
|
||||
}</span>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.rule')}</span>
|
||||
<span className="font-bold w-20">{t('info.process')}</span>
|
||||
<span className="font-mono">{
|
||||
props.connection.metadata?.processPath
|
||||
? `${basePath(props.connection.metadata.processPath)}`
|
||||
: t('info.hostEmpty')
|
||||
}</span>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-20">{t('info.processPath')}</span>
|
||||
<span className="font-mono flex-1 break-all">{
|
||||
props.connection.metadata?.processPath
|
||||
? `${props.connection.metadata.processPath}`
|
||||
: t('info.hostEmpty')
|
||||
}</span>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-20">{t('info.rule')}</span>
|
||||
<span className="font-mono">
|
||||
{ props.connection.rule && `${props.connection.rule}${props.connection.rulePayload && `(${props.connection.rulePayload})`}` }
|
||||
{ props.connection.rule && `${props.connection.rule}${props.connection.rulePayload && ` :: ${props.connection.rulePayload}`}` }
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.chains')}</span>
|
||||
<span className="font-bold w-20">{t('info.chains')}</span>
|
||||
<span className="font-mono flex-1 break-all">
|
||||
{ props.connection.chains?.slice().reverse().join(' / ') }
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex my-3 justify-between">
|
||||
<div className="flex flex-1">
|
||||
<span className="font-bold w-16">{t('info.upload')}</span>
|
||||
<span className="font-bold w-20">{t('info.upload')}</span>
|
||||
<span className="font-mono">{formatTraffic(props.connection.upload ?? 0)}</span>
|
||||
</div>
|
||||
<div className="flex flex-1">
|
||||
<span className="font-bold w-16">{t('info.download')}</span>
|
||||
<span className="font-bold w-20">{t('info.download')}</span>
|
||||
<span className="font-mono">{formatTraffic(props.connection.download ?? 0)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex my-3">
|
||||
<span className="font-bold w-16">{t('info.status')}</span>
|
||||
<span className="font-bold w-20">{t('info.status')}</span>
|
||||
<span className="font-mono">{
|
||||
!props.connection.completed
|
||||
? <span className="text-green">{t('info.opening')}</span>
|
||||
|
@ -7,10 +7,10 @@ import { useMemo, useLayoutEffect, useRef, useState, useEffect } from 'react'
|
||||
|
||||
import { Header, Checkbox, Modal, Icon, Drawer, Card, Button } from '@components'
|
||||
import { fromNow } from '@lib/date'
|
||||
import { formatTraffic } from '@lib/helper'
|
||||
import { basePath, formatTraffic } from '@lib/helper'
|
||||
import { useObject, useVisible } from '@lib/hook'
|
||||
import * as API from '@lib/request'
|
||||
import { BaseComponentProps, RuleType } from '@models'
|
||||
import { BaseComponentProps } from '@models'
|
||||
import { useClient, useConnectionStreamReader, useI18n } from '@stores'
|
||||
|
||||
import { Devices } from './Devices'
|
||||
@ -21,6 +21,7 @@ import './style.scss'
|
||||
enum Columns {
|
||||
Host = 'host',
|
||||
Network = 'network',
|
||||
Process = 'process',
|
||||
Type = 'type',
|
||||
Chains = 'chains',
|
||||
Rule = 'rule',
|
||||
@ -31,7 +32,7 @@ enum Columns {
|
||||
Time = 'time',
|
||||
}
|
||||
|
||||
const shouldCenter = new Set<string>([Columns.Network, Columns.Type, Columns.Rule, Columns.Speed, Columns.Upload, Columns.Download, Columns.SourceIP, Columns.Time])
|
||||
const shouldCenter = new Set<string>([Columns.Network, Columns.Type, Columns.Speed, Columns.Upload, Columns.Download, Columns.SourceIP, Columns.Time, Columns.Process])
|
||||
|
||||
function formatSpeed (upload: number, download: number) {
|
||||
switch (true) {
|
||||
@ -74,13 +75,14 @@ export default function Connections () {
|
||||
id: c.id,
|
||||
host: `${c.metadata.host || c.metadata.destinationIP}:${c.metadata.destinationPort}`,
|
||||
chains: c.chains.slice().reverse().join(' / '),
|
||||
rule: c.rule === RuleType.RuleSet ? `${c.rule}(${c.rulePayload})` : c.rule,
|
||||
rule: c.rulePayload ? `${c.rule} :: ${c.rulePayload}` : c.rule,
|
||||
time: new Date(c.start).getTime(),
|
||||
upload: c.upload,
|
||||
download: c.download,
|
||||
sourceIP: c.metadata.sourceIP,
|
||||
type: c.metadata.type,
|
||||
network: c.metadata.network.toUpperCase(),
|
||||
process: c.metadata.processPath,
|
||||
speed: { upload: c.uploadSpeed, download: c.downloadSpeed },
|
||||
completed: !!c.completed,
|
||||
original: c,
|
||||
@ -100,9 +102,10 @@ export default function Connections () {
|
||||
() => table.createColumns([
|
||||
table.createDataColumn(Columns.Host, { minWidth: 260, width: 260, header: t(`columns.${Columns.Host}`) }),
|
||||
table.createDataColumn(Columns.Network, { minWidth: 80, width: 80, header: t(`columns.${Columns.Network}`) }),
|
||||
table.createDataColumn(Columns.Type, { minWidth: 120, width: 120, header: t(`columns.${Columns.Type}`) }),
|
||||
table.createDataColumn(Columns.Type, { minWidth: 100, width: 100, header: t(`columns.${Columns.Type}`) }),
|
||||
table.createDataColumn(Columns.Chains, { minWidth: 200, width: 200, header: t(`columns.${Columns.Chains}`) }),
|
||||
table.createDataColumn(Columns.Rule, { minWidth: 140, width: 140, header: t(`columns.${Columns.Rule}`) }),
|
||||
table.createDataColumn(Columns.Process, { minWidth: 100, width: 100, header: t(`columns.${Columns.Process}`), cell: cell => cell.value ? basePath(cell.value) : '-' }),
|
||||
table.createDataColumn(
|
||||
row => [row.speed.upload, row.speed.download],
|
||||
{
|
||||
@ -163,7 +166,7 @@ export default function Connections () {
|
||||
sortRowsFn,
|
||||
columnFilterRowsFn,
|
||||
initialState: {
|
||||
sorting: [{ id: Columns.Time, desc: true }],
|
||||
sorting: [{ id: Columns.Time, desc: false }],
|
||||
},
|
||||
columnResizeMode: 'onChange',
|
||||
enableColumnResizing: true,
|
||||
|
@ -15,6 +15,7 @@ export interface FormatConnection {
|
||||
download: number
|
||||
type: string
|
||||
network: string
|
||||
process?: string
|
||||
sourceIP: string
|
||||
speed: {
|
||||
upload: number
|
||||
|
@ -68,6 +68,7 @@ const EN = {
|
||||
network: 'Network',
|
||||
type: 'Type',
|
||||
chains: 'Chains',
|
||||
process: 'Process',
|
||||
rule: 'Rule',
|
||||
time: 'Time',
|
||||
speed: 'Speed',
|
||||
@ -86,6 +87,8 @@ const EN = {
|
||||
upload: 'Upload',
|
||||
download: 'Download',
|
||||
network: 'Network',
|
||||
process: 'Process',
|
||||
processPath: 'Path',
|
||||
inbound: 'Inbound',
|
||||
rule: 'Rule',
|
||||
chains: 'Chains',
|
||||
|
@ -66,6 +66,7 @@ const CN = {
|
||||
columns: {
|
||||
host: '域名',
|
||||
network: '网络',
|
||||
process: '进程',
|
||||
type: '类型',
|
||||
chains: '节点链',
|
||||
rule: '规则',
|
||||
@ -86,6 +87,8 @@ const CN = {
|
||||
upload: '上传',
|
||||
download: '下载',
|
||||
network: '网络',
|
||||
process: '进程',
|
||||
processPath: '路径',
|
||||
inbound: '入口',
|
||||
rule: '规则',
|
||||
chains: '代理',
|
||||
|
@ -17,3 +17,7 @@ export function formatTraffic (num: number) {
|
||||
const exp = Math.floor(Math.log(num || 1) / Math.log(1024))
|
||||
return `${floor(num / Math.pow(1024, exp), 2).toFixed(2)} ${s?.[exp] ?? ''}`
|
||||
}
|
||||
|
||||
export function basePath (path: string) {
|
||||
return path.replace(/.*[/\\]/, '')
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ interface History {
|
||||
|
||||
export interface Proxy {
|
||||
name: string
|
||||
type: 'Direct' | 'Reject' | 'Shadowsocks' | 'Vmess' | 'Socks' | 'Http' | 'Snell'
|
||||
type: 'Direct' | 'Reject' | 'Shadowsocks' | 'Vmess' | 'Trojan' | 'Socks' | 'Http' | 'Snell'
|
||||
history: History[]
|
||||
}
|
||||
|
||||
@ -80,6 +80,7 @@ export interface Connections {
|
||||
network: string
|
||||
type: string
|
||||
host: string
|
||||
processPath?: string
|
||||
sourceIP: string
|
||||
sourcePort: string
|
||||
destinationPort: string
|
||||
|
Loading…
x
Reference in New Issue
Block a user