- {@const activeServers = (ip.active_on_servers ?? []).filter(Boolean)}
- {@const recentServers = (ip.recent_on_servers ?? []).filter(Boolean)}
- {@const primaryServer = ip.primary_server ?? null}
- {@const recentOnly = recentServers.filter((s) => !activeServers.includes(s))}
-
- {#if activeServers.length === 0}
- —
- {:else}
-
- {#each activeServers as srv (srv)}
-
- {srv}
-
- {#if primaryServer && srv === primaryServer}
- primary
- {/if}
- {/each}
-
- {/if}
-
- {#if recentOnly.length > 0}
-
- recent
- {#each recentOnly as srv (srv)}
-
- {srv}
-
- {/each}
-
- {/if}
+
+
{/each}
diff --git a/web/src/routes/users/[username]/+page.svelte b/web/src/routes/users/[username]/+page.svelte
index 3d636e0..9db182d 100644
--- a/web/src/routes/users/[username]/+page.svelte
+++ b/web/src/routes/users/[username]/+page.svelte
@@ -9,7 +9,10 @@
import { Badge } from '$lib/components/ui/badge/index.js';
import { Button } from '$lib/components/ui/button/index.js';
import * as Table from '$lib/components/ui/table/index.js';
+ import * as Tooltip from '$lib/components/ui/tooltip/index.js';
+ import IpServerPresence from '$lib/components/ip-server-presence.svelte';
import CopyIcon from '@lucide/svelte/icons/copy';
+ import InfoIcon from '@lucide/svelte/icons/info';
import { toast } from 'svelte-sonner';
let loading = $state(true);
@@ -187,7 +190,9 @@
IP и подключения
- active/recent с серверами и Geo/ASN (если доступно)
+
+ Снимок шлюза: активные и недавние списки по серверам; Geo/ASN при доступности данных.
+
{#if ipErr}
@@ -202,7 +207,25 @@
IP
- Серверы
+
+
+ Серверы
+
+
+
+
+
+
+ Активные и недавние — это списки на момент снимка шлюза; в ячейке коротко
+ пояснено, что означает каждая группа.
+
+
+
+
+
Geo / ASN
@@ -224,16 +247,12 @@
>
{ip.ip}
-