import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Alert, Button, Input, InputNumber, Modal, Select, Space, Switch, Tabs } from 'antd'; import { BarChartOutlined, ClockCircleOutlined, FileTextOutlined, ReloadOutlined, SettingOutlined, } from '@ant-design/icons'; import { OutboundDomainStrategies } from '@/schemas/primitives'; import { SettingListItem } from '@/components/ui'; import { useMediaQuery } from '@/hooks/useMediaQuery'; import { catTabLabel } from '@/pages/settings/catTabLabel'; import type { XraySettingsValue, SetTemplate } from '@/hooks/useXraySetting'; import './BasicsTab.css'; import { ACCESS_LOG, ERROR_LOG, LOG_LEVELS, MASK_ADDRESS, ROUTING_DOMAIN_STRATEGIES, } from './constants'; interface BasicsTabProps { templateSettings: XraySettingsValue | null; setTemplateSettings: SetTemplate; outboundTestUrl: string; onChangeOutboundTestUrl: (v: string) => void; onResetDefault: () => void; } export default function BasicsTab({ templateSettings, setTemplateSettings, outboundTestUrl, onChangeOutboundTestUrl, onResetDefault, }: BasicsTabProps) { const { t } = useTranslation(); const { isMobile } = useMediaQuery(); const [modal, modalContextHolder] = Modal.useModal(); const mutate = useCallback( (mutator: (next: XraySettingsValue) => void) => { setTemplateSettings((prev) => { if (!prev) return prev; const clone = JSON.parse(JSON.stringify(prev)) as XraySettingsValue; mutator(clone); return clone; }); }, [setTemplateSettings], ); const setLevel0 = useCallback( (field: string, value: number | null) => mutate((tt) => { if (!tt.policy) tt.policy = {}; if (!tt.policy.levels) tt.policy.levels = {}; if (!tt.policy.levels['0']) tt.policy.levels['0'] = {}; if (value === null || value === undefined) { delete tt.policy.levels['0'][field]; } else { tt.policy.levels['0'][field] = value; } }), [mutate], ); function confirmResetDefault() { modal.confirm({ title: t('pages.settings.resetDefaultConfig'), okText: t('reset'), okType: 'danger', cancelText: t('cancel'), onOk: () => onResetDefault(), }); } const freedomStrategy = (templateSettings?.outbounds?.find((o) => o?.protocol === 'freedom' && o?.tag === 'direct')?.settings as | { domainStrategy?: string } | undefined)?.domainStrategy ?? 'AsIs'; const routingStrategy = templateSettings?.routing?.domainStrategy ?? 'AsIs'; const log = (templateSettings?.log || {}) as Record; const policy = (templateSettings?.policy?.system || {}) as Record; const level0 = (templateSettings?.policy?.levels?.['0'] || {}) as Record; const items = [ { key: '1', label: catTabLabel(, t('pages.xray.generalConfigs'), isMobile), children: ( <> ({ value: s, label: s }))} onChange={(next) => mutate((tt) => { if (!tt.outbounds) tt.outbounds = []; const idx = tt.outbounds.findIndex((o) => o?.protocol === 'freedom' && o?.tag === 'direct'); if (idx < 0) { tt.outbounds.push({ protocol: 'freedom', tag: 'direct', settings: { domainStrategy: next } }); } else { const ob = tt.outbounds[idx]; ob.settings = (ob.settings || {}) as Record; (ob.settings as Record).domainStrategy = next; } })} /> } /> ({ value: s, label: s }))} onChange={(next) => mutate((tt) => { if (tt.routing) tt.routing.domainStrategy = next; })} /> } /> onChangeOutboundTestUrl(e.target.value)} placeholder="https://www.google.com/generate_204" /> } /> ), }, { key: '2', label: catTabLabel(, t('pages.xray.statistics'), isMobile), children: ( <> {[ ['statsInboundUplink', t('pages.xray.statsInboundUplink')], ['statsInboundDownlink', t('pages.xray.statsInboundDownlink')], ['statsOutboundUplink', t('pages.xray.statsOutboundUplink')], ['statsOutboundDownlink', t('pages.xray.statsOutboundDownlink')], ].map(([field, label]) => ( mutate((tt) => { if (!tt.policy) tt.policy = {}; if (!tt.policy.system) tt.policy.system = {}; tt.policy.system[field] = checked; })} /> } /> ))} ), }, { key: 'connection', label: catTabLabel(, t('pages.xray.connectionLimits'), isMobile), children: ( <> setLevel0('connIdle', v as number | null)} /> } /> setLevel0('bufferSize', v as number | null)} /> } /> ), }, { key: '3', label: catTabLabel(, t('pages.xray.logConfigs'), isMobile), children: ( <> ({ value: s, label: s }))} onChange={(v) => mutate((tt) => { if (tt.log) tt.log.loglevel = v; })} /> } /> ({ value: s, label: s }))} onChange={(v) => mutate((tt) => { if (tt.log) tt.log.access = v; })} /> } /> ({ value: s, label: s }))]} onChange={(v) => mutate((tt) => { if (tt.log) tt.log.error = v; })} /> } /> ({ value: s, label: s }))]} onChange={(v) => mutate((tt) => { if (tt.log) tt.log.maskAddress = v; })} /> } /> mutate((tt) => { if (tt.log) tt.log.dnsLog = v; })} /> } /> ), }, { key: 'reset', label: catTabLabel(, t('pages.settings.resetDefaultConfig'), isMobile), children: ( ), }, ]; return ( <> {modalContextHolder} ); }