From e53f87ce3098c4edd980e7d77f028096dbdb70a7 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 26 May 2026 02:17:31 +0200 Subject: [PATCH] feat(frontend): protocol tab TUN section (Pattern A) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../pages/inbounds/InboundFormModal.new.tsx | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/inbounds/InboundFormModal.new.tsx b/frontend/src/pages/inbounds/InboundFormModal.new.tsx index 1ff34ae5..49768a0c 100644 --- a/frontend/src/pages/inbounds/InboundFormModal.new.tsx +++ b/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 && ( + <> + + + + + + + + {(fields, { add, remove }) => ( + + + {fields.map((field, j) => ( + + + + + + + ))} + + )} + + + {(fields, { add, remove }) => ( + + + {fields.map((field, j) => ( + + + + + + + ))} + + )} + + + + + + {(fields, { add, remove }) => ( + + Auto system routes + + } + > + + {fields.map((field, j) => ( + + + + + + + ))} + + )} + + + Auto outbounds interface + + } + > + + + + )} + {protocol === Protocols.TUNNEL && ( <> @@ -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 }] : []),