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 React from 'react'
import SettingItem from '../base/base-setting-item' import SettingItem from '../base/base-setting-item'
import { calcTraffic } from '@renderer/utils/calc' import { calcTraffic } from '@renderer/utils/calc'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { BiCopy } from 'react-icons/bi'
interface Props { interface Props {
connection: IMihomoConnectionDetail connection: IMihomoConnectionDetail
onClose: () => void 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 ConnectionDetailModal: React.FC<Props> = (props) => {
const { connection, onClose } = props const { connection, onClose } = props
return ( return (
<Modal <Modal
backdrop="blur" backdrop='blur'
classNames={{ backdrop: 'top-[48px]' }} classNames={{ backdrop: 'top-[48px]' }}
size="xl" size='xl'
hideCloseButton hideCloseButton
isOpen={true} isOpen={true}
onOpenChange={onClose} onOpenChange={onClose}
scrollBehavior="inside" scrollBehavior='inside'
> >
<ModalContent className="flag-emoji break-all"> <ModalContent className='flag-emoji break-all'>
<ModalHeader className="flex app-drag"></ModalHeader> <ModalHeader className='flex app-drag'></ModalHeader>
<ModalBody> <ModalBody>
<SettingItem title="连接类型"> <SettingItem title='连接建立时间'>{dayjs(connection.start).fromNow()}</SettingItem>
{connection.metadata.type}({connection.metadata.network}) <SettingItem title='规则'>
</SettingItem>
<SettingItem title="连接建立时间">{dayjs(connection.start).fromNow()}</SettingItem>
<SettingItem title="规则">
{connection.rule} {connection.rule}
{connection.rulePayload ? `(${connection.rulePayload})` : ''} {connection.rulePayload ? `(${connection.rulePayload})` : ''}
</SettingItem> </SettingItem>
<SettingItem title="代理链">{[...connection.chains].reverse().join('>>')}</SettingItem> <SettingItem title='代理链'>{[...connection.chains].reverse().join('>>')}</SettingItem>
<SettingItem title="上传速度">{calcTraffic(connection.uploadSpeed || 0)}/s</SettingItem> <SettingItem title='上传速度'>{calcTraffic(connection.uploadSpeed || 0)}/s</SettingItem>
<SettingItem title="下载速度">{calcTraffic(connection.downloadSpeed || 0)}/s</SettingItem> <SettingItem title='下载速度'>{calcTraffic(connection.downloadSpeed || 0)}/s</SettingItem>
<SettingItem title="上传量">{calcTraffic(connection.upload)}</SettingItem> <SettingItem title='上传量'>{calcTraffic(connection.upload)}</SettingItem>
<SettingItem title="下载量">{calcTraffic(connection.download)}</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 && ( {connection.metadata.process && (
<SettingItem title="进程名"> <CopyableSettingItem
{connection.metadata.process} title='进程名'
{connection.metadata.uid ? `(${connection.metadata.uid})` : ''} value={connection.metadata.process}
</SettingItem> displayName={`${connection.metadata.process}${connection.metadata.uid ? `(${connection.metadata.uid})` : ''}`}
prefix={['PROCESS-NAME']}
/>
)} )}
{connection.metadata.processPath && ( {connection.metadata.processPath && (
<SettingItem title="进程路径">{connection.metadata.processPath}</SettingItem> <CopyableSettingItem
title='进程路径'
value={connection.metadata.processPath}
prefix={['PROCESS-PATH']}
/>
)} )}
{connection.metadata.sourceIP && ( {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 && ( {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 && ( {connection.metadata.destinationGeoIP && (
<SettingItem title="目标GeoIP">{connection.metadata.destinationGeoIP}</SettingItem> <CopyableSettingItem
title='目标GeoIP'
value={connection.metadata.destinationGeoIP}
prefix={['GEOIP']}
/>
)} )}
{connection.metadata.destinationIPASN && ( {connection.metadata.destinationIPASN && (
<SettingItem title="目标ASN">{connection.metadata.destinationIPASN}</SettingItem> <CopyableSettingItem
title='目标ASN'
value={connection.metadata.destinationIPASN}
prefix={['IP-ASN']}
/>
)} )}
{connection.metadata.sourcePort && ( {connection.metadata.sourcePort && (
<SettingItem title="源端口">{connection.metadata.sourcePort}</SettingItem> <CopyableSettingItem
title='来源端口'
value={connection.metadata.sourcePort}
prefix={['SRC-PORT']}
/>
)} )}
{connection.metadata.destinationPort && ( {connection.metadata.destinationPort && (
<SettingItem title="目标端口">{connection.metadata.destinationPort}</SettingItem> <CopyableSettingItem
title='目标端口'
value={connection.metadata.destinationPort}
prefix={['DST-PORT']}
/>
)} )}
{connection.metadata.inboundIP && ( {connection.metadata.inboundIP && (
<SettingItem title="入站IP">{connection.metadata.inboundIP}</SettingItem> <CopyableSettingItem
title='入站IP'
value={connection.metadata.inboundIP}
prefix={['SRC-IP-CIDR']}
/>
)} )}
{connection.metadata.inboundPort && ( {connection.metadata.inboundPort && (
<SettingItem title="入站端口">{connection.metadata.inboundPort}</SettingItem> <CopyableSettingItem
title='入站端口'
value={connection.metadata.inboundPort}
prefix={['SRC-PORT']}
/>
)} )}
{connection.metadata.inboundName && ( {connection.metadata.inboundName && (
<SettingItem title="入站名称">{connection.metadata.inboundName}</SettingItem> <CopyableSettingItem
title='入站名称'
value={connection.metadata.inboundName}
prefix={['IN-NAME']}
/>
)} )}
{connection.metadata.inboundUser && ( {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 && ( {connection.metadata.dnsMode && (
<SettingItem title="DNS模式">{connection.metadata.dnsMode}</SettingItem> <SettingItem title='DNS模式'>{connection.metadata.dnsMode}</SettingItem>
)} )}
{connection.metadata.specialProxy && ( {connection.metadata.specialProxy && (
<SettingItem title="特殊代理">{connection.metadata.specialProxy}</SettingItem> <SettingItem title='特殊代理'>{connection.metadata.specialProxy}</SettingItem>
)} )}
{connection.metadata.specialRules && ( {connection.metadata.specialRules && (
<SettingItem title="特殊规则">{connection.metadata.specialRules}</SettingItem> <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>
)} )}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button size="sm" variant="light" onPress={onClose}> <Button size='sm' variant='light' onPress={onClose}>
</Button> </Button>
</ModalFooter> </ModalFooter>