From e63cde8fcbee0b86baca83ec6da4819fdaa56517 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 3 Jun 2026 02:45:16 +0200 Subject: [PATCH] feat(settings): move the remark model control to the subscription tab Relocate Remark Model & Separation Character from the General/Panel tab to the Subscription tab's Information section, beside Show Info and Email in Remark, since it only governs how share-link remarks are composed. The sample preview uses concrete example values and renders the separator literally. Also drop the port from the subscription page link rows so each row shows just the inbound remark; the port still appears in the client QR modal and the client info modal. --- frontend/src/models/setting.ts | 2 +- frontend/src/pages/settings/GeneralTab.tsx | 49 ------------- .../pages/settings/SubscriptionGeneralTab.tsx | 69 ++++++++++++++++++- frontend/src/pages/sub/SubPage.tsx | 4 +- web/service/setting.go | 4 +- 5 files changed, 73 insertions(+), 55 deletions(-) diff --git a/frontend/src/models/setting.ts b/frontend/src/models/setting.ts index 24a515af..fcbe1ec1 100644 --- a/frontend/src/models/setting.ts +++ b/frontend/src/models/setting.ts @@ -34,7 +34,7 @@ export class AllSetting { subSupportUrl = ''; subProfileUrl = ''; subAnnounce = ''; - subEnableRouting = true; + subEnableRouting = false; subRoutingRules = ''; subListen = ''; subPort = 2096; diff --git a/frontend/src/pages/settings/GeneralTab.tsx b/frontend/src/pages/settings/GeneralTab.tsx index 7ef47b0e..9ff3a47b 100644 --- a/frontend/src/pages/settings/GeneralTab.tsx +++ b/frontend/src/pages/settings/GeneralTab.tsx @@ -5,7 +5,6 @@ import { Input, InputNumber, Select, - Space, Switch, } from 'antd'; import type { AllSetting } from '@/models/setting'; @@ -23,8 +22,6 @@ interface GeneralTabProps { 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' }, @@ -57,30 +54,6 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp 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) : []; @@ -115,28 +88,6 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp label: t('pages.settings.panelSettings'), children: ( <> - {t('pages.settings.sampleRemark')}: #{remarkSample}} - > - - ({ value: s, label: s }))} - /> - - - updateSetting({ webListen: e.target.value })} /> diff --git a/frontend/src/pages/settings/SubscriptionGeneralTab.tsx b/frontend/src/pages/settings/SubscriptionGeneralTab.tsx index 7ea181ff..2828703a 100644 --- a/frontend/src/pages/settings/SubscriptionGeneralTab.tsx +++ b/frontend/src/pages/settings/SubscriptionGeneralTab.tsx @@ -1,9 +1,14 @@ -import { Collapse, Divider, Input, InputNumber, Switch } from 'antd'; +import { useMemo } from 'react'; +import { Collapse, Divider, Input, InputNumber, Select, Space, Switch } from 'antd'; import { useTranslation } from 'react-i18next'; import type { AllSetting } from '@/models/setting'; import { SettingListItem } from '@/components/ui'; import { sanitizePath, normalizePath } from './uriPath'; +const REMARK_MODELS: Record = { i: 'Inbound', e: 'Email', o: 'Other' }; +const REMARK_SAMPLES: Record = { i: 'Germany', e: 'john', o: 'Relay' }; +const REMARK_SEPARATORS = [' ', '-', '_', '@', ':', '~', '|', ',', '.', '/']; + interface SubscriptionGeneralTabProps { allSetting: AllSetting; updateSetting: (patch: Partial) => void; @@ -12,6 +17,30 @@ interface SubscriptionGeneralTabProps { export default function SubscriptionGeneralTab({ allSetting, updateSetting }: SubscriptionGeneralTabProps) { const { t } = useTranslation(); + 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_SAMPLES[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 }); + } + return ( updateSetting({ subEmailInRemark: v })} /> + + {t('pages.settings.sampleRemark')}:{' '} + + {remarkSample ? `#${remarkSample}` : '—'} + + + } + > + + ({ value: s, label: s === ' ' ? '␣' : s }))} + /> + + + {t('pages.settings.subTitle')} diff --git a/frontend/src/pages/sub/SubPage.tsx b/frontend/src/pages/sub/SubPage.tsx index d8affd56..369db30d 100644 --- a/frontend/src/pages/sub/SubPage.tsx +++ b/frontend/src/pages/sub/SubPage.tsx @@ -32,7 +32,7 @@ import { import { ClipboardManager, IntlUtil, LanguageManager } from '@/utils'; import { isPostQuantumLink } from '@/lib/xray/inbound-link'; -import { LinkTags, linkMetaText, parseLinkParts } from '@/lib/xray/link-label'; +import { LinkTags, parseLinkParts } from '@/lib/xray/link-label'; import { setMessageInstance } from '@/utils/messageBus'; import { pauseAnimationsUntilLeave, useTheme } from '@/hooks/useTheme'; import SubUsageSummary from './SubUsageSummary'; @@ -396,7 +396,7 @@ export default function SubPage() { {links.map((link, idx) => { const parts = parseLinkParts(link, linkEmails[idx] || ''); const fallback = `Link ${idx + 1}`; - const rowTitle = (parts && linkMetaText(parts)) || fallback; + const rowTitle = parts?.remark || fallback; const qrLabel = [parts?.remark, linkEmails[idx]].filter(Boolean).join('-') || rowTitle; const canQr = !isPostQuantumLink(link); return ( diff --git a/web/service/setting.go b/web/service/setting.go index f7f0651e..098ec039 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -61,7 +61,7 @@ var defaultValueMap = map[string]string{ "subSupportUrl": "", "subProfileUrl": "", "subAnnounce": "", - "subEnableRouting": "true", + "subEnableRouting": "false", "subRoutingRules": "", "subListen": "", "subPort": "2096", @@ -76,7 +76,7 @@ var defaultValueMap = map[string]string{ "subURI": "", "subJsonPath": "/json/", "subJsonURI": "", - "subClashEnable": "true", + "subClashEnable": "false", "subClashPath": "/clash/", "subClashURI": "", "subJsonFragment": "",