diff --git a/README.md b/README.md index 4a91095..eba4dee 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ scripts/run-local-e2e.sh # сквозной прог | Дата | Веха | Документ | |---|---|---| +| 2026-10-04 | Аналитика: карточки `pass`, `partial`, `fail` открывают список адресов с этим вердиктом и выгрузку в CSV (`lists/verdict_*`) | [план](docs/changes/2026-10-04_09-55_analytics-verdict-indicators-plan.md) · [итог](docs/changes/2026-10-04_09-55_analytics-verdict-indicators-summary.md) | | 2026-10-04 | Повтор после сбоя self-check — на другом валидаторе: валидатор, проваливший self-check, этому адресу больше не выдаётся; потолок провалов `self_check_max_attempts` (по умолчанию 5, миграция `0012`); поле `self_check_failed_on` | [план](docs/changes/2026-10-04_08-01_self-check-exclude-validator-plan.md) · [итог](docs/changes/2026-10-04_08-01_self-check-exclude-validator-summary.md) | | 2026-10-03 | Раздел «Аналитика»: запуски проверки (миграция `0011`), показатели и списки адресов по запуску, подсети, CSV; сайдбар: связь с control-api и выход наверху, группы разделов; фильтры реестра по запуску и подсети | [план](docs/changes/2026-10-03_16-39_analytics-section-plan.md) · [итог](docs/changes/2026-10-03_18-41_analytics-section-summary.md) · [макет](docs/mockups/analytics-mockup.html) · [USAGE](docs/USAGE.md#аналитика-запусков) · [API](docs/API.md#аналитика-запусков) | | 2026-10-03 | Вердикт без опоздавших результатов: проверки фиксируются в момент вердикта, площадка зондирует адрес один раз за попытку, окно проверки считается от её начала, время записи по часам сервера (`checks.recorded_at`) | [план](docs/changes/2026-10-03_17-21_verdict-no-late-results-plan.md) · [итог](docs/changes/2026-10-03_17-21_verdict-no-late-results-summary.md) · [API](docs/API.md#результаты-после-вердикта) · [USAGE](docs/USAGE.md#просмотр-деталей-и-истории-по-конкретному-адресу) | diff --git a/bin/SHA256SUMS b/bin/SHA256SUMS index fb86211..e5d4836 100644 --- a/bin/SHA256SUMS +++ b/bin/SHA256SUMS @@ -1,4 +1,4 @@ -0ce9e3b5637b892420a61c8c01843a2348faeaddd11a601ed88e0b1ef25f04c8 control-api +43160e29c10730592ba1b25c20b42665d043a7d25b94433b2b89d5fd111a5b36 control-api 9fb6608b84143f7c4f318f3cc92dcd9f95c7831d627b23d67cce5a5908ced704 validator-agent 3e9e14dbb361ee76aaad7c1da6864b3ea111e0ed151403f904b12485631bbf75 prober -b5dce1ecee2ebd03603cf8574ccea7129958923ca3db3b29fa4dfa87ac14f5ab admin-dashboard +bb3ca7ba12a93c5a018a5c7532dfeb722a866ddfa27a9521cb24d0464fa3595d admin-dashboard diff --git a/bin/admin-dashboard b/bin/admin-dashboard index ac5e144..b0eb867 100755 Binary files a/bin/admin-dashboard and b/bin/admin-dashboard differ diff --git a/bin/control-api b/bin/control-api index 60f1e71..5d67a86 100755 Binary files a/bin/control-api and b/bin/control-api differ diff --git a/docs/API.md b/docs/API.md index c0c20c3..1c1e588 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1067,9 +1067,9 @@ curl -s "$BASE/api/v1/admin/ips/203.0.113.10" | python3 -m json.tool ### `GET /api/v1/admin/analytics/runs/{id}/lists/{kind}` Таблица адресов за показателем или классом ошибки: `{"kind", "class", "columns": [...], "rows": [[...]]}`. -`kind`: `egress_https_any`, `egress_https_all`, `ingress_ssh_any`, `ingress_ssh_all` или `error` (с `?class=SSH: таймаут`; +`kind`: `verdict_pass`, `verdict_partial`, `verdict_fail`, `egress_https_any`, `egress_https_all`, `ingress_ssh_any`, `ingress_ssh_all` или `error` (с `?class=SSH: таймаут`; без класса и неизвестный `kind` — `404`). С `?format=csv` — файл CSV (UTF-8 с BOM, `Content-Disposition: attachment`, -имя вида `ingress_ssh_all_run1.csv`). Для `error` строка — одна проваленная проверка: адрес, подсеть, площадка, +имя вида `ingress_ssh_all_run1.csv`). Для `verdict_*` — адреса запуска с этим вердиктом (без `cancelled`, по числовому порядку; число строк равно `summary.pass`/`partial`/`fail`): адрес, подсеть, валидатор (по https-проверкам, «—», если их нет), `Egress` и `Ingress` («успешно из всех», «—» без проверок), «Проверок в цикле» (записано из ожидаемых) и у `partial` ещё «Причина» (как в блоке `reasons`). Для `error` строка — одна проваленная проверка: адрес, подсеть, площадка, валидатор, вердикт адреса, статус («провал, в вердикте» или «провал, после вердикта»). ### `GET /api/v1/admin/config/subnets`, `PUT /api/v1/admin/config/subnets` diff --git a/docs/DASHBOARD.md b/docs/DASHBOARD.md index f25c521..8078449 100644 --- a/docs/DASHBOARD.md +++ b/docs/DASHBOARD.md @@ -58,7 +58,7 @@ admin-dashboard -config /etc/cloud-ip-validator/admin-dashboard.yaml | `/ips/{ip}` | Детали одного адреса, пока он в очереди: все проверки текущей попытки и вся история событий, плюс ссылка на полную историю в реестре (см. ниже). | | `/registry` | **Реестр** — все адреса, когда-либо поставленные на проверку, независимо от того, стоят ли они сейчас в очереди. Переживает удаление адреса из `/ips` и повторное добавление того же адреса позже (см. «Реестр адресов» ниже). Поиск по IP и фильтр по статусу — то же самое, что на `/overview`, плюс отражается в адресной строке (`?q=&status=`), так что отфильтрованную ссылку можно сохранить/переслать. В колонке «Последний результат» под вердиктом — уровни **Egress** и **Ingress** в виде «N из M» с разбивкой по типам проверок (`https`, `icmp`, `ssh`, `tcp`, `tls`…), см. [USAGE.md](USAGE.md#реестр-адресов-и-глубина-истории). | | `/registry/{ip}` | Полная сохранённая история проверок одного адреса по всем циклам (не только текущему) — в отличие от `/ips/{ip}`, которая показывает только текущую попытку. | -| `/analytics` | **Аналитика** одного завершённого запуска (`?run=ID`, по умолчанию последний): выбор запуска (идущий виден, но недоступен), показатели, причины `partial`, качество данных, подсети, egress по целям (по типу проверки, тепловая карта «подсеть × цель»), ingress по площадкам, классы ошибок, валидаторы. Карточки провалов `https`/`ssh` и классы ошибок открывают список адресов с выгрузкой в CSV. Подробности — [USAGE.md](USAGE.md#аналитика-запусков). | +| `/analytics` | **Аналитика** одного завершённого запуска (`?run=ID`, по умолчанию последний): выбор запуска (идущий виден, но недоступен), показатели, причины `partial`, качество данных, подсети, egress по целям (по типу проверки, тепловая карта «подсеть × цель»), ingress по площадкам, классы ошибок, валидаторы. Карточки `pass`/`partial`/`fail`, карточки провалов `https`/`ssh` и классы ошибок открывают список адресов с выгрузкой в CSV. Подробности — [USAGE.md](USAGE.md#аналитика-запусков). | | `/validators` | Список валидаторов + создание/изменение `os_port_id`/удаление. | | `/sites` | Площадки — число слотов не ограничено, форма сверху добавляет новый слот, назначить/сменить/освободить `site_id` в каждой строке; колонка «Статус» показывает бейдж подключения пробера (`unregistered`/`idle`/`unreachable`, по аналогии с `/validators`), см. [USAGE.md](USAGE.md#состояния-площадки). | | `/targets` | Группы целей для egress-проверок — создание/редактирование/удаление. | diff --git a/docs/USAGE.md b/docs/USAGE.md index a41f631..e8c2235 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -440,7 +440,7 @@ curl -s http://:8080/api/v1/admin/registry/203.0.113.10 | python3 - (поздние результаты, неполный набор). После изменения «вердикт без опоздавших результатов» поздних результатов в новых запусках быть не должно. -**Что можно открыть.** Карточки «Egress https: есть провалы / все провалены» и «Ingress ssh: есть провалы / все +**Что можно открыть.** Карточки `pass`, `partial` и `fail` (список адресов с этим вердиктом: подсеть, валидатор, Egress и Ingress «успешно из всех», число проверок в цикле, у `partial` ещё причина; `fail` с нулём не кликается), карточки «Egress https: есть провалы / все провалены» и «Ingress ssh: есть провалы / все провалены», а также каждая строка блока «Классы ошибок ingress» открывают окно со списком адресов (для класса ошибок — с распределением по валидаторам и статусом каждой проверки). В окне кнопки «Скачать CSV» (файл от control-api, UTF-8 с BOM, открывается в Excel) и «Копировать». Строка подсети и строка матрицы «подсеть × цель» ведут в «Реестр» diff --git a/docs/changes/2026-10-04_09-55_analytics-verdict-indicators-plan.md b/docs/changes/2026-10-04_09-55_analytics-verdict-indicators-plan.md new file mode 100644 index 0000000..67e4898 --- /dev/null +++ b/docs/changes/2026-10-04_09-55_analytics-verdict-indicators-plan.md @@ -0,0 +1,76 @@ +# План: кликабельные индикаторы PASS, PARTIAL, FAIL в разделе «Аналитика» + +Статус: реализовано, см. [итог](2026-10-04_09-55_analytics-verdict-indicators-summary.md). + +## 1. Что нужно + +Вверху страницы `/analytics` есть ряд индикаторов. Сейчас кликабельны только четыре «прикладных»: «Egress https: есть провалы / все провалены» и «Ingress ssh: есть провалы / все провалены» (открывают окно со списком адресов, есть «Скачать CSV» и «Копировать»). Нужно сделать кликабельными ещё три: **pass**, **partial**, **fail**. По клику открывается тот же диалог со списком адресов с этим вердиктом. + +Остальные индикаторы («Адресов», «Egress OK», «Ingress OK», «Длительность», «Поздние результаты») остаются как есть: в задаче их нет. + +## 2. Решение + +Новые виды списков строятся по тому же механизму, что и существующие: control-api отдаёт таблицу (JSON или CSV), дашборд проксирует, JS открывает диалог. Новых маршрутов, миграций и новых данных не нужно: вердикт, число проверок и причина `partial` уже вычисляются в `analytics.Compute`. + +### 2.1. control-api (`internal/analytics/lists.go`) + +Три новых вида списка (`kind`): `verdict_pass`, `verdict_partial`, `verdict_fail`. В список входят адреса запуска с этим вердиктом; отменённые (`cancelled`) не входят, как и в остальных списках и в числах `summary`. Порядок — по числовому адресу (`an.sorted()`). + +Столбцы: + +| Вид | Столбцы | +|---|---| +| `verdict_pass` | Адрес, Подсеть, Валидатор, Egress, Ingress, Проверок в цикле | +| `verdict_partial` | Адрес, Подсеть, Валидатор, Egress, Ingress, Проверок в цикле, **Причина** | +| `verdict_fail` | Адрес, Подсеть, Валидатор, Egress, Ingress, Проверок в цикле | + +- «Валидатор» — тот же, что в списках https (`ShortValidator`); пусто → «—». +- «Egress» и «Ingress» — «успешно из всех» по уровню (`8 из 10`); у уровня без проверок — «—». +- «Проверок в цикле» — сохранённых из ожидаемых (`stored из ExpectedChecks`; если ожидаемое неизвестно, только сохранённое). Позволяет сразу увидеть «неполный набор». +- «Причина» у `partial` — та же формулировка, что в блоке «Почему partial» (`reasonName`), поэтому строки списка совпадают со столбиками блока. + +Название CSV: `verdict_pass_run.csv` и т. д. (по общему правилу). Для остальных видов ничего не меняется. Неизвестный `kind` по-прежнему даёт `404`. + +Инвариант: число строк списка равно числу на карточке (`summary.pass / partial / fail`). + +### 2.2. Дашборд (`internal/dashboard/static/analytics.js`, `analytics.css`) + +- В `renderKpis` у плиток `pass`, `partial`, `fail` в поле списка ставится соответствующий `kind`, плитка становится `