11import { Accordion , AccordionContent , AccordionItem , AccordionTrigger } from '@/components/ui/accordion'
2+ import { Alert , AlertDescription } from '@/components/ui/alert'
23import { Badge } from '@/components/ui/badge'
34import { Button } from '@/components/ui/button'
45import { StringArrayPopoverInput } from '@/components/common/string-array-popover-input'
@@ -17,7 +18,7 @@ import { cn } from '@/lib/utils'
1718import { ClientTemplateType , UserStatus , getHosts , useGetClientTemplatesSimple } from '@/service/api'
1819import { queryClient } from '@/utils/query-client'
1920import { useQuery } from '@tanstack/react-query'
20- import { Cable , ChevronsLeftRightEllipsis , Copy , Pencil , GlobeLock , Info , Loader2 , Lock , Network , Plus , Route , Trash2 , X , ListTodo } from 'lucide-react'
21+ import { AlertTriangle , Cable , ChevronsLeftRightEllipsis , Copy , Pencil , GlobeLock , Info , Loader2 , Lock , Network , Plus , Route , Trash2 , X , ListTodo } from 'lucide-react'
2122import { memo , useCallback , useEffect , useMemo , useState } from 'react'
2223import { UseFormReturn } from 'react-hook-form'
2324import { useTranslation } from 'react-i18next'
@@ -324,9 +325,17 @@ const HostModal: React.FC<HostModalProps> = ({ isDialogOpen, onOpenChange, onSub
324325 const [ _isSubmitting , setIsSubmitting ] = useState ( false )
325326 const selectedInboundTag = form . watch ( 'inbound_tag' )
326327 const selectedNoiseSettings = form . watch ( 'noise_settings.xray' )
328+ const selectedFragmentSettings = form . watch ( 'fragment_settings.xray' )
327329 const xPaddingObfsEnabled = form . watch ( 'transport_settings.xhttp_settings.x_padding_obfs_mode' ) === true
328330 const infoPopoverSide = isMobile ? 'bottom' : dir === 'rtl' ? 'left' : 'right'
329331 const infoPopoverAlign = isMobile ? 'center' : 'start'
332+ const hasFragmentPopulated = Boolean (
333+ String ( selectedFragmentSettings ?. packets ?? '' ) . trim ( ) || String ( selectedFragmentSettings ?. length ?? '' ) . trim ( ) || String ( selectedFragmentSettings ?. interval ?? '' ) . trim ( ) ,
334+ )
335+ const hasNoisePopulated = ( selectedNoiseSettings || [ ] ) . some (
336+ noise => noise && ( String ( noise . packet ?? '' ) . trim ( ) || String ( noise . delay ?? '' ) . trim ( ) || String ( noise . rand_range ?? '' ) . trim ( ) ) ,
337+ )
338+ const showFragmentNoiseDeprecatedWarning = hasFragmentPopulated || hasNoisePopulated
330339
331340 const renderCamouflageSection = ( ) => {
332341 return (
@@ -345,6 +354,16 @@ const HostModal: React.FC<HostModalProps> = ({ isDialogOpen, onOpenChange, onSub
345354 </ TabsList >
346355 < TabsContent dir = { dir } value = "xray" >
347356 < div className = "space-y-6" >
357+ { showFragmentNoiseDeprecatedWarning && (
358+ < Alert className = "border-amber-500/40 bg-amber-500/10 text-amber-900 dark:text-amber-100" >
359+ < AlertTriangle className = "h-4 w-4 text-amber-600 dark:text-amber-400" />
360+ < AlertDescription className = "text-xs sm:text-sm" >
361+ { t ( 'hostsDialog.fragmentNoiseDeprecated' , {
362+ defaultValue : '`noise` and `fragment` are being removed in newer versions — use `finalMask` instead.' ,
363+ } ) }
364+ </ AlertDescription >
365+ </ Alert >
366+ ) }
348367 { /* Fragment Settings */ }
349368 < div className = "space-y-4" >
350369 < div className = "flex items-center justify-between" >
0 commit comments