11import { Alert , AlertDescription , AlertTitle } from '@/components/ui/alert'
22import { cn } from '@/lib/utils'
33import type { CoreKitValidationIssue } from '@pasarguard/core-kit'
4- import type { Issue } from '@pasarguard/xray-config-kit'
4+ import type { Issue , Profile } from '@pasarguard/xray-config-kit'
55import type { WireGuardValidationIssue } from '@pasarguard/wireguard-config-kit'
66import { useTranslation } from 'react-i18next'
7+ import { useCoreEditorStore } from '@/features/core-editor/state/core-editor-store'
78
89export type ValidationListItem =
910 | { source : 'core-kit' ; issue : CoreKitValidationIssue }
@@ -15,6 +16,32 @@ export function validationListItemPath(item: ValidationListItem): string {
1516 return typeof p === 'string' ? p : ''
1617}
1718
19+ function formatXrayProfilePath ( path : string , profile : Profile | null | undefined ) : string {
20+ if ( ! profile || ! path . startsWith ( '/' ) ) return path
21+ const parts = path . split ( '/' )
22+ if ( parts . length < 3 ) return path
23+
24+ const collection = parts [ 1 ]
25+ if ( collection === 'routing' && parts [ 2 ] === 'rules' ) {
26+ const ruleIndex = Number ( parts [ 3 ] )
27+ if ( ! Number . isInteger ( ruleIndex ) || ruleIndex < 1 ) return path
28+ const rule = profile . routing ?. rules ?. [ ruleIndex - 1 ] as Record < string , unknown > | undefined
29+ const label = String ( rule ?. tag ?? rule ?. outboundTag ?? rule ?. balancerTag ?? '' ) . trim ( ) || `#${ ruleIndex } `
30+ return [ '/' , collection , parts [ 2 ] , label , ...parts . slice ( 4 ) ] . join ( '/' ) . replace ( '//' , '/' )
31+ }
32+
33+ const rawIndex = Number ( parts [ 2 ] )
34+ if ( ! Number . isInteger ( rawIndex ) || rawIndex < 1 ) return path
35+ const index = rawIndex - 1
36+
37+ let label = ''
38+ if ( collection === 'inbounds' ) label = String ( profile . inbounds ?. [ index ] ?. tag ?? '' ) . trim ( )
39+ else if ( collection === 'outbounds' ) label = String ( profile . outbounds ?. [ index ] ?. tag ?? '' ) . trim ( )
40+
41+ if ( ! label ) label = `#${ rawIndex } `
42+ return [ '/' , collection , label , ...parts . slice ( 3 ) ] . join ( '/' ) . replace ( '//' , '/' )
43+ }
44+
1845/** Same semantics as the “Validation errors” list (not warnings / info-only). */
1946export function filterValidationListBlockingErrors ( items : ValidationListItem [ ] ) : ValidationListItem [ ] {
2047 return items . filter ( i => {
@@ -61,6 +88,7 @@ const DISPLAY_LIMIT = 48
6188/** Lists blocking issues from the Xray config kit (strict compile), core-kit, WireGuard, etc. */
6289export function ValidationSummary ( { items, className } : ValidationSummaryProps ) {
6390 const { t } = useTranslation ( )
91+ const profile = useCoreEditorStore ( s => s . xrayProfile )
6492 if ( items . length === 0 ) return null
6593 const errors = filterValidationListBlockingErrors ( items )
6694 const list = errors . length > 0 ? errors : items
@@ -81,12 +109,12 @@ export function ValidationSummary({ items, className }: ValidationSummaryProps)
81109 < li key = { idx } >
82110 { row . source === 'core-kit' && (
83111 < >
84- { row . issue . path } : { row . issue . message }
112+ { formatXrayProfilePath ( row . issue . path , profile ) } : { row . issue . message }
85113 </ >
86114 ) }
87115 { row . source === 'xray' && (
88116 < >
89- { row . issue . path } : { row . issue . message }
117+ { formatXrayProfilePath ( row . issue . path , profile ) } : { row . issue . message }
90118 { row . issue . code ? (
91119 < span className = "ml-1 text-[0.8em] opacity-80" > [{ row . issue . code } ]</ span >
92120 ) : null }
0 commit comments