mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 12:44:22 +00:00
feat(frontend): protocol tab HTTP and Mixed sections (Pattern A)
Adds the HTTP and Mixed sub-forms. Both share an accounts list — first Form.List usage in the rewrite. Each row binds via [field.name, 'user'] / [field.name, 'pass'] under the parent ['settings', 'accounts'] path, so the wire shape stays exactly what HttpInboundSettingsSchema and MixedInboundSettingsSchema validate. HTTP-only: allowTransparent Switch. Mixed-only: auth Select (noauth/password), udp Switch, conditional ip Input gated on the udp value via Form.useWatch. Tab visibility widens to include http + mixed alongside vless + shadowsocks. The string cast on the includes-check keeps the frozen Protocols const's narrow union from rejecting the broader protocol string at the call site.
This commit is contained in:
parent
591a03ff96
commit
ecd751c310
1 changed files with 74 additions and 2 deletions
|
|
@ -16,7 +16,7 @@ import {
|
||||||
Typography,
|
Typography,
|
||||||
message,
|
message,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { SyncOutlined } from '@ant-design/icons';
|
import { MinusOutlined, PlusOutlined, SyncOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
import { HttpUtil, NumberFormatter, RandomUtil, SizeFormatter } from '@/utils';
|
import { HttpUtil, NumberFormatter, RandomUtil, SizeFormatter } from '@/utils';
|
||||||
import {
|
import {
|
||||||
|
|
@ -34,6 +34,7 @@ import {
|
||||||
import { antdRule } from '@/utils/zodForm';
|
import { antdRule } from '@/utils/zodForm';
|
||||||
import { Protocols, SNIFFING_OPTION } from '@/schemas/primitives';
|
import { Protocols, SNIFFING_OPTION } from '@/schemas/primitives';
|
||||||
import DateTimePicker from '@/components/DateTimePicker';
|
import DateTimePicker from '@/components/DateTimePicker';
|
||||||
|
import InputAddon from '@/components/InputAddon';
|
||||||
import type { DBInbound } from '@/models/dbinbound';
|
import type { DBInbound } from '@/models/dbinbound';
|
||||||
import type { NodeRecord } from '@/api/queries/useNodesQuery';
|
import type { NodeRecord } from '@/api/queries/useNodesQuery';
|
||||||
|
|
||||||
|
|
@ -103,6 +104,7 @@ export default function InboundFormModalNew({
|
||||||
protocol,
|
protocol,
|
||||||
settings: typeof ssMethod === 'string' ? { method: ssMethod } : {},
|
settings: typeof ssMethod === 'string' ? { method: ssMethod } : {},
|
||||||
});
|
});
|
||||||
|
const mixedUdpOn = Form.useWatch(['settings', 'udp'], form) ?? false;
|
||||||
|
|
||||||
const matchesVlessAuth = (
|
const matchesVlessAuth = (
|
||||||
block: { id?: string; label?: string } | undefined | null,
|
block: { id?: string; label?: string } | undefined | null,
|
||||||
|
|
@ -334,6 +336,71 @@ export default function InboundFormModalNew({
|
||||||
|
|
||||||
const protocolTab = (
|
const protocolTab = (
|
||||||
<>
|
<>
|
||||||
|
{(protocol === Protocols.HTTP || protocol === Protocols.MIXED) && (
|
||||||
|
<>
|
||||||
|
<Form.List name={['settings', 'accounts']}>
|
||||||
|
{(fields, { add, remove }) => (
|
||||||
|
<>
|
||||||
|
<Form.Item label="Accounts">
|
||||||
|
<Button size="small" onClick={() => add({ user: '', pass: '' })}>
|
||||||
|
<PlusOutlined /> Add
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
{fields.length > 0 && (
|
||||||
|
<Form.Item wrapperCol={{ span: 24 }}>
|
||||||
|
{fields.map((field, idx) => (
|
||||||
|
<Space.Compact key={field.key} className="mb-8" block>
|
||||||
|
<InputAddon>{String(idx + 1)}</InputAddon>
|
||||||
|
<Form.Item name={[field.name, 'user']} noStyle>
|
||||||
|
<Input placeholder="Username" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name={[field.name, 'pass']} noStyle>
|
||||||
|
<Input placeholder="Password" />
|
||||||
|
</Form.Item>
|
||||||
|
<Button onClick={() => remove(field.name)}>
|
||||||
|
<MinusOutlined />
|
||||||
|
</Button>
|
||||||
|
</Space.Compact>
|
||||||
|
))}
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form.List>
|
||||||
|
{protocol === Protocols.HTTP && (
|
||||||
|
<Form.Item
|
||||||
|
name={['settings', 'allowTransparent']}
|
||||||
|
label="Allow transparent"
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
{protocol === Protocols.MIXED && (
|
||||||
|
<>
|
||||||
|
<Form.Item name={['settings', 'auth']} label="Auth">
|
||||||
|
<Select>
|
||||||
|
<Select.Option value="noauth">noauth</Select.Option>
|
||||||
|
<Select.Option value="password">password</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={['settings', 'udp']}
|
||||||
|
label="UDP"
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
{mixedUdpOn && (
|
||||||
|
<Form.Item name={['settings', 'ip']} label="UDP IP">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{protocol === Protocols.SHADOWSOCKS && (
|
{protocol === Protocols.SHADOWSOCKS && (
|
||||||
<>
|
<>
|
||||||
<Form.Item name={['settings', 'method']} label="Encryption method">
|
<Form.Item name={['settings', 'method']} label="Encryption method">
|
||||||
|
|
@ -500,7 +567,12 @@ export default function InboundFormModalNew({
|
||||||
>
|
>
|
||||||
<Tabs items={[
|
<Tabs items={[
|
||||||
{ key: 'basic', label: t('pages.xray.basicTemplate'), children: basicTab },
|
{ key: 'basic', label: t('pages.xray.basicTemplate'), children: basicTab },
|
||||||
...(protocol === Protocols.VLESS || protocol === Protocols.SHADOWSOCKS
|
...(([
|
||||||
|
Protocols.VLESS,
|
||||||
|
Protocols.SHADOWSOCKS,
|
||||||
|
Protocols.HTTP,
|
||||||
|
Protocols.MIXED,
|
||||||
|
] as string[]).includes(protocol)
|
||||||
? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab }]
|
? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab }]
|
||||||
: []),
|
: []),
|
||||||
{ key: 'sniffing', label: t('pages.inbounds.sniffingTab'), children: sniffingTab },
|
{ key: 'sniffing', label: t('pages.inbounds.sniffingTab'), children: sniffingTab },
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue