diff --git a/frontend/src/pages/xray/outbounds/OutboundFormModal.tsx b/frontend/src/pages/xray/outbounds/OutboundFormModal.tsx
index aa009fb4..24016691 100644
--- a/frontend/src/pages/xray/outbounds/OutboundFormModal.tsx
+++ b/frontend/src/pages/xray/outbounds/OutboundFormModal.tsx
@@ -76,6 +76,13 @@ import {
VmessFields,
WireguardFields,
} from './protocols';
+import {
+ GrpcForm,
+ HttpUpgradeForm,
+ KcpForm,
+ RawForm,
+ WsForm,
+} from './transport';
import './OutboundFormModal.css';
// Pattern A rewrite of OutboundFormModal. Built as a sibling `.new.tsx`
@@ -507,223 +514,15 @@ export default function OutboundFormModal({
/>
- {network === 'tcp' && (
-
- {() => {
- const type =
- form.getFieldValue([
- 'streamSettings',
- 'tcpSettings',
- 'header',
- 'type',
- ]) ?? 'none';
- return (
- <>
-
-
- form.setFieldValue(
- ['streamSettings', 'tcpSettings', 'header'],
- checked
- ? {
- type: 'http',
- request: {
- version: '1.1',
- method: 'GET',
- path: ['/'],
- headers: {},
- },
- response: {
- version: '1.1',
- status: '200',
- reason: 'OK',
- headers: {},
- },
- }
- : { type: 'none' },
- )
- }
- />
-
- {type === 'http' && (
- <>
-
-
-
-
-
-
-
-
-
+ {network === 'tcp' && }
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )}
- >
- );
- }}
-
- )}
+ {network === 'kcp' && }
- {network === 'kcp' && (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )}
+ {network === 'ws' && }
- {network === 'ws' && (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )}
+ {network === 'grpc' && }
- {network === 'grpc' && (
- <>
-
-
-
-
-
-
-
-
-
- >
- )}
-
- {network === 'httpupgrade' && (
- <>
-
-
-
-
-
-
-
-
-
- >
- )}
+ {network === 'httpupgrade' && }
{network === 'xhttp' && (
<>
diff --git a/frontend/src/pages/xray/outbounds/transport/grpc.tsx b/frontend/src/pages/xray/outbounds/transport/grpc.tsx
new file mode 100644
index 00000000..f031ead1
--- /dev/null
+++ b/frontend/src/pages/xray/outbounds/transport/grpc.tsx
@@ -0,0 +1,29 @@
+import { useTranslation } from 'react-i18next';
+import { Form, Input, Switch } from 'antd';
+
+export default function GrpcForm() {
+ const { t } = useTranslation();
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/frontend/src/pages/xray/outbounds/transport/httpupgrade.tsx b/frontend/src/pages/xray/outbounds/transport/httpupgrade.tsx
new file mode 100644
index 00000000..ca904322
--- /dev/null
+++ b/frontend/src/pages/xray/outbounds/transport/httpupgrade.tsx
@@ -0,0 +1,30 @@
+import { useTranslation } from 'react-i18next';
+import { Form, Input } from 'antd';
+
+import { HeaderMapEditor } from '@/components/form';
+
+export default function HttpUpgradeForm() {
+ const { t } = useTranslation();
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/frontend/src/pages/xray/outbounds/transport/index.ts b/frontend/src/pages/xray/outbounds/transport/index.ts
new file mode 100644
index 00000000..9dd145b7
--- /dev/null
+++ b/frontend/src/pages/xray/outbounds/transport/index.ts
@@ -0,0 +1,5 @@
+export { default as RawForm } from './raw';
+export { default as KcpForm } from './kcp';
+export { default as WsForm } from './ws';
+export { default as GrpcForm } from './grpc';
+export { default as HttpUpgradeForm } from './httpupgrade';
diff --git a/frontend/src/pages/xray/outbounds/transport/kcp.tsx b/frontend/src/pages/xray/outbounds/transport/kcp.tsx
new file mode 100644
index 00000000..2bb968d3
--- /dev/null
+++ b/frontend/src/pages/xray/outbounds/transport/kcp.tsx
@@ -0,0 +1,40 @@
+import { useTranslation } from 'react-i18next';
+import { Form, InputNumber } from 'antd';
+
+export default function KcpForm() {
+ const { t } = useTranslation();
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/frontend/src/pages/xray/outbounds/transport/raw.tsx b/frontend/src/pages/xray/outbounds/transport/raw.tsx
new file mode 100644
index 00000000..9ee64a80
--- /dev/null
+++ b/frontend/src/pages/xray/outbounds/transport/raw.tsx
@@ -0,0 +1,121 @@
+import { useTranslation } from 'react-i18next';
+import { Form, Input, Switch, type FormInstance } from 'antd';
+
+import { HeaderMapEditor } from '@/components/form';
+import type { OutboundFormValues } from '@/schemas/forms/outbound-form';
+
+export default function RawForm({ form }: { form: FormInstance }) {
+ const { t } = useTranslation();
+ return (
+
+ {() => {
+ const type =
+ form.getFieldValue([
+ 'streamSettings',
+ 'tcpSettings',
+ 'header',
+ 'type',
+ ]) ?? 'none';
+ return (
+ <>
+
+
+ form.setFieldValue(
+ ['streamSettings', 'tcpSettings', 'header'],
+ checked
+ ? {
+ type: 'http',
+ request: {
+ version: '1.1',
+ method: 'GET',
+ path: ['/'],
+ headers: {},
+ },
+ response: {
+ version: '1.1',
+ status: '200',
+ reason: 'OK',
+ headers: {},
+ },
+ }
+ : { type: 'none' },
+ )
+ }
+ />
+
+ {type === 'http' && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+ >
+ );
+ }}
+
+ );
+}
diff --git a/frontend/src/pages/xray/outbounds/transport/ws.tsx b/frontend/src/pages/xray/outbounds/transport/ws.tsx
new file mode 100644
index 00000000..dff2bc2f
--- /dev/null
+++ b/frontend/src/pages/xray/outbounds/transport/ws.tsx
@@ -0,0 +1,30 @@
+import { useTranslation } from 'react-i18next';
+import { Form, Input, InputNumber } from 'antd';
+
+import { HeaderMapEditor } from '@/components/form';
+
+export default function WsForm() {
+ const { t } = useTranslation();
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}