mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 21:20:29 +08:00
add rule copy
This commit is contained in:
parent
148f4f217e
commit
4c51a4a611
@ -1,102 +1,218 @@
|
||||
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react'
|
||||
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem } from '@nextui-org/react'
|
||||
import React from 'react'
|
||||
import SettingItem from '../base/base-setting-item'
|
||||
import { calcTraffic } from '@renderer/utils/calc'
|
||||
import dayjs from 'dayjs'
|
||||
import { BiCopy } from 'react-icons/bi'
|
||||
|
||||
interface Props {
|
||||
connection: IMihomoConnectionDetail
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const CopyableSettingItem: React.FC<{
|
||||
title: string
|
||||
value: string
|
||||
displayName?: string
|
||||
prefix?: string[]
|
||||
suffix?: string
|
||||
}> = ({ title, value, displayName, prefix = [], suffix = '' }) => {
|
||||
const getSubDomains = (domain: string) =>
|
||||
domain.split('.').length <= 2
|
||||
? [domain]
|
||||
: domain.split('.').map((_, i, parts) => parts.slice(i).join('.')).slice(0, -1)
|
||||
|
||||
const menuItems = [
|
||||
{ key: 'raw', text: value },
|
||||
...prefix.flatMap(p =>
|
||||
(p === 'DOMAIN-SUFFIX' ? getSubDomains(value) : [value]).map(v => ({
|
||||
key: `${p},${v}${suffix}`,
|
||||
text: `${p},${v}${suffix}`
|
||||
}))
|
||||
)
|
||||
]
|
||||
|
||||
return (
|
||||
<SettingItem
|
||||
title={title}
|
||||
actions={
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Button title='复制规则' isIconOnly size='sm' variant='light'>
|
||||
<BiCopy className='text-lg' />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
onAction={key =>
|
||||
navigator.clipboard.writeText(key === 'raw' ? value : key as string)
|
||||
}
|
||||
>
|
||||
{menuItems.map(({ key, text }) => (
|
||||
<DropdownItem key={key}>{text}</DropdownItem>
|
||||
))}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
}
|
||||
>
|
||||
{displayName || value}
|
||||
</SettingItem>
|
||||
)
|
||||
}
|
||||
|
||||
const ConnectionDetailModal: React.FC<Props> = (props) => {
|
||||
const { connection, onClose } = props
|
||||
return (
|
||||
<Modal
|
||||
backdrop="blur"
|
||||
backdrop='blur'
|
||||
classNames={{ backdrop: 'top-[48px]' }}
|
||||
size="xl"
|
||||
size='xl'
|
||||
hideCloseButton
|
||||
isOpen={true}
|
||||
onOpenChange={onClose}
|
||||
scrollBehavior="inside"
|
||||
scrollBehavior='inside'
|
||||
>
|
||||
<ModalContent className="flag-emoji break-all">
|
||||
<ModalHeader className="flex app-drag">连接详情</ModalHeader>
|
||||
<ModalContent className='flag-emoji break-all'>
|
||||
<ModalHeader className='flex app-drag'>连接详情</ModalHeader>
|
||||
<ModalBody>
|
||||
<SettingItem title="连接类型">
|
||||
{connection.metadata.type}({connection.metadata.network})
|
||||
</SettingItem>
|
||||
<SettingItem title="连接建立时间">{dayjs(connection.start).fromNow()}</SettingItem>
|
||||
<SettingItem title="规则">
|
||||
<SettingItem title='连接建立时间'>{dayjs(connection.start).fromNow()}</SettingItem>
|
||||
<SettingItem title='规则'>
|
||||
{connection.rule}
|
||||
{connection.rulePayload ? `(${connection.rulePayload})` : ''}
|
||||
</SettingItem>
|
||||
<SettingItem title="代理链">{[...connection.chains].reverse().join('>>')}</SettingItem>
|
||||
<SettingItem title="上传速度">{calcTraffic(connection.uploadSpeed || 0)}/s</SettingItem>
|
||||
<SettingItem title="下载速度">{calcTraffic(connection.downloadSpeed || 0)}/s</SettingItem>
|
||||
<SettingItem title="上传量">{calcTraffic(connection.upload)}</SettingItem>
|
||||
<SettingItem title="下载量">{calcTraffic(connection.download)}</SettingItem>
|
||||
<SettingItem title='代理链'>{[...connection.chains].reverse().join('>>')}</SettingItem>
|
||||
<SettingItem title='上传速度'>{calcTraffic(connection.uploadSpeed || 0)}/s</SettingItem>
|
||||
<SettingItem title='下载速度'>{calcTraffic(connection.downloadSpeed || 0)}/s</SettingItem>
|
||||
<SettingItem title='上传量'>{calcTraffic(connection.upload)}</SettingItem>
|
||||
<SettingItem title='下载量'>{calcTraffic(connection.download)}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='连接类型'
|
||||
value={connection.metadata.type}
|
||||
displayName={`${connection.metadata.type}(${connection.metadata.network})`}
|
||||
prefix={['IN-TYPE']}
|
||||
/>
|
||||
{connection.metadata.host && (
|
||||
<CopyableSettingItem
|
||||
title='主机'
|
||||
value={connection.metadata.host}
|
||||
prefix={['DOMAIN', 'DOMAIN-SUFFIX']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.sniffHost && (
|
||||
<CopyableSettingItem
|
||||
title='嗅探主机'
|
||||
value={connection.metadata.sniffHost}
|
||||
prefix={['DOMAIN', 'DOMAIN-SUFFIX']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.process && (
|
||||
<SettingItem title="进程名">
|
||||
{connection.metadata.process}
|
||||
{connection.metadata.uid ? `(${connection.metadata.uid})` : ''}
|
||||
</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='进程名'
|
||||
value={connection.metadata.process}
|
||||
displayName={`${connection.metadata.process}${connection.metadata.uid ? `(${connection.metadata.uid})` : ''}`}
|
||||
prefix={['PROCESS-NAME']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.processPath && (
|
||||
<SettingItem title="进程路径">{connection.metadata.processPath}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='进程路径'
|
||||
value={connection.metadata.processPath}
|
||||
prefix={['PROCESS-PATH']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.sourceIP && (
|
||||
<SettingItem title="源IP">{connection.metadata.sourceIP}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='来源IP'
|
||||
value={connection.metadata.sourceIP}
|
||||
prefix={['SRC-IP-CIDR']}
|
||||
suffix='/32'
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.destinationIP && (
|
||||
<SettingItem title="目标IP">{connection.metadata.destinationIP}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='目标IP'
|
||||
value={connection.metadata.destinationIP}
|
||||
prefix={['IP-CIDR']}
|
||||
suffix='/32'
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.destinationGeoIP && (
|
||||
<SettingItem title="目标GeoIP">{connection.metadata.destinationGeoIP}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='目标GeoIP'
|
||||
value={connection.metadata.destinationGeoIP}
|
||||
prefix={['GEOIP']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.destinationIPASN && (
|
||||
<SettingItem title="目标ASN">{connection.metadata.destinationIPASN}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='目标ASN'
|
||||
value={connection.metadata.destinationIPASN}
|
||||
prefix={['IP-ASN']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.sourcePort && (
|
||||
<SettingItem title="源端口">{connection.metadata.sourcePort}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='来源端口'
|
||||
value={connection.metadata.sourcePort}
|
||||
prefix={['SRC-PORT']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.destinationPort && (
|
||||
<SettingItem title="目标端口">{connection.metadata.destinationPort}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='目标端口'
|
||||
value={connection.metadata.destinationPort}
|
||||
prefix={['DST-PORT']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.inboundIP && (
|
||||
<SettingItem title="入站IP">{connection.metadata.inboundIP}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='入站IP'
|
||||
value={connection.metadata.inboundIP}
|
||||
prefix={['SRC-IP-CIDR']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.inboundPort && (
|
||||
<SettingItem title="入站端口">{connection.metadata.inboundPort}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='入站端口'
|
||||
value={connection.metadata.inboundPort}
|
||||
prefix={['SRC-PORT']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.inboundName && (
|
||||
<SettingItem title="入站名称">{connection.metadata.inboundName}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='入站名称'
|
||||
value={connection.metadata.inboundName}
|
||||
prefix={['IN-NAME']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.inboundUser && (
|
||||
<SettingItem title="入站用户">{connection.metadata.inboundUser}</SettingItem>
|
||||
<CopyableSettingItem
|
||||
title='入站用户'
|
||||
value={connection.metadata.inboundUser}
|
||||
prefix={['IN-USER']}
|
||||
/>
|
||||
)}
|
||||
{connection.metadata.host && (
|
||||
<SettingItem title="主机">{connection.metadata.host}</SettingItem>
|
||||
|
||||
<CopyableSettingItem
|
||||
title='DSCP'
|
||||
value={connection.metadata.dscp.toString()}
|
||||
prefix={['DSCP']}
|
||||
/>
|
||||
|
||||
{connection.metadata.remoteDestination && (
|
||||
<SettingItem title='远程目标'>{connection.metadata.remoteDestination}</SettingItem>
|
||||
)}
|
||||
{connection.metadata.dnsMode && (
|
||||
<SettingItem title="DNS模式">{connection.metadata.dnsMode}</SettingItem>
|
||||
<SettingItem title='DNS模式'>{connection.metadata.dnsMode}</SettingItem>
|
||||
)}
|
||||
{connection.metadata.specialProxy && (
|
||||
<SettingItem title="特殊代理">{connection.metadata.specialProxy}</SettingItem>
|
||||
<SettingItem title='特殊代理'>{connection.metadata.specialProxy}</SettingItem>
|
||||
)}
|
||||
{connection.metadata.specialRules && (
|
||||
<SettingItem title="特殊规则">{connection.metadata.specialRules}</SettingItem>
|
||||
)}
|
||||
{connection.metadata.remoteDestination && (
|
||||
<SettingItem title="远程目标">{connection.metadata.remoteDestination}</SettingItem>
|
||||
)}
|
||||
<SettingItem title="DSCP">{connection.metadata.dscp}</SettingItem>
|
||||
{connection.metadata.sniffHost && (
|
||||
<SettingItem title="嗅探主机">{connection.metadata.sniffHost}</SettingItem>
|
||||
<SettingItem title='特殊规则'>{connection.metadata.specialRules}</SettingItem>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button size="sm" variant="light" onPress={onClose}>
|
||||
<Button size='sm' variant='light' onPress={onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user