Enhance Mihomo proxy groups component with new delay management features
- Added new props for managing delay checks across all groups, improving user control over delay monitoring. - Implemented a loading state for delay checks to provide feedback during asynchronous operations. - Updated UI elements to conditionally display delay buttons, enhancing the overall user experience and interaction with proxy groups.
This commit is contained in:
@@ -19,13 +19,22 @@
|
||||
/** Увеличьте, чтобы принудительно перезагрузить список снаружи. */
|
||||
refreshNonce = 0,
|
||||
/** Состояние загрузки для индикатора у родителя. */
|
||||
onLoadingChange
|
||||
onLoadingChange,
|
||||
/** Увеличьте — проверить задержку для всех групп (флот: кнопка в шапке карточки). */
|
||||
delayAllNonce = 0,
|
||||
/** Не показывать «Все задержки» внутри группы (кнопка на родителе). */
|
||||
hideCompactPerGroupDelayButton = false,
|
||||
/** Идёт проверка задержек по всем группам. */
|
||||
onDelayAllChange
|
||||
}: {
|
||||
alias: string;
|
||||
compact?: boolean;
|
||||
hideToolbar?: boolean;
|
||||
refreshNonce?: number;
|
||||
onLoadingChange?: (loading: boolean) => void;
|
||||
delayAllNonce?: number;
|
||||
hideCompactPerGroupDelayButton?: boolean;
|
||||
onDelayAllChange?: (busy: boolean) => void;
|
||||
} = $props();
|
||||
|
||||
const MIHOMO_DELAY_DEFAULT_URL = 'https://www.gstatic.com/generate_204';
|
||||
@@ -150,6 +159,23 @@
|
||||
testingGroup = null;
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
const a = alias;
|
||||
const n = delayAllNonce;
|
||||
if (!a || n <= 0) return;
|
||||
const groupsSnapshot = untrack(() => [...selectableGroups]);
|
||||
void (async () => {
|
||||
untrack(() => onDelayAllChange?.(true));
|
||||
try {
|
||||
for (const [gName] of groupsSnapshot) {
|
||||
await pingGroup(gName);
|
||||
}
|
||||
} finally {
|
||||
untrack(() => onDelayAllChange?.(false));
|
||||
}
|
||||
})();
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if !hideToolbar}
|
||||
@@ -202,11 +228,11 @@
|
||||
{#each selectableGroups as [gName, group] (gName)}
|
||||
{#if compact}
|
||||
<div
|
||||
class="bg-card/40 ring-border/60 space-y-2 rounded-lg p-2 ring-1 sm:p-2.5"
|
||||
class="bg-muted/15 space-y-2 rounded-md border border-border/50 p-2 sm:p-2.5"
|
||||
role="group"
|
||||
aria-label="Группа {gName}"
|
||||
>
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<div class="flex min-w-0 flex-1 flex-wrap items-center gap-x-2 gap-y-1">
|
||||
<Badge variant="outline" class="h-5 px-1.5 font-mono text-[10px] uppercase tracking-wide">
|
||||
{gName}
|
||||
@@ -215,15 +241,17 @@
|
||||
<span class="text-foreground/90 font-medium">{group.now ?? '—'}</span>
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="h-7 shrink-0 px-2 text-xs"
|
||||
onclick={() => pingGroup(gName)}
|
||||
disabled={testingGroup === gName}
|
||||
>
|
||||
{testingGroup === gName ? '…' : 'Все delay'}
|
||||
</Button>
|
||||
{#if !hideCompactPerGroupDelayButton}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="h-7 shrink-0 px-2 text-xs"
|
||||
onclick={() => pingGroup(gName)}
|
||||
disabled={testingGroup === gName}
|
||||
>
|
||||
{testingGroup === gName ? '…' : 'Все задержки'}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1.5" role="list">
|
||||
{#each group.all ?? [] as nodeName (nodeName)}
|
||||
@@ -232,10 +260,10 @@
|
||||
{@const active = group.now === nodeName}
|
||||
<div
|
||||
class={cn(
|
||||
'bg-background focus-within:ring-ring flex min-w-0 max-w-full items-stretch overflow-hidden rounded-md border text-left text-xs shadow-sm transition-colors focus-within:ring-2',
|
||||
'bg-background flex min-w-0 max-w-full items-stretch overflow-hidden rounded-md border text-left text-xs transition-colors',
|
||||
active
|
||||
? 'border-primary bg-accent/25'
|
||||
: 'border-border hover:border-border/80 hover:bg-muted/40'
|
||||
? 'border-primary/60 bg-muted/30'
|
||||
: 'border-border/60 hover:bg-muted/25'
|
||||
)}
|
||||
role="listitem"
|
||||
>
|
||||
@@ -298,7 +326,7 @@
|
||||
onclick={() => pingGroup(gName)}
|
||||
disabled={testingGroup === gName}
|
||||
>
|
||||
{testingGroup === gName ? 'Проверка…' : 'Проверить все'}
|
||||
{testingGroup === gName ? 'Проверка…' : 'Все задержки'}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
|
||||
@@ -51,12 +51,18 @@
|
||||
let pollTimer: ReturnType<typeof setInterval> | null = null;
|
||||
/** Принудительная перезагрузка /proxies для карточки ноды. */
|
||||
let proxyRefreshNonce = $state<Record<string, number>>({});
|
||||
let proxyDelayAllNonce = $state<Record<string, number>>({});
|
||||
let nodeProxyLoading = $state<Record<string, boolean>>({});
|
||||
let nodeDelayAllBusy = $state<Record<string, boolean>>({});
|
||||
|
||||
function bumpProxyRefresh(a: string) {
|
||||
proxyRefreshNonce = { ...proxyRefreshNonce, [a]: (proxyRefreshNonce[a] ?? 0) + 1 };
|
||||
}
|
||||
|
||||
function bumpProxyDelayAll(a: string) {
|
||||
proxyDelayAllNonce = { ...proxyDelayAllNonce, [a]: (proxyDelayAllNonce[a] ?? 0) + 1 };
|
||||
}
|
||||
|
||||
let withMihomo = $derived(rows.filter((r) => r.metaStatus === 'ok').length);
|
||||
let aliveCount = $derived(rows.filter((r) => r.metaStatus === 'ok' && r.alive).length);
|
||||
let sumConn = $derived(
|
||||
@@ -334,8 +340,8 @@
|
||||
<div>
|
||||
<h2 class="text-base font-semibold tracking-tight">Прокси по нодам</h2>
|
||||
<p class="text-muted-foreground mt-0.5 max-w-2xl text-xs leading-relaxed">
|
||||
Автозагрузка групп. Клик по узлу — выбор; иконка справа — проверка задержки. Обновление списка — в
|
||||
шапке карточки.
|
||||
Автозагрузка групп. В шапке: «Все задержки» и обновление списка. Клик по узлу — выбор; справа —
|
||||
проверка одного узла.
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
@@ -358,13 +364,22 @@
|
||||
{r.meta.controller_base}
|
||||
</Card.Description>
|
||||
{/if}
|
||||
<Card.Action>
|
||||
<Card.Action class="flex flex-wrap items-center justify-end gap-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="h-8 px-2 text-xs"
|
||||
disabled={!!nodeProxyLoading[r.alias] || !!nodeDelayAllBusy[r.alias]}
|
||||
onclick={() => bumpProxyDelayAll(r.alias)}
|
||||
>
|
||||
{nodeDelayAllBusy[r.alias] ? 'Проверка…' : 'Все задержки'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="size-8 shrink-0"
|
||||
aria-label="Обновить прокси для {r.alias}"
|
||||
disabled={!!nodeProxyLoading[r.alias]}
|
||||
disabled={!!nodeProxyLoading[r.alias] || !!nodeDelayAllBusy[r.alias]}
|
||||
onclick={() => bumpProxyRefresh(r.alias)}
|
||||
>
|
||||
<RefreshCwIcon
|
||||
@@ -383,10 +398,15 @@
|
||||
alias={r.alias}
|
||||
compact={true}
|
||||
hideToolbar={true}
|
||||
hideCompactPerGroupDelayButton={true}
|
||||
refreshNonce={proxyRefreshNonce[r.alias] ?? 0}
|
||||
delayAllNonce={proxyDelayAllNonce[r.alias] ?? 0}
|
||||
onLoadingChange={(v) => {
|
||||
nodeProxyLoading = { ...nodeProxyLoading, [r.alias]: v };
|
||||
}}
|
||||
onDelayAllChange={(v) => {
|
||||
nodeDelayAllBusy = { ...nodeDelayAllBusy, [r.alias]: v };
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Card.Content>
|
||||
|
||||
Reference in New Issue
Block a user