From 4c51a4a611b47779c4b1760850c83e9c0a83cd07 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sat, 16 Nov 2024 23:12:02 +0800 Subject: [PATCH] add rule copy --- .../connections/connection-detail-modal.tsx | 204 ++++++++++++++---- 1 file changed, 160 insertions(+), 44 deletions(-) diff --git a/src/renderer/src/components/connections/connection-detail-modal.tsx b/src/renderer/src/components/connections/connection-detail-modal.tsx index 09c29ce..a8d287f 100644 --- a/src/renderer/src/components/connections/connection-detail-modal.tsx +++ b/src/renderer/src/components/connections/connection-detail-modal.tsx @@ -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 ( + + + + + + navigator.clipboard.writeText(key === 'raw' ? value : key as string) + } + > + {menuItems.map(({ key, text }) => ( + {text} + ))} + + + } + > + {displayName || value} + + ) +} + const ConnectionDetailModal: React.FC = (props) => { const { connection, onClose } = props return ( - - 连接详情 + + 连接详情 - - {connection.metadata.type}({connection.metadata.network}) - - {dayjs(connection.start).fromNow()} - + {dayjs(connection.start).fromNow()} + {connection.rule} {connection.rulePayload ? `(${connection.rulePayload})` : ''} - {[...connection.chains].reverse().join('>>')} - {calcTraffic(connection.uploadSpeed || 0)}/s - {calcTraffic(connection.downloadSpeed || 0)}/s - {calcTraffic(connection.upload)} - {calcTraffic(connection.download)} + {[...connection.chains].reverse().join('>>')} + {calcTraffic(connection.uploadSpeed || 0)}/s + {calcTraffic(connection.downloadSpeed || 0)}/s + {calcTraffic(connection.upload)} + {calcTraffic(connection.download)} + + {connection.metadata.host && ( + + )} + {connection.metadata.sniffHost && ( + + )} {connection.metadata.process && ( - - {connection.metadata.process} - {connection.metadata.uid ? `(${connection.metadata.uid})` : ''} - + )} {connection.metadata.processPath && ( - {connection.metadata.processPath} + )} {connection.metadata.sourceIP && ( - {connection.metadata.sourceIP} + )} {connection.metadata.destinationIP && ( - {connection.metadata.destinationIP} + )} {connection.metadata.destinationGeoIP && ( - {connection.metadata.destinationGeoIP} + )} {connection.metadata.destinationIPASN && ( - {connection.metadata.destinationIPASN} + )} {connection.metadata.sourcePort && ( - {connection.metadata.sourcePort} + )} {connection.metadata.destinationPort && ( - {connection.metadata.destinationPort} + )} {connection.metadata.inboundIP && ( - {connection.metadata.inboundIP} + )} {connection.metadata.inboundPort && ( - {connection.metadata.inboundPort} + )} {connection.metadata.inboundName && ( - {connection.metadata.inboundName} + )} {connection.metadata.inboundUser && ( - {connection.metadata.inboundUser} + )} - {connection.metadata.host && ( - {connection.metadata.host} + + + + {connection.metadata.remoteDestination && ( + {connection.metadata.remoteDestination} )} {connection.metadata.dnsMode && ( - {connection.metadata.dnsMode} + {connection.metadata.dnsMode} )} {connection.metadata.specialProxy && ( - {connection.metadata.specialProxy} + {connection.metadata.specialProxy} )} {connection.metadata.specialRules && ( - {connection.metadata.specialRules} - )} - {connection.metadata.remoteDestination && ( - {connection.metadata.remoteDestination} - )} - {connection.metadata.dscp} - {connection.metadata.sniffHost && ( - {connection.metadata.sniffHost} + {connection.metadata.specialRules} )} -