diff --git a/web/src/lib/components/mihomo/mihomo-proxy-groups.svelte b/web/src/lib/components/mihomo/mihomo-proxy-groups.svelte index 9e1a002..df207ec 100644 --- a/web/src/lib/components/mihomo/mihomo-proxy-groups.svelte +++ b/web/src/lib/components/mihomo/mihomo-proxy-groups.svelte @@ -6,6 +6,7 @@ import DataQueryState from '$lib/components/fleet/data-query-state.svelte'; import { Skeleton } from '$lib/components/ui/skeleton/index.js'; import { cn } from '$lib/utils.js'; + import RefreshCwIcon from '@lucide/svelte/icons/refresh-cw'; let { alias, @@ -39,8 +40,8 @@ try { proxiesData = await fetchMihomoJson(a, 'proxies'); } catch (e) { - proxiesData = null; proxiesErr = e instanceof ApiError ? e.message : String(e); + // не затираем успешный снимок при сбое обновления — без мерцания UI } finally { proxiesLoading = false; } @@ -59,6 +60,15 @@ return false; } + /** Стабильный порядок групп — меньше скачков DOM при обновлении JSON. */ + let selectableGroups = $derived.by((): [string, MihomoProxyEntry][] => { + const p = proxiesData?.proxies; + if (!p) return []; + return Object.entries(p) + .filter(([_, v]) => isSelectableGroup(v)) + .sort(([a], [b]) => a.localeCompare(b)); + }); + function lastDelay(p: MihomoProxyEntry): number | null { const h = p.history; if (!h?.length) return null; @@ -139,11 +149,20 @@ onclick={() => loadProxies()} disabled={proxiesLoading || !alias} > +