mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-15 23:42:27 +08:00
fix: prevent input focus loss in allowOrigins (#7397)
* fix: update CORS configuration to use key-value pairs for allowed origins * fix: refactor CORS configuration to use AllowOriginItem interface for better type safety
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Delete as DeleteIcon } from '@mui/icons-material'
|
||||
import { Box, Button, Divider, List, ListItem, TextField } from '@mui/material'
|
||||
import { useLockFn, useRequest } from 'ahooks'
|
||||
import { forwardRef, useImperativeHandle, useMemo, useState } from 'react'
|
||||
import { forwardRef, useImperativeHandle, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { BaseDialog, Switch } from '@/components/base'
|
||||
@@ -72,29 +72,39 @@ interface ClashHeaderConfigingRef {
|
||||
close: () => void
|
||||
}
|
||||
|
||||
interface AllowOriginItem {
|
||||
key: number
|
||||
value: string
|
||||
}
|
||||
|
||||
export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
(props, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const { clash, mutateClash, patchClash } = useClash()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const lastKeyRef = useRef(0) // 用于生成唯一的key
|
||||
|
||||
// CORS配置状态管理
|
||||
const [corsConfig, setCorsConfig] = useState<{
|
||||
allowPrivateNetwork: boolean
|
||||
allowOrigins: string[]
|
||||
allowOrigins: AllowOriginItem[]
|
||||
}>(() => {
|
||||
const cors = clash?.['external-controller-cors']
|
||||
const origins = cors?.['allow-origins'] ?? []
|
||||
return {
|
||||
allowPrivateNetwork: cors?.['allow-private-network'] ?? true,
|
||||
allowOrigins: filterBaseOriginsForUI(origins),
|
||||
allowOrigins: filterBaseOriginsForUI(origins).map((origin) => {
|
||||
lastKeyRef.current += 1
|
||||
return { key: lastKeyRef.current, value: origin }
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
// 处理CORS配置变更
|
||||
const handleCorsConfigChange = (
|
||||
key: 'allowPrivateNetwork' | 'allowOrigins',
|
||||
value: boolean | string[],
|
||||
value: boolean | AllowOriginItem[],
|
||||
) => {
|
||||
setCorsConfig((prev) => ({
|
||||
...prev,
|
||||
@@ -104,13 +114,17 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
|
||||
// 添加新的允许来源
|
||||
const handleAddOrigin = () => {
|
||||
handleCorsConfigChange('allowOrigins', [...corsConfig.allowOrigins, ''])
|
||||
lastKeyRef.current += 1
|
||||
handleCorsConfigChange('allowOrigins', [
|
||||
...corsConfig.allowOrigins,
|
||||
{ key: lastKeyRef.current, value: '' },
|
||||
])
|
||||
}
|
||||
|
||||
// 更新允许来源列表中的某一项
|
||||
const handleUpdateOrigin = (index: number, value: string) => {
|
||||
const newOrigins = [...corsConfig.allowOrigins]
|
||||
newOrigins[index] = value
|
||||
newOrigins[index] = { ...newOrigins[index], value }
|
||||
handleCorsConfigChange('allowOrigins', newOrigins)
|
||||
}
|
||||
|
||||
@@ -125,7 +139,9 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
const { loading, run: saveConfig } = useRequest(
|
||||
async () => {
|
||||
// 保存时使用完整的源列表(包括开发URL)
|
||||
const fullOrigins = getFullOrigins(corsConfig.allowOrigins)
|
||||
const fullOrigins = getFullOrigins(
|
||||
corsConfig.allowOrigins.map((origin) => origin.value),
|
||||
)
|
||||
|
||||
await patchClash({
|
||||
'external-controller-cors': {
|
||||
@@ -154,9 +170,13 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
open: () => {
|
||||
const cors = clash?.['external-controller-cors']
|
||||
const origins = cors?.['allow-origins'] ?? []
|
||||
lastKeyRef.current = 0
|
||||
setCorsConfig({
|
||||
allowPrivateNetwork: cors?.['allow-private-network'] ?? true,
|
||||
allowOrigins: filterBaseOriginsForUI(origins),
|
||||
allowOrigins: filterBaseOriginsForUI(origins).map((origin) => {
|
||||
lastKeyRef.current += 1
|
||||
return { key: lastKeyRef.current, value: origin }
|
||||
}),
|
||||
})
|
||||
setOpen(true)
|
||||
},
|
||||
@@ -167,19 +187,6 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
await saveConfig()
|
||||
})
|
||||
|
||||
const originEntries = useMemo(() => {
|
||||
const counts: Record<string, number> = {}
|
||||
return corsConfig.allowOrigins.map((origin, index) => {
|
||||
const occurrence = (counts[origin] = (counts[origin] ?? 0) + 1)
|
||||
const keyBase = origin || 'origin'
|
||||
return {
|
||||
origin,
|
||||
index,
|
||||
key: `${keyBase}-${occurrence}`,
|
||||
}
|
||||
})
|
||||
}, [corsConfig.allowOrigins])
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
@@ -224,7 +231,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
<div style={{ marginBottom: 8, fontWeight: 'bold' }}>
|
||||
{t('settings.sections.externalCors.fields.allowedOrigins')}
|
||||
</div>
|
||||
{originEntries.map(({ origin, index, key }) => (
|
||||
{corsConfig.allowOrigins.map(({ key, value: origin }, index) => (
|
||||
<div
|
||||
key={key}
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user