summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
authorLarvan2 <[email protected]>2026-06-04 21:14:57 +0800
committerLarvan2 <[email protected]>2026-06-04 21:14:57 +0800
commitcc6efa25afc9853771565a5f68d1cc24b3a945b2 (patch)
treeb428b0aec1f183d2c2bddbba45f081bede7f1da5 /src/components
parent64e7ca292446242c4769b8e54bd4db048eb46170 (diff)
feat(proxies): add latency test URL and timeout configuration
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Config.tsx12
-rw-r--r--src/components/proxies/Proxies.tsx6
-rw-r--r--src/components/proxies/ProxyGroup.tsx6
-rw-r--r--src/components/proxies/Settings.module.scss67
-rw-r--r--src/components/proxies/Settings.tsx55
5 files changed, 130 insertions, 16 deletions
diff --git a/src/components/Config.tsx b/src/components/Config.tsx
index 2d3f08b..553faad 100644
--- a/src/components/Config.tsx
+++ b/src/components/Config.tsx
@@ -38,7 +38,6 @@ type Props = {
dispatch: DispatchFn;
configs: ClashGeneralConfig;
selectedChartStyleIndex: number;
- latencyTestUrl: string;
apiConfig: ClashAPIConfig;
};
@@ -46,7 +45,6 @@ export default function Config({
dispatch,
configs,
selectedChartStyleIndex,
- latencyTestUrl,
apiConfig,
}: Props) {
const { t, i18n } = useTranslation();
@@ -277,16 +275,6 @@ export default function Config({
</div>
<div className={s0.section}>
<div>
- <div className={s0.label}>{t('latency_test_url')}</div>
- <SelfControlledInput
- name="latencyTestUrl"
- type="text"
- value={latencyTestUrl}
- onBlur={handleInputOnBlur}
- className=""
- />
- </div>
- <div>
<div className={s0.label}>{t('lang')}</div>
<div>
<Select
diff --git a/src/components/proxies/Proxies.tsx b/src/components/proxies/Proxies.tsx
index e8e3d4b..667c990 100644
--- a/src/components/proxies/Proxies.tsx
+++ b/src/components/proxies/Proxies.tsx
@@ -28,6 +28,8 @@ type AppConfig = {
autoCloseOldConns: boolean;
proxiesLayout: string;
proxyGroupByProvider: boolean;
+ latencyTestUrl: string;
+ latencyTestTimeout: number;
};
type Props = {
@@ -35,7 +37,6 @@ type Props = {
groupNames: string[];
proxies: ProxiesMapping;
delay: DelayMapping;
- latencyTestUrl: string;
collapsibleIsOpen: Record<string, boolean>;
proxyProviders: FormattedProxyProvider[];
apiConfig: ClashAPIConfig;
@@ -48,13 +49,13 @@ export default function Proxies({
groupNames,
proxies,
delay,
- latencyTestUrl,
collapsibleIsOpen,
proxyProviders,
apiConfig,
showModalClosePrevConns,
appConfig,
}: Props) {
+ const { latencyTestUrl, latencyTestTimeout } = appConfig;
const {
isSettingsModalOpen,
openSettingsModal,
@@ -99,6 +100,7 @@ export default function Proxies({
proxySortBy={appConfig.proxySortBy}
isOpen={Boolean(collapsibleIsOpen[`proxyGroup:${name}`])}
latencyTestUrl={latencyTestUrl}
+ latencyTestTimeout={latencyTestTimeout}
proxyGroupByProvider={appConfig.proxyGroupByProvider}
/>
</div>
diff --git a/src/components/proxies/ProxyGroup.tsx b/src/components/proxies/ProxyGroup.tsx
index b493ff1..6991da6 100644
--- a/src/components/proxies/ProxyGroup.tsx
+++ b/src/components/proxies/ProxyGroup.tsx
@@ -92,6 +92,7 @@ type Props = {
proxies: ProxiesMapping;
isOpen: boolean;
latencyTestUrl: string;
+ latencyTestTimeout?: number;
apiConfig: ClashAPIConfig;
dispatch: DispatchFn;
proxyGroupByProvider?: boolean;
@@ -105,6 +106,7 @@ export const ProxyGroup = memo(function ProxyGroup({
proxies,
isOpen,
latencyTestUrl,
+ latencyTestTimeout = 5000,
apiConfig,
dispatch,
proxyGroupByProvider = false,
@@ -172,7 +174,7 @@ export const ProxyGroup = memo(function ProxyGroup({
setIsTestingLatency(true);
try {
if (version.meta === true) {
- await proxiesAPI.requestDelayForProxyGroup(apiConfig, name, latencyTestUrl);
+ await proxiesAPI.requestDelayForProxyGroup(apiConfig, name, latencyTestUrl, latencyTestTimeout);
await dispatch(fetchProxies(apiConfig));
} else {
await requestDelayForProxies(apiConfig, all);
@@ -180,7 +182,7 @@ export const ProxyGroup = memo(function ProxyGroup({
}
} catch (err) {}
setIsTestingLatency(false);
- }, [all, apiConfig, dispatch, name, version.meta, latencyTestUrl, requestDelayForProxies]);
+ }, [all, apiConfig, dispatch, name, version.meta, latencyTestUrl, latencyTestTimeout, requestDelayForProxies]);
return (
<div className={s0.group}>
diff --git a/src/components/proxies/Settings.module.scss b/src/components/proxies/Settings.module.scss
index 364d07d..d3eb540 100644
--- a/src/components/proxies/Settings.module.scss
+++ b/src/components/proxies/Settings.module.scss
@@ -8,6 +8,73 @@
padding: 13px 0;
}
+.urlInputWrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+ width: 240px;
+}
+
+.urlInput {
+ width: 100%;
+ padding: 4px 24px 4px 8px;
+ border: 1px solid var(--color-separator);
+ border-radius: 4px;
+ background: var(--color-bg-1, transparent);
+ color: inherit;
+ font-size: 12px;
+ outline: none;
+
+ &:focus {
+ border-color: var(--color-focus-blue, #409eff);
+ }
+}
+
+.urlClearBtn {
+ position: absolute;
+ right: 6px;
+ background: none;
+ border: none;
+ cursor: pointer;
+ color: var(--color-text-secondary, #909399);
+ padding: 0;
+ line-height: 1;
+ font-size: 14px;
+ display: flex;
+ align-items: center;
+
+ &:hover {
+ color: var(--color-text, inherit);
+ }
+}
+
+.timeoutInputWrapper {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.timeoutInput {
+ width: 70px;
+ padding: 4px 8px;
+ border: 1px solid var(--color-separator);
+ border-radius: 4px;
+ background: var(--color-bg-1, transparent);
+ color: inherit;
+ font-size: 12px;
+ text-align: right;
+ outline: none;
+
+ &:focus {
+ border-color: var(--color-focus-blue, #409eff);
+ }
+}
+
+.timeoutUnit {
+ font-size: 12px;
+ color: var(--color-text-secondary, #909399);
+}
+
hr {
height: 1px;
background-color: var(--color-separator);
diff --git a/src/components/proxies/Settings.tsx b/src/components/proxies/Settings.tsx
index d61925a..649d9b9 100644
--- a/src/components/proxies/Settings.tsx
+++ b/src/components/proxies/Settings.tsx
@@ -17,6 +17,8 @@ type AppConfig = {
autoCloseOldConns: boolean;
proxiesLayout: string;
proxyGroupByProvider: boolean;
+ latencyTestUrl: string;
+ latencyTestTimeout: number;
};
type Props = {
@@ -41,10 +43,63 @@ export default function Settings({ appConfig }: Props) {
},
[updateAppConfig],
);
+
+ const handleLatencyUrlChange = useCallback(
+ (e: React.ChangeEvent<HTMLInputElement>) => {
+ updateAppConfig('latencyTestUrl', e.target.value);
+ },
+ [updateAppConfig],
+ );
+
+ const handleLatencyUrlClear = useCallback(() => {
+ updateAppConfig('latencyTestUrl', '');
+ }, [updateAppConfig]);
+
+ const handleLatencyTimeoutChange = useCallback(
+ (e: React.ChangeEvent<HTMLInputElement>) => {
+ const v = parseInt(e.target.value, 10);
+ if (!isNaN(v) && v > 0) updateAppConfig('latencyTestTimeout', v);
+ },
+ [updateAppConfig],
+ );
+
const { t } = useTranslation();
return (
<>
<div className={s.labeledInput}>
+ <span>{t('latency_test_url')}</span>
+ <div className={s.urlInputWrapper}>
+ <input
+ className={s.urlInput}
+ type="text"
+ value={appConfig.latencyTestUrl}
+ onChange={handleLatencyUrlChange}
+ spellCheck={false}
+ />
+ {appConfig.latencyTestUrl && (
+ <button className={s.urlClearBtn} onClick={handleLatencyUrlClear} tabIndex={-1}>
+ ×
+ </button>
+ )}
+ </div>
+ </div>
+ <div className={s.labeledInput}>
+ <span>{t('latency_test_timeout')}</span>
+ <div className={s.timeoutInputWrapper}>
+ <input
+ className={s.timeoutInput}
+ type="number"
+ min={100}
+ max={30000}
+ step={100}
+ value={appConfig.latencyTestTimeout}
+ onChange={handleLatencyTimeoutChange}
+ />
+ <span className={s.timeoutUnit}>ms</span>
+ </div>
+ </div>
+ <hr />
+ <div className={s.labeledInput}>
<span>{t('sort_in_grp')}</span>
<div>
<Select