mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-09-13 16:23:08 +00:00
Кнопка в карточке ноды открывает модалку: выбор маршрута (по умолчанию / IP-адрес / интерфейс) с подсказками из данных ноды, ожидание, затем отчёт картинкой либо тем же отчётом в JSON. Есть копирование JSON, скачивание SVG, повтор проверки и полноэкранный режим. Кнопка показывается только для узлов 3.3.0+ (versions.node) и только для подключённых — иначе админ упирался бы в ошибку панели. Отчёт вставляется как <img src="data:...">, а не сырым SVG в разметку: он несёт встроенный моноширинный шрифт и <style>, на которых держится выравнивание колонок, и санитайзер их выбрасывает. В <img> SVG рисуется в изолированном контексте без скриптов и внешних запросов — и безопаснее, и вернее по виду. Зум и панорамирование — react-zoom-pan-pinch с той же конфигурацией, что в самой панели Remnawave. Своя реализация обязательна: index.html задаёт user-scalable=no, поэтому браузерного пинча нет ни в мобильном вебе, ни в Mini App. Колесо намеренно не масштабирует, иначе прокрутка над отчётом превращается в зум. В отличие от панели стартовый масштаб считается от читаемой ширины: на телефоне «вписано по ширине» превращает отчёт в серую рябь. На 390px это 2.42x с панорамированием, на десктопе — 1x. При смене ширины (полный экран, поворот) масштаб пересчитывается. Опрос задачи с потолком в три минуты — иначе забытая открытой модалка опрашивала бы панель бесконечно. Пока проверка идёт, модалка не закрывается: задача уже поставлена, терять её результат молча хуже. Заодно в AdminRemnawave.tsx осели автоправки biome (import type, Math.pow -> **) — файл всё равно правился, они механические. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import { GEOCHECK_MIN_NODE_VERSION, isVersionAtLeast, supportsGeoCheck } from './nodeVersion';
|
||
|
||
describe('isVersionAtLeast', () => {
|
||
it.each([
|
||
['3.3.0', true],
|
||
['3.3.1', true],
|
||
['3.4.0', true],
|
||
['4.0.0', true],
|
||
['v3.3.0', true],
|
||
['3.3', true],
|
||
['3.2.9', false],
|
||
['3.2.99', false],
|
||
['2.9.9', false],
|
||
['3', false],
|
||
])('%s vs 3.3.0 -> %s', (value, expected) => {
|
||
expect(isVersionAtLeast(value, '3.3.0')).toBe(expected);
|
||
});
|
||
|
||
it('сравнивает числа, а не строки: 3.10.0 новее 3.9.0', () => {
|
||
expect(isVersionAtLeast('3.10.0', '3.9.0')).toBe(true);
|
||
});
|
||
|
||
it('пререлиз целевой версии считается достаточным — фича там уже есть', () => {
|
||
expect(isVersionAtLeast('3.3.0-rc.1', '3.3.0')).toBe(true);
|
||
});
|
||
|
||
it.each([
|
||
undefined,
|
||
null,
|
||
'',
|
||
'unknown',
|
||
'dev',
|
||
])('нераспознанное значение %s -> false', (value) => {
|
||
expect(isVersionAtLeast(value, '3.3.0')).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('supportsGeoCheck', () => {
|
||
it('смотрит именно на версию узла, а не xray', () => {
|
||
expect(supportsGeoCheck({ node: '3.3.0' })).toBe(true);
|
||
expect(supportsGeoCheck({ node: '3.2.0' })).toBe(false);
|
||
});
|
||
|
||
it.each([undefined, null, {}])('без версии узла — false (%s)', (versions) => {
|
||
expect(supportsGeoCheck(versions as { node?: string } | null | undefined)).toBe(false);
|
||
});
|
||
|
||
it('порог совпадает с задокументированным минимумом', () => {
|
||
expect(supportsGeoCheck({ node: GEOCHECK_MIN_NODE_VERSION })).toBe(true);
|
||
});
|
||
});
|