From eb769e3f1f95549f6e6c8035dc4b6ea54664d202 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 15 Jul 2026 06:29:49 +0200 Subject: [PATCH] fix(frontend): map outbound mobile-card actions through the real index too The desktop outbounds table was keyed by the outbound's real index, but the mobile card list was left keying the probe trigger and every test-state lookup by the positional row index. With a hidden balancer-loopback outbound present, tapping Check on a mobile card probed the wrong outbound and the Test-All results landed on the wrong card. Key onTest and the testResult/isTesting reads by record.key, matching the desktop columns. --- .../pages/xray/outbounds/OutboundCardList.tsx | 18 +++++----- .../test/outbounds-loopback-index.test.tsx | 35 +++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/frontend/src/pages/xray/outbounds/OutboundCardList.tsx b/frontend/src/pages/xray/outbounds/OutboundCardList.tsx index 967bfae75..706dad1d3 100644 --- a/frontend/src/pages/xray/outbounds/OutboundCardList.tsx +++ b/frontend/src/pages/xray/outbounds/OutboundCardList.tsx @@ -63,8 +63,8 @@ export default function OutboundCardList({ setShowEgressIp((prev) => ({ ...prev, [key]: visible })); }; - const renderEgress = (index: number, rowKey: string) => { - const result = testResult(outboundTestStates, index); + const renderEgress = (testKey: number, rowKey: string) => { + const result = testResult(outboundTestStates, testKey); const egress = result?.egress; const isEgressVisible = !!showEgressIp[rowKey]; const flag = countryFlag(egress?.country); @@ -156,26 +156,26 @@ export default function OutboundCardList({ ))} )} - {renderEgress(index, String(record.key))} + {renderEgress(record.key, String(record.key))}
↑ {SizeFormatter.sizeFormat(trafficFor(outboundsTraffic, record).up)} ↓ {SizeFormatter.sizeFormat(trafficFor(outboundsTraffic, record).down)} - {testResult(outboundTestStates, index) ? ( - - ) : isTesting(outboundTestStates, index) ? ( + {testResult(outboundTestStates, record.key) ? ( + + ) : isTesting(outboundTestStates, record.key) ? ( ) : null}
diff --git a/frontend/src/test/outbounds-loopback-index.test.tsx b/frontend/src/test/outbounds-loopback-index.test.tsx index 783a20177..b3dfbdcdd 100644 --- a/frontend/src/test/outbounds-loopback-index.test.tsx +++ b/frontend/src/test/outbounds-loopback-index.test.tsx @@ -53,4 +53,39 @@ describe('OutboundsTab hidden-loopback index mapping', () => { expect(onTest).toHaveBeenCalledTimes(1); expect(onTest.mock.calls[0][0]).toBe(2); }); + + it('probes the real array index from the mobile card list as well', () => { + const onTest = vi.fn(); + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + + renderWithProviders( + + + , + ); + + const cards = document.querySelectorAll('.outbound-card'); + expect(cards.length).toBe(2); + + const checkButton = cards[1].querySelector('button[aria-label="Check"]') as HTMLButtonElement; + fireEvent.click(checkButton); + + expect(onTest).toHaveBeenCalledTimes(1); + expect(onTest.mock.calls[0][0]).toBe(2); + }); });