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}
)}
-