add rule copy

This commit is contained in:
xishang0128 2024-11-16 23:12:02 +08:00
parent 148f4f217e
commit 4c51a4a611

View File

@ -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>