Files
3x-ui-agent/frontend/src/pages/xray/outbounds/outbounds-tab-helpers.ts
T
Muse 5031a70ccb P9(4): remove local-core live-test trio — outbound speed test + egress probe, restart/stop xray endpoints
Per user decision 2026-10-21 (reverses the earlier keep call in
PANEL-LITE-SPEC.md, now amended): the lite panel never runs a local
core, so measuring/probing from the panel host is meaningless.

Backend:
- delete service/outbound probe implementation (probe_http.go and its
  tests) and the TestOutbound/TestOutbounds batch prober; outbound
  traffic accounting (AddTraffic/GetOutboundsTraffic/Reset) unchanged
- drop POST /panel/api/xray/testOutbound + testOutbounds routes and the
  outboundTestUrl setting (get/update plumbing removed; stored rows in
  existing DBs are inert)
- drop POST /panel/api/server/restartXrayService + stopXrayService
  routes/handlers and the node-sync allowlist entry; the service-level
  Stop/RestartXrayService stay for internal import/restore flows
- node-sync allowlist contract test updated to the new inventory

Frontend:
- remove test buttons/mode switch/test-all from outbounds tab, card
  list and table columns; delete TestResultPopover and CountryPill;
  drop the egress/country/latency columns fed by probe results
- remove outboundTestUrl state and save plumbing from useXraySetting
  and the Basics tab field; drop OutboundTestResult schemas
- delete the 15 now-dead i18n keys from all 13 locales (incl. the
  restart/stop keys orphaned since P6/P7 — i18n-dead-keys test green)
- tests: drop the test-URL hook test, re-probe the loopback index
  mapping through Move-to-top, regenerate API types (gen)
2026-10-21 16:35:53 +00:00

79 lines
2.9 KiB
TypeScript

import { OutboundProtocols as Protocols } from '@/schemas/primitives';
import type { OutboundTrafficRow } from '@/hooks/useXraySetting';
import type { OutboundRow } from './outbounds-tab-types';
/**
* Translate a table row's positional index into that outbound's index in the
* full, unfiltered outbounds array. The table hides balancer-loopback outbounds
* but keeps each visible row's original index in `key`, so any handler that
* mutates the outbounds array (or probes an outbound by index) must map the
* positional index back through `key` or it operates on the wrong outbound once
* a hidden loopback precedes it.
*/
export function originalOutboundIndex(rows: OutboundRow[], positionalIndex: number): number {
const row = rows[positionalIndex];
return row ? row.key : positionalIndex;
}
export function outboundAddresses(o: OutboundRow): string[] {
const settings = o.settings as Record<string, unknown> | undefined;
switch (o.protocol) {
case Protocols.VMess: {
const serverObj = settings?.vnext as Array<{ address: string; port: number }> | undefined;
return serverObj ? serverObj.map((s) => `${s.address}:${s.port}`) : [];
}
case Protocols.VLESS:
return [`${settings?.address || ''}:${settings?.port || ''}`];
case Protocols.HTTP:
case Protocols.Socks:
case Protocols.Shadowsocks:
case Protocols.Trojan: {
const serverObj = settings?.servers as Array<{ address: string; port: number }> | undefined;
return serverObj ? serverObj.map((s) => `${s.address}:${s.port}`) : [];
}
case Protocols.DNS: {
const addr = (settings?.rewriteAddress as string) || (settings?.address as string) || '';
const port =
(settings?.rewritePort as string | number) || (settings?.port as string | number) || '';
return addr || port ? [`${addr}:${port}`] : [];
}
case Protocols.Wireguard:
return ((settings?.peers as Array<{ endpoint?: string }>) || [])
.map((p) => p.endpoint || '')
.filter(Boolean);
default:
return [];
}
}
export function showSecurity(security?: string): boolean {
return security === 'tls' || security === 'reality';
}
export function trafficFor(
outboundsTraffic: OutboundTrafficRow[],
o: OutboundRow,
): { up: number; down: number } {
const tr = outboundsTraffic.find((x) => x.tag === o.tag);
return { up: tr?.up || 0, down: tr?.down || 0 };
}
export function countryFlag(country?: string): string {
const code = (country || '').trim().toUpperCase();
if (!/^[A-Z]{2}$/.test(code)) return '';
return String.fromCodePoint(...[...code].map((ch) => 0x1f1e6 + ch.charCodeAt(0) - 65));
}
export function countryName(country?: string, locale?: string): string {
const code = (country || '').trim().toUpperCase();
if (!/^[A-Z]{2}$/.test(code)) return '';
try {
return (
new Intl.DisplayNames(locale ? [locale] : undefined, { type: 'region' }).of(code) || code
);
} catch {
return code;
}
}