Add network identity diagnostics
Build and Deploy Gateway / build-and-push (push) Successful in 20s
Build and Deploy Gateway / deploy (push) Successful in 13s

This commit is contained in:
2026-08-11 16:19:23 +03:00
parent 3566f4bc0b
commit 6381760b27
8 changed files with 211 additions and 9 deletions
@@ -10,6 +10,7 @@ import { Drawer } from '../../ui/Drawer.js';
import { Tooltip } from '../../ui/Tooltip.js';
import {
CONNECTIVITY_IP_SOURCES,
CONNECTIVITY_NETWORK_SOURCE,
CONNECTIVITY_SITES,
MAX_CUSTOM_DIAGNOSTIC_SERVICES,
} from '../../../shared/connectivityDiagnostics.js';
@@ -134,6 +135,32 @@ function IpCell({
return <code aria-label={`${route}: ${value.address}`}>{value.address}</code>;
}
function NetworkCell({
path,
pending,
route,
}: {
path: DiagnosticPath | undefined;
pending: boolean;
route: string;
}) {
let status: StatusValue | null = null;
if (path?.available === false) status = ['is-muted', '—'];
else if (pending) status = ['is-running', 'Тестируем'];
else if (!path?.available) status = ['is-muted', '—'];
const identity = [path?.network?.asn, path?.network?.provider].filter(Boolean).join(' · ');
const location = [path?.network?.city, path?.network?.country].filter(Boolean).join(', ');
if (!status && !identity && !location) status = ['is-error', 'Нет ответа'];
if (status) return <>
<Status value={status} route={route} /><br />
<span className="client-diagnostics-status is-muted" aria-hidden="true">&nbsp;</span>
</>;
return <span aria-label={`${route}: ${[identity, location].filter(Boolean).join(', ')}`}>
<span className="client-diagnostics-status">{identity || location}</span><br />
<span className="client-diagnostics-status is-muted">{identity && location ? location : <>&nbsp;</>}</span>
</span>;
}
function mergeItems<T>(previous: T[] = [], incoming: T[] = [], key: (item: T) => string) {
const merged = [...previous];
for (const item of incoming) {
@@ -161,6 +188,7 @@ function mergePath(previous: DiagnosticPath | undefined, incoming: DiagnosticPat
ipv4: { addresses, sources },
ipv6,
ipv6Source,
network: incoming.available === false ? null : incoming.network ?? previous?.network ?? null,
sites,
};
}
@@ -242,6 +270,7 @@ export function ConnectivityDiagnosticsPanel({
try {
let next = result;
const targets = [
CONNECTIVITY_NETWORK_SOURCE.id,
...CONNECTIVITY_IP_SOURCES.map(({ id }) => `ip:${id}`),
...sites.map(({ id }) => `site:${id}`),
];
@@ -378,7 +407,24 @@ export function ConnectivityDiagnosticsPanel({
<th>Напрямую</th>
<th>VPN{result?.vpn?.server?.label ? ` · ${result.vpn.server.label}` : ''}</th>
</tr></thead>
<tbody>{CONNECTIVITY_IP_SOURCES.map((source) => {
<tbody>
<tr
data-diagnostic-target={CONNECTIVITY_NETWORK_SOURCE.id}
className={activeTarget === CONNECTIVITY_NETWORK_SOURCE.id ? 'is-running' : undefined}
>
<th scope="row">{CONNECTIVITY_NETWORK_SOURCE.label}</th>
<td><NetworkCell
path={result?.direct}
pending={activeTarget === CONNECTIVITY_NETWORK_SOURCE.id}
route="Напрямую, сеть"
/></td>
<td><NetworkCell
path={result?.vpn}
pending={activeTarget === CONNECTIVITY_NETWORK_SOURCE.id}
route="VPN, сеть"
/></td>
</tr>
{CONNECTIVITY_IP_SOURCES.map((source) => {
const target = `ip:${source.id}`;
const running = activeTarget === target;
return <tr key={source.id} data-diagnostic-target={target} className={running ? 'is-running' : undefined}>