import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Collapse, Input, InputNumber, Select, Space, Switch, } from 'antd'; import type { AllSetting } from '@/models/setting'; import { HttpUtil, LanguageManager } from '@/utils'; import SettingListItem from '@/components/SettingListItem'; interface ApiMsg { success?: boolean; obj?: T; } interface GeneralTabProps { allSetting: AllSetting; updateSetting: (patch: Partial) => void; } const REMARK_MODELS: Record = { i: 'Inbound', e: 'Email', o: 'Other' }; const REMARK_SEPARATORS = [' ', '-', '_', '@', ':', '~', '|', ',', '.', '/']; const DATEPICKER_LIST: { name: string; value: 'gregorian' | 'jalalian' }[] = [ { name: 'Gregorian (Standard)', value: 'gregorian' }, { name: 'Jalalian (شمسی)', value: 'jalalian' }, ]; export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProps) { const { t } = useTranslation(); const [lang, setLang] = useState(() => LanguageManager.getLanguage()); const [inboundOptions, setInboundOptions] = useState<{ label: string; value: string }[]>([]); useEffect(() => { let cancelled = false; (async () => { // /options is the slim picker-shaped endpoint — it skips the heavy // per-client settings and clientStats payloads that /list ships. const msg = await HttpUtil.get('/panel/api/inbounds/options') as ApiMsg<{ tag: string; protocol: string; port: number; }[]>; if (cancelled) return; if (msg?.success && Array.isArray(msg.obj)) { setInboundOptions(msg.obj.map((ib) => ({ label: `${ib.tag} (${ib.protocol}@${ib.port})`, value: ib.tag, }))); } else { setInboundOptions([]); } })(); return () => { cancelled = true; }; }, []); const remarkModel = useMemo(() => { const rm = allSetting.remarkModel || ''; return rm.length > 1 ? rm.substring(1).split('') : []; }, [allSetting.remarkModel]); const remarkSeparator = useMemo(() => { const rm = allSetting.remarkModel || '-'; return rm.length > 1 ? rm.charAt(0) : '-'; }, [allSetting.remarkModel]); const remarkSample = useMemo(() => { const parts = remarkModel.map((k) => REMARK_MODELS[k]); return parts.length === 0 ? '' : parts.join(remarkSeparator); }, [remarkModel, remarkSeparator]); function setRemarkModel(parts: string[]) { updateSetting({ remarkModel: remarkSeparator + parts.join('') }); } function setRemarkSeparator(sep: string) { const tail = (allSetting.remarkModel || '-').substring(1); updateSetting({ remarkModel: sep + tail }); } const ldapInboundTagList = useMemo(() => { const csv = allSetting.ldapInboundTags || ''; return csv.length ? csv.split(',').map((s) => s.trim()).filter(Boolean) : []; }, [allSetting.ldapInboundTags]); function setLdapInboundTagList(list: string[]) { updateSetting({ ldapInboundTags: Array.isArray(list) ? list.join(',') : '' }); } function onLangChange(value: string) { setLang(value); LanguageManager.setLanguage(value); } const langOptions = useMemo( () => LanguageManager.supportedLanguages.map((l: { value: string; name: string; icon: string }) => ({ value: l.value, label: ( <> {l.icon}   {l.name} ), })), [], ); return ( {t('pages.settings.sampleRemark')}: #{remarkSample}} > ({ value: s, label: s }))} /> updateSetting({ webListen: e.target.value })} /> updateSetting({ webDomain: e.target.value })} /> updateSetting({ webPort: Number(v) || 0 })} /> updateSetting({ webBasePath: e.target.value })} /> updateSetting({ sessionMaxAge: Number(v) || 0 })} /> updateSetting({ trustedProxyCIDRs: e.target.value })} /> updateSetting({ panelProxy: e.target.value })} /> updateSetting({ pageSize: Number(v) || 0 })} /> updateSetting({ webCertFile: e.target.value })} /> updateSetting({ webKeyFile: e.target.value })} /> ), }, { key: '4', label: t('pages.settings.externalTraffic'), children: ( <> updateSetting({ externalTrafficInformEnable: v })} /> updateSetting({ externalTrafficInformURI: e.target.value })} /> updateSetting({ restartXrayOnClientDisable: v })} /> ), }, { key: '5', label: t('pages.settings.dateAndTime'), children: ( <> updateSetting({ timeLocation: e.target.value })} /> updateSetting({ ldapHost: e.target.value })} /> updateSetting({ ldapPort: Number(v) || 0 })} /> updateSetting({ ldapUseTLS: v })} /> updateSetting({ ldapBindDN: e.target.value })} /> updateSetting({ ldapPassword: e.target.value })} /> updateSetting({ ldapBaseDN: e.target.value })} /> updateSetting({ ldapUserFilter: e.target.value })} /> updateSetting({ ldapUserAttr: e.target.value })} /> updateSetting({ ldapVlessField: e.target.value })} /> updateSetting({ ldapFlagField: e.target.value })} /> updateSetting({ ldapTruthyValues: e.target.value })} /> updateSetting({ ldapInvertFlag: v })} /> updateSetting({ ldapSyncCron: e.target.value })} /> <>