Преглед на файлове

feat(frontend): protocol tab TUN section (Pattern A)

Adds the TUN sub-form: interface name, MTU, four primitive-array
Form.Lists (gateway, dns, autoSystemRoutingTable), userLevel,
autoOutboundsInterface.

Primitive Form.Lists bind each row's Input directly to `field.name`
(no inner key) — distinct from the object-row Form.Lists that bind to
`[field.name, 'fieldKey']`.

The Form.useWatch('protocol') return type comes from the schema's
protocol enum which excludes 'tun' (TUN is in the legacy Protocols
const for data parity but never accepted by the wire validator). Cast
to string at the source so per-section comparisons against
Protocols.TUN typecheck. Why: legacy DB rows with protocol === 'tun'
still need to render; widening here keeps reads from rejecting them.

Tab visibility widens to TUN.
MHSanaei преди 21 часа
родител
ревизия
e53f87ce30
променени са 1 файла, в които са добавени 89 реда и са изтрити 1 реда
  1. 89 1
      frontend/src/pages/inbounds/InboundFormModal.new.tsx

+ 89 - 1
frontend/src/pages/inbounds/InboundFormModal.new.tsx

@@ -95,7 +95,7 @@ export default function InboundFormModalNew({
   const [saving, setSaving] = useState(false);
 
   const selectableNodes = (availableNodes || []).filter((n) => n.enable);
-  const protocol = Form.useWatch('protocol', form) ?? '';
+  const protocol = (Form.useWatch('protocol', form) ?? '') as string;
   const isNodeEligible = NODE_ELIGIBLE_PROTOCOLS.has(protocol);
   const sniffingEnabled = Form.useWatch(['sniffing', 'enabled'], form) ?? false;
   const vlessEncryption = Form.useWatch(['settings', 'encryption'], form) ?? '';
@@ -336,6 +336,93 @@ export default function InboundFormModalNew({
 
   const protocolTab = (
     <>
+      {protocol === Protocols.TUN && (
+        <>
+          <Form.Item name={['settings', 'name']} label="Interface name">
+            <Input placeholder="xray0" />
+          </Form.Item>
+          <Form.Item name={['settings', 'mtu']} label="MTU">
+            <InputNumber min={0} />
+          </Form.Item>
+          <Form.List name={['settings', 'gateway']}>
+            {(fields, { add, remove }) => (
+              <Form.Item label="Gateway">
+                <Button size="small" onClick={() => add('')}>
+                  <PlusOutlined />
+                </Button>
+                {fields.map((field, j) => (
+                  <Space.Compact key={field.key} block className="mt-4">
+                    <Form.Item name={field.name} noStyle>
+                      <Input placeholder={j === 0 ? '10.0.0.1/16' : 'fc00::1/64'} />
+                    </Form.Item>
+                    <Button size="small" onClick={() => remove(field.name)}>
+                      <MinusOutlined />
+                    </Button>
+                  </Space.Compact>
+                ))}
+              </Form.Item>
+            )}
+          </Form.List>
+          <Form.List name={['settings', 'dns']}>
+            {(fields, { add, remove }) => (
+              <Form.Item label="DNS">
+                <Button size="small" onClick={() => add('')}>
+                  <PlusOutlined />
+                </Button>
+                {fields.map((field, j) => (
+                  <Space.Compact key={field.key} block className="mt-4">
+                    <Form.Item name={field.name} noStyle>
+                      <Input placeholder={j === 0 ? '1.1.1.1' : '8.8.8.8'} />
+                    </Form.Item>
+                    <Button size="small" onClick={() => remove(field.name)}>
+                      <MinusOutlined />
+                    </Button>
+                  </Space.Compact>
+                ))}
+              </Form.Item>
+            )}
+          </Form.List>
+          <Form.Item name={['settings', 'userLevel']} label="User level">
+            <InputNumber min={0} />
+          </Form.Item>
+          <Form.List name={['settings', 'autoSystemRoutingTable']}>
+            {(fields, { add, remove }) => (
+              <Form.Item
+                label={
+                  <Tooltip title="Windows-only. CIDRs added to the system routing table automatically so matching traffic goes through TUN.">
+                    Auto system routes
+                  </Tooltip>
+                }
+              >
+                <Button size="small" onClick={() => add('')}>
+                  <PlusOutlined />
+                </Button>
+                {fields.map((field, j) => (
+                  <Space.Compact key={field.key} block className="mt-4">
+                    <Form.Item name={field.name} noStyle>
+                      <Input placeholder={j === 0 ? '0.0.0.0/0' : '::/0'} />
+                    </Form.Item>
+                    <Button size="small" onClick={() => remove(field.name)}>
+                      <MinusOutlined />
+                    </Button>
+                  </Space.Compact>
+                ))}
+              </Form.Item>
+            )}
+          </Form.List>
+          <Form.Item
+            name={['settings', 'autoOutboundsInterface']}
+            label={
+              <Tooltip title="Physical interface for outbound traffic. Use 'auto' to detect; auto-enabled when Auto system routes is set.">
+                Auto outbounds interface
+              </Tooltip>
+            }
+          >
+            <Input placeholder="auto" />
+          </Form.Item>
+        </>
+      )}
+
       {protocol === Protocols.TUNNEL && (
         <>
           <Form.Item name={['settings', 'rewriteAddress']} label="Rewrite address">
@@ -627,6 +714,7 @@ export default function InboundFormModalNew({
               Protocols.HTTP,
               Protocols.MIXED,
               Protocols.TUNNEL,
+              Protocols.TUN,
             ] as string[]).includes(protocol)
               ? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab }]
               : []),