mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-06 05:04:22 +00:00
refactor(frontend): fold HysteriaMasqueradeForm into the hysteria forms
Inline the masquerade fields directly into both hysteria transport forms (inbounds/form/protocols/hysteria + xray/outbounds/transport/hysteria) and delete the shared lib/xray/forms/transport/HysteriaMasqueradeForm so each hysteria form is self-contained. The masquerade JSX is unchanged; form is typed as the untyped FormInstance (as the shared component was) so the masquerade name paths still resolve. No behavior change.
This commit is contained in:
parent
8a34eeedc9
commit
8cddff2c41
4 changed files with 213 additions and 131 deletions
|
|
@ -1,120 +0,0 @@
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { Form, Input, InputNumber, Select, Switch } from 'antd';
|
|
||||||
import type { FormInstance } from 'antd';
|
|
||||||
|
|
||||||
import { HeaderMapEditor } from '@/components/form';
|
|
||||||
|
|
||||||
const MASQ_PATH = ['streamSettings', 'hysteriaSettings', 'masquerade'];
|
|
||||||
|
|
||||||
interface HysteriaMasqueradeFormProps {
|
|
||||||
form: FormInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function HysteriaMasqueradeForm({ form }: HysteriaMasqueradeFormProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Form.Item label={t('pages.inbounds.form.masquerade')}>
|
|
||||||
<Form.Item shouldUpdate noStyle>
|
|
||||||
{() => {
|
|
||||||
const m = form.getFieldValue(MASQ_PATH);
|
|
||||||
return (
|
|
||||||
<Switch
|
|
||||||
checked={!!m}
|
|
||||||
onChange={(checked) =>
|
|
||||||
form.setFieldValue(
|
|
||||||
MASQ_PATH,
|
|
||||||
checked
|
|
||||||
? {
|
|
||||||
type: '', dir: '', url: '',
|
|
||||||
rewriteHost: false, insecure: false,
|
|
||||||
content: '', headers: {}, statusCode: 0,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.Item>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item shouldUpdate noStyle>
|
|
||||||
{() => {
|
|
||||||
const m = form.getFieldValue(MASQ_PATH) as { type?: string } | undefined;
|
|
||||||
if (!m) return null;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.type')}
|
|
||||||
name={[...MASQ_PATH, 'type']}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
options={[
|
|
||||||
{ value: '', label: 'default (404 page)' },
|
|
||||||
{ value: 'proxy', label: 'proxy (reverse proxy)' },
|
|
||||||
{ value: 'file', label: 'file (serve directory)' },
|
|
||||||
{ value: 'string', label: 'string (fixed body)' },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
{m.type === 'proxy' && (
|
|
||||||
<>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.upstreamUrl')}
|
|
||||||
name={[...MASQ_PATH, 'url']}
|
|
||||||
>
|
|
||||||
<Input placeholder="https://www.example.com" />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.rewriteHost')}
|
|
||||||
name={[...MASQ_PATH, 'rewriteHost']}
|
|
||||||
valuePropName="checked"
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.skipTlsVerify')}
|
|
||||||
name={[...MASQ_PATH, 'insecure']}
|
|
||||||
valuePropName="checked"
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{m.type === 'file' && (
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.directory')}
|
|
||||||
name={[...MASQ_PATH, 'dir']}
|
|
||||||
>
|
|
||||||
<Input placeholder="/var/www/html" />
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
{m.type === 'string' && (
|
|
||||||
<>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.statusCode')}
|
|
||||||
name={[...MASQ_PATH, 'statusCode']}
|
|
||||||
>
|
|
||||||
<InputNumber min={0} max={599} style={{ width: '100%' }} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.body')}
|
|
||||||
name={[...MASQ_PATH, 'content']}
|
|
||||||
>
|
|
||||||
<Input.TextArea autoSize={{ minRows: 3 }} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t('pages.inbounds.form.headers')}
|
|
||||||
name={[...MASQ_PATH, 'headers']}
|
|
||||||
>
|
|
||||||
<HeaderMapEditor mode="v1" />
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
export { default as FinalMaskForm } from './FinalMaskForm';
|
export { default as FinalMaskForm } from './FinalMaskForm';
|
||||||
export { default as HysteriaMasqueradeForm } from './HysteriaMasqueradeForm';
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, InputNumber, type FormInstance } from 'antd';
|
import { Form, Input, InputNumber, Select, Switch, type FormInstance } from 'antd';
|
||||||
|
|
||||||
import { HysteriaMasqueradeForm } from '@/lib/xray/forms/transport';
|
import { HeaderMapEditor } from '@/components/form';
|
||||||
import type { InboundFormValues } from '@/schemas/forms/inbound-form';
|
|
||||||
|
|
||||||
export default function HysteriaFields({ form }: { form: FormInstance<InboundFormValues> }) {
|
const MASQ_PATH = ['streamSettings', 'hysteriaSettings', 'masquerade'];
|
||||||
|
|
||||||
|
export default function HysteriaFields({ form }: { form: FormInstance }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -21,7 +22,107 @@ export default function HysteriaFields({ form }: { form: FormInstance<InboundFor
|
||||||
<InputNumber min={1} style={{ width: '100%' }} />
|
<InputNumber min={1} style={{ width: '100%' }} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<HysteriaMasqueradeForm form={form} />
|
<Form.Item label={t('pages.inbounds.form.masquerade')}>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => {
|
||||||
|
const m = form.getFieldValue(MASQ_PATH);
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
checked={!!m}
|
||||||
|
onChange={(checked) =>
|
||||||
|
form.setFieldValue(
|
||||||
|
MASQ_PATH,
|
||||||
|
checked
|
||||||
|
? {
|
||||||
|
type: '', dir: '', url: '',
|
||||||
|
rewriteHost: false, insecure: false,
|
||||||
|
content: '', headers: {}, statusCode: 0,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => {
|
||||||
|
const m = form.getFieldValue(MASQ_PATH) as { type?: string } | undefined;
|
||||||
|
if (!m) return null;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.type')}
|
||||||
|
name={[...MASQ_PATH, 'type']}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={[
|
||||||
|
{ value: '', label: 'default (404 page)' },
|
||||||
|
{ value: 'proxy', label: 'proxy (reverse proxy)' },
|
||||||
|
{ value: 'file', label: 'file (serve directory)' },
|
||||||
|
{ value: 'string', label: 'string (fixed body)' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
{m.type === 'proxy' && (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.upstreamUrl')}
|
||||||
|
name={[...MASQ_PATH, 'url']}
|
||||||
|
>
|
||||||
|
<Input placeholder="https://www.example.com" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.rewriteHost')}
|
||||||
|
name={[...MASQ_PATH, 'rewriteHost']}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.skipTlsVerify')}
|
||||||
|
name={[...MASQ_PATH, 'insecure']}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{m.type === 'file' && (
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.directory')}
|
||||||
|
name={[...MASQ_PATH, 'dir']}
|
||||||
|
>
|
||||||
|
<Input placeholder="/var/www/html" />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
{m.type === 'string' && (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.statusCode')}
|
||||||
|
name={[...MASQ_PATH, 'statusCode']}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={599} style={{ width: '100%' }} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.body')}
|
||||||
|
name={[...MASQ_PATH, 'content']}
|
||||||
|
>
|
||||||
|
<Input.TextArea autoSize={{ minRows: 3 }} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.headers')}
|
||||||
|
name={[...MASQ_PATH, 'headers']}
|
||||||
|
>
|
||||||
|
<HeaderMapEditor mode="v1" />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, Input, InputNumber, type FormInstance } from 'antd';
|
import { Form, Input, InputNumber, Select, Switch, type FormInstance } from 'antd';
|
||||||
|
|
||||||
import { HysteriaMasqueradeForm } from '@/lib/xray/forms/transport';
|
import { HeaderMapEditor } from '@/components/form';
|
||||||
import type { OutboundFormValues } from '@/schemas/forms/outbound-form';
|
|
||||||
|
|
||||||
export default function HysteriaForm({ form }: { form: FormInstance<OutboundFormValues> }) {
|
const MASQ_PATH = ['streamSettings', 'hysteriaSettings', 'masquerade'];
|
||||||
|
|
||||||
|
export default function HysteriaForm({ form }: { form: FormInstance }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -26,7 +27,108 @@ export default function HysteriaForm({ form }: { form: FormInstance<OutboundForm
|
||||||
>
|
>
|
||||||
<InputNumber min={1} style={{ width: '100%' }} />
|
<InputNumber min={1} style={{ width: '100%' }} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<HysteriaMasqueradeForm form={form} />
|
|
||||||
|
<Form.Item label={t('pages.inbounds.form.masquerade')}>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => {
|
||||||
|
const m = form.getFieldValue(MASQ_PATH);
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
checked={!!m}
|
||||||
|
onChange={(checked) =>
|
||||||
|
form.setFieldValue(
|
||||||
|
MASQ_PATH,
|
||||||
|
checked
|
||||||
|
? {
|
||||||
|
type: '', dir: '', url: '',
|
||||||
|
rewriteHost: false, insecure: false,
|
||||||
|
content: '', headers: {}, statusCode: 0,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => {
|
||||||
|
const m = form.getFieldValue(MASQ_PATH) as { type?: string } | undefined;
|
||||||
|
if (!m) return null;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.type')}
|
||||||
|
name={[...MASQ_PATH, 'type']}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={[
|
||||||
|
{ value: '', label: 'default (404 page)' },
|
||||||
|
{ value: 'proxy', label: 'proxy (reverse proxy)' },
|
||||||
|
{ value: 'file', label: 'file (serve directory)' },
|
||||||
|
{ value: 'string', label: 'string (fixed body)' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
{m.type === 'proxy' && (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.upstreamUrl')}
|
||||||
|
name={[...MASQ_PATH, 'url']}
|
||||||
|
>
|
||||||
|
<Input placeholder="https://www.example.com" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.rewriteHost')}
|
||||||
|
name={[...MASQ_PATH, 'rewriteHost']}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.skipTlsVerify')}
|
||||||
|
name={[...MASQ_PATH, 'insecure']}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{m.type === 'file' && (
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.directory')}
|
||||||
|
name={[...MASQ_PATH, 'dir']}
|
||||||
|
>
|
||||||
|
<Input placeholder="/var/www/html" />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
{m.type === 'string' && (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.statusCode')}
|
||||||
|
name={[...MASQ_PATH, 'statusCode']}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={599} style={{ width: '100%' }} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.body')}
|
||||||
|
name={[...MASQ_PATH, 'content']}
|
||||||
|
>
|
||||||
|
<Input.TextArea autoSize={{ minRows: 3 }} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('pages.inbounds.form.headers')}
|
||||||
|
name={[...MASQ_PATH, 'headers']}
|
||||||
|
>
|
||||||
|
<HeaderMapEditor mode="v1" />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue