Kaynağa Gözat

fix(frontend): forceRender all tabs so fields register at modal open (B18)

AntD Tabs with the `items` API lazy-mounts inactive tab panes by
default. The Form.Items inside an unvisited tab never register, so:

- Form.useWatch on a parent path (e.g. 'sniffing') returns a partial
  view containing only registered children. Until the user clicked the
  Sniffing tab, Advanced > Sniffing JSON showed `{sniffing: {}}`
  instead of the full default object set by setFieldsValue.
- After visiting the Sniffing tab once, the `sniffing.enabled` Form.Item
  registered, so useWatch suddenly returned `{enabled: false}` — still
  partial, because the rest of the sniffing children only register when
  their Form.Items mount in conditional sub-sections.

Setting `forceRender: true` on every tab item forces all tab panes to
mount at modal open. Every Form.Item registers immediately; the watch
result reflects the full form value seeded by buildAddModeValues. This
also likely resolves the earlier "Invalid discriminator value" error
on submit, which surfaced when streamSettings had an unregistered
security field whose Form.Item hadn't mounted yet.
MHSanaei 1 gün önce
ebeveyn
işleme
90e11dc0f6
1 değiştirilmiş dosya ile 12 ekleme ve 6 silme
  1. 12 6
      frontend/src/pages/inbounds/InboundFormModal.tsx

+ 12 - 6
frontend/src/pages/inbounds/InboundFormModal.tsx

@@ -2752,7 +2752,13 @@ export default function InboundFormModal({
           onValuesChange={onValuesChange}
         >
           <Tabs items={[
-            { key: 'basic', label: t('pages.xray.basicTemplate'), children: basicTab },
+            // forceRender on every tab so all Form.Items register at modal
+            // open, not lazily on first visit. Without it, AntD's items API
+            // lazy-mounts inactive tabs — their fields don't register, so
+            // Form.useWatch on a parent path (e.g. 'sniffing') returns the
+            // partial-view {} until the user touches the tab and the
+            // inner Form.Item for `sniffing.enabled` registers.
+            { key: 'basic', label: t('pages.xray.basicTemplate'), children: basicTab, forceRender: true },
             ...(([
               Protocols.VLESS,
               Protocols.SHADOWSOCKS,
@@ -2762,16 +2768,16 @@ export default function InboundFormModal({
               Protocols.TUN,
               Protocols.WIREGUARD,
             ] as string[]).includes(protocol) || isFallbackHost
-              ? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab }]
+              ? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab, forceRender: true }]
               : []),
             ...(streamEnabled
               ? [
-                  { key: 'stream', label: t('pages.inbounds.streamTab'), children: streamTab },
-                  { key: 'security', label: t('pages.inbounds.securityTab'), children: securityTab },
+                  { key: 'stream', label: t('pages.inbounds.streamTab'), children: streamTab, forceRender: true },
+                  { key: 'security', label: t('pages.inbounds.securityTab'), children: securityTab, forceRender: true },
                 ]
               : []),
-            { key: 'sniffing', label: t('pages.inbounds.sniffingTab'), children: sniffingTab },
-            { key: 'advanced', label: t('pages.xray.advancedTemplate'), children: advancedTab },
+            { key: 'sniffing', label: t('pages.inbounds.sniffingTab'), children: sniffingTab, forceRender: true },
+            { key: 'advanced', label: t('pages.xray.advancedTemplate'), children: advancedTab, forceRender: true },
           ]} />
         </Form>
       </Modal>