From 49bec1db0fc091d687e4fdcf760294d24e75d9b3 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 2 Jun 2026 00:17:21 +0200 Subject: [PATCH] fix(fallbacks): allow free-form dest entries for external servers (#4748) Since v3.1.0 every fallback row had to reference a panel inbound via childId, so rows with only a free-form dest (e.g. 8080 or 127.0.0.1:8080 to an external Nginx) were silently dropped at three layers: the frontend save filter, the backend SetByMaster guard, and BuildFallbacksJSON. A row is now valid when it has a child OR an explicit dest; self-references normalize to childId 0, and BuildFallbacksJSON prefers an explicit dest (also fixing rows whose child was deleted). UI gains allowClear on the child picker; help text updated across all locales. Verified end-to-end in Docker: a free-form dest fallback now persists and is injected into the live xray config. Refs #4554, #4639. --- .../src/pages/inbounds/form/FallbacksCard.tsx | 3 ++- .../pages/inbounds/form/useInboundFallbacks.ts | 4 ++-- web/service/fallback.go | 18 +++++++++++------- web/translation/ar-EG.json | 2 +- web/translation/en-US.json | 2 +- web/translation/es-ES.json | 2 +- web/translation/fa-IR.json | 2 +- web/translation/id-ID.json | 2 +- web/translation/ja-JP.json | 2 +- web/translation/pt-BR.json | 2 +- web/translation/ru-RU.json | 2 +- web/translation/tr-TR.json | 2 +- web/translation/uk-UA.json | 2 +- web/translation/vi-VN.json | 2 +- web/translation/zh-CN.json | 2 +- web/translation/zh-TW.json | 2 +- 16 files changed, 28 insertions(+), 23 deletions(-) diff --git a/frontend/src/pages/inbounds/form/FallbacksCard.tsx b/frontend/src/pages/inbounds/form/FallbacksCard.tsx index 41f0e823..0705e25c 100644 --- a/frontend/src/pages/inbounds/form/FallbacksCard.tsx +++ b/frontend/src/pages/inbounds/form/FallbacksCard.tsx @@ -44,12 +44,13 @@ export default function FallbacksCard({ value={record.childId} options={fallbackChildOptions} placeholder={t('pages.inbounds.fallbacks.pickInbound') || 'Pick an inbound'} + allowClear showSearch={{ filterOption: (input, option) => ((option?.label as string) || '').toLowerCase().includes(input.toLowerCase()), }} style={{ width: '100%' }} - onChange={(v) => updateFallback(record.rowKey, { childId: v })} + onChange={(v) => updateFallback(record.rowKey, { childId: v ?? null })} />