mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 12:44:22 +00:00
refactor(frontend): split outbound-only protocol forms into per-protocol files
Replace the grouped outbound-only-fields.tsx + outbound-freedom-fields.tsx with one file per protocol under outbounds/protocols/: freedom.tsx, blackhole.tsx, dns.tsx, loopback.tsx (+ barrel). Matches the prompt's 1-file-per-protocol structure. Outbound snapshots unchanged -> no behavior change. typecheck/lint/build green.
This commit is contained in:
parent
62870103df
commit
2be473aea3
7 changed files with 108 additions and 97 deletions
|
|
@ -62,9 +62,8 @@ import {
|
|||
newStreamSlice,
|
||||
} from './outbound-form-helpers';
|
||||
import { OutboundCoreProtocolFields } from './outbound-core-fields';
|
||||
import { OutboundOnlyProtocolFields } from './outbound-only-fields';
|
||||
import { FreedomOutboundFields } from './outbound-freedom-fields';
|
||||
import { WireguardOutboundFields } from './outbound-wireguard-fields';
|
||||
import { BlackholeFields, DnsFields, FreedomFields, LoopbackFields } from './protocols';
|
||||
import './OutboundFormModal.css';
|
||||
|
||||
// Pattern A rewrite of OutboundFormModal. Built as a sibling `.new.tsx`
|
||||
|
|
@ -391,9 +390,11 @@ export default function OutboundFormModal({
|
|||
|
||||
<OutboundCoreProtocolFields protocol={protocol} />
|
||||
|
||||
<OutboundOnlyProtocolFields protocol={protocol} />
|
||||
{protocol === 'loopback' && <LoopbackFields />}
|
||||
{protocol === 'blackhole' && <BlackholeFields />}
|
||||
{protocol === 'dns' && <DnsFields />}
|
||||
|
||||
{protocol === 'freedom' && <FreedomOutboundFields form={form} />}
|
||||
{protocol === 'freedom' && <FreedomFields form={form} />}
|
||||
|
||||
{protocol === 'vless' && (
|
||||
<Form.Item shouldUpdate noStyle>
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Form, Input, InputNumber, Select } from 'antd';
|
||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
import { DNSRuleActions } from '@/schemas/primitives';
|
||||
|
||||
export function OutboundOnlyProtocolFields({ protocol }: { protocol: string }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
{protocol === 'loopback' && (
|
||||
<Form.Item label={t('pages.xray.outboundForm.inboundTag')} name={['settings', 'inboundTag']}>
|
||||
<Input placeholder={t('pages.xray.outboundForm.inboundTagPlaceholder')} />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
{protocol === 'blackhole' && (
|
||||
<Form.Item label={t('pages.xray.outboundForm.responseType')} name={['settings', 'type']}>
|
||||
<Select
|
||||
options={[
|
||||
{ value: '', label: '(empty)' },
|
||||
{ value: 'none', label: 'none' },
|
||||
{ value: 'http', label: 'http' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
{protocol === 'dns' && (
|
||||
<>
|
||||
<Form.Item label={t('pages.xray.outboundForm.rewriteNetwork')} name={['settings', 'rewriteNetwork']}>
|
||||
<Select
|
||||
allowClear
|
||||
placeholder={t('pages.xray.outboundForm.unchanged')}
|
||||
options={[
|
||||
{ value: 'udp', label: 'udp' },
|
||||
{ value: 'tcp', label: 'tcp' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.inbounds.form.rewriteAddress')} name={['settings', 'rewriteAddress']}>
|
||||
<Input placeholder={t('pages.xray.outboundForm.unchangedAddress')} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.inbounds.form.rewritePort')} name={['settings', 'rewritePort']}>
|
||||
<InputNumber min={0} max={65535} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.xray.tun.userLevel')} name={['settings', 'userLevel']}>
|
||||
<InputNumber min={0} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<Form.List name={['settings', 'rules']}>
|
||||
{(fields, { add, remove }) => (
|
||||
<>
|
||||
<Form.Item label={t('pages.xray.outboundForm.rules')}>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => add({ action: 'direct', qtype: '', domain: '' })}
|
||||
/>
|
||||
</Form.Item>
|
||||
{fields.map((field, index) => (
|
||||
<div key={field.key}>
|
||||
<Form.Item wrapperCol={{ md: { span: 14, offset: 8 } }}>
|
||||
<div className="item-heading">
|
||||
<span>{t('pages.xray.outboundForm.ruleN', { n: index + 1 })}</span>
|
||||
<DeleteOutlined
|
||||
className="danger-icon"
|
||||
onClick={() => remove(field.name)}
|
||||
/>
|
||||
</div>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.xray.outboundForm.action')} name={[field.name, 'action']}>
|
||||
<Select
|
||||
options={DNSRuleActions.map((a) => ({ value: a, label: a }))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="QType" name={[field.name, 'qtype']}>
|
||||
<Input placeholder="1,3,23-24" />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('domainName')} name={[field.name, 'domain']}>
|
||||
<Input placeholder="domain:example.com" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
17
frontend/src/pages/xray/outbounds/protocols/blackhole.tsx
Normal file
17
frontend/src/pages/xray/outbounds/protocols/blackhole.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Form, Select } from 'antd';
|
||||
|
||||
export default function BlackholeFields() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Form.Item label={t('pages.xray.outboundForm.responseType')} name={['settings', 'type']}>
|
||||
<Select
|
||||
options={[
|
||||
{ value: '', label: '(empty)' },
|
||||
{ value: 'none', label: 'none' },
|
||||
{ value: 'http', label: 'http' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
70
frontend/src/pages/xray/outbounds/protocols/dns.tsx
Normal file
70
frontend/src/pages/xray/outbounds/protocols/dns.tsx
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Form, Input, InputNumber, Select } from 'antd';
|
||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
import { DNSRuleActions } from '@/schemas/primitives';
|
||||
|
||||
export default function DnsFields() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<Form.Item label={t('pages.xray.outboundForm.rewriteNetwork')} name={['settings', 'rewriteNetwork']}>
|
||||
<Select
|
||||
allowClear
|
||||
placeholder={t('pages.xray.outboundForm.unchanged')}
|
||||
options={[
|
||||
{ value: 'udp', label: 'udp' },
|
||||
{ value: 'tcp', label: 'tcp' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.inbounds.form.rewriteAddress')} name={['settings', 'rewriteAddress']}>
|
||||
<Input placeholder={t('pages.xray.outboundForm.unchangedAddress')} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.inbounds.form.rewritePort')} name={['settings', 'rewritePort']}>
|
||||
<InputNumber min={0} max={65535} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.xray.tun.userLevel')} name={['settings', 'userLevel']}>
|
||||
<InputNumber min={0} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<Form.List name={['settings', 'rules']}>
|
||||
{(fields, { add, remove }) => (
|
||||
<>
|
||||
<Form.Item label={t('pages.xray.outboundForm.rules')}>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => add({ action: 'direct', qtype: '', domain: '' })}
|
||||
/>
|
||||
</Form.Item>
|
||||
{fields.map((field, index) => (
|
||||
<div key={field.key}>
|
||||
<Form.Item wrapperCol={{ md: { span: 14, offset: 8 } }}>
|
||||
<div className="item-heading">
|
||||
<span>{t('pages.xray.outboundForm.ruleN', { n: index + 1 })}</span>
|
||||
<DeleteOutlined
|
||||
className="danger-icon"
|
||||
onClick={() => remove(field.name)}
|
||||
/>
|
||||
</div>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('pages.xray.outboundForm.action')} name={[field.name, 'action']}>
|
||||
<Select
|
||||
options={DNSRuleActions.map((a) => ({ value: a, label: a }))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="QType" name={[field.name, 'qtype']}>
|
||||
<Input placeholder="1,3,23-24" />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('domainName')} name={[field.name, 'domain']}>
|
||||
<Input placeholder="domain:example.com" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
|||
import { OutboundDomainStrategies } from '@/schemas/primitives';
|
||||
import type { OutboundFormValues } from '@/schemas/forms/outbound-form';
|
||||
|
||||
export function FreedomOutboundFields({ form }: { form: FormInstance<OutboundFormValues> }) {
|
||||
export default function FreedomFields({ form }: { form: FormInstance<OutboundFormValues> }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
4
frontend/src/pages/xray/outbounds/protocols/index.ts
Normal file
4
frontend/src/pages/xray/outbounds/protocols/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export { default as FreedomFields } from './freedom';
|
||||
export { default as LoopbackFields } from './loopback';
|
||||
export { default as BlackholeFields } from './blackhole';
|
||||
export { default as DnsFields } from './dns';
|
||||
11
frontend/src/pages/xray/outbounds/protocols/loopback.tsx
Normal file
11
frontend/src/pages/xray/outbounds/protocols/loopback.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Form, Input } from 'antd';
|
||||
|
||||
export default function LoopbackFields() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Form.Item label={t('pages.xray.outboundForm.inboundTag')} name={['settings', 'inboundTag']}>
|
||||
<Input placeholder={t('pages.xray.outboundForm.inboundTagPlaceholder')} />
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue