mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-01 16:07:17 +00:00
feat(fallbacks): add per-rule dest override
Operators can now type an explicit dest (e.g. "8443", "127.0.0.1:8443", "/dev/shm/x.sock") on each fallback row to override the auto-resolved child listen+port. Empty keeps the existing auto behavior. Adds the column to inbound_fallbacks (GORM AutoMigrate), threads it through the panel form, API docs, and translations.
This commit is contained in:
@@ -365,13 +365,21 @@ export default function InboundFormModal({
|
||||
return;
|
||||
}
|
||||
setFallbacks(
|
||||
(msg.obj as { childId: number; name?: string; alpn?: string; path?: string; xver?: number }[])
|
||||
(msg.obj as {
|
||||
childId: number;
|
||||
name?: string;
|
||||
alpn?: string;
|
||||
path?: string;
|
||||
dest?: string;
|
||||
xver?: number;
|
||||
}[])
|
||||
.map((r) => ({
|
||||
rowKey: `fb-${++fallbackKeyRef.current}`,
|
||||
childId: r.childId,
|
||||
name: r.name || '',
|
||||
alpn: r.alpn || '',
|
||||
path: r.path || '',
|
||||
dest: r.dest || '',
|
||||
xver: r.xver || 0,
|
||||
})),
|
||||
);
|
||||
@@ -385,6 +393,7 @@ export default function InboundFormModal({
|
||||
name: c.name,
|
||||
alpn: c.alpn,
|
||||
path: c.path,
|
||||
dest: c.dest,
|
||||
xver: Number(c.xver) || 0,
|
||||
sortOrder: i,
|
||||
})),
|
||||
@@ -437,6 +446,7 @@ export default function InboundFormModal({
|
||||
name: '',
|
||||
alpn: '',
|
||||
path: '',
|
||||
dest: '',
|
||||
xver: 0,
|
||||
}]);
|
||||
};
|
||||
@@ -445,11 +455,11 @@ export default function InboundFormModal({
|
||||
setFallbacks((prev) => prev.map((r) => {
|
||||
if (r.rowKey !== rowKey) return r;
|
||||
// When the picker selects a new child inbound and the row hasn't
|
||||
// been hand-edited yet (sni/alpn/path all blank, xver = 0), pull
|
||||
// the SNI/ALPN/Path defaults off that child. Operators who
|
||||
// been hand-edited yet (sni/alpn/path/dest all blank, xver = 0),
|
||||
// pull the SNI/ALPN/Path defaults off that child. Operators who
|
||||
// intentionally typed values keep them — we only fill the empties.
|
||||
if (typeof patch.childId === 'number' && patch.childId !== r.childId) {
|
||||
const isPristine = !r.name && !r.alpn && !r.path && r.xver === 0;
|
||||
const isPristine = !r.name && !r.alpn && !r.path && !r.dest && r.xver === 0;
|
||||
if (isPristine) return { ...r, ...patch, ...deriveFallbackDefaults(patch.childId) };
|
||||
}
|
||||
return { ...r, ...patch };
|
||||
@@ -490,6 +500,7 @@ export default function InboundFormModal({
|
||||
name: derived.name ?? '',
|
||||
alpn: derived.alpn ?? '',
|
||||
path: derived.path ?? '',
|
||||
dest: '',
|
||||
xver: derived.xver ?? 0,
|
||||
};
|
||||
});
|
||||
@@ -1079,6 +1090,12 @@ export default function InboundFormModal({
|
||||
value={record.path}
|
||||
onChange={(e) => updateFallback(record.rowKey, { path: e.target.value })}
|
||||
/>
|
||||
<InputAddon>Dest</InputAddon>
|
||||
<Input
|
||||
placeholder={t('pages.inbounds.fallbacks.destPlaceholder') || 'auto'}
|
||||
value={record.dest}
|
||||
onChange={(e) => updateFallback(record.rowKey, { dest: e.target.value })}
|
||||
/>
|
||||
<InputAddon>xver</InputAddon>
|
||||
<InputNumber
|
||||
min={0}
|
||||
|
||||
Reference in New Issue
Block a user