diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 466c694..0a3f43a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -11,7 +11,7 @@ body: attributes: label: Версии description: Panel, Node Agent, HAProxy и ОС ноды. - placeholder: "Panel 2.0.2, Agent 2.0.2, HAProxy 3.4, Ubuntu 24.04" + placeholder: "Panel 2.0.0, Agent 2.0.0, HAProxy 3.4, Ubuntu 24.04" validations: required: true - type: textarea diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e37d2..d1999f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,5 @@ # Changelog -## 2.0.2 — Подсказки к весу и стоимости - -- В таблице «Вес и стоимость отдельных IP» у DNS-пула появились подсказки к «Вес» и «Стоимость» и строка с формулой и примером под текущий алгоритм (для «Меньше соединений»: доля IP = вес ÷ стоимость). - -## 2.0.1 — Толерантность на одном DNS-пуле - -- Исправлено: маршрут с одним сервером-доменом в режиме DNS-пула терял «Толерантность» и алгоритм «Меньше соединений» при сохранении — панель сворачивала его в старый формат одиночного маршрута, где эти настройки не хранятся. Теперь такой маршрут остаётся пулом серверов, и толерантность сохраняется и применяется агентом. Маршруты без толерантности и с закреплением по хешу IP рендерятся как раньше, байт в байт. -- Агент для этого не меняется; номер 2.0.1 у Panel и Node Agent общий. - ## 2.0.0 — Готовые образы и расширенная балансировка Panel и Node Agent — 2.0.0, HAProxy renderer v21. Первый стабильный релиз после 1.0.8; в него вошли все изменения предварительных сборок 1.1.x. Заметки к релизу с инструкцией по обновлению: [docs/releases/2.0.0.md](docs/releases/2.0.0.md). @@ -28,7 +19,7 @@ Panel и Node Agent — 2.0.0, HAProxy renderer v21. Первый стабиль - **Домены в «Доверенных адресах» PROXY protocol.** `accept_proxy_from` принимает, кроме IP и подсетей, домены (до 32 на маршрут): домен означает все его A/AAAA-адреса (DNS-пул). Для порта с доменами рендерер добавляет `acl nf_pp_trusted src -f /etc/haproxy/nodeflow/pp-trusted-.acl` и `expect-proxy … if { src <статические> } || nf_pp_trusted` с аннотацией `# nf-pp-trusted`; порты без доменов рендерятся байт-в-байт как раньше (версия рендерера не меняется). Node Agent **1.1.3** резолвит домены перед каждой проверкой/перезагрузкой HAProxy и затем каждые 30 с; при изменении набора атомарно переписывает файл и подменяет ACL через runtime API (`prepare/add/commit acl`) без reload; без изменений — ни одной команды в сокет; при сбое DNS остаётся последний известный набор. Панель требует Agent ≥ 1.1.3: `422 pp_trusted_domains_requires_agent_1_1_3` при сохранении и публикации. В редакторе подсказка «IP, подсети или домены…», предпросмотр совпадает с рендерером. - **Splice-буферы 1 МиБ, когда ядро позволяет.** Node Agent **1.1.2** при старте и в каждом heartbeat поднимает `fs.pipe-max-size` до 1048576 (никогда не понижает) и ставит `fs.pipe-user-pages-soft = 0`: пишет прямо в `/proc/sys/fs/*` (без `sysctl`), сохраняет `/etc/sysctl.d/90-nodeflow-pipes.conf`; `NODE_AGENT_TUNE_SYSCTL=off` — только отчёт. Heartbeat сообщает `metrics.kernel_pipes {pipe_max_size, pipe_user_pages_soft, tuned, managed}`. systemd-юнит агента открывает на запись только эти два файла `/proc/sys` и `/etc/sysctl.d` (`ProtectKernelTunables` остаётся); самообновление юнит не меняет, поэтому на нодах, установленных 1.0.x, нужен однократный drop-in `20-kernel-pipes.conf` (см. заметки к релизу). Панель рендерит `tune.pipesize 1048576` для ноды, где `tuned=true`, `pipe_max_size ≥ 1048576` и `pipe_user_pages_soft = 0`, иначе прежние 262144. - **«Авто» размер stick-table от RAM ноды — изменение поведения.** `sticky_table_entries=''` для `sticky_mode=source_table` больше не означает фиксированные 100k: размер = clamp(5 % RAM / 228 Б / N, 100k, 10m), округлённый вниз до k, где N — число включённых «Авто»-таблиц на ноде; RAM из последнего heartbeat (`memory_total_bytes`), округлённый вниз до 256 МиБ, чтобы колебания не публиковали ревизии; RAM неизвестна — 1m. Память занимается только по мере прихода клиентов. Явные размеры не меняются. `GET` маршрута/списка отдаёт read-only `sticky_table_entries_effective` (например `919k`); редактор показывает «Авто: ~N клиентов (5% RAM ноды), ≈X МБ при полной таблице», превью совпадает с рендером. -- **«Меньше соединений»: стоимость и толерантность.** Для `balance_algorithm=leastconn` действуют `servers[].cost` и `ip_weights[].cost` (0,01..100): соединение с сервером стоимости *c* считается за *c*, панель рендерит статический `weight` = base/cost × K (без Agent; без стоимости конфиг байт-в-байт прежний). Новое поле `balance_tolerance` (алиас `leastping_tolerance`, та же колонка, без миграции): серверы, чья нагрузка (соединения × стоимость / вес) не больше минимума на столько процентов, считаются равными и делят новых клиентов по весу; при толерантности > 0 Node Agent 1.1.1 каждые 5 с читает `scur` и выставляет runtime-веса (гистерезис ×1,5, только изменённые веса). Требует Agent ≥ 1.1.1 (`422 leastconn_tolerance_requires_agent_1_1_1`). В редакторе «Стоимость» теперь видна и для «Меньше соединений», в блоке «Распределение клиентов» — «Толерантность, %». +- **«Меньше соединений»: вес и толерантность.** Для `balance_algorithm=leastconn` новые клиенты делятся пропорционально весу сервера и отдельного IP. В редакторе у этого алгоритма только «Вес»: стоимость там была бы просто обратным весом, поэтому колонки «Стоимость» нет, а сохранённые ранее `cost` при открытии маршрута переводятся в веса с теми же пропорциями. API по-прежнему принимает `servers[].cost` и `ip_weights[].cost` для `leastconn` (доля = вес ÷ стоимость, панель рендерит статический `weight` = base/cost × K; без стоимости конфиг байт-в-байт прежний). Новое поле `balance_tolerance` (алиас `leastping_tolerance`, та же колонка, без миграции): серверы, чья нагрузка (соединения / вес) не больше минимума на столько процентов, считаются равными и делят новых клиентов по весу; при толерантности > 0 Node Agent каждые 5 с читает `scur` и выставляет runtime-веса (гистерезис ×1,5, только изменённые веса). Требует Agent ≥ 1.1.1 (`422 leastconn_tolerance_requires_agent_1_1_1`). Маршрут из одного домена в режиме DNS-пула сохраняет толерантность и алгоритм (остаётся пулом серверов, а не сворачивается в одиночный маршрут). Подсказки к «Вес» и «Стоимость» в таблицах серверов и отдельных IP. ### Из предварительных сборок 1.1.x diff --git a/README.md b/README.md index df85889..5bbc442 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ NodeFlow — панель управления парком HAProxy-нод дл - **SNI-маршрутизация и фолбэк.** Общие listener'ы на порт, несколько SNI на маршрут, «Фолбэк» для всего, что не совпало; IP-, доменные и Unix-socket backend'ы. - **Несколько серверов и DNS-пулы.** До 16 серверов на маршрут в режимах «Пул» и «Основной + резервные»; домен как DNS-пул (все A/AAAA-адреса, с исключением недоступных), отдельные веса для IP пула. -- **Балансировка.** `roundrobin`, `static-rr`, `random`, `leastconn` и `leastping` («Меньше задержка»). Для `leastconn`/`leastping` — стоимость сервера и толерантность: близкие по нагрузке или задержке серверы делят клиентов по весу, веса на лету выставляет Agent через runtime API, без reload. +- **Балансировка.** `roundrobin`, `static-rr`, `random`, `leastconn` и `leastping` («Меньше задержка»). Вес сервера и отдельного IP DNS-пула, для `leastping` — ещё стоимость (множитель задержки); толерантность: близкие по нагрузке или задержке серверы делят клиентов по весу, веса на лету выставляет Agent через runtime API, без reload. - **Закрепление клиента.** Хеш IP (consistent или map-based, группировка IPv6 по префиксу) или таблица с TTL, переживающая reload; размер «Авто» подбирается от RAM ноды. - **PROXY protocol.** Приём от доверенных IP, подсетей и доменов (Agent резолвит их и обновляет ACL без reload), вариант «от всех»; health-check с PROXY-заголовком. - **Ограничение скорости.** Лимиты upload/download на IP клиента — фильтрами HAProxy или в ядре через nftables (`shaper_mode=kernel`), без потери splice. @@ -58,7 +58,7 @@ curl -fsSL https://raw.githubusercontent.com/NodeFlow-dev/nodeflow/main/install. 2. предложит режим доступа: Caddy cookie-gate (ссылка активации ставит защищённую cookie) или без него — токен администратора Panel нужен в любом случае; 3. установит Docker и **Caddy** — Caddy сам получит сертификат Let's Encrypt и будет проксировать HTTPS на Panel, которая слушает только `127.0.0.1:8080`; 4. скачает install kit последнего релиза, проверит его по SHA-256, который GitHub публикует для каждого asset релиза, возьмёт из него `compose.release.yaml`, сгенерирует `.env`, CA, сертификат mTLS и ключ подписи обновлений в `/opt/nodeflow`; -5. выполнит `docker compose pull && docker compose up -d` с образом `ghcr.io/nodeflow-dev/nodeflow-panel:2.0.2` — на сервере ничего не собирается, миграции БД применяет сам образ; +5. выполнит `docker compose pull && docker compose up -d` с образом `ghcr.io/nodeflow-dev/nodeflow-panel:2.0.0` — на сервере ничего не собирается, миграции БД применяет сам образ; 6. опубликует подписанные релизы Node Agent (amd64 и arm64) и сохранит реквизиты входа в `~/nodeflow-credentials.txt` (права `0600`). Файрвол установщик не меняет. Для автоматизации без вопросов передайте переменные `NODEFLOW_DOMAIN`, `NODEFLOW_AUTH_MODE=cookie|none` и при необходимости `NODEFLOW_VERSION=2.0.0` (по умолчанию — последний релиз): @@ -90,7 +90,7 @@ sudo NODE_AGENT_TOKEN=<токен> bash install-node.sh Команды выполняются от root (`sudo -i`): каталог `/opt/nodeflow` закрыт для остальных пользователей. ```bash -v=2.0.2 +v=2.0.0 kit=NodeFlow-Panel-$v-Agent-$v-install-kit curl -fsSLO "https://github.com/NodeFlow-dev/nodeflow/releases/download/v$v/$kit.tar.gz" # сверьте с digest asset'а на странице релиза или в API: @@ -119,7 +119,7 @@ curl -fsSL https://raw.githubusercontent.com/NodeFlow-dev/nodeflow/main/install. Найдя `/opt/nodeflow/.env`, он работает как апгрейдер: делает `pg_dump` и архив конфигурации в `/var/backups/nodeflow/`, сохраняет `.env`, `tls/`, `pki/` и Caddy-сниппет `/etc/caddy/conf.d/nodeflow-panel.caddy`, переводит установку со сборки из исходников на образ ghcr.io, запускает миграции и проверяет, что Panel отвечает версией 2.0.0. При ошибке возвращаются прежние `compose.yaml` и `.env`; дамп БД остаётся (миграции автоматически не откатываются). -Затем в **Настройки → Node Agent** обновите ноды до 2.0.2 — updater заменит Agent атомарно и откатит его при неудачном запуске. Самообновление не меняет systemd-юнит, поэтому на нодах, установленных версиями 1.0.x, один раз добавьте права на настройку pipe-буферов ядра (без этого splice остаётся на 256 КиБ) — или переустановите Agent из меню ноды: +Затем в **Настройки → Node Agent** обновите ноды до 2.0.0 — updater заменит Agent атомарно и откатит его при неудачном запуске. Самообновление не меняет systemd-юнит, поэтому на нодах, установленных версиями 1.0.x, один раз добавьте права на настройку pipe-буферов ядра (без этого splice остаётся на 256 КиБ) — или переустановите Agent из меню ноды: ```bash sudo install -d /etc/systemd/system/nodeflow-node-agent.service.d diff --git a/cmd/node-agent/main.go b/cmd/node-agent/main.go index 6e9a8da..554d110 100644 --- a/cmd/node-agent/main.go +++ b/cmd/node-agent/main.go @@ -14,7 +14,7 @@ import ( "github.com/nodeflow/nodeflow/internal/agent" ) -var version = "2.0.2" +var version = "2.0.0" func main() { showVersion := flag.Bool("version", false, "print Node Agent version and exit") diff --git a/cmd/panel-api/main.go b/cmd/panel-api/main.go index e90d7f4..b7da1ea 100644 --- a/cmd/panel-api/main.go +++ b/cmd/panel-api/main.go @@ -18,7 +18,7 @@ import ( // panelVersion is the published Panel release version. Release builds may // replace it with -ldflags "-X main.panelVersion=...". -var panelVersion = "2.0.2" +var panelVersion = "2.0.0" func main() { if len(os.Args) > 1 { diff --git a/compose.release.yaml b/compose.release.yaml index 4048db2..1c3a882 100644 --- a/compose.release.yaml +++ b/compose.release.yaml @@ -30,7 +30,7 @@ services: <<: *hardening migrate: - image: ghcr.io/nodeflow-dev/nodeflow-panel:${NODEFLOW_VERSION:-2.0.2} + image: ghcr.io/nodeflow-dev/nodeflow-panel:${NODEFLOW_VERSION:-2.0.0} restart: "no" command: ["migrate"] depends_on: @@ -79,7 +79,7 @@ services: <<: *hardening panel-api: - image: ghcr.io/nodeflow-dev/nodeflow-panel:${NODEFLOW_VERSION:-2.0.2} + image: ghcr.io/nodeflow-dev/nodeflow-panel:${NODEFLOW_VERSION:-2.0.0} restart: unless-stopped depends_on: migrate: diff --git a/docs/install/README-NODE-AGENT.txt b/docs/install/README-NODE-AGENT.txt index 1108b13..a728718 100644 --- a/docs/install/README-NODE-AGENT.txt +++ b/docs/install/README-NODE-AGENT.txt @@ -2,13 +2,13 @@ NODEFLOW NODE AGENT — SIGNED RELEASE UPLOAD =========================================== Бинарники Agent — отдельные assets GitHub Release: - nodeflow-node-agent-2.0.2-linux-amd64 - nodeflow-node-agent-2.0.2-linux-arm64 + nodeflow-node-agent-2.0.0-linux-amd64 + nodeflow-node-agent-2.0.0-linux-arm64 install.sh публикует их в Panel сам. Для ручной загрузки скачайте файл и сверьте SHA-256 с digest, который GitHub показывает для asset'а: - v=2.0.2 f=nodeflow-node-agent-2.0.2-linux-amd64 + v=2.0.0 f=nodeflow-node-agent-2.0.0-linux-amd64 curl -fsSLO https://github.com/NodeFlow-dev/nodeflow/releases/download/v$v/$f curl -fsSL https://api.github.com/repos/NodeFlow-dev/nodeflow/releases/tags/v$v \ | jq -r --arg n "$f" '.assets[] | select(.name == $n) | .digest' @@ -17,7 +17,7 @@ install.sh публикует их в Panel сам. Для ручной загр В Panel откройте: Настройки → Node Agent (подписанные релизы) -Версия 2.0.2, ОС linux, архитектура amd64 или arm64 — по файлу. Выберите +Версия 2.0.0, ОС linux, архитектура amd64 или arm64 — по файлу. Выберите бинарник и нажмите «Загрузить и подписать». Затем назначьте релиз на странице нужной ноды. diff --git a/docs/install/index.html b/docs/install/index.html index 3111d11..d3a0db8 100644 --- a/docs/install/index.html +++ b/docs/install/index.html @@ -34,7 +34,7 @@

Как установить Panel и подключить первую HAPro
Корень комплектаinstall.sh

Установщик и апгрейдер Panel, compose.release.yaml для готового образа ghcr.io/nodeflow-dev/nodeflow-panel, шаблон nodeflow.env.example, SHA256SUMS файлов комплекта.

scripts/ · configs/ · docs/scripts/install-node.sh

Скрипты PKI (init-mtls-pki.sh, init-update-signing-key.sh), ручная установка Agent и подготовка UFW ноды, systemd-юнит Agent, эта инструкция и примеры reverse proxy в docs/install/reverse-proxy/.

-
Бинарники Agent в комплект не входят. nodeflow-node-agent-2.0.2-linux-amd64 и nodeflow-node-agent-2.0.2-linux-arm64 лежат отдельными assets GitHub Release. install.sh скачивает оба, сверяет SHA-256 с digest, который GitHub публикует для asset'а, и публикует их в Panel.
+
Бинарники Agent в комплект не входят. nodeflow-node-agent-2.0.0-linux-amd64 и nodeflow-node-agent-2.0.0-linux-arm64 лежат отдельными assets GitHub Release. install.sh скачивает оба, сверяет SHA-256 с digest, который GitHub публикует для asset'а, и публикует их в Panel.
1

Подготовьте сервер Panel

Нужен домен, публичный IP и чистый Ubuntu или Debian.

@@ -158,7 +158,7 @@

Как установить Panel и подключить первую HAPro
5

Опубликуйте Node Agent

Без совместимого подписанного релиза Panel не начнёт установку ноды.

Автоматический установщик публикует Agent сам. Вручную:

-
  1. Скачайте nodeflow-node-agent-2.0.2-linux-amd64 (или -arm64) из assets GitHub Release.
  2. Сверьте sha256sum файла с digest asset'а на странице релиза (или в https://api.github.com/repos/NodeFlow-dev/nodeflow/releases/tags/v2.0.0, поле digest).
  3. Откройте Настройки → Node Agent (подписанные релизы).
  4. Версия: 2.0.0.
  5. ОС: linux.
  6. Архитектура: amd64 или arm64 — по файлу.
  7. Выберите файл и нажмите «Загрузить и подписать».
+
  1. Скачайте nodeflow-node-agent-2.0.0-linux-amd64 (или -arm64) из assets GitHub Release.
  2. Сверьте sha256sum файла с digest asset'а на странице релиза (или в https://api.github.com/repos/NodeFlow-dev/nodeflow/releases/tags/v2.0.0, поле digest).
  3. Откройте Настройки → Node Agent (подписанные релизы).
  4. Версия: 2.0.0.
  5. ОС: linux.
  6. Архитектура: amd64 или arm64 — по файлу.
  7. Выберите файл и нажмите «Загрузить и подписать».
Panel подписывает бинарник собственным Ed25519-ключом. Нода проверяет подпись, SHA-256 и порядок релиза; при неудачном запуске updater возвращает прежний Agent.
@@ -177,7 +177,7 @@

Как установить Panel и подключить первую HAPro
3. Проверить обновление
cd /opt/nodeflow
 sudo docker compose ps
 curl -fsS http://127.0.0.1:8080/healthz
-

После обновления Panel обновите Agent на нодах: «Настройки → Node Agent» → «Обновить до 2.0.2». Для нод, установленных версиями 1.0.x, см. раздел «Обновление с 1.0.x» в заметках к релизу 2.0.0 (однократный systemd drop-in для pipe-буферов ядра).

+

После обновления Panel обновите Agent на нодах: «Настройки → Node Agent» → «Обновить до 2.0.0». Для нод, установленных версиями 1.0.x, см. раздел «Обновление с 1.0.x» в заметках к релизу 2.0.0 (однократный systemd drop-in для pipe-буферов ядра).

8

Проверьте результат

Четыре короткие проверки после установки или обновления.

diff --git a/docs/releases/2.0.0.md b/docs/releases/2.0.0.md index 9021afc..9e3b6d5 100644 --- a/docs/releases/2.0.0.md +++ b/docs/releases/2.0.0.md @@ -8,7 +8,7 @@ Panel **2.0.0** · Node Agent **2.0.0** · HAProxy renderer **v21** - **Несколько серверов на маршрут.** До 16 серверов в режимах «Пул» (все активны) и «Основной + резервные» (переключение по порядку). Сервер-домен можно сделать DNS-пулом: HAProxy использует все его A/AAAA-адреса и исключает недоступные. Для DNS-пула в режиме «Основной + резервные» можно задать статичный основной IP (`preferred_ip`). - **Фолбэк вместо `any_tcp`/`destination_ip`.** Один режим «Фолбэк» для всего, что не совпало по SNI; старые значения принимаются и приводятся к `fallback` автоматически. -- **Алгоритмы балансировки.** `roundrobin`, `static-rr`, `random` (1–5 выборок, по умолчанию 2), `leastconn` («Меньше соединений») и `leastping` («Меньше задержка», аналог Xray leastLoad). Для `leastconn` и `leastping` есть стоимость сервера и отдельного IP (`cost`) и толерантность (`balance_tolerance`): серверы с близкой нагрузкой или задержкой считаются равными и делят клиентов по весу. Веса на лету выставляет Node Agent через runtime API HAProxy, без reload. Также: вес сервера, отдельные веса IP DNS-пула (`ip_weights`), плавный ввод после восстановления (`slowstart`). +- **Алгоритмы балансировки.** `roundrobin`, `static-rr`, `random` (1–5 выборок, по умолчанию 2), `leastconn` («Меньше соединений») и `leastping` («Меньше задержка», аналог Xray leastLoad). Для `leastconn` доля клиентов задаётся весом сервера и отдельного IP (например, вес 2 у сервера на 4 ядра против 2 ядер), для `leastping` есть ещё стоимость — множитель задержки. У обоих есть толерантность (`balance_tolerance`): серверы с близкой нагрузкой или задержкой считаются равными и делят клиентов по весу. Веса на лету выставляет Node Agent через runtime API HAProxy, без reload. Также: вес сервера, отдельные веса IP DNS-пула (`ip_weights`), плавный ввод после восстановления (`slowstart`). - **Закрепление клиента.** `source` — хеш IP клиента (consistent или map-based, `hash-balance-factor`, группировка IPv6 по префиксу); `source_table` — запоминание клиента на `sticky_ttl` в stick-table, которая переживает reload. Размер таблицы «Авто» подбирается от RAM ноды. - **PROXY protocol от доверенных адресов.** `accept_proxy_from` принимает IP, подсети и **домены** (до 32 доменов на маршрут; Node Agent резолвит их A/AAAA и обновляет ACL без reload), есть вариант «от всех». Health-check отправляет PROXY-заголовок (`check-send-proxy`). - **Ограничение скорости в ядре.** `shaper_mode=kernel`: лимиты на IP клиента применяет Node Agent через nftables, HAProxy сохраняет zero-copy splice. diff --git a/docs/releases/2.0.1.md b/docs/releases/2.0.1.md deleted file mode 100644 index 38dff43..0000000 --- a/docs/releases/2.0.1.md +++ /dev/null @@ -1,16 +0,0 @@ -# NodeFlow 2.0.1 - -Panel **2.0.1** · Node Agent **2.0.1** · HAProxy renderer **v21** - -Исправление к 2.0.0. - -## Исправлено - -- **«Толерантность» пропадала после сохранения** на маршрутах, где единственный сервер — домен в режиме DNS-пула (например, `co-de…` со всеми его A/AAAA-адресами), а первый сервер выбирается «Меньше соединений». Панель сохраняла такой маршрут в старом формате одиночного маршрута, в котором нет полей алгоритма и толерантности, и при следующем открытии поле было пустым. Теперь маршрут остаётся пулом серверов: толерантность сохраняется, а агент каждые 5 с выравнивает веса адресов пула. -- Маршруты без толерантности и с закреплением по хешу IP клиента не меняются: конфигурация HAProxy для них рендерится байт в байт как в 2.0.0. - -## Обновление - -Повторно запустите `install.sh` или обновите образ до `ghcr.io/nodeflow-dev/nodeflow-panel:2.0.1`. Миграций нет. Node Agent обновлять не обязательно — 2.0.0 уже умеет толерантность; 2.0.1 можно назначить в «Настройки → Node Agent» для единой версии. - -После обновления откройте затронутые маршруты, снова задайте толерантность и сохраните. diff --git a/docs/releases/2.0.2.md b/docs/releases/2.0.2.md deleted file mode 100644 index c7e42b9..0000000 --- a/docs/releases/2.0.2.md +++ /dev/null @@ -1,13 +0,0 @@ -# NodeFlow 2.0.2 - -Panel **2.0.2** · Node Agent **2.0.2** · HAProxy renderer **v21** - -Улучшение редактора маршрута. - -## Изменено - -- **Подсказки к весу и стоимости отдельных IP.** В таблице «Вес и стоимость отдельных IP» у DNS-пула заголовки «Вес» и «Стоимость» теперь с подсказкой при наведении, а над таблицей — строка с формулой и примером под текущий алгоритм. Для «Меньше соединений»: доля IP = вес ÷ стоимость, например, для серверов на 4 и 2 ядра — вес 2 у 4-ядерного (или стоимость 2 у 2-ядерного), и он получит вдвое больше клиентов. Подсказка к весу сервера тоже уточнена. - -## Обновление - -Повторно запустите `install.sh` или обновите образ до `ghcr.io/nodeflow-dev/nodeflow-panel:2.0.2`. Миграций нет. Node Agent обновлять не обязательно — изменений в агенте нет, 2.0.2 можно назначить в «Настройки → Node Agent» для единой версии. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9477cf7..f8c3015 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "nodeflow-frontend", - "version": "2.0.2", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nodeflow-frontend", - "version": "2.0.2", + "version": "2.0.0", "dependencies": { "@mantine/core": "^8.3.10", "@mantine/hooks": "^8.3.10", diff --git a/frontend/package.json b/frontend/package.json index 54b1a73..eff11f6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "nodeflow-frontend", "private": true, - "version": "2.0.2", + "version": "2.0.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/features/routes/leastconnFold.ts b/frontend/src/features/routes/leastconnFold.ts new file mode 100644 index 0000000..26a5dfc --- /dev/null +++ b/frontend/src/features/routes/leastconnFold.ts @@ -0,0 +1,52 @@ +/** + * «Меньше соединений» splits new clients by weight ÷ cost, so a cost there is + * just an inverse weight. The editor shows only «Вес» in that mode and folds + * any stored cost into integer weights with the same ratios. + */ + +export interface FoldServer { + weight: number | ''; + cost: number | ''; + ipWeights: { ip: string; weight: number | ''; cost: number | '' }[]; +} + +const num = (v: number | '', fallback: number) => (v === '' || !(Number(v) > 0) ? fallback : Number(v)); + +/** + * Returns servers with cost folded into weight (costs cleared), or null when + * nothing sets a cost. Ratios are kept exactly when small integers allow it + * (up to 256), else rounded like the HAProxy render (max weight 256). + */ +export function foldLeastConnCosts(servers: T[]): T[] | null { + const hasCost = servers.some((s) => num(s.cost, 0) > 0 || s.ipWeights.some((w) => num(w.cost, 0) > 0)); + if (!hasCost) return null; + const serverRatio = (s: FoldServer) => num(s.weight, 1) / num(s.cost, 1); + const ipRatio = (s: FoldServer, w: FoldServer['ipWeights'][number]) => + num(w.weight === '' ? s.weight : w.weight, 1) / num(w.cost === '' ? s.cost : w.cost, 1); + const ratios: number[] = []; + servers.forEach((s) => { + ratios.push(serverRatio(s)); + s.ipWeights.forEach((w) => ratios.push(ipRatio(s, w))); + }); + const min = Math.min(...ratios); + const max = Math.max(...ratios); + let scale = 256 / max; + for (let m = 1; m <= 256; m++) { + const k = m / min; + if (max * k > 256 + 1e-9) break; + if (ratios.every((r) => Math.abs(r * k - Math.round(r * k)) < 1e-6 * Math.max(1, r * k))) { scale = k; break; } + } + const toWeight = (r: number) => Math.min(256, Math.max(1, Math.round(r * scale))); + return servers.map((s) => { + const weight = toWeight(serverRatio(s)); + return { + ...s, + weight: weight === 1 ? '' : weight, + cost: '', + ipWeights: s.ipWeights.map((w) => { + const ipWeight = toWeight(ipRatio(s, w)); + return { ...w, weight: ipWeight === weight ? '' : ipWeight, cost: '' }; + }), + }; + }); +} diff --git a/frontend/src/features/routes/model.ts b/frontend/src/features/routes/model.ts index 0ce457b..459eaf3 100644 --- a/frontend/src/features/routes/model.ts +++ b/frontend/src/features/routes/model.ts @@ -2,6 +2,7 @@ import { randomUUID } from '../../lib/uuid'; import { agentVersionAtLeast } from '../../lib/agentVersion'; import type { RouteRecord } from '../../lib/contracts'; import { formatBytes } from '../../lib/format'; +import { foldLeastConnCosts } from './leastconnFold'; export type RouteMatchMode = 'sni' | 'fallback'; export type RouteTargetMode = 'ip' | 'domain' | 'unix'; @@ -499,7 +500,7 @@ export function routeToDraft(route: RouteRecord): RouteDraft { servers = withCanonicalFailoverRoles(servers); } - return { + const draft: RouteDraft = { name: routeDisplayName(route), matchMode, listenerIP, listenerPort: route.listener_port, snis: route.snis ?? [], acceptProxyEnabled: storedAcceptProxy.length > 0, @@ -532,6 +533,13 @@ export function routeToDraft(route: RouteRecord): RouteDraft { shaperMode: route.shaper_mode === 'kernel' ? 'kernel' : 'haproxy', expertOverride: route.custom_fragment ?? '', }; + // «Меньше соединений» has no cost column: a stored cost is an inverse + // weight there, so it is folded into weights with the same ratios. + if (leastconnActive(draft)) { + const folded = foldLeastConnCosts(draft.servers); + if (folded) draft.servers = folded; + } + return draft; } export function isIPAddress(value: string): boolean { @@ -917,7 +925,7 @@ export function validateRouteDraft(draft: RouteDraft, peers: RouteRecord[], edit if (s.weight !== '' && (!Number.isInteger(Number(s.weight)) || Number(s.weight) < 1 || Number(s.weight) > 256)) { add('servers', `Сервер ${i + 1}: вес — целое число от 1 до 256.`); } - if (s.cost !== '' && (!Number.isFinite(Number(s.cost)) || Number(s.cost) <= 0 || Number(s.cost) > 100)) { + if (costActive(draft) && s.cost !== '' && (!Number.isFinite(Number(s.cost)) || Number(s.cost) <= 0 || Number(s.cost) > 100)) { add('servers', `Сервер ${i + 1}: стоимость — число больше 0 и не больше 100.`); } if (s.ipWeights.length > 0) { @@ -931,7 +939,7 @@ export function validateRouteDraft(draft: RouteDraft, peers: RouteRecord[], edit if (s.ipWeights.some((w) => w.weight !== '' && (!Number.isInteger(w.weight) || w.weight < 1 || w.weight > 256))) { add('servers', `Сервер ${i + 1}: вес IP — целое число от 1 до 256.`); } - if (s.ipWeights.some((w) => w.cost !== '' && (!Number.isFinite(w.cost) || w.cost < 0.01 || w.cost > 100))) { + if (costActive(draft) && s.ipWeights.some((w) => w.cost !== '' && (!Number.isFinite(w.cost) || w.cost < 0.01 || w.cost > 100))) { add('servers', `Сервер ${i + 1}: стоимость IP — число от 0,01 до 100.`); } const withWeight = s.ipWeights.some((w) => w.weight !== ''); @@ -1030,9 +1038,13 @@ export function leastconnActive(draft: RouteDraft): boolean { return effectiveBalanceMode(draft) === 'pool' && stickyApplicable(draft) && effectiveBalanceAlgorithm(draft) === 'leastconn'; } -/** «Стоимость» (server and per-IP) applies: latency or connections mode. */ +/** + * «Стоимость» (server and per-IP) applies only in latency mode. With + * «Меньше соединений» the share is weight ÷ cost, so the weight alone + * expresses it and the editor offers no cost there. + */ export function costActive(draft: RouteDraft): boolean { - return leastpingActive(draft) || leastconnActive(draft); + return leastpingActive(draft); } /** First Node Agent release that applies the leastconn tolerance. */ @@ -1096,7 +1108,7 @@ export function routePayload(draft: RouteDraft, enabled: boolean, expectedVersio const balanceAlgorithm: BalanceAlgorithm | '' = balanceApplicable ? effectiveBalanceAlgorithm(draft) : ''; const latency = leastpingActive(draft); const connections = leastconnActive(draft); - const withCost = latency || connections; + const withCost = latency; // First server mirrors into the legacy target fields (canonical target for // older readers). Route-level dns_pool is never derived from servers[]. diff --git a/frontend/src/fixtures/demo.ts b/frontend/src/fixtures/demo.ts index ddce90e..b38aeb6 100644 --- a/frontend/src/fixtures/demo.ts +++ b/frontend/src/fixtures/demo.ts @@ -93,7 +93,7 @@ function demoServer( * cdn.video — random(2) draws, remembers clients 15 min in a small stick-table; * storage-backup — leastLoad/leastPing with per-server and per-IP (DNS pool) costs; * update.service — DNS pool with per-IP runtime weights, source hash (default); - * metrics.internal — leastconn with a 20 % tolerance, a costlier second server + * metrics.internal — leastconn with a 20 % tolerance, a twice-as-heavy first server * and slow-start for a server that just came back. */ function demoDistribution(index: number, nodeIndex: number, name: string, port: number): Partial { @@ -145,8 +145,8 @@ function demoDistribution(index: number, nodeIndex: number, name: string, port: sticky_enabled: false, sticky_mode: 'none', sticky_ttl: '', slowstart: '60s', health_check: true, servers: [ - demoServer(id, 1, 'main-a', `10.20.${nodeIndex}.61`, port), - demoServer(id, 2, 'main-b', `10.20.${nodeIndex}.62`, port, { cost: 2 }), + demoServer(id, 1, 'main-a', `10.20.${nodeIndex}.61`, port, { weight: 2 }), + demoServer(id, 2, 'main-b', `10.20.${nodeIndex}.62`, port), ], }; } diff --git a/frontend/src/pages/RouteEditorPage.tsx b/frontend/src/pages/RouteEditorPage.tsx index eee25e1..09f5da7 100644 --- a/frontend/src/pages/RouteEditorPage.tsx +++ b/frontend/src/pages/RouteEditorPage.tsx @@ -231,10 +231,8 @@ function PreferredIPLine({ server, hasOtherServers, error, onChange }: { } const IP_WEIGHT_HELP = 'Доля новых клиентов для этого IP: 2 — вдвое больше, чем у IP с весом 1. Пусто — вес сервера (по умолчанию 1).'; -const IP_COST_CONN_HELP = 'Сколько весит одно соединение на этом IP: 2 — каждое соединение считается за два, и IP получает вдвое меньше клиентов. Пусто — стоимость сервера (по умолчанию 1).'; const IP_COST_PING_HELP = 'Множитель задержки этого IP: 2 — IP кажется вдвое медленнее и выбирается реже. Пусто — стоимость сервера (по умолчанию 1).'; -const COST_OFF_HELP = 'Стоимость учитывают алгоритмы «Меньше соединений» и «Меньше задержка».'; -const IP_SHARE_CONN_NOTE = 'Доля IP = вес ÷ стоимость. Например, 4 ядра против 2: вес 2 у 4-ядерного (или стоимость 2 у 2-ядерного) — он получит вдвое больше клиентов. При «Запоминании» уже закреплённые клиенты остаются на своём IP.'; +const IP_SHARE_CONN_NOTE = 'Новые клиенты делятся пропорционально весу: 4 ядра против 2 — вес 2 у 4-ядерного, и он получит вдвое больше клиентов. При «Запоминании» уже закреплённые клиенты остаются на своём IP.'; const IP_SHARE_PING_NOTE = 'Чем меньше задержка × стоимость, тем больше клиентов получает IP; вес задаёт долю при равной задержке. Под мощность сервера: 4 ядра против 2 — вес 2 у 4-ядерного.'; const IP_SHARE_NOTE = 'Доля IP пропорциональна весу. Например, 4 ядра против 2: вес 2 у 4-ядерного — он получит вдвое больше клиентов.'; @@ -278,7 +276,7 @@ function IPWeightsEditor({ server, agentAllowed, showCost, connections, weightsF return (
- Вес и стоимость отдельных IP + {showCost ? 'Вес и стоимость отдельных IP' : 'Вес отдельных IP'} Пусто — как у сервера.{weightsFixed ? ' Сейчас веса фиксированы и не применятся.' : ''}
{!agentAllowed &&

} @@ -287,8 +285,8 @@ function IPWeightsEditor({ server, agentAllowed, showCost, connections, weightsF

{connections ? IP_SHARE_CONN_NOTE : showCost ? IP_SHARE_PING_NOTE : IP_SHARE_NOTE}

)} {server.ipWeights.length > 0 && ( - // Cost column is always present (disabled when the algorithm ignores it) so the table never reflows. -
+ // Cost column only for «Меньше задержка»; elsewhere the weight alone sets the share. +
IP @@ -296,11 +294,13 @@ function IPWeightsEditor({ server, agentAllowed, showCost, connections, weightsF Вес - - + {showCost && ( + + Стоимость + )} {/* Stays in grid flow: a hidden (absolute) cell would shift every row by one column. */}
@@ -310,9 +310,9 @@ function IPWeightsEditor({ server, agentAllowed, showCost, connections, weightsF patch(w.ip, { weight: v === '' ? '' : Number(v) })} aria-label={`Вес ${w.ip}`} /> - - patch(w.ip, { cost: v === '' ? '' : Number(v) })} aria-label={`Стоимость ${w.ip}`} /> - + {showCost && + patch(w.ip, { cost: v === '' ? '' : Number(v) })} aria-label={`Стоимость ${w.ip}`} /> + } removeIP(w.ip)} aria-label={`Убрать ${w.ip}`}> @@ -427,17 +427,19 @@ function ServersEditor({ servers, balanceMode: rawBalanceMode, poolSettings, onC const canRemove = servers.length > 1; const { perServer, general } = splitServerErrors(errors); - // One template for every mode, so switching DNS-пул / algorithm / failover never - // resizes «Адрес»: Вес and Стоимость (pool only) stay as disabled cells, and in - // «Основной + резервные» the role badge takes those same two tracks. - const columns: ServerColumn[] = ['name', 'type', 'host', 'port', 'dns', 'weight', 'cost', 'actions']; + // One template per mode: Вес stays as a disabled cell outside the pool, and + // Стоимость exists only for «Меньше задержка» (elsewhere the weight alone sets + // the share). In «Основной + резервные» the role badge takes the weight track. + const costColumn = Boolean(poolSettings?.showCost); + const columns: ServerColumn[] = costColumn + ? ['name', 'type', 'host', 'port', 'dns', 'weight', 'cost', 'actions'] + : ['name', 'type', 'host', 'port', 'dns', 'weight', 'actions']; const col = (key: ServerColumn) => (key === 'role' ? columns.indexOf('weight') : columns.indexOf(key)) + 1; const tableStyle = { '--srv-cols': columns.map((key) => SERVER_COLUMN_TRACKS[key]).join(' '), '--srv-sub-start': String(col('name')), } as CSSProperties; const weightOn = Boolean(poolSettings); - const costOn = Boolean(poolSettings?.showCost); const offHint = 'Нужно два сервера или DNS-пул в режиме «Пул»'; const update = (index: number, patch: Partial) => { @@ -479,15 +481,13 @@ function ServersEditor({ servers, balanceMode: rawBalanceMode, poolSettings, onC Вес - - + {costColumn && ( + + Стоимость + )} }
@@ -582,19 +582,18 @@ function ServersEditor({ servers, balanceMode: rawBalanceMode, poolSettings, onC />
- + {costColumn && (
update(index, { cost: v === '' ? '' : Number(v) })} min={0.01} max={100} decimalScale={2} hideControls inputMode="decimal" - disabled={!costOn} - error={costOn && errorFor('cost') ? true : undefined} + error={errorFor('cost') ? true : undefined} />
-
+ )} }
@@ -764,7 +763,7 @@ function DistributionBlock({ draft, update, agent110, agentVersion, autoTableEnt )} {family === 'leastconn' && ( <> - + update('leastpingTolerancePct', v)} placeholder="0" min={0} max={100} allowDecimal={false} inputMode="numeric" @@ -772,7 +771,7 @@ function DistributionBlock({ draft, update, agent110, agentVersion, autoTableEnt /> - Стоимость — в таблице серверов. Толерантность больше 0 применяет агент ноды каждые 5 с.{!leastconnToleranceSupported(agentVersion) ? ` Нужен Node Agent ${LEASTCONN_TOLERANCE_MIN_AGENT}, на ноде ${agentVersion ?? 'неизвестно'}.` : ''} + Вес — в таблице серверов. Толерантность больше 0 применяет агент ноды каждые 5 с.{!leastconnToleranceSupported(agentVersion) ? ` Нужен Node Agent ${LEASTCONN_TOLERANCE_MIN_AGENT}, на ноде ${agentVersion ?? 'неизвестно'}.` : ''} )} @@ -1159,7 +1158,7 @@ export function RouteEditorPage() { // steer the hash); cost only to latency mode (leastping, not overridden by the IP hash). const weightsFixed = (stickyMode !== 'source' && algorithm === 'static-rr') || (stickyMode === 'source' && draft.stickyHash === 'map-based'); const poolSettings = showSticky - ? { showCost: stickyMode !== 'source' && (algorithm === 'leastping' || algorithm === 'leastconn'), connections: stickyMode !== 'source' && algorithm === 'leastconn', weightsFixed, agentAllowed: agent110 } + ? { showCost: stickyMode !== 'source' && algorithm === 'leastping', connections: stickyMode !== 'source' && algorithm === 'leastconn', weightsFixed, agentAllowed: agent110 } : null; // ── Section summaries (one line of current state next to each title) ── diff --git a/frontend/tests/leastconnFold.test.ts b/frontend/tests/leastconnFold.test.ts new file mode 100644 index 0000000..0ed6948 --- /dev/null +++ b/frontend/tests/leastconnFold.test.ts @@ -0,0 +1,32 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { foldLeastConnCosts } from '../src/features/routes/leastconnFold.ts'; + +const ip = (addr: string, weight: number | '', cost: number | '') => ({ ip: addr, weight, cost }); + +test('no cost: nothing to fold', () => { + assert.equal(foldLeastConnCosts([{ weight: 2, cost: '', ipWeights: [ip('192.0.2.1', 3, '')] }]), null); +}); + +test('per-IP cost 2 becomes half the weight of the other addresses', () => { + // Production shape: DNS pool, one IP with cost 2, the rest inherit 1/1. + const out = foldLeastConnCosts([{ weight: '', cost: '', ipWeights: [ip('31.77.147.33', '', 2)] }])!; + assert.deepEqual(out[0], { weight: 2, cost: '', ipWeights: [ip('31.77.147.33', '', '')].map((w) => ({ ...w, weight: 1 })) }); +}); + +test('ratios weight/cost are preserved with small integers', () => { + const out = foldLeastConnCosts([ + { weight: '', cost: 2, ipWeights: [] }, // 0.5 + { weight: '', cost: '', ipWeights: [] }, // 1 + { weight: 2, cost: 0.5, ipWeights: [] }, // 4 + ])!; + assert.deepEqual(out.map((s) => s.weight), ['', 2, 8]); + assert.ok(out.every((s) => s.cost === '')); +}); + +test('non-integer ratios fall back to the render scale (max 256)', () => { + const out = foldLeastConnCosts([{ weight: '', cost: 3, ipWeights: [] }, { weight: '', cost: 1.37, ipWeights: [] }])!; + const [a, b] = out.map((s) => (s.weight === '' ? 1 : s.weight)); + assert.equal(b, 256); + assert.ok(Math.abs(a / b - 1.37 / 3) < 0.01); +}); diff --git a/internal/panel/web_dist/assets/IconArrowUp-Cj3lrfzR.js b/internal/panel/web_dist/assets/IconArrowUp-DwKi77Ll.js similarity index 98% rename from internal/panel/web_dist/assets/IconArrowUp-Cj3lrfzR.js rename to internal/panel/web_dist/assets/IconArrowUp-DwKi77Ll.js index 1c7831c..8c0457c 100644 --- a/internal/panel/web_dist/assets/IconArrowUp-Cj3lrfzR.js +++ b/internal/panel/web_dist/assets/IconArrowUp-DwKi77Ll.js @@ -1 +1 @@ -import{r as s,q as j,s as F,t as W,j as _,y as k,v as A,V as ae,aF as O,o as ie,G as ue,D as le,K as ce,E as de,C as fe,w as me,c as L}from"./index-Dy6W__Vz.js";import{_ as E,u as P}from"./format-D6_ab21F.js";function ve(t,e){if(t===e||Number.isNaN(t)&&Number.isNaN(e))return!0;if(!(t instanceof Object)||!(e instanceof Object))return!1;const n=Object.keys(t),{length:o}=n;if(o!==Object.keys(e).length)return!1;for(let a=0;a{o.current||(o.current=window.setTimeout(()=>{t(m),o.current=null},e))},[e]),i=s.useCallback(()=>{o.current&&(window.clearTimeout(o.current),o.current=null)},[]);return s.useEffect(()=>(n.autoInvoke&&a(),i),[i,a]),{start:a,clear:i}}function ye(t,e,n){const o=s.useRef(null),a=s.useRef(null);return s.useEffect(()=>{const i=typeof n=="function"?n():n;return(i||a.current)&&(o.current=new MutationObserver(t),o.current.observe(i||a.current,e)),()=>{o.current?.disconnect()}},[t,e]),a}function we(){const[t,e]=s.useState(!1);return s.useEffect(()=>e(!0),[]),t}var Re={};function Ce(){return typeof process<"u"&&Re?"production":"development"}var B={root:"m_96b553a6"};function Ne(t,e){if(!e||!t)return!1;let n=e.parentNode;for(;n!=null;){if(n===t)return!0;n=n.parentNode}return!1}function Se({target:t,parent:e,ref:n,displayAfterTransitionEnd:o}){const a=s.useRef(-1),[i,m]=s.useState(!1),[R,C]=s.useState(typeof o=="boolean"?o:!1),l=()=>{if(!t||!e||!n.current)return;const u=t.getBoundingClientRect(),c=e.getBoundingClientRect(),f=window.getComputedStyle(t),h=window.getComputedStyle(e),b=E(f.borderTopWidth)+E(h.borderTopWidth),y=E(f.borderLeftWidth)+E(h.borderLeftWidth),p={top:u.top-c.top-b,left:u.left-c.left-y,width:u.width,height:u.height};n.current.style.transform=`translateY(${p.top}px) translateX(${p.left}px)`,n.current.style.width=`${p.width}px`,n.current.style.height=`${p.height}px`},d=()=>{window.clearTimeout(a.current),n.current&&(n.current.style.transitionDuration="0ms"),l(),a.current=window.setTimeout(()=>{n.current&&(n.current.style.transitionDuration="")},30)},g=s.useRef(null),v=s.useRef(null);return s.useEffect(()=>{if(l(),t)return g.current=new ResizeObserver(d),g.current.observe(t),e&&(v.current=new ResizeObserver(d),v.current.observe(e)),()=>{g.current?.disconnect(),v.current?.disconnect()}},[e,t]),s.useEffect(()=>{if(e){const u=c=>{Ne(c.target,e)&&(d(),C(!1))};return e.addEventListener("transitionend",u),()=>{e.removeEventListener("transitionend",u)}}},[e]),be(()=>{Ce()!=="test"&&m(!0)},20,{autoInvoke:!0}),ye(u=>{u.forEach(c=>{c.type==="attributes"&&c.attributeName==="dir"&&d()})},{attributes:!0,attributeFilter:["dir"]},()=>document.documentElement),{initialized:i,hidden:R}}const Ee=A((t,{transitionDuration:e})=>({root:{"--transition-duration":typeof e=="number"?`${e}ms`:e}})),T=j((t,e)=>{const n=F("FloatingIndicator",null,t),{classNames:o,className:a,style:i,styles:m,unstyled:R,vars:C,target:l,parent:d,transitionDuration:g,mod:v,displayAfterTransitionEnd:u,attributes:c,...f}=n,h=W({name:"FloatingIndicator",classes:B,props:n,className:a,style:i,classNames:o,styles:m,unstyled:R,attributes:c,vars:C,varsResolver:Ee}),b=s.useRef(null),{initialized:y,hidden:p}=Se({target:l,parent:d,ref:b,displayAfterTransitionEnd:u}),S=P(e,b);return!l||!d?null:_.jsx(k,{ref:S,mod:[{initialized:y,hidden:p},v],...h("root"),...f})});T.displayName="@mantine/core/FloatingIndicator";T.classes=B;var D={root:"m_cf365364",indicator:"m_9e182ccd",label:"m_1738fcb2",input:"m_1714d588",control:"m_69686b9b",innerLabel:"m_78882f40"};const _e={withItemsBorders:!0},ke=A((t,{radius:e,color:n,transitionDuration:o,size:a,transitionTimingFunction:i})=>({root:{"--sc-radius":e===void 0?void 0:me(e),"--sc-color":n?fe(n,t):void 0,"--sc-shadow":n?void 0:"var(--mantine-shadow-xs)","--sc-transition-duration":o===void 0?void 0:`${o}ms`,"--sc-transition-timing-function":i,"--sc-padding":de(a,"sc-padding"),"--sc-font-size":ce(a)}})),U=j((t,e)=>{const n=F("SegmentedControl",_e,t),{classNames:o,className:a,style:i,styles:m,unstyled:R,vars:C,data:l,value:d,defaultValue:g,onChange:v,size:u,name:c,disabled:f,readOnly:h,fullWidth:b,orientation:y,radius:p,color:S,transitionDuration:xe,transitionTimingFunction:Te,variant:q,autoContrast:K,withItemsBorders:G,mod:H,attributes:X,...Y}=n,w=W({name:"SegmentedControl",props:n,classes:D,className:a,style:i,classNames:o,styles:m,unstyled:R,attributes:X,vars:C,varsResolver:ke}),M=ae(),z=l.map(r=>typeof r=="string"?{label:r,value:r}:r),J=we(),[Q,Z]=s.useState(O()),[V,ee]=s.useState(null),[I,te]=s.useState({}),ne=(r,x)=>{I[x]=r,te(I)},[N,re]=ie({value:d,defaultValue:g,finalValue:Array.isArray(l)?z.find(r=>!r.disabled)?.value??l[0]?.value??null:null,onChange:v}),$=ue(c),se=z.map(r=>s.createElement(k,{...w("control"),mod:{active:N===r.value,orientation:y},key:r.value},s.createElement("input",{...w("input"),disabled:f||r.disabled,type:"radio",name:$,value:r.value,id:`${$}-${r.value}`,checked:N===r.value,onChange:()=>!h&&re(r.value),"data-focus-ring":M.focusRing,key:`${r.value}-input`}),s.createElement(k,{component:"label",...w("label"),mod:{active:N===r.value&&!(f||r.disabled),disabled:f||r.disabled,"read-only":h},htmlFor:`${$}-${r.value}`,ref:x=>ne(x,r.value),__vars:{"--sc-label-color":S!==void 0?le({color:S,theme:M,autoContrast:K}):void 0},key:`${r.value}-label`},_.jsx("span",{...w("innerLabel"),children:r.label})))),oe=P(e,r=>ee(r));return ge(()=>{Z(O())},[l.length]),l.length===0?null:_.jsxs(k,{...w("root"),variant:q,size:u,ref:oe,mod:[{"full-width":b,orientation:y,initialized:J,"with-items-borders":G},H],...Y,role:"radiogroup","data-disabled":f,children:[typeof N=="string"&&_.jsx(T,{target:I[N],parent:V,component:"span",transitionDuration:"var(--sc-transition-duration)",...w("indicator")},Q),se]})});U.classes=D;U.displayName="@mantine/core/SegmentedControl";const Ie=[["path",{d:"M12 5l0 14",key:"svg-0"}],["path",{d:"M18 13l-6 6",key:"svg-1"}],["path",{d:"M6 13l6 6",key:"svg-2"}]],Oe=L("outline","arrow-down","ArrowDown",Ie);const $e=[["path",{d:"M12 5l0 14",key:"svg-0"}],["path",{d:"M18 11l-6 -6",key:"svg-1"}],["path",{d:"M6 11l6 -6",key:"svg-2"}]],je=L("outline","arrow-up","ArrowUp",$e);export{Oe as I,U as S,je as a,Ce as g}; +import{r as s,q as j,s as F,t as W,j as _,y as k,v as A,V as ae,aF as O,o as ie,G as ue,D as le,K as ce,E as de,C as fe,w as me,c as L}from"./index-fgrXogF6.js";import{_ as E,u as P}from"./format-DGDz36zr.js";function ve(t,e){if(t===e||Number.isNaN(t)&&Number.isNaN(e))return!0;if(!(t instanceof Object)||!(e instanceof Object))return!1;const n=Object.keys(t),{length:o}=n;if(o!==Object.keys(e).length)return!1;for(let a=0;a{o.current||(o.current=window.setTimeout(()=>{t(m),o.current=null},e))},[e]),i=s.useCallback(()=>{o.current&&(window.clearTimeout(o.current),o.current=null)},[]);return s.useEffect(()=>(n.autoInvoke&&a(),i),[i,a]),{start:a,clear:i}}function ye(t,e,n){const o=s.useRef(null),a=s.useRef(null);return s.useEffect(()=>{const i=typeof n=="function"?n():n;return(i||a.current)&&(o.current=new MutationObserver(t),o.current.observe(i||a.current,e)),()=>{o.current?.disconnect()}},[t,e]),a}function we(){const[t,e]=s.useState(!1);return s.useEffect(()=>e(!0),[]),t}var Re={};function Ce(){return typeof process<"u"&&Re?"production":"development"}var B={root:"m_96b553a6"};function Ne(t,e){if(!e||!t)return!1;let n=e.parentNode;for(;n!=null;){if(n===t)return!0;n=n.parentNode}return!1}function Se({target:t,parent:e,ref:n,displayAfterTransitionEnd:o}){const a=s.useRef(-1),[i,m]=s.useState(!1),[R,C]=s.useState(typeof o=="boolean"?o:!1),l=()=>{if(!t||!e||!n.current)return;const u=t.getBoundingClientRect(),c=e.getBoundingClientRect(),f=window.getComputedStyle(t),h=window.getComputedStyle(e),b=E(f.borderTopWidth)+E(h.borderTopWidth),y=E(f.borderLeftWidth)+E(h.borderLeftWidth),p={top:u.top-c.top-b,left:u.left-c.left-y,width:u.width,height:u.height};n.current.style.transform=`translateY(${p.top}px) translateX(${p.left}px)`,n.current.style.width=`${p.width}px`,n.current.style.height=`${p.height}px`},d=()=>{window.clearTimeout(a.current),n.current&&(n.current.style.transitionDuration="0ms"),l(),a.current=window.setTimeout(()=>{n.current&&(n.current.style.transitionDuration="")},30)},g=s.useRef(null),v=s.useRef(null);return s.useEffect(()=>{if(l(),t)return g.current=new ResizeObserver(d),g.current.observe(t),e&&(v.current=new ResizeObserver(d),v.current.observe(e)),()=>{g.current?.disconnect(),v.current?.disconnect()}},[e,t]),s.useEffect(()=>{if(e){const u=c=>{Ne(c.target,e)&&(d(),C(!1))};return e.addEventListener("transitionend",u),()=>{e.removeEventListener("transitionend",u)}}},[e]),be(()=>{Ce()!=="test"&&m(!0)},20,{autoInvoke:!0}),ye(u=>{u.forEach(c=>{c.type==="attributes"&&c.attributeName==="dir"&&d()})},{attributes:!0,attributeFilter:["dir"]},()=>document.documentElement),{initialized:i,hidden:R}}const Ee=A((t,{transitionDuration:e})=>({root:{"--transition-duration":typeof e=="number"?`${e}ms`:e}})),T=j((t,e)=>{const n=F("FloatingIndicator",null,t),{classNames:o,className:a,style:i,styles:m,unstyled:R,vars:C,target:l,parent:d,transitionDuration:g,mod:v,displayAfterTransitionEnd:u,attributes:c,...f}=n,h=W({name:"FloatingIndicator",classes:B,props:n,className:a,style:i,classNames:o,styles:m,unstyled:R,attributes:c,vars:C,varsResolver:Ee}),b=s.useRef(null),{initialized:y,hidden:p}=Se({target:l,parent:d,ref:b,displayAfterTransitionEnd:u}),S=P(e,b);return!l||!d?null:_.jsx(k,{ref:S,mod:[{initialized:y,hidden:p},v],...h("root"),...f})});T.displayName="@mantine/core/FloatingIndicator";T.classes=B;var D={root:"m_cf365364",indicator:"m_9e182ccd",label:"m_1738fcb2",input:"m_1714d588",control:"m_69686b9b",innerLabel:"m_78882f40"};const _e={withItemsBorders:!0},ke=A((t,{radius:e,color:n,transitionDuration:o,size:a,transitionTimingFunction:i})=>({root:{"--sc-radius":e===void 0?void 0:me(e),"--sc-color":n?fe(n,t):void 0,"--sc-shadow":n?void 0:"var(--mantine-shadow-xs)","--sc-transition-duration":o===void 0?void 0:`${o}ms`,"--sc-transition-timing-function":i,"--sc-padding":de(a,"sc-padding"),"--sc-font-size":ce(a)}})),U=j((t,e)=>{const n=F("SegmentedControl",_e,t),{classNames:o,className:a,style:i,styles:m,unstyled:R,vars:C,data:l,value:d,defaultValue:g,onChange:v,size:u,name:c,disabled:f,readOnly:h,fullWidth:b,orientation:y,radius:p,color:S,transitionDuration:xe,transitionTimingFunction:Te,variant:q,autoContrast:K,withItemsBorders:G,mod:H,attributes:X,...Y}=n,w=W({name:"SegmentedControl",props:n,classes:D,className:a,style:i,classNames:o,styles:m,unstyled:R,attributes:X,vars:C,varsResolver:ke}),M=ae(),z=l.map(r=>typeof r=="string"?{label:r,value:r}:r),J=we(),[Q,Z]=s.useState(O()),[V,ee]=s.useState(null),[I,te]=s.useState({}),ne=(r,x)=>{I[x]=r,te(I)},[N,re]=ie({value:d,defaultValue:g,finalValue:Array.isArray(l)?z.find(r=>!r.disabled)?.value??l[0]?.value??null:null,onChange:v}),$=ue(c),se=z.map(r=>s.createElement(k,{...w("control"),mod:{active:N===r.value,orientation:y},key:r.value},s.createElement("input",{...w("input"),disabled:f||r.disabled,type:"radio",name:$,value:r.value,id:`${$}-${r.value}`,checked:N===r.value,onChange:()=>!h&&re(r.value),"data-focus-ring":M.focusRing,key:`${r.value}-input`}),s.createElement(k,{component:"label",...w("label"),mod:{active:N===r.value&&!(f||r.disabled),disabled:f||r.disabled,"read-only":h},htmlFor:`${$}-${r.value}`,ref:x=>ne(x,r.value),__vars:{"--sc-label-color":S!==void 0?le({color:S,theme:M,autoContrast:K}):void 0},key:`${r.value}-label`},_.jsx("span",{...w("innerLabel"),children:r.label})))),oe=P(e,r=>ee(r));return ge(()=>{Z(O())},[l.length]),l.length===0?null:_.jsxs(k,{...w("root"),variant:q,size:u,ref:oe,mod:[{"full-width":b,orientation:y,initialized:J,"with-items-borders":G},H],...Y,role:"radiogroup","data-disabled":f,children:[typeof N=="string"&&_.jsx(T,{target:I[N],parent:V,component:"span",transitionDuration:"var(--sc-transition-duration)",...w("indicator")},Q),se]})});U.classes=D;U.displayName="@mantine/core/SegmentedControl";const Ie=[["path",{d:"M12 5l0 14",key:"svg-0"}],["path",{d:"M18 13l-6 6",key:"svg-1"}],["path",{d:"M6 13l6 6",key:"svg-2"}]],Oe=L("outline","arrow-down","ArrowDown",Ie);const $e=[["path",{d:"M12 5l0 14",key:"svg-0"}],["path",{d:"M18 11l-6 -6",key:"svg-1"}],["path",{d:"M6 11l6 -6",key:"svg-2"}]],je=L("outline","arrow-up","ArrowUp",$e);export{Oe as I,U as S,je as a,Ce as g}; diff --git a/internal/panel/web_dist/assets/IconDots-B4BXVaDG.js b/internal/panel/web_dist/assets/IconDots-BNcckjtc.js similarity index 77% rename from internal/panel/web_dist/assets/IconDots-B4BXVaDG.js rename to internal/panel/web_dist/assets/IconDots-BNcckjtc.js index 6716cb8..eb16bd7 100644 --- a/internal/panel/web_dist/assets/IconDots-B4BXVaDG.js +++ b/internal/panel/web_dist/assets/IconDots-BNcckjtc.js @@ -1 +1 @@ -import{c as o}from"./index-Dy6W__Vz.js";const t=[["path",{d:"M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-0"}],["path",{d:"M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-1"}],["path",{d:"M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-2"}]],e=o("outline","dots","Dots",t);export{e as I}; +import{c as o}from"./index-fgrXogF6.js";const t=[["path",{d:"M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-0"}],["path",{d:"M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-1"}],["path",{d:"M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-2"}]],e=o("outline","dots","Dots",t);export{e as I}; diff --git a/internal/panel/web_dist/assets/IconKey-D6H2eVar.js b/internal/panel/web_dist/assets/IconKey-DrhZ0AMo.js similarity index 95% rename from internal/panel/web_dist/assets/IconKey-D6H2eVar.js rename to internal/panel/web_dist/assets/IconKey-DrhZ0AMo.js index bf0330a..d4150f4 100644 --- a/internal/panel/web_dist/assets/IconKey-D6H2eVar.js +++ b/internal/panel/web_dist/assets/IconKey-DrhZ0AMo.js @@ -1 +1 @@ -import{r as N,q as R,s as $,a6 as d,t as k,j as S,y as b,v as z,c as B}from"./index-Dy6W__Vz.js";function E(s){return N.Children.toArray(s).filter(Boolean)}var u={root:"m_4081bf90"};const I={preventGrowOverflow:!0,gap:"md",align:"center",justify:"flex-start",wrap:"wrap"},K=z((s,{grow:t,preventGrowOverflow:e,gap:r,align:o,justify:a,wrap:l},{childWidth:n})=>({root:{"--group-child-width":t&&e?n:void 0,"--group-gap":d(r),"--group-align":o,"--group-justify":a,"--group-wrap":l}})),h=R((s,t)=>{const e=$("Group",I,s),{classNames:r,className:o,style:a,styles:l,unstyled:n,children:y,gap:g,align:O,justify:P,wrap:W,grow:v,preventGrowOverflow:q,vars:f,variant:m,__size:w,mod:x,attributes:G,...j}=e,c=E(y),i=c.length,p=d(g??"md"),C={childWidth:`calc(${100/i}% - (${p} - ${p} / ${i}))`},_=k({name:"Group",props:e,stylesCtx:C,className:o,style:a,classes:u,classNames:r,styles:l,unstyled:n,attributes:G,vars:f,varsResolver:K});return S.jsx(b,{..._("root"),ref:t,variant:m,mod:[{grow:v},x],size:w,...j,children:c})});h.classes=u;h.displayName="@mantine/core/Group";const M=[["path",{d:"M16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1 -4.069 0l-.301 -.301l-6.558 6.558a2 2 0 0 1 -1.239 .578l-.175 .008h-1.172a1 1 0 0 1 -.993 -.883l-.007 -.117v-1.172a2 2 0 0 1 .467 -1.284l.119 -.13l.414 -.414h2v-2h2v-2l2.144 -2.144l-.301 -.301a2.877 2.877 0 0 1 0 -4.069l2.643 -2.643a2.877 2.877 0 0 1 4.069 0",key:"svg-0"}],["path",{d:"M15 9h.01",key:"svg-1"}]],V=B("outline","key","Key",M);export{h as G,V as I}; +import{r as N,q as R,s as $,a6 as d,t as k,j as S,y as b,v as z,c as B}from"./index-fgrXogF6.js";function E(s){return N.Children.toArray(s).filter(Boolean)}var u={root:"m_4081bf90"};const I={preventGrowOverflow:!0,gap:"md",align:"center",justify:"flex-start",wrap:"wrap"},K=z((s,{grow:t,preventGrowOverflow:e,gap:r,align:o,justify:a,wrap:l},{childWidth:n})=>({root:{"--group-child-width":t&&e?n:void 0,"--group-gap":d(r),"--group-align":o,"--group-justify":a,"--group-wrap":l}})),h=R((s,t)=>{const e=$("Group",I,s),{classNames:r,className:o,style:a,styles:l,unstyled:n,children:y,gap:g,align:O,justify:P,wrap:W,grow:v,preventGrowOverflow:q,vars:f,variant:m,__size:w,mod:x,attributes:G,...j}=e,c=E(y),i=c.length,p=d(g??"md"),C={childWidth:`calc(${100/i}% - (${p} - ${p} / ${i}))`},_=k({name:"Group",props:e,stylesCtx:C,className:o,style:a,classes:u,classNames:r,styles:l,unstyled:n,attributes:G,vars:f,varsResolver:K});return S.jsx(b,{..._("root"),ref:t,variant:m,mod:[{grow:v},x],size:w,...j,children:c})});h.classes=u;h.displayName="@mantine/core/Group";const M=[["path",{d:"M16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1 -4.069 0l-.301 -.301l-6.558 6.558a2 2 0 0 1 -1.239 .578l-.175 .008h-1.172a1 1 0 0 1 -.993 -.883l-.007 -.117v-1.172a2 2 0 0 1 .467 -1.284l.119 -.13l.414 -.414h2v-2h2v-2l2.144 -2.144l-.301 -.301a2.877 2.877 0 0 1 0 -4.069l2.643 -2.643a2.877 2.877 0 0 1 4.069 0",key:"svg-0"}],["path",{d:"M15 9h.01",key:"svg-1"}]],V=B("outline","key","Key",M);export{h as G,V as I}; diff --git a/internal/panel/web_dist/assets/IconPlus-N6bDt4BE.js b/internal/panel/web_dist/assets/IconPlus-D0GthIF3.js similarity index 98% rename from internal/panel/web_dist/assets/IconPlus-N6bDt4BE.js rename to internal/panel/web_dist/assets/IconPlus-D0GthIF3.js index f3aea0d..bd5de7b 100644 --- a/internal/panel/web_dist/assets/IconPlus-N6bDt4BE.js +++ b/internal/panel/web_dist/assets/IconPlus-D0GthIF3.js @@ -1 +1 @@ -import{r as x,t as D,j as l,y as T,x as P,E as L,K as fe,Y as ge,R as H,q as N,s as G,Z as K,o as X,F as ve,G as be,v as me,C as xe,w as Se,c as J}from"./index-Dy6W__Vz.js";import{g as ye}from"./IconArrowUp-Cj3lrfzR.js";var Q={root:"m_5f75b09e",body:"m_5f6e695e",labelWrapper:"m_d3ea56bb",label:"m_8ee546b8",description:"m_328f68c0",error:"m_8e8a99cc"};const we=Q,ee=x.forwardRef(({__staticSelector:n,__stylesApiProps:r,className:t,classNames:e,styles:a,unstyled:d,children:i,label:h,description:o,id:p,disabled:f,error:s,size:c,labelPosition:S="left",bodyElement:y="div",labelElement:v="label",variant:b,style:R,vars:C,mod:g,attributes:_,...z},w)=>{const m=D({name:n,props:r,className:t,style:R,classes:Q,classNames:e,styles:a,unstyled:d,attributes:_});return l.jsx(T,{...m("root"),ref:w,__vars:{"--label-fz":fe(c),"--label-lh":L(c,"label-lh")},mod:[{"label-position":S},g],variant:b,size:c,...z,children:l.jsxs(T,{component:y,htmlFor:y==="label"?p:void 0,...m("body"),children:[i,l.jsxs("div",{...m("labelWrapper"),"data-disabled":f||void 0,children:[h&&l.jsx(T,{component:v,htmlFor:v==="label"?p:void 0,...m("label"),"data-disabled":f||void 0,children:h}),o&&l.jsx(P.Description,{size:c,__inheritStyles:!1,...m("description"),children:o}),s&&typeof s!="boolean"&&l.jsx(P.Error,{size:c,__inheritStyles:!1,...m("error"),children:s})]})]})})});ee.displayName="@mantine/core/InlineInput";function Ce({children:n,role:r}){const t=ge();return t?l.jsx("div",{role:r,"aria-labelledby":t.labelId,"aria-describedby":t.describedBy,children:n}):l.jsx(l.Fragment,{children:n})}function W(){return W=Object.assign?Object.assign.bind():function(n){for(var r=1;r{const{autosize:t,maxRows:e,minRows:a,__staticSelector:d,resize:i,...h}=G("Textarea",Be,n),o=t&&ye()!=="test",p=o?{maxRows:e,minRows:a}:{};return l.jsx(K,{component:o?Ae:"textarea",ref:r,...h,__staticSelector:d||"Textarea",multiline:!0,"data-no-overflow":t&&e===void 0||void 0,__vars:{"--input-resize":i},...p})});te.classes=K.classes;te.displayName="@mantine/core/Textarea";var re={root:"m_5f93f3bb",input:"m_926b4011",track:"m_9307d992",thumb:"m_93039a1d",trackLabel:"m_8277e082"};const ne=x.createContext(null),Oe=ne.Provider,$e=()=>x.useContext(ne),A=N((n,r)=>{const{value:t,defaultValue:e,onChange:a,size:d,wrapperProps:i,children:h,readOnly:o,disabled:p,...f}=G("SwitchGroup",null,n),[s,c]=X({value:t,defaultValue:e,finalValue:[],onChange:a}),S=y=>{const v=y.currentTarget.value;!o&&c(s.includes(v)?s.filter(b=>b!==v):[...s,v])};return l.jsx(Oe,{value:{value:s,onChange:S,size:d,disabled:p},children:l.jsx(P.Wrapper,{size:d,ref:r,...i,...f,labelElement:"div",__staticSelector:"SwitchGroup",children:l.jsx(Ce,{role:"group",children:h})})})});A.classes=P.Wrapper.classes;A.displayName="@mantine/core/SwitchGroup";const Ve={labelPosition:"right",withThumbIndicator:!0},Ye=me((n,{radius:r,color:t,size:e})=>({root:{"--switch-radius":r===void 0?void 0:Se(r),"--switch-height":L(e,"switch-height"),"--switch-width":L(e,"switch-width"),"--switch-thumb-size":L(e,"switch-thumb-size"),"--switch-label-font-size":L(e,"switch-label-font-size"),"--switch-track-label-padding":L(e,"switch-track-label-padding"),"--switch-color":t?xe(t,n):void 0}})),B=N((n,r)=>{const t=G("Switch",Ve,n),{classNames:e,className:a,style:d,styles:i,unstyled:h,vars:o,color:p,label:f,offLabel:s,onLabel:c,id:S,size:y,radius:v,wrapperProps:b,thumbIcon:R,checked:C,defaultChecked:g,onChange:_,labelPosition:z,description:w,error:m,disabled:ae,variant:ie,rootRef:oe,mod:se,withThumbIndicator:ce,attributes:le,...de}=t,E=$e(),ue=y||E?.size,I=D({name:"Switch",props:t,classes:re,className:a,style:d,classNames:e,styles:i,unstyled:h,attributes:le,vars:o,varsResolver:Ye}),{styleProps:he,rest:F}=ve(de),O=be(S),k={checked:E?.value.includes(F.value)??C,onChange:j=>{E?.onChange(j),_?.(j)},disabled:E?.disabled??ae},[$,pe]=X({value:k.checked??C,defaultValue:g,finalValue:!1});return l.jsxs(ee,{...I("root"),__staticSelector:"Switch",__stylesApiProps:t,id:O,size:ue,labelPosition:z,label:f,description:w,error:m,disabled:k.disabled,bodyElement:"label",labelElement:"span",classNames:e,styles:i,unstyled:h,"data-checked":k.checked,variant:ie,ref:oe,mod:se,inert:F.inert,...he,...b,children:[l.jsx("input",{...F,...k,checked:$,"data-checked":k.checked,onChange:j=>{k.onChange?.(j),pe(j.currentTarget.checked)},id:O,ref:r,type:"checkbox",role:"switch",inert:F.inert,...I("input")}),l.jsxs(T,{"aria-hidden":"true",component:"span",mod:{error:m,"label-position":z,"without-labels":!c&&!s},...I("track"),children:[l.jsx(T,{component:"span",mod:{"reduce-motion":!0,"with-thumb-indicator":ce&&!R},...I("thumb"),children:R}),l.jsx("span",{...I("trackLabel"),children:$?c:s})]})]})});B.classes={...re,...we};B.displayName="@mantine/core/Switch";B.Group=A;const qe=[["path",{d:"M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0",key:"svg-0"}],["path",{d:"M12 9h.01",key:"svg-1"}],["path",{d:"M11 12h1v4h1",key:"svg-2"}]],Ke=J("outline","info-circle","InfoCircle",qe);const Ue=[["path",{d:"M12 5l0 14",key:"svg-0"}],["path",{d:"M5 12l14 0",key:"svg-1"}]],Xe=J("outline","plus","Plus",Ue);export{Ke as I,B as S,te as T,Xe as a,Ce as b,ee as c,we as d}; +import{r as x,t as D,j as l,y as T,x as P,E as L,K as fe,Y as ge,R as H,q as N,s as G,Z as K,o as X,F as ve,G as be,v as me,C as xe,w as Se,c as J}from"./index-fgrXogF6.js";import{g as ye}from"./IconArrowUp-DwKi77Ll.js";var Q={root:"m_5f75b09e",body:"m_5f6e695e",labelWrapper:"m_d3ea56bb",label:"m_8ee546b8",description:"m_328f68c0",error:"m_8e8a99cc"};const we=Q,ee=x.forwardRef(({__staticSelector:n,__stylesApiProps:r,className:t,classNames:e,styles:a,unstyled:d,children:i,label:h,description:o,id:p,disabled:f,error:s,size:c,labelPosition:S="left",bodyElement:y="div",labelElement:v="label",variant:b,style:R,vars:C,mod:g,attributes:_,...z},w)=>{const m=D({name:n,props:r,className:t,style:R,classes:Q,classNames:e,styles:a,unstyled:d,attributes:_});return l.jsx(T,{...m("root"),ref:w,__vars:{"--label-fz":fe(c),"--label-lh":L(c,"label-lh")},mod:[{"label-position":S},g],variant:b,size:c,...z,children:l.jsxs(T,{component:y,htmlFor:y==="label"?p:void 0,...m("body"),children:[i,l.jsxs("div",{...m("labelWrapper"),"data-disabled":f||void 0,children:[h&&l.jsx(T,{component:v,htmlFor:v==="label"?p:void 0,...m("label"),"data-disabled":f||void 0,children:h}),o&&l.jsx(P.Description,{size:c,__inheritStyles:!1,...m("description"),children:o}),s&&typeof s!="boolean"&&l.jsx(P.Error,{size:c,__inheritStyles:!1,...m("error"),children:s})]})]})})});ee.displayName="@mantine/core/InlineInput";function Ce({children:n,role:r}){const t=ge();return t?l.jsx("div",{role:r,"aria-labelledby":t.labelId,"aria-describedby":t.describedBy,children:n}):l.jsx(l.Fragment,{children:n})}function W(){return W=Object.assign?Object.assign.bind():function(n){for(var r=1;r{const{autosize:t,maxRows:e,minRows:a,__staticSelector:d,resize:i,...h}=G("Textarea",Be,n),o=t&&ye()!=="test",p=o?{maxRows:e,minRows:a}:{};return l.jsx(K,{component:o?Ae:"textarea",ref:r,...h,__staticSelector:d||"Textarea",multiline:!0,"data-no-overflow":t&&e===void 0||void 0,__vars:{"--input-resize":i},...p})});te.classes=K.classes;te.displayName="@mantine/core/Textarea";var re={root:"m_5f93f3bb",input:"m_926b4011",track:"m_9307d992",thumb:"m_93039a1d",trackLabel:"m_8277e082"};const ne=x.createContext(null),Oe=ne.Provider,$e=()=>x.useContext(ne),A=N((n,r)=>{const{value:t,defaultValue:e,onChange:a,size:d,wrapperProps:i,children:h,readOnly:o,disabled:p,...f}=G("SwitchGroup",null,n),[s,c]=X({value:t,defaultValue:e,finalValue:[],onChange:a}),S=y=>{const v=y.currentTarget.value;!o&&c(s.includes(v)?s.filter(b=>b!==v):[...s,v])};return l.jsx(Oe,{value:{value:s,onChange:S,size:d,disabled:p},children:l.jsx(P.Wrapper,{size:d,ref:r,...i,...f,labelElement:"div",__staticSelector:"SwitchGroup",children:l.jsx(Ce,{role:"group",children:h})})})});A.classes=P.Wrapper.classes;A.displayName="@mantine/core/SwitchGroup";const Ve={labelPosition:"right",withThumbIndicator:!0},Ye=me((n,{radius:r,color:t,size:e})=>({root:{"--switch-radius":r===void 0?void 0:Se(r),"--switch-height":L(e,"switch-height"),"--switch-width":L(e,"switch-width"),"--switch-thumb-size":L(e,"switch-thumb-size"),"--switch-label-font-size":L(e,"switch-label-font-size"),"--switch-track-label-padding":L(e,"switch-track-label-padding"),"--switch-color":t?xe(t,n):void 0}})),B=N((n,r)=>{const t=G("Switch",Ve,n),{classNames:e,className:a,style:d,styles:i,unstyled:h,vars:o,color:p,label:f,offLabel:s,onLabel:c,id:S,size:y,radius:v,wrapperProps:b,thumbIcon:R,checked:C,defaultChecked:g,onChange:_,labelPosition:z,description:w,error:m,disabled:ae,variant:ie,rootRef:oe,mod:se,withThumbIndicator:ce,attributes:le,...de}=t,E=$e(),ue=y||E?.size,I=D({name:"Switch",props:t,classes:re,className:a,style:d,classNames:e,styles:i,unstyled:h,attributes:le,vars:o,varsResolver:Ye}),{styleProps:he,rest:F}=ve(de),O=be(S),k={checked:E?.value.includes(F.value)??C,onChange:j=>{E?.onChange(j),_?.(j)},disabled:E?.disabled??ae},[$,pe]=X({value:k.checked??C,defaultValue:g,finalValue:!1});return l.jsxs(ee,{...I("root"),__staticSelector:"Switch",__stylesApiProps:t,id:O,size:ue,labelPosition:z,label:f,description:w,error:m,disabled:k.disabled,bodyElement:"label",labelElement:"span",classNames:e,styles:i,unstyled:h,"data-checked":k.checked,variant:ie,ref:oe,mod:se,inert:F.inert,...he,...b,children:[l.jsx("input",{...F,...k,checked:$,"data-checked":k.checked,onChange:j=>{k.onChange?.(j),pe(j.currentTarget.checked)},id:O,ref:r,type:"checkbox",role:"switch",inert:F.inert,...I("input")}),l.jsxs(T,{"aria-hidden":"true",component:"span",mod:{error:m,"label-position":z,"without-labels":!c&&!s},...I("track"),children:[l.jsx(T,{component:"span",mod:{"reduce-motion":!0,"with-thumb-indicator":ce&&!R},...I("thumb"),children:R}),l.jsx("span",{...I("trackLabel"),children:$?c:s})]})]})});B.classes={...re,...we};B.displayName="@mantine/core/Switch";B.Group=A;const qe=[["path",{d:"M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0",key:"svg-0"}],["path",{d:"M12 9h.01",key:"svg-1"}],["path",{d:"M11 12h1v4h1",key:"svg-2"}]],Ke=J("outline","info-circle","InfoCircle",qe);const Ue=[["path",{d:"M12 5l0 14",key:"svg-0"}],["path",{d:"M5 12l14 0",key:"svg-1"}]],Xe=J("outline","plus","Plus",Ue);export{Ke as I,B as S,te as T,Xe as a,Ce as b,ee as c,we as d}; diff --git a/internal/panel/web_dist/assets/IconServer-BpOSndTX.js b/internal/panel/web_dist/assets/IconServer-DmZ16e5j.js similarity index 88% rename from internal/panel/web_dist/assets/IconServer-BpOSndTX.js rename to internal/panel/web_dist/assets/IconServer-DmZ16e5j.js index 40b07b0..cd08be3 100644 --- a/internal/panel/web_dist/assets/IconServer-BpOSndTX.js +++ b/internal/panel/web_dist/assets/IconServer-DmZ16e5j.js @@ -1 +1 @@ -import{c as e}from"./index-Dy6W__Vz.js";const a=[["path",{d:"M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4",key:"svg-0"}],["path",{d:"M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4",key:"svg-1"}]],t=e("outline","refresh","Refresh",a);const o=[["path",{d:"M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3",key:"svg-0"}],["path",{d:"M3 15a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3l0 -2",key:"svg-1"}],["path",{d:"M7 8l0 .01",key:"svg-2"}],["path",{d:"M7 16l0 .01",key:"svg-3"}]],h=e("outline","server","Server",o);export{t as I,h as a}; +import{c as e}from"./index-fgrXogF6.js";const a=[["path",{d:"M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4",key:"svg-0"}],["path",{d:"M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4",key:"svg-1"}]],t=e("outline","refresh","Refresh",a);const o=[["path",{d:"M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3",key:"svg-0"}],["path",{d:"M3 15a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3l0 -2",key:"svg-1"}],["path",{d:"M7 8l0 .01",key:"svg-2"}],["path",{d:"M7 16l0 .01",key:"svg-3"}]],h=e("outline","server","Server",o);export{t as I,h as a}; diff --git a/internal/panel/web_dist/assets/IconTrash-CZzjtN_Z.js b/internal/panel/web_dist/assets/IconTrash-Bdw5EaPs.js similarity index 81% rename from internal/panel/web_dist/assets/IconTrash-CZzjtN_Z.js rename to internal/panel/web_dist/assets/IconTrash-Bdw5EaPs.js index 952c942..9d43587 100644 --- a/internal/panel/web_dist/assets/IconTrash-CZzjtN_Z.js +++ b/internal/panel/web_dist/assets/IconTrash-Bdw5EaPs.js @@ -1 +1 @@ -import{c as a}from"./index-Dy6W__Vz.js";const t=[["path",{d:"M4 7l16 0",key:"svg-0"}],["path",{d:"M10 11l0 6",key:"svg-1"}],["path",{d:"M14 11l0 6",key:"svg-2"}],["path",{d:"M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12",key:"svg-3"}],["path",{d:"M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3",key:"svg-4"}]],s=a("outline","trash","Trash",t);export{s as I}; +import{c as a}from"./index-fgrXogF6.js";const t=[["path",{d:"M4 7l16 0",key:"svg-0"}],["path",{d:"M10 11l0 6",key:"svg-1"}],["path",{d:"M14 11l0 6",key:"svg-2"}],["path",{d:"M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12",key:"svg-3"}],["path",{d:"M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3",key:"svg-4"}]],s=a("outline","trash","Trash",t);export{s as I}; diff --git a/internal/panel/web_dist/assets/NodeDetailPage-qxCia4WP.js b/internal/panel/web_dist/assets/NodeDetailPage-J8oehTrg.js similarity index 98% rename from internal/panel/web_dist/assets/NodeDetailPage-qxCia4WP.js rename to internal/panel/web_dist/assets/NodeDetailPage-J8oehTrg.js index 099cbcf..6165b5b 100644 --- a/internal/panel/web_dist/assets/NodeDetailPage-qxCia4WP.js +++ b/internal/panel/web_dist/assets/NodeDetailPage-J8oehTrg.js @@ -1,2 +1,2 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/demo-node-detail-DkbalCRs.js","assets/demo-42aef_vS.js"])))=>i.map(i=>d[i]); -import{c as qe,j as e,r as a,B as R,I as Rs,a as As,u as Es,g as O,A as we,h as et,k as Os,l as st,_ as Ms,m as Ts,n as tt,i as nt,e as at,L as Cs,S as Oe,f as rt,T as fs}from"./index-Dy6W__Vz.js";import{a as zs,T as Ce,M as j,I as js,b as $e,c as it,P as lt}from"./PageHeader-C4N9uitv.js";import{b as D,a as De,f as Me,t as os,e as ot,c as as,s as ct,g as dt,T as rs,I as ut,S as Fs,R as ht}from"./format-D6_ab21F.js";import{m as pt,r as is,S as ft,e as xt,c as mt,P as gt,I as jt,a as bt,b as vt,f as yt,g as _t,A as Nt}from"./model-BX4frb_O.js";import{I as St,a as kt,S as wt}from"./IconArrowUp-Cj3lrfzR.js";import{I as Hs,a as Us,S as Ct}from"./IconPlus-N6bDt4BE.js";import{h as $t,r as Ve,p as xs,I as ls,a as Ye}from"./platform-C19YEZOH.js";import{I as Dt,a as Pt,T as qs,u as It,S as ge}from"./TrafficChart-BU3flakD.js";import{i as Rt}from"./haproxy-BnB0NJ0D.js";import{i as At}from"./interaction-BrakVCuN.js";import{I as cs}from"./IconTrash-CZzjtN_Z.js";import{I as Et}from"./IconDots-B4BXVaDG.js";import{I as ms}from"./IconServer-BpOSndTX.js";import{G as Ze}from"./IconKey-D6H2eVar.js";import"./chart-react-C4b8adjg.js";import"./chart-engine-Dbh3Q7E_.js";import"./chart-renderer-CWmX7Ukt.js";const Ot=[["path",{d:"M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1",key:"svg-0"}],["path",{d:"M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415",key:"svg-1"}],["path",{d:"M16 5l3 3",key:"svg-2"}]],bs=qe("outline","edit","Edit",Ot);const Mt=[["path",{d:"M9 3v18",key:"svg-0"}],["path",{d:"M3 9h18",key:"svg-1"}],["path",{d:"M3 15h10",key:"svg-2"}],["path",{d:"M15 3v10",key:"svg-3"}],["path",{d:"M11 21h-6a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v8",key:"svg-4"}],["path",{d:"M15 19l2 2l4 -4",key:"svg-5"}]],Tt=qe("outline","firewall-check","FirewallCheck",Mt);const zt=[["path",{d:"M7 6a7.75 7.75 0 1 0 10 0",key:"svg-0"}],["path",{d:"M12 4l0 8",key:"svg-1"}]],es=qe("outline","power","Power",zt);const Ft=[["path",{d:"M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-2",key:"svg-0"}],["path",{d:"M12 20h-6a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h10.5",key:"svg-1"}],["path",{d:"M16 18a2 2 0 1 0 4 0a2 2 0 1 0 -4 0",key:"svg-2"}],["path",{d:"M18 14.5v1.5",key:"svg-3"}],["path",{d:"M18 20v1.5",key:"svg-4"}],["path",{d:"M21.032 16.25l-1.299 .75",key:"svg-5"}],["path",{d:"M16.27 19l-1.3 .75",key:"svg-6"}],["path",{d:"M14.97 16.25l1.3 .75",key:"svg-7"}],["path",{d:"M19.733 19l1.3 .75",key:"svg-8"}],["path",{d:"M7 8v.01",key:"svg-9"}],["path",{d:"M7 16v.01",key:"svg-10"}]],$s=qe("outline","server-cog","ServerCog",Ft);const Ht=[["path",{d:"M16 18a2 2 0 0 1 2 2a2 2 0 0 1 2 -2a2 2 0 0 1 -2 -2a2 2 0 0 1 -2 2m0 -12a2 2 0 0 1 2 2a2 2 0 0 1 2 -2a2 2 0 0 1 -2 -2a2 2 0 0 1 -2 2m-7 12a6 6 0 0 1 6 -6a6 6 0 0 1 -6 -6a6 6 0 0 1 -6 6a6 6 0 0 1 6 6",key:"svg-0"}]],Ut=qe("outline","sparkles","Sparkles",Ht);function ke({values:s}){const t=s.filter(Number.isFinite).slice(-28);if(t.length<2)return e.jsx("span",{className:"nf-mini-sparkline is-empty","aria-hidden":"true"});const o=Math.min(...t),l=Math.max(...t),i=Math.max(1,l-o),c=t.map((g,f)=>`${f/(t.length-1)*100},${20-(g-o)/i*16}`).join(" ");return e.jsx("svg",{className:"nf-mini-sparkline",viewBox:"0 0 100 22",preserveAspectRatio:"none","aria-hidden":"true",children:e.jsx("polyline",{points:c})})}function ss(s,t,o,l,i=c=>D(c,1)){if(!l||t==null)return`${s}: история ещё собирается`;const c=o==null?"дельта недоступна":`дельта ${o>=0?"+":""}${i(o)}`;return`${s}: среднее ${i(t)}, ${c}, точек ${l}`}function ts(s){const t=s.filter(Number.isFinite);if(t.length)return{average:t.reduce((o,l)=>o+l,0)/t.length,delta:t.at(-1)-t[0],sample_count:t.length}}function de({children:s,hint:t}){return e.jsxs("span",{className:"nf-detail-kpi__label",children:[s,t&&e.jsx(Ce,{label:t,multiline:!0,w:260,openDelay:250,children:e.jsx(Hs,{size:14,tabIndex:0,"aria-label":t})})]})}function qt({metrics:s,history:t,summary:o,currentRx:l,currentTx:i,rateSampledAt:c,live:g,mtlsConnected:f}){const P=pt(s),M=(s?.load??[]).slice(0,3),p=s?.haproxy_runtime,m=Object.values(p?.backends??{}),K=p?m.reduce((y,v)=>y+(Number(v.sessions_current)||0),0):void 0,x=p?m.reduce((y,v)=>y+(Number(v.sessions_total)||0),0):void 0,L=g&&Number.isFinite(p?.connections_current)?Number(p?.connections_current):void 0,F=Number.isFinite(p?.connections_total)?Number(p?.connections_total):void 0,w=g&&Number.isFinite(p?.connection_rate)?Number(p?.connection_rate):void 0,A=t.flatMap(y=>y.rx_bps===null?[]:[y.rx_bps]),Y=t.flatMap(y=>y.tx_bps===null?[]:[y.tx_bps]),Q=t.map(y=>Number(y.cpu_percent)).filter(Number.isFinite),te=t.map(y=>Number(y.memory_percent)).filter(Number.isFinite),H=ts(Q)??o?.cpu_percent,b=ts(te)??o?.memory_percent,T=ts(A)??o?.rx_bps,S=ts(Y)??o?.tx_bps,U=Number(s?.process_count),N=(s?.process_names??[]).filter(Boolean),B=Number.isFinite(U)&&U>=0?`Процессов: ${D(U)}${N.length?`. Основные: ${N.join(", ")}`:""}`:N.length?`Основные процессы: ${N.join(", ")}`:"Список процессов ещё не получен";return e.jsxs("section",{className:"nf-surface nf-detail-kpis","aria-label":"Система, сеть и соединения",children:[e.jsxs("div",{className:"nf-detail-kpi",children:[e.jsx(de,{hint:ss("CPU",H?.average,H?.delta,H?.sample_count,y=>`${D(y,1)}%`),children:"CPU"}),e.jsx("strong",{children:Number.isFinite(Number(s?.cpu_percent))?`${D(Number(s?.cpu_percent),1)}%`:"—"}),e.jsx(ke,{values:Q})]}),e.jsxs("div",{className:"nf-detail-kpi is-memory",children:[e.jsx(de,{hint:ss("RAM",b?.average,b?.delta,b?.sample_count,y=>`${D(y,1)}%`),children:"RAM"}),e.jsxs("strong",{children:[De(P.used)," ",e.jsxs("small",{children:["/ ",De(P.total)]})]}),e.jsx("span",{className:"nf-detail-kpi__sub",children:P.percent==null?"Нет данных":`${D(P.percent,1)}% занято`}),e.jsx(ke,{values:te})]}),e.jsxs("div",{className:"nf-detail-kpi is-load",children:[e.jsx(de,{hint:"Нормализованные значения Linux load average за 1, 5 и 15 минут",children:"Load (1м / 5м / 15м)"}),e.jsx("strong",{children:M.length?M.map(y=>D(y,2)).join(" / "):"—"}),e.jsx("span",{className:"nf-detail-kpi__sub",children:"текущий срез"}),e.jsx(ke,{values:[]})]}),e.jsxs("div",{className:"nf-detail-kpi is-network",children:[e.jsxs(de,{hint:ss("RX",T?.average,T?.delta,T?.sample_count,Me),children:[e.jsx(St,{size:17})," RX"]}),e.jsx("strong",{children:Me(l)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:l===null?c?`последняя точка ${os(c)}`:"нет свежей точки":"HAProxy сейчас"}),e.jsx(ke,{values:A})]}),e.jsxs("div",{className:"nf-detail-kpi is-network",children:[e.jsxs(de,{hint:ss("TX",S?.average,S?.delta,S?.sample_count,Me),children:[e.jsx(kt,{size:17})," TX"]}),e.jsx("strong",{children:Me(i)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:i===null?c?`последняя точка ${os(c)}`:"нет свежей точки":"HAProxy сейчас"}),e.jsx(ke,{values:Y})]}),e.jsxs("div",{className:"nf-detail-kpi",children:[e.jsx(de,{hint:p?`${w==null?"Rate не получен":`${D(w)} новых/с`} · ${F==null?"total не получен":`${D(F)} всего`}`:"HAProxy runtime ещё не получен",children:"Соединения"}),e.jsx("strong",{children:D(L)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:w==null&&F==null?"Rate и total не получены":`${w==null?"— новых/с":`${D(w)} новых/с`} · ${F==null?"— всего":`${D(F)} всего`}`}),e.jsx(ke,{values:[]})]}),e.jsxs("div",{className:"nf-detail-kpi",children:[e.jsx(de,{hint:p?`${D(x)} TCP-сессий всего`:"HAProxy runtime ещё не получен",children:"TCP-сессии"}),e.jsx("strong",{children:D(K)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:x==null?"Total не получен":`${D(x)} всего`}),e.jsx(ke,{values:[]})]}),e.jsxs("div",{className:"nf-detail-kpi is-uptime",children:[e.jsx(de,{hint:B,children:"Время работы"}),e.jsx("strong",{children:ot(Number(s?.uptime_seconds))}),e.jsx("span",{className:"nf-detail-kpi__sub",children:Number.isFinite(U)?`${D(U)} процессов`:"без перезапуска Agent"})]}),e.jsxs("div",{className:`nf-detail-kpi nf-detail-kpi--mtls${f?" is-ready":""}`,children:[e.jsx(de,{children:"mTLS соединение"}),e.jsxs("strong",{children:[e.jsx(zs,{size:21})," ",f?"На связи":"Нет свежего сигнала"]}),e.jsx("span",{className:"nf-detail-kpi__sub",children:"последний heartbeat по защищённому каналу"})]})]})}function Ds(s){const t=s.details&&typeof s.details.summary=="string"?s.details.summary:"";return t||({"route.created":"Создан маршрут","route.updated":"Изменён маршрут","route.enabled":"Маршрут включён","route.disabled":"Маршрут выключен","route.deleted":"Удалён маршрут","route.change":"Изменён маршрут","agent.update.assigned":"Назначено обновление Node Agent","agent.update.assign":"Назначено обновление Node Agent","agent.update.rollback":"Назначен откат Node Agent","firewall.policy.updated":"Изменена политика UFW","firewall.policy":"Изменена политика UFW","node.update":"Изменены параметры ноды"}[s.action]??s.action.replaceAll("."," · "))}function Lt({action:s}){return s.startsWith("route")?e.jsx(Dt,{size:16}):s.startsWith("firewall")?e.jsx(Tt,{size:16}):s.includes("update")?e.jsx(ls,{size:16}):e.jsx(it,{size:16})}function Bt(s){return{installed:"Установлено",idle:"Готов",assigned:"Назначено",downloading:"Загрузка",verifying:"Проверка",activating:"Установка",failed:"Ошибка",rolled_back:"Автооткат"}[s??""]??s??"Нет данных"}function gs(s){return`${s.version} · sequence #${s.sequence}`}function Wt({metrics:s,agentVersion:t,agentPort:o,mtlsReady:l,credentialLastUsed:i,routes:c,firewall:g,update:f,releases:P,audit:M,partialErrors:p,busyAction:m,onFirewallMode:K,onAssignRelease:x,onRollback:L,onOpenNodeSettings:F}){const[w,A]=a.useState(null),[Y,Q]=a.useState(!1),[te,H]=a.useState(""),b=$t(s),T=a.useMemo(()=>P.filter(d=>Ve(d,b)).sort((d,V)=>V.sequence-d.sequence),[P,b?.os,b?.arch]),S=f?.actual_sequence??0,U=T.filter(d=>d.sequence>S),N=T.filter(d=>d.sequenced.enabled).map(d=>d.listener_port))].sort((d,V)=>d-V),v=String(s?.haproxy_version??""),J=async()=>{if(!(!w||!f)){if(!b||!Ve(w,b)){H("Платформа ноды неизвестна или изменилась. Обновите состояние перед откатом.");return}Q(!0),H("");try{await L(w,f.actual_sequence,f.desired_release?.sequence??0),A(null)}catch(d){H(d instanceof Error?d.message:"Откат не назначен")}finally{Q(!1)}}};return e.jsxs("div",{className:"nf-detail-bottom-grid",children:[e.jsxs(as,{id:"operations",className:"nf-detail-operations",title:"Обновление и firewall",children:[e.jsxs("div",{className:"nf-operation-row",children:[e.jsxs("div",{className:"nf-operation-label",children:[e.jsx("span",{children:"Node Agent"}),e.jsx("strong",{children:t||"—"})]}),e.jsxs("div",{className:"nf-operation-state",children:[e.jsx("span",{className:`nf-state-chip is-${f?.state??"unknown"}`,children:Bt(f?.state)}),e.jsx("small",{children:b?B?`${xs(b)} · доступна ${B.version}`:`${xs(b)} · обновлений нет`:"платформа не получена"})]}),e.jsxs("div",{className:"nf-operation-actions",children:[U.length>1?e.jsxs(j,{position:"bottom-end",withinPortal:!0,shadow:"md",children:[e.jsx(j.Target,{children:e.jsx(R,{variant:"default",size:"xs",leftSection:e.jsx(ls,{size:15}),rightSection:e.jsx(js,{size:14}),disabled:!f||!b||m==="update",loading:m==="update",children:"Обновить"})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Label,{children:"Выберите версию"}),U.map(d=>e.jsx(j.Item,{leftSection:e.jsx(ls,{size:15}),onClick:()=>x(d),children:gs(d)},d.id))]})]}):e.jsx(R,{variant:"default",size:"xs",leftSection:e.jsx(ls,{size:15}),disabled:!f||!b||!B,loading:m==="update",onClick:()=>f&&B&&b&&Ve(B,b)&&x(B),children:"Обновить"}),N.length>1?e.jsxs(j,{position:"bottom-end",withinPortal:!0,shadow:"md",children:[e.jsx(j.Target,{children:e.jsx(R,{variant:"subtle",color:"gray",size:"xs",leftSection:e.jsx(Ye,{size:15}),rightSection:e.jsx(js,{size:14}),disabled:!b||m==="rollback",children:"Откатить"})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Label,{children:"Выберите версию"}),N.map(d=>e.jsx(j.Item,{leftSection:e.jsx(Ye,{size:15}),onClick:()=>{H(""),A(d)},children:gs(d)},d.id))]})]}):e.jsx(R,{variant:"subtle",color:"gray",size:"xs",leftSection:e.jsx(Ye,{size:15}),disabled:!b||N.length===0||m==="rollback",onClick:()=>{H("");const d=N[0];d&&b&&Ve(d,b)&&A(d)},children:"Откатить"})]})]}),!b&&e.jsx("p",{className:"nf-operation-error",role:"status",children:"Назначение релиза заблокировано: Agent ещё не передал os и arch."}),(p.update||p.releases||f?.last_error)&&e.jsx("p",{className:"nf-operation-error",role:"alert",children:f?.last_error||p.update||p.releases}),e.jsxs("div",{className:"nf-operation-row nf-operation-row--firewall",children:[e.jsxs("div",{className:"nf-operation-label",children:[e.jsx("span",{children:"Политика UFW"}),e.jsx("strong",{children:g?.mode==="apply"?"Автооткрытие разрешено":g?.mode==="observe"?"Только проверка":g?.mode==="off"?"Не управляется":"—"})]}),e.jsxs("div",{className:"nf-listener-ports",children:[e.jsx("span",{children:"Порты по плану"}),e.jsx("strong",{children:y.length?y.join(", "):"нет активных"})]}),e.jsx(wt,{size:"xs",value:g?.mode??"off",onChange:d=>K(d),data:[{label:"Выкл.",value:"off"},{label:"Проверка",value:"observe"},{label:"Авто",value:"apply"}],disabled:!g||m==="firewall","aria-label":"Политика управления UFW"})]}),p.firewall&&e.jsxs("p",{className:"nf-operation-error",role:"alert",children:["UFW: ",p.firewall]}),e.jsxs("button",{className:"nf-operation-disclosure",type:"button",onClick:F,children:["Дополнительные настройки ноды ",e.jsx(Rs,{size:15})]})]}),e.jsx(as,{className:"nf-detail-audit",title:"Последние действия",children:p.audit?e.jsx("div",{className:"nf-detail-panel-state",role:"alert",children:p.audit}):M.length?e.jsx("div",{className:"nf-audit-scroll",role:"list","aria-label":"Последние действия, прокручиваемый список",children:[...M].sort((d,V)=>Date.parse(V.created_at)-Date.parse(d.created_at)).map(d=>e.jsxs("div",{className:"nf-audit-row",role:"listitem",children:[e.jsx("i",{children:e.jsx(Lt,{action:d.action})}),e.jsx("strong",{title:Ds(d),children:Ds(d)}),e.jsx("time",{dateTime:d.created_at,children:new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit"}).format(new Date(d.created_at))}),e.jsx("span",{children:d.actor_type==="agent"?"Agent":"Оператор"}),e.jsx("em",{children:"Успешно"})]},d.id))}):e.jsx("div",{className:"nf-detail-panel-state",children:"Действий пока нет."})}),e.jsx(as,{className:"nf-detail-versions",title:"Версии и соединение",children:e.jsxs("dl",{children:[e.jsxs("div",{children:[e.jsx("dt",{children:"HAProxy"}),e.jsx(Ce,{label:v||"Полная версия не получена",openDelay:250,children:e.jsx("dd",{tabIndex:0,children:ct(v)})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Node Agent"}),e.jsx("dd",{children:t||"—"})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"mTLS соединение"}),e.jsxs("dd",{className:l?"is-ready":"",children:[e.jsx(zs,{size:17})," ",l?"На связи":"Нет свежего сигнала"]})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Связь с Panel"}),e.jsxs("dd",{children:["Исходящий mTLS · :",o]})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Последняя авторизация"}),e.jsx(Ce,{label:dt(i),openDelay:250,children:e.jsx("dd",{tabIndex:0,children:i?os(i):"—"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Политика обновления"}),e.jsxs("dd",{children:[e.jsx(Ut,{size:16})," Ed25519 · автооткат"]})]})]})}),e.jsx($e,{opened:!!w,onClose:()=>!Y&&A(null),title:"Откатить Node Agent?",classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs("div",{className:"nf-confirm-dialog",children:[e.jsxs("p",{children:["Будет назначен подписанный релиз ",e.jsx("strong",{children:w?gs(w):"—"})," для ",e.jsx("strong",{children:xs(b)}),". Updater проверит Ed25519, SHA-256 и вернёт текущий бинарник при ошибке запуска."]}),te&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:te}),e.jsxs("div",{children:[e.jsx(R,{variant:"default",disabled:Y,onClick:()=>A(null),children:"Отмена"}),e.jsx(R,{leftSection:e.jsx(Ye,{size:16}),loading:Y,onClick:J,children:"Откатить"})]})]})})]})}const Kt={active:"Активен",pending:"Применяется",failed:"Ошибка",draft:"Черновик",disabled:"Выключен",deleting:"Удаляется"};function vs(s){return s.match_mode==="sni"||!s.fallback&&s.snis.length?`SNI ${s.snis.join(", ")}`:s.fallback||s.match_mode==="any_tcp"||s.match_mode==="destination_ip"?"Фолбэк":s.snis.length?`SNI ${s.snis.join(", ")}`:"Фолбэк"}function ys(s){if(s.target_type==="unix")return s.unix_socket_path||"Unix socket";const t=`${s.target_host||"—"}:${s.target_port||"—"}`;return s.dns_pool?`DNS-пул · ${t}`:t}function Ps(s,t,o,l){const i=l?l.get(s.id):t?.routes.find(f=>f.route_id===s.id),c=i?o?.haproxy_runtime?.backends?.[i.backend_key]:void 0,g=i?o?.haproxy_runtime?.servers?.[i.backend_key]:void 0;return{report:i,backend:c,servers:g}}function Ls(s,t){const o=Object.values(t??{}).filter(Rt),l=o.filter(P=>["UP","OPEN","READY"].includes(String(P.status??"").trim().toUpperCase())).length,i=String(s?.status??"").trim(),c=i.toUpperCase();if(o.length)return{tone:l===o.length?"online":l===0?"offline":"degraded",label:`${l}/${o.length}`,detail:i||"Backend status: UNKNOWN",tooltip:`HAProxy backend: ${i||"UNKNOWN"} · серверов ${l}/${o.length}`};if(!s)return{tone:"degraded",label:"—",detail:"Backend ещё не наблюдался",tooltip:"Backend ещё не наблюдался"};const g=["UP","OPEN","READY"].includes(c)?"online":["DOWN","CLOSED","MAINT","STOPPED"].some(P=>c.startsWith(P))?"offline":"degraded",f=i||"UNKNOWN";return{tone:g,label:f,detail:"Карта серверов не получена",tooltip:`HAProxy backend: ${f} · карта серверов не получена`}}function Qt(s,t){return t==="enabled"?s.enabled:t==="draft"?!s.enabled&&s.deployment_state!=="failed":t==="failed"?s.deployment_state==="failed":!0}const Xt={"1m":2e3,"5m":1e4,"1h":12e4,"24h":24e5,"7d":168e5,"30d":72e6};function Gt(s,t,o){const l=s.id.split("").reduce((p,m)=>p+m.charCodeAt(0),0),i=o?.haproxy_runtime?.backends,c=Object.values(i??{}).find(p=>Number(p.rx_bps)>0||Number(p.tx_bps)>0),g=Number(c?.rx_bps)||198e6,f=Number(c?.tx_bps)||124e6,P=Xt[t],M=Date.now();return Array.from({length:60},(p,m)=>{const K=.7+m/170,x=1+Math.sin((m+l%13)/4.8)*.13+Math.cos(m/8.5)*.06;return{timestamp:new Date(M-(59-m)*P).toISOString(),rx_bps:Math.max(0,Math.round(g*K*x)),tx_bps:Math.max(0,Math.round(f*K*(1+Math.sin((m+5)/6.4)*.1)))}})}const ns=100;function Jt(s){return`${s.listener_ip||"*"}:${s.listener_port}`}function Is(s){return s.fallback||s.match_mode==="any_tcp"||s.match_mode==="destination_ip"}function Vt(s){const t=[],o=new Map;for(const l of s){const i=Jt(l);let c=o.get(i);c||(c=[],t.push(i),o.set(i,c)),c.push(l)}return t.map(l=>{const i=o.get(l),c=i.filter(f=>!Is(f)),g=i.filter(Is);return{key:l,routes:[...c,...g],hasFallback:g.length>0,hasSNI:c.length>0}})}const Yt=a.memo(function({route:t,report:o,backend:l,servers:i,previousID:c,nextID:g,pending:f,dragging:P,dropTarget:M,ordering:p,reorderEnabled:m,reorderDisabledReason:K,onEdit:x,onToggle:L,onStats:F,onRequestDelete:w,onMove:A,onDragStart:Y,onDragEnd:Q,onDragOver:te,onDrop:H}){const b=Ls(l,i),T=o?.limit_bytes??t.quota_bytes,S=o?.limit_bytes?o.quota_used_bytes??o.used_bytes:o?.used_bytes,U=T&&S!=null?Math.min(100,S/T*100):null,N=is(t),B=vs(t),y=ys(t);return e.jsxs("div",{className:`nf-detail-route-row is-${t.deployment_state}${f?" is-busy":""}${P?" is-dragging":""}${M?" is-drop-target":""}${p?" is-ordering":""}`,role:"row",tabIndex:0,"aria-label":`Редактировать маршрут ${N}`,onClick:v=>{At(v.target,v.currentTarget)||x(t)},onKeyDown:v=>{v.key==="Enter"&&v.target===v.currentTarget&&x(t)},onDragOver:v=>te(v,t.id),onDrop:v=>H(v,t.id),children:[e.jsx("div",{role:"cell",className:"nf-route-toggle","data-row-action":!0,children:e.jsx(Ct,{size:"sm",checked:t.enabled,disabled:f||t.delete_pending,onChange:v=>L(t,v.currentTarget.checked),"aria-label":`${t.enabled?"Выключить":"Включить"} маршрут ${N}`})}),e.jsxs("div",{role:"cell",className:"nf-route-name-cell",children:[e.jsxs("div",{className:"nf-sort-controls","data-row-action":!0,children:[e.jsx(Ce,{label:m?"Перетащить маршрут":K,openDelay:250,children:e.jsx("span",{className:"nf-sort-grip-wrap",children:e.jsx(we,{className:"nf-sort-grip",variant:"subtle",color:"gray",size:"sm",draggable:m,disabled:!m,"aria-label":`Перетащить маршрут ${N}`,onDragStart:v=>Y(v,t.id),onDragEnd:Q,children:e.jsx(jt,{size:15})})})}),e.jsxs("div",{className:"nf-sort-step-actions",children:[e.jsx(we,{variant:"subtle",color:"gray",size:"xs",disabled:!m||!c,"aria-label":`Переместить ${N} выше`,onClick:()=>{c&&A(t.id,c)},children:e.jsx(bt,{size:12})}),e.jsx(we,{variant:"subtle",color:"gray",size:"xs",disabled:!m||!g,"aria-label":`Переместить ${N} ниже`,onClick:()=>{g&&A(t.id,g)},children:e.jsx(js,{size:12})})]})]}),e.jsxs("button",{className:"nf-route-name",onClick:()=>x(t),title:N,children:[e.jsx("i",{className:t.enabled?"is-online":""}),e.jsxs("span",{children:[e.jsx("strong",{children:N}),e.jsx("small",{className:`is-${t.deployment_state}`,children:Kt[t.deployment_state]??t.deployment_state})]})]})]}),e.jsxs("span",{role:"cell",className:"nf-route-mono",children:[t.listener_ip||"*",":",t.listener_port]}),e.jsx(Ce,{label:B,openDelay:350,children:e.jsx("span",{role:"cell",tabIndex:0,className:"nf-route-ellipsis",children:B})}),e.jsx(Ce,{label:y,openDelay:350,children:e.jsx("span",{role:"cell",tabIndex:0,className:"nf-route-ellipsis",children:y})}),e.jsx("span",{role:"cell",children:D(l?.connections_current)}),e.jsx("span",{role:"cell",children:D(l?.tcp_sessions_current??l?.sessions_current)}),e.jsxs("span",{role:"cell",className:"nf-route-rate",children:[e.jsxs("b",{children:["↓ ",Me(l?.rx_bps)]}),e.jsxs("small",{children:["↑ ",Me(l?.tx_bps)]})]}),e.jsxs("span",{role:"cell",className:"nf-route-quota",children:[e.jsx("b",{children:De(S)}),e.jsx("small",{children:T?`/ ${De(T)}`:"без лимита"}),e.jsx("i",{className:U==null?"is-unlimited":void 0,children:e.jsx("em",{style:{width:`${U??100}%`}})})]}),e.jsx(Ce,{label:b.tooltip,openDelay:300,children:e.jsxs("span",{role:"cell",className:`nf-route-health is-${b.tone}`,children:[e.jsx("i",{})," ",b.label]})}),e.jsx("span",{role:"cell","data-row-action":!0,children:e.jsxs(j,{position:"bottom-end",withinPortal:!0,children:[e.jsx(j.Target,{children:e.jsx(we,{variant:"subtle",color:"gray",size:"md","aria-label":`Действия маршрута ${N}`,children:e.jsx(vt,{size:16})})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Item,{leftSection:e.jsx(et,{size:16}),onClick:()=>F(t),children:"Статистика"}),e.jsx(j.Item,{leftSection:e.jsx(bs,{size:16}),onClick:()=>x(t),children:"Редактировать"}),e.jsx(j.Divider,{}),e.jsx(j.Item,{color:"red",leftSection:e.jsx(cs,{size:16}),onClick:()=>w(t),children:"Удалить"})]})]})})]})});function Zt({nodeID:s,routes:t,traffic:o,metrics:l,busyRouteID:i,orderingRouteID:c="",error:g,onToggle:f,onDelete:P,onReorder:M}){const p=As(),m=Es(),[K,x]=a.useState(""),[L,F]=a.useState("all"),[w,A]=a.useState(null),[Y,Q]=a.useState(!1),[te,H]=a.useState(""),[b,T]=a.useState(!1),[S,U]=a.useState(null),[N,B]=a.useState("24h"),[y,v]=a.useState([]),[J,d]=a.useState(!1),[V,ne]=a.useState(""),[Te,ue]=a.useState(""),[ze,Pe]=a.useState(""),Z=a.useRef(0),be=a.useMemo(()=>({all:t.length,enabled:t.filter(n=>n.enabled).length,draft:t.filter(n=>!n.enabled&&n.deployment_state!=="failed").length,failed:t.filter(n=>n.deployment_state==="failed").length}),[t]),ve=K.trim().toLowerCase(),he=a.useMemo(()=>t.filter(n=>Qt(n,L)?ve?`${is(n)} ${n.listener_ip}:${n.listener_port} ${vs(n)} ${ys(n)}`.toLowerCase().includes(ve):!0:!1),[t,L,ve]),ye=new URLSearchParams(m.search).get("demo")==="1",_e=ye?"?demo=1":"",Ie=L==="all"&&!K.trim()&&!i&&!c,Le=K.trim()||L!=="all"?"Сбросьте поиск и фильтры, чтобы менять порядок.":"Дождитесь завершения текущего изменения.",pe=a.useMemo(()=>Vt(he),[he]),ee=a.useMemo(()=>pe.flatMap(n=>n.routes),[pe]),ds=a.useMemo(()=>new Map((o?.routes??[]).map(n=>[n.route_id,n])),[o?.routes]),[Re,Be]=a.useState(1),fe=Math.max(1,Math.ceil(ee.length/ns)),W=Math.min(Re,fe);a.useEffect(()=>{Be(1)},[L,ve]);const ae=fe>1,C=ae?(W-1)*ns:0,xe=ae?C+ns:ee.length,X=a.useMemo(()=>{if(!ae)return pe.map(_=>({..._,lastOnPage:!0}));const n=[];let u=0;for(const _ of pe){const E=Math.max(C,u),re=Math.min(xe,u+_.routes.length);if(E=xe)break}return n},[pe,ae,C,xe]),I=a.useMemo(()=>{const n=new Map;return ee.forEach((u,_)=>n.set(u.id,{previousID:ee[_-1]?.id,nextID:ee[_+1]?.id})),n},[ee]),G=a.useRef({reorderEnabled:Ie,draggingID:Te,onReorder:M,onToggle:f,nodeID:s,demoQuery:_e,navigate:p});G.current={reorderEnabled:Ie,draggingID:Te,onReorder:M,onToggle:f,nodeID:s,demoQuery:_e,navigate:p};const Fe=a.useCallback(n=>{const{navigate:u,nodeID:_,demoQuery:E}=G.current;u(`/nodes/${_}/routes/${n.id}${E}`)},[]),He=a.useCallback((n,u)=>{G.current.onToggle(n,u)},[]),We=a.useCallback((n,u)=>{G.current.onReorder(n,u)},[]),oe=a.useCallback(n=>{H(""),A(n)},[]),ce=a.useCallback((n,u)=>{G.current.reorderEnabled&&(n.stopPropagation(),n.dataTransfer.effectAllowed="move",n.dataTransfer.setData("text/plain",u),G.current.draggingID=u,ue(u))},[]),Ae=a.useCallback((n,u)=>{const{reorderEnabled:_,draggingID:E}=G.current;!_||!E||u===E||(n.preventDefault(),n.dataTransfer.dropEffect="move",Pe(u))},[]),se=a.useCallback((n,u)=>{n.preventDefault(),n.stopPropagation();const{reorderEnabled:_,draggingID:E,onReorder:re}=G.current,Ne=E||n.dataTransfer.getData("text/plain");G.current.draggingID="",ue(""),Pe(""),_&&Ne&&Ne!==u&&re(Ne,u)},[]),Ke=a.useCallback(()=>{G.current.draggingID="",ue(""),Pe("")},[]);a.useEffect(()=>{if(!S)return;const n=++Z.current;if(v([]),ne(""),ye){v(Gt(S,N,l)),d(!1);return}const u=new AbortController;return d(!0),O(`/api/v1/nodes/${encodeURIComponent(s)}/routes/${encodeURIComponent(S.id)}/traffic/history?range=${encodeURIComponent(N)}`,{signal:u.signal}).then(_=>{Z.current===n&&v(_.samples??[])}).catch(_=>{!u.signal.aborted&&Z.current===n&&ne(_ instanceof Error?_.message:"История маршрута недоступна")}).finally(()=>{!u.signal.aborted&&Z.current===n&&d(!1)}),()=>u.abort()},[ye,l,s,N,S]);const us=a.useCallback(n=>{Z.current+=1,v([]),ne(""),d(!0),B("24h"),U(n)},[]),Qe=n=>{n!==N&&(Z.current+=1,v([]),ne(""),d(!0),B(n))},Ue=()=>{Z.current+=1,U(null),v([]),ne(""),d(!1)},Xe=async()=>{if(w){Q(!0),H("");try{await P(w),A(null)}catch(n){H(n instanceof Error?n.message:"Маршрут не удалён")}finally{Q(!1)}}};return e.jsxs("section",{className:`nf-surface nf-detail-routes${b?" is-relaxed":""}`,"aria-labelledby":"node-routes-title",children:[e.jsxs("header",{className:"nf-detail-routes__toolbar",children:[e.jsx("div",{className:"nf-detail-routes__title",children:e.jsx("h2",{id:"node-routes-title",children:"Маршруты"})}),e.jsx(ft,{className:"nf-detail-route-tabs",value:L,onChange:F,label:"Фильтр маршрутов",items:[{value:"all",label:"Все",count:be.all},{value:"enabled",label:"Включены",count:be.enabled},{value:"draft",label:"Черновики",count:be.draft}]}),e.jsxs("div",{className:"nf-detail-routes__tools",children:[e.jsx(rs,{value:K,onChange:n=>x(n.currentTarget.value),placeholder:"Поиск маршрутов...",leftSection:e.jsx(Pt,{size:16}),"aria-label":"Поиск маршрутов"}),e.jsxs(j,{position:"bottom-end",withinPortal:!0,children:[e.jsx(j.Target,{children:e.jsx(R,{variant:"default",leftSection:e.jsx(xt,{size:16}),children:"Фильтры"})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Label,{children:"Состояние"}),[["all","Все маршруты"],["enabled","Только включённые"],["draft","Только черновики"],["failed",`С ошибкой (${be.failed})`]].map(([n,u])=>e.jsx(j.Item,{className:L===n?"is-selected":"",onClick:()=>F(n),children:u},n))]})]}),e.jsx(we,{variant:"default",size:"lg",onClick:()=>T(n=>!n),"aria-label":"Переключить плотность строк","aria-pressed":b,children:e.jsx(mt,{size:17})})]})]}),g&&e.jsxs("div",{className:"nf-inline-error",role:"alert",children:[e.jsx(ut,{size:16}),e.jsx("span",{children:g})]}),e.jsx("div",{className:"nf-route-table-scroll",tabIndex:0,"aria-label":"Маршруты ноды",children:e.jsxs("div",{className:"nf-detail-route-table",role:"table","aria-rowcount":he.length+1,children:[e.jsx("div",{className:"nf-detail-route-head",role:"row",children:["Статус","Маршрут","Слушает","Правило соответствия","Назначение","Соединения","TCP-сессии","RX / TX","Трафик","Бэкенды","Действия"].map(n=>e.jsx("span",{role:"columnheader",children:n},n))}),X.map(({key:n,routes:u,hasFallback:_,hasSNI:E,lastOnPage:re},Ne)=>e.jsxs("div",{className:"nf-route-listener-group",role:"rowgroup","aria-label":`Listener ${n}`,children:[(pe.length>1||Ne===0)&&e.jsx("div",{className:"nf-route-listener-group__header",role:"presentation","aria-hidden":!0,children:e.jsx("span",{className:"nf-route-listener-group__key",children:n})}),u.map(ie=>{const{report:hs,backend:Ee,servers:le}=Ps(ie,o,l,ds),$=I.get(ie.id);return e.jsx(Yt,{route:ie,report:hs,backend:Ee,servers:le,previousID:$?.previousID,nextID:$?.nextID,pending:i===ie.id,dragging:Te===ie.id,dropTarget:ze===ie.id,ordering:c===ie.id,reorderEnabled:Ie,reorderDisabledReason:Le,onEdit:Fe,onToggle:He,onStats:us,onRequestDelete:oe,onMove:We,onDragStart:ce,onDragEnd:Ke,onDragOver:Ae,onDrop:se},ie.id)}),E&&!_&&re&&e.jsx("div",{className:"nf-route-listener-group__no-fallback",role:"presentation",children:e.jsx("span",{children:"несовпавшие соединения сбрасываются"})})]},n))]})}),ae&&e.jsxs("footer",{className:"nf-table-footer",children:[e.jsxs("span",{children:["Показано ",C+1,"–",Math.min(ee.length,xe)," из ",ee.length," маршрутов"]}),e.jsx(gt,{total:fe,value:W,onChange:Be,size:"sm",withEdges:!0,siblings:1,boundaries:1}),e.jsxs("span",{children:[ns," / стр."]})]}),!he.length&&e.jsx(Fs,{title:t.length?"Ничего не найдено":"Маршрутов пока нет",description:t.length?"Измените поиск или фильтр состояния.":"Создайте listener → target. Новый маршрут сохранится выключенным черновиком.",action:t.length?void 0:e.jsx(R,{leftSection:e.jsx(Us,{size:17}),onClick:()=>p(`/nodes/${s}/routes/new${_e}`),children:"Добавить маршрут"})}),e.jsx($e,{opened:!!w,onClose:()=>!Y&&A(null),title:"Удалить маршрут?",classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs("div",{className:"nf-confirm-dialog",children:[e.jsxs("p",{children:["Маршрут ",e.jsx("strong",{children:w?is(w):""})," будет сначала безопасно исключён из HAProxy, затем удалён после подтверждения Agent."]}),te&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:te}),e.jsxs("div",{children:[e.jsx(R,{variant:"default",onClick:()=>A(null),disabled:Y,children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(cs,{size:16}),onClick:Xe,loading:Y,children:"Удалить"})]})]})}),e.jsx($e,{opened:!!S,onClose:Ue,title:S?`Статистика · ${is(S)}`:"Статистика маршрута",size:"xl",classNames:{content:"nf-dialog nf-route-stats-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:S&&(()=>{const{report:n,backend:u,servers:_}=Ps(S,o,l),E=Ls(u,_);return e.jsxs("div",{className:"nf-route-stats",children:[e.jsxs("div",{className:"nf-route-stats__context",children:[e.jsxs("span",{children:[S.listener_ip||"*",":",S.listener_port]}),e.jsx("span",{children:vs(S)}),e.jsxs("span",{children:["→ ",ys(S)]})]}),e.jsxs("div",{className:"nf-route-stats__rail",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Соединения"}),e.jsx("strong",{children:D(u?.connections_current)}),e.jsxs("small",{children:[D(u?.session_rate)," новых/с"]})]}),e.jsxs("div",{children:[e.jsx("span",{children:"TCP-сессии"}),e.jsx("strong",{children:D(u?.tcp_sessions_current??u?.sessions_current)}),e.jsxs("small",{children:[D(u?.sessions_total)," всего"]})]}),e.jsxs("div",{children:[e.jsx("span",{children:"Трафик за месяц"}),e.jsx("strong",{children:De(n?.used_bytes)}),e.jsxs("small",{children:["RX ",De(n?.bytes_in)," · TX ",De(n?.bytes_out)]})]}),e.jsxs("div",{children:[e.jsx("span",{children:"Backend health"}),e.jsx("strong",{children:E.label==="—"?"Нет данных":E.label}),e.jsx("small",{children:E.detail})]})]}),V&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:V}),e.jsxs("div",{className:`nf-route-stats__chart${J?" is-loading":""}`,"aria-busy":J,children:[e.jsx(qs,{samples:y,range:N,onRangeChange:Qe,emptyTitle:J?"Загружаем историю…":V?"История недоступна":"Нет точек за выбранный период",emptyDescription:J?"Новая выборка заменит предыдущий период.":V?"Повторите запрос или выберите другой период.":"HAProxy не передал точки для этого маршрута и диапазона.",emptyFooterLabel:J?"Запрос выполняется":V?"Запрос завершился ошибкой":"Точек нет",status:J?{tone:"stale",label:"Загрузка"}:V?{tone:"offline",label:"Ошибка загрузки"}:void 0}),J&&e.jsx("div",{className:"nf-route-stats__loading",children:"Загружаем историю…"})]})]})})()})]})}const _s=new URLSearchParams(window.location.search).get("demo")==="1"||!1;function en(s){return s instanceof Error?s.message:"Данные недоступны"}function je(s,t,o,l){return s.status==="fulfilled"?s.value:(l[o]=en(s.reason),t)}function sn(s){return s.fetchQuery({queryKey:Ts,queryFn:()=>O("/api/v1/agent-releases"),staleTime:1/0})}async function tn(s,t,o){if(_s){const{createDemoDetail:p}=await Ms(async()=>{const{createDemoDetail:m}=await import("./demo-node-detail-DkbalCRs.js");return{createDemoDetail:m}},__vite__mapDeps([0,1]));return p(t,o)}const l=await Promise.allSettled([O(`/api/v1/nodes/${t}`),O(`/api/v1/nodes/${t}/operational`),O(`/api/v1/nodes/${t}/routes`),O(`/api/v1/nodes/${t}/traffic`),O(`/api/v1/nodes/${t}/traffic/history?range=${encodeURIComponent(o)}`),O(`/api/v1/nodes/${t}/firewall`),O(`/api/v1/nodes/${t}/agent-update`),sn(s),O(`/api/v1/nodes/${t}/audit?limit=40`)]),i=l[0];if(i.status==="rejected")throw i.reason;const c={},g=je(l[1],null,"operational",c),f=je(l[2],[],"routes",c),P=je(l[3],null,"traffic",c),M=je(l[4],null,"history",c);return{bundle:{node:i.value,operational:g,routes:f,traffic:P,history:M},firewall:je(l[5],null,"firewall",c),update:je(l[6],null,"update",c),releases:je(l[7],[],"releases",c),audit:je(l[8],[],"audit",c),partialErrors:c}}function nn(s,t){const o=Os();return It({queryKey:["node-detail",s,t,_s],queryFn:()=>tn(o,s,t),enabled:!!s,...st,retry:(l,i)=>!("status"in Object(i)&&i.status===401)&&l<2})}function an(){return _s}const rn={online:"Работает",degraded:"Требует внимания",offline:"Недоступна",stopped:"HAProxy выключен"};function ln(s,t){return{enabled:t,expected_version:s.version}}function on(){return e.jsxs("main",{className:"nf-page nf-node-detail-page",children:[e.jsxs("div",{className:"nf-detail-skeleton-head",children:[e.jsx(ge,{height:16,width:180}),e.jsx(ge,{height:34,width:340})]}),e.jsxs("div",{className:"nf-detail-skeleton-top",children:[e.jsx(ge,{height:340}),e.jsx(ge,{height:340})]}),e.jsx(ge,{height:295,mt:12}),e.jsxs("div",{className:"nf-detail-skeleton-bottom",children:[e.jsx(ge,{height:206}),e.jsx(ge,{height:206}),e.jsx(ge,{height:206})]})]})}function wn(){const{nodeId:s=""}=tt(),t=As(),o=Es(),l=Os(),i=an(),c=new URLSearchParams(o.search).get("demo")==="1"?"?demo=1":"",[g,f]=a.useState("24h"),[P,M]=a.useState(""),[p,m]=a.useState(""),[K,x]=a.useState(""),[L,F]=a.useState({}),[w,A]=a.useState(null),[Y,Q]=a.useState(null),[te,H]=a.useState(null),[b,T]=a.useState(!1),[S,U]=a.useState(!1),[N,B]=a.useState(""),[y,v]=a.useState(""),[J,d]=a.useState(!1),[V,ne]=a.useState(""),[Te,ue]=a.useState(!1),[ze,Pe]=a.useState(""),[Z,be]=a.useState(!1),[ve,he]=a.useState(""),[ye,_e]=a.useState([]),[Ie,Le]=a.useState(""),[pe,ee]=a.useState(null),[ds,Re]=a.useState(!1),[Be,fe]=a.useState(!1),[W,ae]=a.useState(!1),C=nn(s,g),xe=a.useRef(null);C.data&&(xe.current={nodeID:s,data:C.data});const X=C.data??(xe.current?.nodeID===s?xe.current.data:void 0),I=X?.bundle,G=a.useMemo(()=>(I?.routes??[]).map(r=>L[r.id]===void 0?r:L[r.id]).filter(r=>r!==null),[I?.routes,L]),Fe=a.useMemo(()=>{if(!ye.length)return G;const r=new Map(ye.map((h,k)=>[h,k]));return[...G].sort((h,k)=>(r.get(h.id)??Number.MAX_SAFE_INTEGER)-(r.get(k.id)??Number.MAX_SAFE_INTEGER))},[ye,G]),He=a.useMemo(()=>yt(I?.history?.samples??[],g),[I?.history?.samples,g]),We=async()=>{F({}),A(null),Q(null),H(null),ee(null),x(""),await l.invalidateQueries({queryKey:Ts,refetchType:"none"}),await C.refetch()},oe=()=>l.invalidateQueries({queryKey:["node-detail",s]});if(a.useEffect(()=>{const r=G.map(h=>h.id);_e(h=>h.length===r.length&&h.every(k=>r.includes(k))?h:r)},[G]),C.isPending&&!X)return e.jsx(on,{});if(C.isError&&nt(C.error))return e.jsx(at,{onSuccess:()=>C.refetch()});if(!X||!I)return e.jsx("main",{className:"nf-page",children:e.jsx(Fs,{title:"Нода не загрузилась",description:C.error instanceof Error?C.error.message:"Нода не найдена",tone:"error",action:e.jsxs(e.Fragment,{children:[e.jsx(R,{variant:"default",onClick:()=>t(`/nodes${c}`),children:"К списку нод"}),e.jsx(ht,{onClick:()=>C.refetch()})]})})});const ce=I.operational?.latest_heartbeat?.metrics,Ae=I.operational?.latest_heartbeat,se=_t({...I}),Ke=Ae?.received_at?Date.parse(Ae.received_at):Number.NaN,us=Number.isFinite(Ke)&&Date.now()-Ke<=45e3,Qe=!!(Ae&&us&&se!=="offline"),Ue=I.operational?.rate_sampled_at,Xe=Ue?Date.parse(Ue):Number.NaN,n=se!=="offline"&&Number.isFinite(Xe)&&Date.now()-Xe<=45e3,u=n&&Number.isFinite(I.operational?.rx_bits_per_second)?Number(I.operational?.rx_bits_per_second):null,_=n&&Number.isFinite(I.operational?.tx_bits_per_second)?Number(I.operational?.tx_bits_per_second):null,E=[...He].reverse().find(r=>r.rx_bps!==null||r.tx_bps!==null),re=E?.timestamp?Date.parse(E.timestamp):Number.NaN,Ne=Math.max(45e3,(I.history?.bucket_seconds??15)*2500),ie=!!(E&&(!Number.isFinite(re)||Date.now()-re>Ne)),hs=C.isError||ie?{tone:"stale",label:"Данные устарели"}:E?se==="offline"?{tone:"offline",label:"Нода недоступна"}:se==="degraded"||!n?{tone:"degraded",label:n?"Нода деградирует":"Нет текущей точки"}:{tone:"online",label:"Онлайн"}:{tone:"offline",label:"Нет свежих данных"},Ee=w??X.firewall,le=Y??X.update,$=te??I.node,Ns=typeof $.metadata?.agent_port=="number"?$.metadata.agent_port:4200,z=pe??I.operational?.haproxy_control,me=z?.desired_enabled!==!1,Ss=!me&&se!=="offline"?"stopped":se,ps=()=>{B($.name),v($.address),ne(""),T(!0)},ks=()=>{T(!1),U(!0)},Bs=()=>{Pe(""),he(""),ue(!0)},Ws=async()=>{if(ze===$.name){be(!0),he("");try{i||(await O(`/api/v1/nodes/${s}`,{method:"DELETE"}),await l.invalidateQueries({queryKey:["overview"]})),ue(!1),t(`/nodes${c}`,{replace:!0})}catch(r){he(r instanceof Error?r.message:"Нода не удалена")}finally{be(!1)}}},Ks=async()=>{const r=N.trim(),h=y.trim();if(!r||!h){ne("Укажите название и IP-адрес ноды.");return}d(!0),ne("");try{const k=i?{...$,name:r,address:h,updated_at:new Date().toISOString()}:await O(`/api/v1/nodes/${s}`,{method:"PUT",body:JSON.stringify({name:r,address:h,metadata:$.metadata??{}})});H(k),i||await oe(),T(!1)}catch(k){ne(k instanceof Error?k.message:"Параметры ноды не сохранены")}finally{d(!1)}},Qs=async(r,h)=>{M(r.id),x("");try{if(i){const k={...r,enabled:h,deployed:h,deployment_state:h?"active":"disabled",version:r.version+1,updated_at:new Date().toISOString()},{upsertDemoRoute:q}=await Ms(async()=>{const{upsertDemoRoute:Se}=await import("./demo-42aef_vS.js");return{upsertDemoRoute:Se}},[]);q(s,k),F(Se=>({...Se,[r.id]:k}))}else{const k=await O(`/api/v1/nodes/${s}/routes/${r.id}`,{method:"PATCH",body:JSON.stringify(ln(r,h))});F(q=>({...q,[r.id]:k})),await oe(),F(q=>{const{[r.id]:Se,...Ge}=q;return Ge})}}catch(k){x(k instanceof Error?k.message:"Маршрут не изменён")}finally{M("")}},Xs=async r=>{M(r.id),x("");try{i?F(h=>({...h,[r.id]:null})):(await O(`/api/v1/nodes/${s}/routes/${r.id}?expected_version=${r.version}`,{method:"DELETE"}),await oe())}catch(h){throw x(h instanceof Error?h.message:"Маршрут не удалён"),h}finally{M("")}},Gs=async(r,h)=>{if(r===h||Ie)return;const k=Fe.map(Je=>Je.id),q=[...k],Se=q.indexOf(r),Ge=q.indexOf(h);if(!(Se<0||Ge<0)){q.splice(Ge,0,q.splice(Se,1)[0]),_e(q),Le(r),x("");try{i||(await O(`/api/v1/nodes/${s}/routes/order`,{method:"PUT",body:JSON.stringify({route_ids:q})}),await oe())}catch(Je){_e(k),x(Je instanceof Error?Je.message:"Порядок маршрутов не сохранён"),i||oe()}finally{Le("")}}},ws=async r=>{if(!(!z||W)){ae(!0),x("");try{const h=i?{...z,supported:!0,desired_enabled:r,generation:z.generation+1,actual_enabled:r,active_state:r?"active":"inactive",report_generation:z.generation+1,updated_at:new Date().toISOString(),reported_at:new Date().toISOString()}:await O(`/api/v1/nodes/${s}/haproxy`,{method:"PUT",body:JSON.stringify({enabled:r,expected_generation:z.generation})});ee(h),Re(!1),i||(await oe(),ee(null))}catch(h){x(h instanceof Error?h.message:`HAProxy не ${r?"включён":"выключен"}`)}finally{ae(!1)}}},Js=async()=>{if(!(!z||W||!me)){ae(!0),x("");try{const r=i?{...z,supported:!0,desired_enabled:!0,restart_generation:z.restart_generation+1,actual_enabled:!0,active_state:"reloading",report_generation:z.generation,updated_at:new Date().toISOString()}:await O(`/api/v1/nodes/${s}/haproxy/restart`,{method:"POST",body:JSON.stringify({expected_generation:z.restart_generation})});ee(r),fe(!1),i||(await oe(),ee(null))}catch(r){x(r instanceof Error?r.message:"HAProxy не перезагружен")}finally{ae(!1)}}},Vs=async r=>{if(Ee){m("firewall"),x("");try{if(i)A({...Ee,mode:r,updated_at:new Date().toISOString()});else{const h=await O(`/api/v1/nodes/${s}/firewall`,{method:"PUT",body:JSON.stringify({mode:r})});A(h)}}catch(h){x(h instanceof Error?h.message:"Режим UFW не изменён")}finally{m("")}}},Ys=async r=>{if(!le){x("Состояние Node Agent недоступно. Обновите данные и повторите.");return}m("update"),x("");try{if(i&&le)Q({...le,desired_release:r,state:"assigned",updated_at:new Date().toISOString()});else{const h=await O(`/api/v1/nodes/${s}/agent-update`,{method:"PUT",body:JSON.stringify({release_id:r.id,expected_actual_sequence:le.actual_sequence,expected_desired_sequence:le.desired_release?.sequence??0})});Q(h)}}catch(h){x(h instanceof Error?h.message:"Релиз не назначен")}finally{m("")}},Zs=async(r,h,k)=>{m("rollback"),x("");try{if(i&&le)Q({...le,desired_release:r,state:"assigned",updated_at:new Date().toISOString()});else{const q=await O(`/api/v1/nodes/${s}/agent-update/rollback`,{method:"POST",body:JSON.stringify({target_release_id:r.id,expected_actual_sequence:h,expected_desired_sequence:k})});Q(q)}}catch(q){throw x(q instanceof Error?q.message:"Откат не назначен"),q}finally{m("")}};return e.jsxs("main",{className:"nf-page nf-node-detail-page",children:[e.jsx(lt,{className:"nf-detail-header",breadcrumb:e.jsxs(e.Fragment,{children:[e.jsx(Cs,{to:`/nodes${c}`,children:"Ноды"}),e.jsx("span",{children:"/"}),e.jsx("span",{"aria-current":"page",children:$.name})]}),title:$.name,meta:e.jsxs(e.Fragment,{children:[e.jsx("code",{children:$.address}),e.jsxs("span",{className:`nf-detail-status is-${Ss}`,children:[e.jsx("i",{}),rn[Ss]]}),e.jsxs("span",{className:"nf-detail-heartbeat",children:["Последний сигнал: ",os($.last_seen_at)]})]}),actions:e.jsxs(e.Fragment,{children:[e.jsx(R,{component:Cs,to:`/nodes/${s}/routes/new${c}`,className:"nf-primary-action",leftSection:e.jsx(Us,{size:18}),children:"Добавить маршрут"}),e.jsx(we,{variant:"default",size:"lg",onClick:ps,"aria-label":"Настройки ноды",children:e.jsx(Rs,{size:18})}),e.jsxs(j,{position:"bottom-end",withinPortal:!0,children:[e.jsx(j.Target,{children:e.jsx(we,{variant:"default",size:"lg","aria-label":"Действия ноды",children:e.jsx(Et,{size:19})})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Item,{leftSection:e.jsx(ms,{size:16}),onClick:We,children:"Обновить данные"}),e.jsx(j.Item,{leftSection:e.jsx(bs,{size:16}),onClick:ps,children:"Редактировать ноду"}),e.jsx(j.Item,{leftSection:e.jsx($s,{size:16}),onClick:ks,children:"Переустановить Node Agent"}),e.jsx(j.Divider,{}),e.jsx(j.Item,{color:"red",leftSection:e.jsx(ms,{size:16}),disabled:!z?.supported||!me||W,onClick:()=>fe(!0),children:"Жёстко перезагрузить HAProxy"}),e.jsx(j.Item,{color:me?"red":"nodeflow",leftSection:e.jsx(es,{size:16}),disabled:!z?.supported||W,onClick:()=>{me?Re(!0):ws(!0)},children:me?"Выключить HAProxy":"Включить HAProxy"}),e.jsx(j.Item,{color:"red",leftSection:e.jsx(cs,{size:16}),onClick:Bs,children:"Удалить ноду"})]})]})]})}),se!=="online"&&me&&e.jsxs("div",{className:`nf-detail-state-banner is-${se}`,role:"status",children:[e.jsx("strong",{children:se==="offline"?"Нода не отвечает.":"Нода работает с ограничениями."}),e.jsx("span",{children:se==="offline"?"Показаны последние сохранённые значения; управляющие действия могут ждать восстановления связи.":"Проверьте HAProxy runtime, backend health и состояние применения маршрутов."})]}),!me&&e.jsxs("div",{className:"nf-detail-state-banner is-haproxy-off",role:"status",children:[e.jsx("strong",{children:"HAProxy выключен."}),e.jsx("span",{children:"Node Agent остаётся на связи, но listener-порты и все маршруты остановлены."})]}),z&&!z.supported&&e.jsxs("div",{className:"nf-detail-state-banner",role:"status",children:[e.jsx("strong",{children:"Управление HAProxy недоступно."}),e.jsx("span",{children:"Обновите Node Agent до версии с поддержкой включения и выключения сервиса."})]}),K&&e.jsxs("div",{className:"nf-inline-error nf-detail-action-error",role:"alert",children:[K,e.jsx("button",{type:"button",onClick:()=>x(""),children:"Закрыть"})]}),X.partialErrors.operational&&e.jsxs("div",{className:"nf-inline-error nf-detail-action-error",role:"alert",children:["Системная статистика временно недоступна: ",X.partialErrors.operational]}),e.jsxs("div",{className:"nf-detail-top-grid",children:[e.jsx(as,{className:"nf-detail-chart",title:"Трафик ноды",description:X.partialErrors.history?`История недоступна: ${X.partialErrors.history}`:C.isError?`Новый диапазон не загружен: ${C.error instanceof Error?C.error.message:"данные недоступны"}`:!C.data&&C.isFetching?"Обновляем диапазон без перезагрузки страницы…":void 0,children:e.jsx(qs,{samples:He,range:g,onRangeChange:f,currentRx:u,currentTx:_,status:hs})}),e.jsx(qt,{metrics:ce,history:He,summary:I.operational?.metrics_summary,currentRx:u,currentTx:_,rateSampledAt:Ue,live:se!=="offline",mtlsConnected:Qe})]}),e.jsx(Zt,{nodeID:s,routes:Fe,traffic:I.traffic,metrics:ce,busyRouteID:P,orderingRouteID:Ie,error:X.partialErrors.routes||X.partialErrors.traffic,onToggle:Qs,onDelete:Xs,onReorder:Gs}),e.jsx(Wt,{metrics:ce,agentVersion:Ae?.agent_version,agentPort:Ns,mtlsReady:Qe,credentialLastUsed:I.operational?.credential_last_used_at,routes:Fe,firewall:Ee,update:le,releases:X.releases,audit:X.audit,partialErrors:X.partialErrors,busyAction:p,onFirewallMode:Vs,onAssignRelease:Ys,onRollback:Zs,onOpenNodeSettings:ps}),e.jsx($e,{opened:ds,onClose:()=>!W&&Re(!1),title:"Выключить HAProxy?",size:"sm",closeOnClickOutside:!W,closeOnEscape:!W,classNames:{content:"nf-dialog nf-haproxy-control-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"md",children:[e.jsxs("div",{className:"nf-haproxy-control-warning",children:[e.jsx(es,{size:20}),e.jsxs("div",{children:[e.jsx("strong",{children:"Все маршруты этой ноды остановятся."}),e.jsx("span",{children:"Node Agent останется на связи. HAProxy можно будет снова включить из этого же меню."})]})]}),z?.last_error&&e.jsxs("div",{className:"nf-inline-error",role:"alert",children:["Последняя ошибка: ",z.last_error]}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:W,onClick:()=>Re(!1),children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(es,{size:16}),loading:W,onClick:()=>{ws(!1)},children:"Выключить HAProxy"})]})]})}),e.jsx($e,{opened:Be,onClose:()=>!W&&fe(!1),title:"Жёстко перезагрузить HAProxy?",size:"sm",closeOnClickOutside:!W,closeOnEscape:!W,classNames:{content:"nf-dialog nf-haproxy-control-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"md",children:[e.jsxs("div",{className:"nf-haproxy-control-warning",children:[e.jsx(es,{size:20}),e.jsxs("div",{children:[e.jsx("strong",{children:"Все активные соединения будут немедленно оборваны."}),e.jsx("span",{children:"Это именно systemd restart, а не безопасный reload. Клиентам потребуется переподключиться."})]})]}),z?.last_error&&e.jsxs("div",{className:"nf-inline-error",role:"alert",children:["Последняя ошибка: ",z.last_error]}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:W,onClick:()=>fe(!1),children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(ms,{size:16}),loading:W,onClick:()=>{Js()},children:"Жёстко перезагрузить"})]})]})}),e.jsx($e,{opened:b,onClose:()=>!J&&T(!1),title:"Настройки ноды",size:"lg",closeOnClickOutside:!J,closeOnEscape:!J,classNames:{content:"nf-dialog nf-node-settings-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"lg",children:[e.jsxs(Oe,{gap:"sm",children:[e.jsx(rs,{label:"Название ноды",value:N,onChange:r=>B(r.currentTarget.value),autoFocus:!0,required:!0}),e.jsx(rs,{label:"IP-адрес ноды",value:y,onChange:r=>v(r.currentTarget.value),required:!0})]}),V&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:V}),e.jsx(rt,{color:"gray",icon:e.jsx(Hs,{size:18}),title:"Переустановка Node Agent",children:e.jsxs(Oe,{gap:8,children:[e.jsx(fs,{size:"sm",children:"NodeFlow повторно проверит отпечаток SSH-ключа хоста, установит Agent и дождётся нового mTLS-сигнала. ID ноды и маршруты не меняются; при ошибке прежние учётные данные будут автоматически восстановлены."}),e.jsx(R,{variant:"default",size:"xs",leftSection:e.jsx($s,{size:15}),onClick:ks,children:"Переустановить Agent"})]})}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:J,onClick:()=>T(!1),children:"Отмена"}),e.jsx(R,{leftSection:e.jsx(bs,{size:16}),loading:J,onClick:Ks,children:"Сохранить"})]})]})}),e.jsx(Nt,{opened:S,onClose:()=>U(!1),onInstalled:()=>{We()},demo:i,reinstallTarget:{id:$.id,name:$.name,address:$.address,sshPort:typeof $.metadata?.ssh_port=="number"?$.metadata.ssh_port:22,agentPort:Ns,allowFirewallApply:Ee?.mode==="apply",os:typeof ce?.os=="string"?ce.os:void 0,arch:typeof ce?.arch=="string"?ce.arch:void 0}}),e.jsx($e,{opened:Te,onClose:()=>!Z&&ue(!1),title:"Удалить ноду?",closeOnClickOutside:!Z,closeOnEscape:!Z,classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"md",children:[e.jsxs(fs,{size:"sm",c:"dimmed",children:["Запись ",e.jsx(fs,{component:"span",inherit:!0,fw:600,c:"var(--nf-text)",children:$.name})," и связанные данные будут удалены из Panel. Node Agent и HAProxy на сервере останутся установленными."]}),e.jsx(rs,{label:e.jsxs(e.Fragment,{children:["Для подтверждения введите ",e.jsx("strong",{children:$.name})]}),value:ze,onChange:r=>Pe(r.currentTarget.value),disabled:Z,autoComplete:"off",autoFocus:!0}),ve&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:ve}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:Z,onClick:()=>ue(!1),children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(cs,{size:16}),loading:Z,disabled:ze!==$.name,onClick:Ws,children:"Удалить ноду"})]})]})})]})}export{wn as NodeDetailPage}; +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/demo-node-detail-DYja70C8.js","assets/demo-k0hjezoN.js"])))=>i.map(i=>d[i]); +import{c as qe,j as e,r as a,B as R,I as Rs,a as As,u as Es,g as O,A as we,h as et,k as Os,l as st,_ as Ms,m as Ts,n as tt,i as nt,e as at,L as Cs,S as Oe,f as rt,T as fs}from"./index-fgrXogF6.js";import{a as zs,T as Ce,M as j,I as js,b as $e,c as it,P as lt}from"./PageHeader-Fvu-o_Iq.js";import{b as D,a as De,f as Me,t as os,e as ot,c as as,s as ct,g as dt,T as rs,I as ut,S as Fs,R as ht}from"./format-DGDz36zr.js";import{m as pt,r as is,S as ft,e as xt,c as mt,P as gt,I as jt,a as bt,b as vt,f as yt,g as _t,A as Nt}from"./model-Dv87zZ-k.js";import{I as St,a as kt,S as wt}from"./IconArrowUp-DwKi77Ll.js";import{I as Hs,a as Us,S as Ct}from"./IconPlus-D0GthIF3.js";import{h as $t,r as Ve,p as xs,I as ls,a as Ye}from"./platform-DnnQQ6bP.js";import{I as Dt,a as Pt,T as qs,u as It,S as ge}from"./TrafficChart-84ShhOyf.js";import{i as Rt}from"./haproxy-BnB0NJ0D.js";import{i as At}from"./interaction-BrakVCuN.js";import{I as cs}from"./IconTrash-Bdw5EaPs.js";import{I as Et}from"./IconDots-BNcckjtc.js";import{I as ms}from"./IconServer-DmZ16e5j.js";import{G as Ze}from"./IconKey-DrhZ0AMo.js";import"./chart-react-C4b8adjg.js";import"./chart-engine-Dbh3Q7E_.js";import"./chart-renderer-CWmX7Ukt.js";const Ot=[["path",{d:"M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1",key:"svg-0"}],["path",{d:"M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415",key:"svg-1"}],["path",{d:"M16 5l3 3",key:"svg-2"}]],bs=qe("outline","edit","Edit",Ot);const Mt=[["path",{d:"M9 3v18",key:"svg-0"}],["path",{d:"M3 9h18",key:"svg-1"}],["path",{d:"M3 15h10",key:"svg-2"}],["path",{d:"M15 3v10",key:"svg-3"}],["path",{d:"M11 21h-6a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v8",key:"svg-4"}],["path",{d:"M15 19l2 2l4 -4",key:"svg-5"}]],Tt=qe("outline","firewall-check","FirewallCheck",Mt);const zt=[["path",{d:"M7 6a7.75 7.75 0 1 0 10 0",key:"svg-0"}],["path",{d:"M12 4l0 8",key:"svg-1"}]],es=qe("outline","power","Power",zt);const Ft=[["path",{d:"M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-2",key:"svg-0"}],["path",{d:"M12 20h-6a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h10.5",key:"svg-1"}],["path",{d:"M16 18a2 2 0 1 0 4 0a2 2 0 1 0 -4 0",key:"svg-2"}],["path",{d:"M18 14.5v1.5",key:"svg-3"}],["path",{d:"M18 20v1.5",key:"svg-4"}],["path",{d:"M21.032 16.25l-1.299 .75",key:"svg-5"}],["path",{d:"M16.27 19l-1.3 .75",key:"svg-6"}],["path",{d:"M14.97 16.25l1.3 .75",key:"svg-7"}],["path",{d:"M19.733 19l1.3 .75",key:"svg-8"}],["path",{d:"M7 8v.01",key:"svg-9"}],["path",{d:"M7 16v.01",key:"svg-10"}]],$s=qe("outline","server-cog","ServerCog",Ft);const Ht=[["path",{d:"M16 18a2 2 0 0 1 2 2a2 2 0 0 1 2 -2a2 2 0 0 1 -2 -2a2 2 0 0 1 -2 2m0 -12a2 2 0 0 1 2 2a2 2 0 0 1 2 -2a2 2 0 0 1 -2 -2a2 2 0 0 1 -2 2m-7 12a6 6 0 0 1 6 -6a6 6 0 0 1 -6 -6a6 6 0 0 1 -6 6a6 6 0 0 1 6 6",key:"svg-0"}]],Ut=qe("outline","sparkles","Sparkles",Ht);function ke({values:s}){const t=s.filter(Number.isFinite).slice(-28);if(t.length<2)return e.jsx("span",{className:"nf-mini-sparkline is-empty","aria-hidden":"true"});const o=Math.min(...t),l=Math.max(...t),i=Math.max(1,l-o),c=t.map((g,f)=>`${f/(t.length-1)*100},${20-(g-o)/i*16}`).join(" ");return e.jsx("svg",{className:"nf-mini-sparkline",viewBox:"0 0 100 22",preserveAspectRatio:"none","aria-hidden":"true",children:e.jsx("polyline",{points:c})})}function ss(s,t,o,l,i=c=>D(c,1)){if(!l||t==null)return`${s}: история ещё собирается`;const c=o==null?"дельта недоступна":`дельта ${o>=0?"+":""}${i(o)}`;return`${s}: среднее ${i(t)}, ${c}, точек ${l}`}function ts(s){const t=s.filter(Number.isFinite);if(t.length)return{average:t.reduce((o,l)=>o+l,0)/t.length,delta:t.at(-1)-t[0],sample_count:t.length}}function de({children:s,hint:t}){return e.jsxs("span",{className:"nf-detail-kpi__label",children:[s,t&&e.jsx(Ce,{label:t,multiline:!0,w:260,openDelay:250,children:e.jsx(Hs,{size:14,tabIndex:0,"aria-label":t})})]})}function qt({metrics:s,history:t,summary:o,currentRx:l,currentTx:i,rateSampledAt:c,live:g,mtlsConnected:f}){const P=pt(s),M=(s?.load??[]).slice(0,3),p=s?.haproxy_runtime,m=Object.values(p?.backends??{}),K=p?m.reduce((y,v)=>y+(Number(v.sessions_current)||0),0):void 0,x=p?m.reduce((y,v)=>y+(Number(v.sessions_total)||0),0):void 0,L=g&&Number.isFinite(p?.connections_current)?Number(p?.connections_current):void 0,F=Number.isFinite(p?.connections_total)?Number(p?.connections_total):void 0,w=g&&Number.isFinite(p?.connection_rate)?Number(p?.connection_rate):void 0,A=t.flatMap(y=>y.rx_bps===null?[]:[y.rx_bps]),Y=t.flatMap(y=>y.tx_bps===null?[]:[y.tx_bps]),Q=t.map(y=>Number(y.cpu_percent)).filter(Number.isFinite),te=t.map(y=>Number(y.memory_percent)).filter(Number.isFinite),H=ts(Q)??o?.cpu_percent,b=ts(te)??o?.memory_percent,T=ts(A)??o?.rx_bps,S=ts(Y)??o?.tx_bps,U=Number(s?.process_count),N=(s?.process_names??[]).filter(Boolean),B=Number.isFinite(U)&&U>=0?`Процессов: ${D(U)}${N.length?`. Основные: ${N.join(", ")}`:""}`:N.length?`Основные процессы: ${N.join(", ")}`:"Список процессов ещё не получен";return e.jsxs("section",{className:"nf-surface nf-detail-kpis","aria-label":"Система, сеть и соединения",children:[e.jsxs("div",{className:"nf-detail-kpi",children:[e.jsx(de,{hint:ss("CPU",H?.average,H?.delta,H?.sample_count,y=>`${D(y,1)}%`),children:"CPU"}),e.jsx("strong",{children:Number.isFinite(Number(s?.cpu_percent))?`${D(Number(s?.cpu_percent),1)}%`:"—"}),e.jsx(ke,{values:Q})]}),e.jsxs("div",{className:"nf-detail-kpi is-memory",children:[e.jsx(de,{hint:ss("RAM",b?.average,b?.delta,b?.sample_count,y=>`${D(y,1)}%`),children:"RAM"}),e.jsxs("strong",{children:[De(P.used)," ",e.jsxs("small",{children:["/ ",De(P.total)]})]}),e.jsx("span",{className:"nf-detail-kpi__sub",children:P.percent==null?"Нет данных":`${D(P.percent,1)}% занято`}),e.jsx(ke,{values:te})]}),e.jsxs("div",{className:"nf-detail-kpi is-load",children:[e.jsx(de,{hint:"Нормализованные значения Linux load average за 1, 5 и 15 минут",children:"Load (1м / 5м / 15м)"}),e.jsx("strong",{children:M.length?M.map(y=>D(y,2)).join(" / "):"—"}),e.jsx("span",{className:"nf-detail-kpi__sub",children:"текущий срез"}),e.jsx(ke,{values:[]})]}),e.jsxs("div",{className:"nf-detail-kpi is-network",children:[e.jsxs(de,{hint:ss("RX",T?.average,T?.delta,T?.sample_count,Me),children:[e.jsx(St,{size:17})," RX"]}),e.jsx("strong",{children:Me(l)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:l===null?c?`последняя точка ${os(c)}`:"нет свежей точки":"HAProxy сейчас"}),e.jsx(ke,{values:A})]}),e.jsxs("div",{className:"nf-detail-kpi is-network",children:[e.jsxs(de,{hint:ss("TX",S?.average,S?.delta,S?.sample_count,Me),children:[e.jsx(kt,{size:17})," TX"]}),e.jsx("strong",{children:Me(i)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:i===null?c?`последняя точка ${os(c)}`:"нет свежей точки":"HAProxy сейчас"}),e.jsx(ke,{values:Y})]}),e.jsxs("div",{className:"nf-detail-kpi",children:[e.jsx(de,{hint:p?`${w==null?"Rate не получен":`${D(w)} новых/с`} · ${F==null?"total не получен":`${D(F)} всего`}`:"HAProxy runtime ещё не получен",children:"Соединения"}),e.jsx("strong",{children:D(L)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:w==null&&F==null?"Rate и total не получены":`${w==null?"— новых/с":`${D(w)} новых/с`} · ${F==null?"— всего":`${D(F)} всего`}`}),e.jsx(ke,{values:[]})]}),e.jsxs("div",{className:"nf-detail-kpi",children:[e.jsx(de,{hint:p?`${D(x)} TCP-сессий всего`:"HAProxy runtime ещё не получен",children:"TCP-сессии"}),e.jsx("strong",{children:D(K)}),e.jsx("span",{className:"nf-detail-kpi__sub",children:x==null?"Total не получен":`${D(x)} всего`}),e.jsx(ke,{values:[]})]}),e.jsxs("div",{className:"nf-detail-kpi is-uptime",children:[e.jsx(de,{hint:B,children:"Время работы"}),e.jsx("strong",{children:ot(Number(s?.uptime_seconds))}),e.jsx("span",{className:"nf-detail-kpi__sub",children:Number.isFinite(U)?`${D(U)} процессов`:"без перезапуска Agent"})]}),e.jsxs("div",{className:`nf-detail-kpi nf-detail-kpi--mtls${f?" is-ready":""}`,children:[e.jsx(de,{children:"mTLS соединение"}),e.jsxs("strong",{children:[e.jsx(zs,{size:21})," ",f?"На связи":"Нет свежего сигнала"]}),e.jsx("span",{className:"nf-detail-kpi__sub",children:"последний heartbeat по защищённому каналу"})]})]})}function Ds(s){const t=s.details&&typeof s.details.summary=="string"?s.details.summary:"";return t||({"route.created":"Создан маршрут","route.updated":"Изменён маршрут","route.enabled":"Маршрут включён","route.disabled":"Маршрут выключен","route.deleted":"Удалён маршрут","route.change":"Изменён маршрут","agent.update.assigned":"Назначено обновление Node Agent","agent.update.assign":"Назначено обновление Node Agent","agent.update.rollback":"Назначен откат Node Agent","firewall.policy.updated":"Изменена политика UFW","firewall.policy":"Изменена политика UFW","node.update":"Изменены параметры ноды"}[s.action]??s.action.replaceAll("."," · "))}function Lt({action:s}){return s.startsWith("route")?e.jsx(Dt,{size:16}):s.startsWith("firewall")?e.jsx(Tt,{size:16}):s.includes("update")?e.jsx(ls,{size:16}):e.jsx(it,{size:16})}function Bt(s){return{installed:"Установлено",idle:"Готов",assigned:"Назначено",downloading:"Загрузка",verifying:"Проверка",activating:"Установка",failed:"Ошибка",rolled_back:"Автооткат"}[s??""]??s??"Нет данных"}function gs(s){return`${s.version} · sequence #${s.sequence}`}function Wt({metrics:s,agentVersion:t,agentPort:o,mtlsReady:l,credentialLastUsed:i,routes:c,firewall:g,update:f,releases:P,audit:M,partialErrors:p,busyAction:m,onFirewallMode:K,onAssignRelease:x,onRollback:L,onOpenNodeSettings:F}){const[w,A]=a.useState(null),[Y,Q]=a.useState(!1),[te,H]=a.useState(""),b=$t(s),T=a.useMemo(()=>P.filter(d=>Ve(d,b)).sort((d,V)=>V.sequence-d.sequence),[P,b?.os,b?.arch]),S=f?.actual_sequence??0,U=T.filter(d=>d.sequence>S),N=T.filter(d=>d.sequenced.enabled).map(d=>d.listener_port))].sort((d,V)=>d-V),v=String(s?.haproxy_version??""),J=async()=>{if(!(!w||!f)){if(!b||!Ve(w,b)){H("Платформа ноды неизвестна или изменилась. Обновите состояние перед откатом.");return}Q(!0),H("");try{await L(w,f.actual_sequence,f.desired_release?.sequence??0),A(null)}catch(d){H(d instanceof Error?d.message:"Откат не назначен")}finally{Q(!1)}}};return e.jsxs("div",{className:"nf-detail-bottom-grid",children:[e.jsxs(as,{id:"operations",className:"nf-detail-operations",title:"Обновление и firewall",children:[e.jsxs("div",{className:"nf-operation-row",children:[e.jsxs("div",{className:"nf-operation-label",children:[e.jsx("span",{children:"Node Agent"}),e.jsx("strong",{children:t||"—"})]}),e.jsxs("div",{className:"nf-operation-state",children:[e.jsx("span",{className:`nf-state-chip is-${f?.state??"unknown"}`,children:Bt(f?.state)}),e.jsx("small",{children:b?B?`${xs(b)} · доступна ${B.version}`:`${xs(b)} · обновлений нет`:"платформа не получена"})]}),e.jsxs("div",{className:"nf-operation-actions",children:[U.length>1?e.jsxs(j,{position:"bottom-end",withinPortal:!0,shadow:"md",children:[e.jsx(j.Target,{children:e.jsx(R,{variant:"default",size:"xs",leftSection:e.jsx(ls,{size:15}),rightSection:e.jsx(js,{size:14}),disabled:!f||!b||m==="update",loading:m==="update",children:"Обновить"})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Label,{children:"Выберите версию"}),U.map(d=>e.jsx(j.Item,{leftSection:e.jsx(ls,{size:15}),onClick:()=>x(d),children:gs(d)},d.id))]})]}):e.jsx(R,{variant:"default",size:"xs",leftSection:e.jsx(ls,{size:15}),disabled:!f||!b||!B,loading:m==="update",onClick:()=>f&&B&&b&&Ve(B,b)&&x(B),children:"Обновить"}),N.length>1?e.jsxs(j,{position:"bottom-end",withinPortal:!0,shadow:"md",children:[e.jsx(j.Target,{children:e.jsx(R,{variant:"subtle",color:"gray",size:"xs",leftSection:e.jsx(Ye,{size:15}),rightSection:e.jsx(js,{size:14}),disabled:!b||m==="rollback",children:"Откатить"})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Label,{children:"Выберите версию"}),N.map(d=>e.jsx(j.Item,{leftSection:e.jsx(Ye,{size:15}),onClick:()=>{H(""),A(d)},children:gs(d)},d.id))]})]}):e.jsx(R,{variant:"subtle",color:"gray",size:"xs",leftSection:e.jsx(Ye,{size:15}),disabled:!b||N.length===0||m==="rollback",onClick:()=>{H("");const d=N[0];d&&b&&Ve(d,b)&&A(d)},children:"Откатить"})]})]}),!b&&e.jsx("p",{className:"nf-operation-error",role:"status",children:"Назначение релиза заблокировано: Agent ещё не передал os и arch."}),(p.update||p.releases||f?.last_error)&&e.jsx("p",{className:"nf-operation-error",role:"alert",children:f?.last_error||p.update||p.releases}),e.jsxs("div",{className:"nf-operation-row nf-operation-row--firewall",children:[e.jsxs("div",{className:"nf-operation-label",children:[e.jsx("span",{children:"Политика UFW"}),e.jsx("strong",{children:g?.mode==="apply"?"Автооткрытие разрешено":g?.mode==="observe"?"Только проверка":g?.mode==="off"?"Не управляется":"—"})]}),e.jsxs("div",{className:"nf-listener-ports",children:[e.jsx("span",{children:"Порты по плану"}),e.jsx("strong",{children:y.length?y.join(", "):"нет активных"})]}),e.jsx(wt,{size:"xs",value:g?.mode??"off",onChange:d=>K(d),data:[{label:"Выкл.",value:"off"},{label:"Проверка",value:"observe"},{label:"Авто",value:"apply"}],disabled:!g||m==="firewall","aria-label":"Политика управления UFW"})]}),p.firewall&&e.jsxs("p",{className:"nf-operation-error",role:"alert",children:["UFW: ",p.firewall]}),e.jsxs("button",{className:"nf-operation-disclosure",type:"button",onClick:F,children:["Дополнительные настройки ноды ",e.jsx(Rs,{size:15})]})]}),e.jsx(as,{className:"nf-detail-audit",title:"Последние действия",children:p.audit?e.jsx("div",{className:"nf-detail-panel-state",role:"alert",children:p.audit}):M.length?e.jsx("div",{className:"nf-audit-scroll",role:"list","aria-label":"Последние действия, прокручиваемый список",children:[...M].sort((d,V)=>Date.parse(V.created_at)-Date.parse(d.created_at)).map(d=>e.jsxs("div",{className:"nf-audit-row",role:"listitem",children:[e.jsx("i",{children:e.jsx(Lt,{action:d.action})}),e.jsx("strong",{title:Ds(d),children:Ds(d)}),e.jsx("time",{dateTime:d.created_at,children:new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit"}).format(new Date(d.created_at))}),e.jsx("span",{children:d.actor_type==="agent"?"Agent":"Оператор"}),e.jsx("em",{children:"Успешно"})]},d.id))}):e.jsx("div",{className:"nf-detail-panel-state",children:"Действий пока нет."})}),e.jsx(as,{className:"nf-detail-versions",title:"Версии и соединение",children:e.jsxs("dl",{children:[e.jsxs("div",{children:[e.jsx("dt",{children:"HAProxy"}),e.jsx(Ce,{label:v||"Полная версия не получена",openDelay:250,children:e.jsx("dd",{tabIndex:0,children:ct(v)})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Node Agent"}),e.jsx("dd",{children:t||"—"})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"mTLS соединение"}),e.jsxs("dd",{className:l?"is-ready":"",children:[e.jsx(zs,{size:17})," ",l?"На связи":"Нет свежего сигнала"]})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Связь с Panel"}),e.jsxs("dd",{children:["Исходящий mTLS · :",o]})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Последняя авторизация"}),e.jsx(Ce,{label:dt(i),openDelay:250,children:e.jsx("dd",{tabIndex:0,children:i?os(i):"—"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Политика обновления"}),e.jsxs("dd",{children:[e.jsx(Ut,{size:16})," Ed25519 · автооткат"]})]})]})}),e.jsx($e,{opened:!!w,onClose:()=>!Y&&A(null),title:"Откатить Node Agent?",classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs("div",{className:"nf-confirm-dialog",children:[e.jsxs("p",{children:["Будет назначен подписанный релиз ",e.jsx("strong",{children:w?gs(w):"—"})," для ",e.jsx("strong",{children:xs(b)}),". Updater проверит Ed25519, SHA-256 и вернёт текущий бинарник при ошибке запуска."]}),te&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:te}),e.jsxs("div",{children:[e.jsx(R,{variant:"default",disabled:Y,onClick:()=>A(null),children:"Отмена"}),e.jsx(R,{leftSection:e.jsx(Ye,{size:16}),loading:Y,onClick:J,children:"Откатить"})]})]})})]})}const Kt={active:"Активен",pending:"Применяется",failed:"Ошибка",draft:"Черновик",disabled:"Выключен",deleting:"Удаляется"};function vs(s){return s.match_mode==="sni"||!s.fallback&&s.snis.length?`SNI ${s.snis.join(", ")}`:s.fallback||s.match_mode==="any_tcp"||s.match_mode==="destination_ip"?"Фолбэк":s.snis.length?`SNI ${s.snis.join(", ")}`:"Фолбэк"}function ys(s){if(s.target_type==="unix")return s.unix_socket_path||"Unix socket";const t=`${s.target_host||"—"}:${s.target_port||"—"}`;return s.dns_pool?`DNS-пул · ${t}`:t}function Ps(s,t,o,l){const i=l?l.get(s.id):t?.routes.find(f=>f.route_id===s.id),c=i?o?.haproxy_runtime?.backends?.[i.backend_key]:void 0,g=i?o?.haproxy_runtime?.servers?.[i.backend_key]:void 0;return{report:i,backend:c,servers:g}}function Ls(s,t){const o=Object.values(t??{}).filter(Rt),l=o.filter(P=>["UP","OPEN","READY"].includes(String(P.status??"").trim().toUpperCase())).length,i=String(s?.status??"").trim(),c=i.toUpperCase();if(o.length)return{tone:l===o.length?"online":l===0?"offline":"degraded",label:`${l}/${o.length}`,detail:i||"Backend status: UNKNOWN",tooltip:`HAProxy backend: ${i||"UNKNOWN"} · серверов ${l}/${o.length}`};if(!s)return{tone:"degraded",label:"—",detail:"Backend ещё не наблюдался",tooltip:"Backend ещё не наблюдался"};const g=["UP","OPEN","READY"].includes(c)?"online":["DOWN","CLOSED","MAINT","STOPPED"].some(P=>c.startsWith(P))?"offline":"degraded",f=i||"UNKNOWN";return{tone:g,label:f,detail:"Карта серверов не получена",tooltip:`HAProxy backend: ${f} · карта серверов не получена`}}function Qt(s,t){return t==="enabled"?s.enabled:t==="draft"?!s.enabled&&s.deployment_state!=="failed":t==="failed"?s.deployment_state==="failed":!0}const Xt={"1m":2e3,"5m":1e4,"1h":12e4,"24h":24e5,"7d":168e5,"30d":72e6};function Gt(s,t,o){const l=s.id.split("").reduce((p,m)=>p+m.charCodeAt(0),0),i=o?.haproxy_runtime?.backends,c=Object.values(i??{}).find(p=>Number(p.rx_bps)>0||Number(p.tx_bps)>0),g=Number(c?.rx_bps)||198e6,f=Number(c?.tx_bps)||124e6,P=Xt[t],M=Date.now();return Array.from({length:60},(p,m)=>{const K=.7+m/170,x=1+Math.sin((m+l%13)/4.8)*.13+Math.cos(m/8.5)*.06;return{timestamp:new Date(M-(59-m)*P).toISOString(),rx_bps:Math.max(0,Math.round(g*K*x)),tx_bps:Math.max(0,Math.round(f*K*(1+Math.sin((m+5)/6.4)*.1)))}})}const ns=100;function Jt(s){return`${s.listener_ip||"*"}:${s.listener_port}`}function Is(s){return s.fallback||s.match_mode==="any_tcp"||s.match_mode==="destination_ip"}function Vt(s){const t=[],o=new Map;for(const l of s){const i=Jt(l);let c=o.get(i);c||(c=[],t.push(i),o.set(i,c)),c.push(l)}return t.map(l=>{const i=o.get(l),c=i.filter(f=>!Is(f)),g=i.filter(Is);return{key:l,routes:[...c,...g],hasFallback:g.length>0,hasSNI:c.length>0}})}const Yt=a.memo(function({route:t,report:o,backend:l,servers:i,previousID:c,nextID:g,pending:f,dragging:P,dropTarget:M,ordering:p,reorderEnabled:m,reorderDisabledReason:K,onEdit:x,onToggle:L,onStats:F,onRequestDelete:w,onMove:A,onDragStart:Y,onDragEnd:Q,onDragOver:te,onDrop:H}){const b=Ls(l,i),T=o?.limit_bytes??t.quota_bytes,S=o?.limit_bytes?o.quota_used_bytes??o.used_bytes:o?.used_bytes,U=T&&S!=null?Math.min(100,S/T*100):null,N=is(t),B=vs(t),y=ys(t);return e.jsxs("div",{className:`nf-detail-route-row is-${t.deployment_state}${f?" is-busy":""}${P?" is-dragging":""}${M?" is-drop-target":""}${p?" is-ordering":""}`,role:"row",tabIndex:0,"aria-label":`Редактировать маршрут ${N}`,onClick:v=>{At(v.target,v.currentTarget)||x(t)},onKeyDown:v=>{v.key==="Enter"&&v.target===v.currentTarget&&x(t)},onDragOver:v=>te(v,t.id),onDrop:v=>H(v,t.id),children:[e.jsx("div",{role:"cell",className:"nf-route-toggle","data-row-action":!0,children:e.jsx(Ct,{size:"sm",checked:t.enabled,disabled:f||t.delete_pending,onChange:v=>L(t,v.currentTarget.checked),"aria-label":`${t.enabled?"Выключить":"Включить"} маршрут ${N}`})}),e.jsxs("div",{role:"cell",className:"nf-route-name-cell",children:[e.jsxs("div",{className:"nf-sort-controls","data-row-action":!0,children:[e.jsx(Ce,{label:m?"Перетащить маршрут":K,openDelay:250,children:e.jsx("span",{className:"nf-sort-grip-wrap",children:e.jsx(we,{className:"nf-sort-grip",variant:"subtle",color:"gray",size:"sm",draggable:m,disabled:!m,"aria-label":`Перетащить маршрут ${N}`,onDragStart:v=>Y(v,t.id),onDragEnd:Q,children:e.jsx(jt,{size:15})})})}),e.jsxs("div",{className:"nf-sort-step-actions",children:[e.jsx(we,{variant:"subtle",color:"gray",size:"xs",disabled:!m||!c,"aria-label":`Переместить ${N} выше`,onClick:()=>{c&&A(t.id,c)},children:e.jsx(bt,{size:12})}),e.jsx(we,{variant:"subtle",color:"gray",size:"xs",disabled:!m||!g,"aria-label":`Переместить ${N} ниже`,onClick:()=>{g&&A(t.id,g)},children:e.jsx(js,{size:12})})]})]}),e.jsxs("button",{className:"nf-route-name",onClick:()=>x(t),title:N,children:[e.jsx("i",{className:t.enabled?"is-online":""}),e.jsxs("span",{children:[e.jsx("strong",{children:N}),e.jsx("small",{className:`is-${t.deployment_state}`,children:Kt[t.deployment_state]??t.deployment_state})]})]})]}),e.jsxs("span",{role:"cell",className:"nf-route-mono",children:[t.listener_ip||"*",":",t.listener_port]}),e.jsx(Ce,{label:B,openDelay:350,children:e.jsx("span",{role:"cell",tabIndex:0,className:"nf-route-ellipsis",children:B})}),e.jsx(Ce,{label:y,openDelay:350,children:e.jsx("span",{role:"cell",tabIndex:0,className:"nf-route-ellipsis",children:y})}),e.jsx("span",{role:"cell",children:D(l?.connections_current)}),e.jsx("span",{role:"cell",children:D(l?.tcp_sessions_current??l?.sessions_current)}),e.jsxs("span",{role:"cell",className:"nf-route-rate",children:[e.jsxs("b",{children:["↓ ",Me(l?.rx_bps)]}),e.jsxs("small",{children:["↑ ",Me(l?.tx_bps)]})]}),e.jsxs("span",{role:"cell",className:"nf-route-quota",children:[e.jsx("b",{children:De(S)}),e.jsx("small",{children:T?`/ ${De(T)}`:"без лимита"}),e.jsx("i",{className:U==null?"is-unlimited":void 0,children:e.jsx("em",{style:{width:`${U??100}%`}})})]}),e.jsx(Ce,{label:b.tooltip,openDelay:300,children:e.jsxs("span",{role:"cell",className:`nf-route-health is-${b.tone}`,children:[e.jsx("i",{})," ",b.label]})}),e.jsx("span",{role:"cell","data-row-action":!0,children:e.jsxs(j,{position:"bottom-end",withinPortal:!0,children:[e.jsx(j.Target,{children:e.jsx(we,{variant:"subtle",color:"gray",size:"md","aria-label":`Действия маршрута ${N}`,children:e.jsx(vt,{size:16})})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Item,{leftSection:e.jsx(et,{size:16}),onClick:()=>F(t),children:"Статистика"}),e.jsx(j.Item,{leftSection:e.jsx(bs,{size:16}),onClick:()=>x(t),children:"Редактировать"}),e.jsx(j.Divider,{}),e.jsx(j.Item,{color:"red",leftSection:e.jsx(cs,{size:16}),onClick:()=>w(t),children:"Удалить"})]})]})})]})});function Zt({nodeID:s,routes:t,traffic:o,metrics:l,busyRouteID:i,orderingRouteID:c="",error:g,onToggle:f,onDelete:P,onReorder:M}){const p=As(),m=Es(),[K,x]=a.useState(""),[L,F]=a.useState("all"),[w,A]=a.useState(null),[Y,Q]=a.useState(!1),[te,H]=a.useState(""),[b,T]=a.useState(!1),[S,U]=a.useState(null),[N,B]=a.useState("24h"),[y,v]=a.useState([]),[J,d]=a.useState(!1),[V,ne]=a.useState(""),[Te,ue]=a.useState(""),[ze,Pe]=a.useState(""),Z=a.useRef(0),be=a.useMemo(()=>({all:t.length,enabled:t.filter(n=>n.enabled).length,draft:t.filter(n=>!n.enabled&&n.deployment_state!=="failed").length,failed:t.filter(n=>n.deployment_state==="failed").length}),[t]),ve=K.trim().toLowerCase(),he=a.useMemo(()=>t.filter(n=>Qt(n,L)?ve?`${is(n)} ${n.listener_ip}:${n.listener_port} ${vs(n)} ${ys(n)}`.toLowerCase().includes(ve):!0:!1),[t,L,ve]),ye=new URLSearchParams(m.search).get("demo")==="1",_e=ye?"?demo=1":"",Ie=L==="all"&&!K.trim()&&!i&&!c,Le=K.trim()||L!=="all"?"Сбросьте поиск и фильтры, чтобы менять порядок.":"Дождитесь завершения текущего изменения.",pe=a.useMemo(()=>Vt(he),[he]),ee=a.useMemo(()=>pe.flatMap(n=>n.routes),[pe]),ds=a.useMemo(()=>new Map((o?.routes??[]).map(n=>[n.route_id,n])),[o?.routes]),[Re,Be]=a.useState(1),fe=Math.max(1,Math.ceil(ee.length/ns)),W=Math.min(Re,fe);a.useEffect(()=>{Be(1)},[L,ve]);const ae=fe>1,C=ae?(W-1)*ns:0,xe=ae?C+ns:ee.length,X=a.useMemo(()=>{if(!ae)return pe.map(_=>({..._,lastOnPage:!0}));const n=[];let u=0;for(const _ of pe){const E=Math.max(C,u),re=Math.min(xe,u+_.routes.length);if(E=xe)break}return n},[pe,ae,C,xe]),I=a.useMemo(()=>{const n=new Map;return ee.forEach((u,_)=>n.set(u.id,{previousID:ee[_-1]?.id,nextID:ee[_+1]?.id})),n},[ee]),G=a.useRef({reorderEnabled:Ie,draggingID:Te,onReorder:M,onToggle:f,nodeID:s,demoQuery:_e,navigate:p});G.current={reorderEnabled:Ie,draggingID:Te,onReorder:M,onToggle:f,nodeID:s,demoQuery:_e,navigate:p};const Fe=a.useCallback(n=>{const{navigate:u,nodeID:_,demoQuery:E}=G.current;u(`/nodes/${_}/routes/${n.id}${E}`)},[]),He=a.useCallback((n,u)=>{G.current.onToggle(n,u)},[]),We=a.useCallback((n,u)=>{G.current.onReorder(n,u)},[]),oe=a.useCallback(n=>{H(""),A(n)},[]),ce=a.useCallback((n,u)=>{G.current.reorderEnabled&&(n.stopPropagation(),n.dataTransfer.effectAllowed="move",n.dataTransfer.setData("text/plain",u),G.current.draggingID=u,ue(u))},[]),Ae=a.useCallback((n,u)=>{const{reorderEnabled:_,draggingID:E}=G.current;!_||!E||u===E||(n.preventDefault(),n.dataTransfer.dropEffect="move",Pe(u))},[]),se=a.useCallback((n,u)=>{n.preventDefault(),n.stopPropagation();const{reorderEnabled:_,draggingID:E,onReorder:re}=G.current,Ne=E||n.dataTransfer.getData("text/plain");G.current.draggingID="",ue(""),Pe(""),_&&Ne&&Ne!==u&&re(Ne,u)},[]),Ke=a.useCallback(()=>{G.current.draggingID="",ue(""),Pe("")},[]);a.useEffect(()=>{if(!S)return;const n=++Z.current;if(v([]),ne(""),ye){v(Gt(S,N,l)),d(!1);return}const u=new AbortController;return d(!0),O(`/api/v1/nodes/${encodeURIComponent(s)}/routes/${encodeURIComponent(S.id)}/traffic/history?range=${encodeURIComponent(N)}`,{signal:u.signal}).then(_=>{Z.current===n&&v(_.samples??[])}).catch(_=>{!u.signal.aborted&&Z.current===n&&ne(_ instanceof Error?_.message:"История маршрута недоступна")}).finally(()=>{!u.signal.aborted&&Z.current===n&&d(!1)}),()=>u.abort()},[ye,l,s,N,S]);const us=a.useCallback(n=>{Z.current+=1,v([]),ne(""),d(!0),B("24h"),U(n)},[]),Qe=n=>{n!==N&&(Z.current+=1,v([]),ne(""),d(!0),B(n))},Ue=()=>{Z.current+=1,U(null),v([]),ne(""),d(!1)},Xe=async()=>{if(w){Q(!0),H("");try{await P(w),A(null)}catch(n){H(n instanceof Error?n.message:"Маршрут не удалён")}finally{Q(!1)}}};return e.jsxs("section",{className:`nf-surface nf-detail-routes${b?" is-relaxed":""}`,"aria-labelledby":"node-routes-title",children:[e.jsxs("header",{className:"nf-detail-routes__toolbar",children:[e.jsx("div",{className:"nf-detail-routes__title",children:e.jsx("h2",{id:"node-routes-title",children:"Маршруты"})}),e.jsx(ft,{className:"nf-detail-route-tabs",value:L,onChange:F,label:"Фильтр маршрутов",items:[{value:"all",label:"Все",count:be.all},{value:"enabled",label:"Включены",count:be.enabled},{value:"draft",label:"Черновики",count:be.draft}]}),e.jsxs("div",{className:"nf-detail-routes__tools",children:[e.jsx(rs,{value:K,onChange:n=>x(n.currentTarget.value),placeholder:"Поиск маршрутов...",leftSection:e.jsx(Pt,{size:16}),"aria-label":"Поиск маршрутов"}),e.jsxs(j,{position:"bottom-end",withinPortal:!0,children:[e.jsx(j.Target,{children:e.jsx(R,{variant:"default",leftSection:e.jsx(xt,{size:16}),children:"Фильтры"})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Label,{children:"Состояние"}),[["all","Все маршруты"],["enabled","Только включённые"],["draft","Только черновики"],["failed",`С ошибкой (${be.failed})`]].map(([n,u])=>e.jsx(j.Item,{className:L===n?"is-selected":"",onClick:()=>F(n),children:u},n))]})]}),e.jsx(we,{variant:"default",size:"lg",onClick:()=>T(n=>!n),"aria-label":"Переключить плотность строк","aria-pressed":b,children:e.jsx(mt,{size:17})})]})]}),g&&e.jsxs("div",{className:"nf-inline-error",role:"alert",children:[e.jsx(ut,{size:16}),e.jsx("span",{children:g})]}),e.jsx("div",{className:"nf-route-table-scroll",tabIndex:0,"aria-label":"Маршруты ноды",children:e.jsxs("div",{className:"nf-detail-route-table",role:"table","aria-rowcount":he.length+1,children:[e.jsx("div",{className:"nf-detail-route-head",role:"row",children:["Статус","Маршрут","Слушает","Правило соответствия","Назначение","Соединения","TCP-сессии","RX / TX","Трафик","Бэкенды","Действия"].map(n=>e.jsx("span",{role:"columnheader",children:n},n))}),X.map(({key:n,routes:u,hasFallback:_,hasSNI:E,lastOnPage:re},Ne)=>e.jsxs("div",{className:"nf-route-listener-group",role:"rowgroup","aria-label":`Listener ${n}`,children:[(pe.length>1||Ne===0)&&e.jsx("div",{className:"nf-route-listener-group__header",role:"presentation","aria-hidden":!0,children:e.jsx("span",{className:"nf-route-listener-group__key",children:n})}),u.map(ie=>{const{report:hs,backend:Ee,servers:le}=Ps(ie,o,l,ds),$=I.get(ie.id);return e.jsx(Yt,{route:ie,report:hs,backend:Ee,servers:le,previousID:$?.previousID,nextID:$?.nextID,pending:i===ie.id,dragging:Te===ie.id,dropTarget:ze===ie.id,ordering:c===ie.id,reorderEnabled:Ie,reorderDisabledReason:Le,onEdit:Fe,onToggle:He,onStats:us,onRequestDelete:oe,onMove:We,onDragStart:ce,onDragEnd:Ke,onDragOver:Ae,onDrop:se},ie.id)}),E&&!_&&re&&e.jsx("div",{className:"nf-route-listener-group__no-fallback",role:"presentation",children:e.jsx("span",{children:"несовпавшие соединения сбрасываются"})})]},n))]})}),ae&&e.jsxs("footer",{className:"nf-table-footer",children:[e.jsxs("span",{children:["Показано ",C+1,"–",Math.min(ee.length,xe)," из ",ee.length," маршрутов"]}),e.jsx(gt,{total:fe,value:W,onChange:Be,size:"sm",withEdges:!0,siblings:1,boundaries:1}),e.jsxs("span",{children:[ns," / стр."]})]}),!he.length&&e.jsx(Fs,{title:t.length?"Ничего не найдено":"Маршрутов пока нет",description:t.length?"Измените поиск или фильтр состояния.":"Создайте listener → target. Новый маршрут сохранится выключенным черновиком.",action:t.length?void 0:e.jsx(R,{leftSection:e.jsx(Us,{size:17}),onClick:()=>p(`/nodes/${s}/routes/new${_e}`),children:"Добавить маршрут"})}),e.jsx($e,{opened:!!w,onClose:()=>!Y&&A(null),title:"Удалить маршрут?",classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs("div",{className:"nf-confirm-dialog",children:[e.jsxs("p",{children:["Маршрут ",e.jsx("strong",{children:w?is(w):""})," будет сначала безопасно исключён из HAProxy, затем удалён после подтверждения Agent."]}),te&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:te}),e.jsxs("div",{children:[e.jsx(R,{variant:"default",onClick:()=>A(null),disabled:Y,children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(cs,{size:16}),onClick:Xe,loading:Y,children:"Удалить"})]})]})}),e.jsx($e,{opened:!!S,onClose:Ue,title:S?`Статистика · ${is(S)}`:"Статистика маршрута",size:"xl",classNames:{content:"nf-dialog nf-route-stats-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:S&&(()=>{const{report:n,backend:u,servers:_}=Ps(S,o,l),E=Ls(u,_);return e.jsxs("div",{className:"nf-route-stats",children:[e.jsxs("div",{className:"nf-route-stats__context",children:[e.jsxs("span",{children:[S.listener_ip||"*",":",S.listener_port]}),e.jsx("span",{children:vs(S)}),e.jsxs("span",{children:["→ ",ys(S)]})]}),e.jsxs("div",{className:"nf-route-stats__rail",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Соединения"}),e.jsx("strong",{children:D(u?.connections_current)}),e.jsxs("small",{children:[D(u?.session_rate)," новых/с"]})]}),e.jsxs("div",{children:[e.jsx("span",{children:"TCP-сессии"}),e.jsx("strong",{children:D(u?.tcp_sessions_current??u?.sessions_current)}),e.jsxs("small",{children:[D(u?.sessions_total)," всего"]})]}),e.jsxs("div",{children:[e.jsx("span",{children:"Трафик за месяц"}),e.jsx("strong",{children:De(n?.used_bytes)}),e.jsxs("small",{children:["RX ",De(n?.bytes_in)," · TX ",De(n?.bytes_out)]})]}),e.jsxs("div",{children:[e.jsx("span",{children:"Backend health"}),e.jsx("strong",{children:E.label==="—"?"Нет данных":E.label}),e.jsx("small",{children:E.detail})]})]}),V&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:V}),e.jsxs("div",{className:`nf-route-stats__chart${J?" is-loading":""}`,"aria-busy":J,children:[e.jsx(qs,{samples:y,range:N,onRangeChange:Qe,emptyTitle:J?"Загружаем историю…":V?"История недоступна":"Нет точек за выбранный период",emptyDescription:J?"Новая выборка заменит предыдущий период.":V?"Повторите запрос или выберите другой период.":"HAProxy не передал точки для этого маршрута и диапазона.",emptyFooterLabel:J?"Запрос выполняется":V?"Запрос завершился ошибкой":"Точек нет",status:J?{tone:"stale",label:"Загрузка"}:V?{tone:"offline",label:"Ошибка загрузки"}:void 0}),J&&e.jsx("div",{className:"nf-route-stats__loading",children:"Загружаем историю…"})]})]})})()})]})}const _s=new URLSearchParams(window.location.search).get("demo")==="1"||!1;function en(s){return s instanceof Error?s.message:"Данные недоступны"}function je(s,t,o,l){return s.status==="fulfilled"?s.value:(l[o]=en(s.reason),t)}function sn(s){return s.fetchQuery({queryKey:Ts,queryFn:()=>O("/api/v1/agent-releases"),staleTime:1/0})}async function tn(s,t,o){if(_s){const{createDemoDetail:p}=await Ms(async()=>{const{createDemoDetail:m}=await import("./demo-node-detail-DYja70C8.js");return{createDemoDetail:m}},__vite__mapDeps([0,1]));return p(t,o)}const l=await Promise.allSettled([O(`/api/v1/nodes/${t}`),O(`/api/v1/nodes/${t}/operational`),O(`/api/v1/nodes/${t}/routes`),O(`/api/v1/nodes/${t}/traffic`),O(`/api/v1/nodes/${t}/traffic/history?range=${encodeURIComponent(o)}`),O(`/api/v1/nodes/${t}/firewall`),O(`/api/v1/nodes/${t}/agent-update`),sn(s),O(`/api/v1/nodes/${t}/audit?limit=40`)]),i=l[0];if(i.status==="rejected")throw i.reason;const c={},g=je(l[1],null,"operational",c),f=je(l[2],[],"routes",c),P=je(l[3],null,"traffic",c),M=je(l[4],null,"history",c);return{bundle:{node:i.value,operational:g,routes:f,traffic:P,history:M},firewall:je(l[5],null,"firewall",c),update:je(l[6],null,"update",c),releases:je(l[7],[],"releases",c),audit:je(l[8],[],"audit",c),partialErrors:c}}function nn(s,t){const o=Os();return It({queryKey:["node-detail",s,t,_s],queryFn:()=>tn(o,s,t),enabled:!!s,...st,retry:(l,i)=>!("status"in Object(i)&&i.status===401)&&l<2})}function an(){return _s}const rn={online:"Работает",degraded:"Требует внимания",offline:"Недоступна",stopped:"HAProxy выключен"};function ln(s,t){return{enabled:t,expected_version:s.version}}function on(){return e.jsxs("main",{className:"nf-page nf-node-detail-page",children:[e.jsxs("div",{className:"nf-detail-skeleton-head",children:[e.jsx(ge,{height:16,width:180}),e.jsx(ge,{height:34,width:340})]}),e.jsxs("div",{className:"nf-detail-skeleton-top",children:[e.jsx(ge,{height:340}),e.jsx(ge,{height:340})]}),e.jsx(ge,{height:295,mt:12}),e.jsxs("div",{className:"nf-detail-skeleton-bottom",children:[e.jsx(ge,{height:206}),e.jsx(ge,{height:206}),e.jsx(ge,{height:206})]})]})}function wn(){const{nodeId:s=""}=tt(),t=As(),o=Es(),l=Os(),i=an(),c=new URLSearchParams(o.search).get("demo")==="1"?"?demo=1":"",[g,f]=a.useState("24h"),[P,M]=a.useState(""),[p,m]=a.useState(""),[K,x]=a.useState(""),[L,F]=a.useState({}),[w,A]=a.useState(null),[Y,Q]=a.useState(null),[te,H]=a.useState(null),[b,T]=a.useState(!1),[S,U]=a.useState(!1),[N,B]=a.useState(""),[y,v]=a.useState(""),[J,d]=a.useState(!1),[V,ne]=a.useState(""),[Te,ue]=a.useState(!1),[ze,Pe]=a.useState(""),[Z,be]=a.useState(!1),[ve,he]=a.useState(""),[ye,_e]=a.useState([]),[Ie,Le]=a.useState(""),[pe,ee]=a.useState(null),[ds,Re]=a.useState(!1),[Be,fe]=a.useState(!1),[W,ae]=a.useState(!1),C=nn(s,g),xe=a.useRef(null);C.data&&(xe.current={nodeID:s,data:C.data});const X=C.data??(xe.current?.nodeID===s?xe.current.data:void 0),I=X?.bundle,G=a.useMemo(()=>(I?.routes??[]).map(r=>L[r.id]===void 0?r:L[r.id]).filter(r=>r!==null),[I?.routes,L]),Fe=a.useMemo(()=>{if(!ye.length)return G;const r=new Map(ye.map((h,k)=>[h,k]));return[...G].sort((h,k)=>(r.get(h.id)??Number.MAX_SAFE_INTEGER)-(r.get(k.id)??Number.MAX_SAFE_INTEGER))},[ye,G]),He=a.useMemo(()=>yt(I?.history?.samples??[],g),[I?.history?.samples,g]),We=async()=>{F({}),A(null),Q(null),H(null),ee(null),x(""),await l.invalidateQueries({queryKey:Ts,refetchType:"none"}),await C.refetch()},oe=()=>l.invalidateQueries({queryKey:["node-detail",s]});if(a.useEffect(()=>{const r=G.map(h=>h.id);_e(h=>h.length===r.length&&h.every(k=>r.includes(k))?h:r)},[G]),C.isPending&&!X)return e.jsx(on,{});if(C.isError&&nt(C.error))return e.jsx(at,{onSuccess:()=>C.refetch()});if(!X||!I)return e.jsx("main",{className:"nf-page",children:e.jsx(Fs,{title:"Нода не загрузилась",description:C.error instanceof Error?C.error.message:"Нода не найдена",tone:"error",action:e.jsxs(e.Fragment,{children:[e.jsx(R,{variant:"default",onClick:()=>t(`/nodes${c}`),children:"К списку нод"}),e.jsx(ht,{onClick:()=>C.refetch()})]})})});const ce=I.operational?.latest_heartbeat?.metrics,Ae=I.operational?.latest_heartbeat,se=_t({...I}),Ke=Ae?.received_at?Date.parse(Ae.received_at):Number.NaN,us=Number.isFinite(Ke)&&Date.now()-Ke<=45e3,Qe=!!(Ae&&us&&se!=="offline"),Ue=I.operational?.rate_sampled_at,Xe=Ue?Date.parse(Ue):Number.NaN,n=se!=="offline"&&Number.isFinite(Xe)&&Date.now()-Xe<=45e3,u=n&&Number.isFinite(I.operational?.rx_bits_per_second)?Number(I.operational?.rx_bits_per_second):null,_=n&&Number.isFinite(I.operational?.tx_bits_per_second)?Number(I.operational?.tx_bits_per_second):null,E=[...He].reverse().find(r=>r.rx_bps!==null||r.tx_bps!==null),re=E?.timestamp?Date.parse(E.timestamp):Number.NaN,Ne=Math.max(45e3,(I.history?.bucket_seconds??15)*2500),ie=!!(E&&(!Number.isFinite(re)||Date.now()-re>Ne)),hs=C.isError||ie?{tone:"stale",label:"Данные устарели"}:E?se==="offline"?{tone:"offline",label:"Нода недоступна"}:se==="degraded"||!n?{tone:"degraded",label:n?"Нода деградирует":"Нет текущей точки"}:{tone:"online",label:"Онлайн"}:{tone:"offline",label:"Нет свежих данных"},Ee=w??X.firewall,le=Y??X.update,$=te??I.node,Ns=typeof $.metadata?.agent_port=="number"?$.metadata.agent_port:4200,z=pe??I.operational?.haproxy_control,me=z?.desired_enabled!==!1,Ss=!me&&se!=="offline"?"stopped":se,ps=()=>{B($.name),v($.address),ne(""),T(!0)},ks=()=>{T(!1),U(!0)},Bs=()=>{Pe(""),he(""),ue(!0)},Ws=async()=>{if(ze===$.name){be(!0),he("");try{i||(await O(`/api/v1/nodes/${s}`,{method:"DELETE"}),await l.invalidateQueries({queryKey:["overview"]})),ue(!1),t(`/nodes${c}`,{replace:!0})}catch(r){he(r instanceof Error?r.message:"Нода не удалена")}finally{be(!1)}}},Ks=async()=>{const r=N.trim(),h=y.trim();if(!r||!h){ne("Укажите название и IP-адрес ноды.");return}d(!0),ne("");try{const k=i?{...$,name:r,address:h,updated_at:new Date().toISOString()}:await O(`/api/v1/nodes/${s}`,{method:"PUT",body:JSON.stringify({name:r,address:h,metadata:$.metadata??{}})});H(k),i||await oe(),T(!1)}catch(k){ne(k instanceof Error?k.message:"Параметры ноды не сохранены")}finally{d(!1)}},Qs=async(r,h)=>{M(r.id),x("");try{if(i){const k={...r,enabled:h,deployed:h,deployment_state:h?"active":"disabled",version:r.version+1,updated_at:new Date().toISOString()},{upsertDemoRoute:q}=await Ms(async()=>{const{upsertDemoRoute:Se}=await import("./demo-k0hjezoN.js");return{upsertDemoRoute:Se}},[]);q(s,k),F(Se=>({...Se,[r.id]:k}))}else{const k=await O(`/api/v1/nodes/${s}/routes/${r.id}`,{method:"PATCH",body:JSON.stringify(ln(r,h))});F(q=>({...q,[r.id]:k})),await oe(),F(q=>{const{[r.id]:Se,...Ge}=q;return Ge})}}catch(k){x(k instanceof Error?k.message:"Маршрут не изменён")}finally{M("")}},Xs=async r=>{M(r.id),x("");try{i?F(h=>({...h,[r.id]:null})):(await O(`/api/v1/nodes/${s}/routes/${r.id}?expected_version=${r.version}`,{method:"DELETE"}),await oe())}catch(h){throw x(h instanceof Error?h.message:"Маршрут не удалён"),h}finally{M("")}},Gs=async(r,h)=>{if(r===h||Ie)return;const k=Fe.map(Je=>Je.id),q=[...k],Se=q.indexOf(r),Ge=q.indexOf(h);if(!(Se<0||Ge<0)){q.splice(Ge,0,q.splice(Se,1)[0]),_e(q),Le(r),x("");try{i||(await O(`/api/v1/nodes/${s}/routes/order`,{method:"PUT",body:JSON.stringify({route_ids:q})}),await oe())}catch(Je){_e(k),x(Je instanceof Error?Je.message:"Порядок маршрутов не сохранён"),i||oe()}finally{Le("")}}},ws=async r=>{if(!(!z||W)){ae(!0),x("");try{const h=i?{...z,supported:!0,desired_enabled:r,generation:z.generation+1,actual_enabled:r,active_state:r?"active":"inactive",report_generation:z.generation+1,updated_at:new Date().toISOString(),reported_at:new Date().toISOString()}:await O(`/api/v1/nodes/${s}/haproxy`,{method:"PUT",body:JSON.stringify({enabled:r,expected_generation:z.generation})});ee(h),Re(!1),i||(await oe(),ee(null))}catch(h){x(h instanceof Error?h.message:`HAProxy не ${r?"включён":"выключен"}`)}finally{ae(!1)}}},Js=async()=>{if(!(!z||W||!me)){ae(!0),x("");try{const r=i?{...z,supported:!0,desired_enabled:!0,restart_generation:z.restart_generation+1,actual_enabled:!0,active_state:"reloading",report_generation:z.generation,updated_at:new Date().toISOString()}:await O(`/api/v1/nodes/${s}/haproxy/restart`,{method:"POST",body:JSON.stringify({expected_generation:z.restart_generation})});ee(r),fe(!1),i||(await oe(),ee(null))}catch(r){x(r instanceof Error?r.message:"HAProxy не перезагружен")}finally{ae(!1)}}},Vs=async r=>{if(Ee){m("firewall"),x("");try{if(i)A({...Ee,mode:r,updated_at:new Date().toISOString()});else{const h=await O(`/api/v1/nodes/${s}/firewall`,{method:"PUT",body:JSON.stringify({mode:r})});A(h)}}catch(h){x(h instanceof Error?h.message:"Режим UFW не изменён")}finally{m("")}}},Ys=async r=>{if(!le){x("Состояние Node Agent недоступно. Обновите данные и повторите.");return}m("update"),x("");try{if(i&&le)Q({...le,desired_release:r,state:"assigned",updated_at:new Date().toISOString()});else{const h=await O(`/api/v1/nodes/${s}/agent-update`,{method:"PUT",body:JSON.stringify({release_id:r.id,expected_actual_sequence:le.actual_sequence,expected_desired_sequence:le.desired_release?.sequence??0})});Q(h)}}catch(h){x(h instanceof Error?h.message:"Релиз не назначен")}finally{m("")}},Zs=async(r,h,k)=>{m("rollback"),x("");try{if(i&&le)Q({...le,desired_release:r,state:"assigned",updated_at:new Date().toISOString()});else{const q=await O(`/api/v1/nodes/${s}/agent-update/rollback`,{method:"POST",body:JSON.stringify({target_release_id:r.id,expected_actual_sequence:h,expected_desired_sequence:k})});Q(q)}}catch(q){throw x(q instanceof Error?q.message:"Откат не назначен"),q}finally{m("")}};return e.jsxs("main",{className:"nf-page nf-node-detail-page",children:[e.jsx(lt,{className:"nf-detail-header",breadcrumb:e.jsxs(e.Fragment,{children:[e.jsx(Cs,{to:`/nodes${c}`,children:"Ноды"}),e.jsx("span",{children:"/"}),e.jsx("span",{"aria-current":"page",children:$.name})]}),title:$.name,meta:e.jsxs(e.Fragment,{children:[e.jsx("code",{children:$.address}),e.jsxs("span",{className:`nf-detail-status is-${Ss}`,children:[e.jsx("i",{}),rn[Ss]]}),e.jsxs("span",{className:"nf-detail-heartbeat",children:["Последний сигнал: ",os($.last_seen_at)]})]}),actions:e.jsxs(e.Fragment,{children:[e.jsx(R,{component:Cs,to:`/nodes/${s}/routes/new${c}`,className:"nf-primary-action",leftSection:e.jsx(Us,{size:18}),children:"Добавить маршрут"}),e.jsx(we,{variant:"default",size:"lg",onClick:ps,"aria-label":"Настройки ноды",children:e.jsx(Rs,{size:18})}),e.jsxs(j,{position:"bottom-end",withinPortal:!0,children:[e.jsx(j.Target,{children:e.jsx(we,{variant:"default",size:"lg","aria-label":"Действия ноды",children:e.jsx(Et,{size:19})})}),e.jsxs(j.Dropdown,{children:[e.jsx(j.Item,{leftSection:e.jsx(ms,{size:16}),onClick:We,children:"Обновить данные"}),e.jsx(j.Item,{leftSection:e.jsx(bs,{size:16}),onClick:ps,children:"Редактировать ноду"}),e.jsx(j.Item,{leftSection:e.jsx($s,{size:16}),onClick:ks,children:"Переустановить Node Agent"}),e.jsx(j.Divider,{}),e.jsx(j.Item,{color:"red",leftSection:e.jsx(ms,{size:16}),disabled:!z?.supported||!me||W,onClick:()=>fe(!0),children:"Жёстко перезагрузить HAProxy"}),e.jsx(j.Item,{color:me?"red":"nodeflow",leftSection:e.jsx(es,{size:16}),disabled:!z?.supported||W,onClick:()=>{me?Re(!0):ws(!0)},children:me?"Выключить HAProxy":"Включить HAProxy"}),e.jsx(j.Item,{color:"red",leftSection:e.jsx(cs,{size:16}),onClick:Bs,children:"Удалить ноду"})]})]})]})}),se!=="online"&&me&&e.jsxs("div",{className:`nf-detail-state-banner is-${se}`,role:"status",children:[e.jsx("strong",{children:se==="offline"?"Нода не отвечает.":"Нода работает с ограничениями."}),e.jsx("span",{children:se==="offline"?"Показаны последние сохранённые значения; управляющие действия могут ждать восстановления связи.":"Проверьте HAProxy runtime, backend health и состояние применения маршрутов."})]}),!me&&e.jsxs("div",{className:"nf-detail-state-banner is-haproxy-off",role:"status",children:[e.jsx("strong",{children:"HAProxy выключен."}),e.jsx("span",{children:"Node Agent остаётся на связи, но listener-порты и все маршруты остановлены."})]}),z&&!z.supported&&e.jsxs("div",{className:"nf-detail-state-banner",role:"status",children:[e.jsx("strong",{children:"Управление HAProxy недоступно."}),e.jsx("span",{children:"Обновите Node Agent до версии с поддержкой включения и выключения сервиса."})]}),K&&e.jsxs("div",{className:"nf-inline-error nf-detail-action-error",role:"alert",children:[K,e.jsx("button",{type:"button",onClick:()=>x(""),children:"Закрыть"})]}),X.partialErrors.operational&&e.jsxs("div",{className:"nf-inline-error nf-detail-action-error",role:"alert",children:["Системная статистика временно недоступна: ",X.partialErrors.operational]}),e.jsxs("div",{className:"nf-detail-top-grid",children:[e.jsx(as,{className:"nf-detail-chart",title:"Трафик ноды",description:X.partialErrors.history?`История недоступна: ${X.partialErrors.history}`:C.isError?`Новый диапазон не загружен: ${C.error instanceof Error?C.error.message:"данные недоступны"}`:!C.data&&C.isFetching?"Обновляем диапазон без перезагрузки страницы…":void 0,children:e.jsx(qs,{samples:He,range:g,onRangeChange:f,currentRx:u,currentTx:_,status:hs})}),e.jsx(qt,{metrics:ce,history:He,summary:I.operational?.metrics_summary,currentRx:u,currentTx:_,rateSampledAt:Ue,live:se!=="offline",mtlsConnected:Qe})]}),e.jsx(Zt,{nodeID:s,routes:Fe,traffic:I.traffic,metrics:ce,busyRouteID:P,orderingRouteID:Ie,error:X.partialErrors.routes||X.partialErrors.traffic,onToggle:Qs,onDelete:Xs,onReorder:Gs}),e.jsx(Wt,{metrics:ce,agentVersion:Ae?.agent_version,agentPort:Ns,mtlsReady:Qe,credentialLastUsed:I.operational?.credential_last_used_at,routes:Fe,firewall:Ee,update:le,releases:X.releases,audit:X.audit,partialErrors:X.partialErrors,busyAction:p,onFirewallMode:Vs,onAssignRelease:Ys,onRollback:Zs,onOpenNodeSettings:ps}),e.jsx($e,{opened:ds,onClose:()=>!W&&Re(!1),title:"Выключить HAProxy?",size:"sm",closeOnClickOutside:!W,closeOnEscape:!W,classNames:{content:"nf-dialog nf-haproxy-control-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"md",children:[e.jsxs("div",{className:"nf-haproxy-control-warning",children:[e.jsx(es,{size:20}),e.jsxs("div",{children:[e.jsx("strong",{children:"Все маршруты этой ноды остановятся."}),e.jsx("span",{children:"Node Agent останется на связи. HAProxy можно будет снова включить из этого же меню."})]})]}),z?.last_error&&e.jsxs("div",{className:"nf-inline-error",role:"alert",children:["Последняя ошибка: ",z.last_error]}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:W,onClick:()=>Re(!1),children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(es,{size:16}),loading:W,onClick:()=>{ws(!1)},children:"Выключить HAProxy"})]})]})}),e.jsx($e,{opened:Be,onClose:()=>!W&&fe(!1),title:"Жёстко перезагрузить HAProxy?",size:"sm",closeOnClickOutside:!W,closeOnEscape:!W,classNames:{content:"nf-dialog nf-haproxy-control-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"md",children:[e.jsxs("div",{className:"nf-haproxy-control-warning",children:[e.jsx(es,{size:20}),e.jsxs("div",{children:[e.jsx("strong",{children:"Все активные соединения будут немедленно оборваны."}),e.jsx("span",{children:"Это именно systemd restart, а не безопасный reload. Клиентам потребуется переподключиться."})]})]}),z?.last_error&&e.jsxs("div",{className:"nf-inline-error",role:"alert",children:["Последняя ошибка: ",z.last_error]}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:W,onClick:()=>fe(!1),children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(ms,{size:16}),loading:W,onClick:()=>{Js()},children:"Жёстко перезагрузить"})]})]})}),e.jsx($e,{opened:b,onClose:()=>!J&&T(!1),title:"Настройки ноды",size:"lg",closeOnClickOutside:!J,closeOnEscape:!J,classNames:{content:"nf-dialog nf-node-settings-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"lg",children:[e.jsxs(Oe,{gap:"sm",children:[e.jsx(rs,{label:"Название ноды",value:N,onChange:r=>B(r.currentTarget.value),autoFocus:!0,required:!0}),e.jsx(rs,{label:"IP-адрес ноды",value:y,onChange:r=>v(r.currentTarget.value),required:!0})]}),V&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:V}),e.jsx(rt,{color:"gray",icon:e.jsx(Hs,{size:18}),title:"Переустановка Node Agent",children:e.jsxs(Oe,{gap:8,children:[e.jsx(fs,{size:"sm",children:"NodeFlow повторно проверит отпечаток SSH-ключа хоста, установит Agent и дождётся нового mTLS-сигнала. ID ноды и маршруты не меняются; при ошибке прежние учётные данные будут автоматически восстановлены."}),e.jsx(R,{variant:"default",size:"xs",leftSection:e.jsx($s,{size:15}),onClick:ks,children:"Переустановить Agent"})]})}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:J,onClick:()=>T(!1),children:"Отмена"}),e.jsx(R,{leftSection:e.jsx(bs,{size:16}),loading:J,onClick:Ks,children:"Сохранить"})]})]})}),e.jsx(Nt,{opened:S,onClose:()=>U(!1),onInstalled:()=>{We()},demo:i,reinstallTarget:{id:$.id,name:$.name,address:$.address,sshPort:typeof $.metadata?.ssh_port=="number"?$.metadata.ssh_port:22,agentPort:Ns,allowFirewallApply:Ee?.mode==="apply",os:typeof ce?.os=="string"?ce.os:void 0,arch:typeof ce?.arch=="string"?ce.arch:void 0}}),e.jsx($e,{opened:Te,onClose:()=>!Z&&ue(!1),title:"Удалить ноду?",closeOnClickOutside:!Z,closeOnEscape:!Z,classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:e.jsxs(Oe,{gap:"md",children:[e.jsxs(fs,{size:"sm",c:"dimmed",children:["Запись ",e.jsx(fs,{component:"span",inherit:!0,fw:600,c:"var(--nf-text)",children:$.name})," и связанные данные будут удалены из Panel. Node Agent и HAProxy на сервере останутся установленными."]}),e.jsx(rs,{label:e.jsxs(e.Fragment,{children:["Для подтверждения введите ",e.jsx("strong",{children:$.name})]}),value:ze,onChange:r=>Pe(r.currentTarget.value),disabled:Z,autoComplete:"off",autoFocus:!0}),ve&&e.jsx("div",{className:"nf-inline-error",role:"alert",children:ve}),e.jsxs(Ze,{justify:"flex-end",children:[e.jsx(R,{variant:"default",disabled:Z,onClick:()=>ue(!1),children:"Отмена"}),e.jsx(R,{color:"red",leftSection:e.jsx(cs,{size:16}),loading:Z,disabled:ze!==$.name,onClick:Ws,children:"Удалить ноду"})]})]})})]})}export{wn as NodeDetailPage}; diff --git a/internal/panel/web_dist/assets/NodesOverviewPage-esI7wwJs.js b/internal/panel/web_dist/assets/NodesOverviewPage-B2WqQpz1.js similarity index 97% rename from internal/panel/web_dist/assets/NodesOverviewPage-esI7wwJs.js rename to internal/panel/web_dist/assets/NodesOverviewPage-B2WqQpz1.js index 0235940..bc3f9db 100644 --- a/internal/panel/web_dist/assets/NodesOverviewPage-esI7wwJs.js +++ b/internal/panel/web_dist/assets/NodesOverviewPage-B2WqQpz1.js @@ -1 +1 @@ -import{c as je,j as e,r as i,u as me,a as ge,d as be,A as U,L as ve,I as _e,b as Me,l as Re,i as De,e as Te,B as oe,f as Ae,g as ze}from"./index-Dy6W__Vz.js";import{T as de,I as Ne,M,P as Pe}from"./PageHeader-C4N9uitv.js";import{P as Oe,d as G,m as Ee,I as Fe,a as Le,b as Ue,S as Be,c as qe,A as He,e as Xe}from"./model-BX4frb_O.js";import{f as V,a as A,t as Ge,b as K,s as Ke,T as ue,I as Ve,S as ne,R as Qe,c as ae,d as We}from"./format-D6_ab21F.js";import{I as J,a as xe}from"./IconPlus-N6bDt4BE.js";import{I as Je,a as Ze}from"./IconArrowUp-Cj3lrfzR.js";import{I as Ye,u as es,a as fe,T as ss,S as re}from"./TrafficChart-BU3flakD.js";import{l as ns,i as as}from"./useTrafficOverview-7XLu6zlh.js";import{I as rs}from"./IconServer-BpOSndTX.js";import"./chart-react-C4b8adjg.js";import"./IconKey-D6H2eVar.js";import"./chart-engine-Dbh3Q7E_.js";import"./chart-renderer-CWmX7Ukt.js";const ts=[["path",{d:"M5 12l14 0",key:"svg-0"}],["path",{d:"M13 18l6 -6",key:"svg-1"}],["path",{d:"M13 6l6 6",key:"svg-2"}]],os=je("outline","arrow-right","ArrowRight",ts);const ls=[["path",{d:"M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-0"}],["path",{d:"M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6",key:"svg-1"}]],is=je("outline","eye","Eye",ls);function cs({values:r}){const s=`nf-sparkline-${i.useId().replaceAll(":","")}`;if(r.length<2)return null;const o=Math.max(...r,1),a=Math.min(...r),d=Math.max(1,o-a),t=r.map((j,p)=>({x:p/(r.length-1)*100,y:30-(j-a)/d*24})),h=t.map(({x:j,y:p})=>`${j},${p}`).join(" "),c=`M ${t.map(({x:j,y:p})=>`${j} ${p}`).join(" L ")} L 100 36 L 0 36 Z`;return e.jsxs("svg",{className:"nf-sparkline",viewBox:"0 0 100 36",preserveAspectRatio:"none","aria-hidden":"true",children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:s,x1:"0",y1:"0",x2:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:"var(--nf-accent-strong)",stopOpacity:".3"}),e.jsx("stop",{offset:"100%",stopColor:"var(--nf-accent-strong)",stopOpacity:"0"})]})}),e.jsx("path",{className:"nf-sparkline__area",d:c,fill:`url(#${s})`}),e.jsx("polyline",{points:h})]})}function ds({rx:r,tx:s,rateComplete:o,aggregateScope:a,monthUsed:d,monthLimit:t,connections:h,health:c,trend:j}){const p=t>0?Math.min(100,d/t*100):0;return e.jsxs("div",{className:"nf-kpi-stack",children:[e.jsxs("section",{className:"nf-kpi nf-kpi--speed",children:[e.jsxs("header",{children:["Общая скорость ",e.jsx(J,{size:14}),!o&&e.jsx("span",{className:"nf-kpi-rate-state",children:"Неполные данные"})]}),e.jsxs("div",{className:"nf-speed-values",children:[e.jsxs("div",{children:[e.jsxs("strong",{children:[e.jsx(Je,{})," ",V(r)]}),e.jsx("span",{children:"RX суммарно"})]}),e.jsxs("div",{children:[e.jsxs("strong",{children:[e.jsx(Ze,{})," ",V(s)]}),e.jsx("span",{children:"TX суммарно"})]})]}),e.jsx(cs,{values:j})]}),e.jsxs("section",{className:"nf-kpi nf-kpi--traffic",children:[e.jsxs("header",{children:["Трафик за месяц ",e.jsx(J,{size:14})]}),e.jsxs("div",{className:"nf-quota-copy",children:[e.jsx("strong",{children:A(d)}),e.jsx("span",{children:t>0?`из ${A(t)}`:a?"без общего лимита":"без лимита"})]}),e.jsx("div",{className:`nf-progress${t>0?"":" is-unlimited"}`,role:"img","aria-label":t>0?`Использовано ${Math.round(p)} процентов квоты`:"Трафик без лимита",children:e.jsx("i",{style:{"--nf-progress":t>0?p/100:1}})}),e.jsx("small",{children:t>0?`${Math.round(p)}% использовано`:a?"Общий лимит не задан":"Квота не задана"})]}),e.jsxs("div",{className:"nf-kpi-pair",children:[e.jsxs("section",{className:"nf-kpi nf-kpi--connections",children:[e.jsxs("header",{children:["Соединения ",e.jsx(J,{size:14})]}),e.jsxs("div",{className:"nf-kpi__readout",children:[e.jsx("strong",{children:h===null?"—":h.toLocaleString("ru-RU")}),e.jsx("span",{children:h===null?"нет полной текущей точки":"активных · текущий срез"})]})]}),e.jsxs("section",{className:"nf-kpi nf-kpi--health",children:[e.jsxs("header",{children:["Health ",e.jsx(J,{size:14})]}),e.jsxs("div",{className:"nf-health-body",children:[e.jsx("div",{className:"nf-health-ring",style:{"--health":`${c.percent??0}%`},children:e.jsx("strong",{children:c.percent===null?"—":`${c.percent}%`})}),e.jsxs("div",{className:"nf-health-legend",children:[e.jsxs("span",{children:[e.jsx("i",{className:"is-up"}),e.jsx("b",{children:c.up})," Работает"]}),e.jsxs("span",{children:[e.jsx("i",{className:"is-warn"}),e.jsx("b",{children:c.degraded})," Деградирует"]}),e.jsxs("span",{children:[e.jsx("i",{className:"is-down"}),e.jsx("b",{children:c.down})," Недоступно"]})]})]})]})]})]})}const us={online:"Работает",degraded:"Деградирует",offline:"Недоступна"};function xs(r,s){const o=r.node.metadata,a=o&&typeof o=="object"?Number(o[s]):0;return Number.isFinite(a)?a:0}const fs=i.memo(function({item:s,previousID:o,nextID:a,reorderEnabled:d,reorderDisabledReason:t,ordering:h,dragging:c,dropTarget:j,onDragStart:p,onDragEnd:g,onDragOver:I,onDrop:z,onMove:w}){const m=me(),T=ge(),R=be(m.search),_=`/nodes/${s.node.id}${R}`,O=`/nodes/${s.node.id}/routes/new${R}`,E=G(s),x=s.latest_heartbeat,f=x?.metrics,y=f?.haproxy_runtime,u=f?.load??[],C=Number(f?.cpu_percent),$=Ee(f),F=s.rate_sampled_at?s.rx_bits_per_second:null,P=s.rate_sampled_at?s.tx_bits_per_second:null,b=s.traffic_observed?s.traffic_used_bytes:null,N=xs(s,"traffic_limit_bytes"),k=b!==null&&N>0?Math.min(100,b/N*100):0,B=()=>T(_),S=l=>l.stopPropagation(),Z=l=>l instanceof Element&&!!l.closest('a, button, input, select, textarea, [role="button"], [role="menuitem"]'),q=l=>{Z(l.target)||B()},H=l=>{l.key!=="Enter"||l.target!==l.currentTarget||(l.preventDefault(),B())};return e.jsxs("div",{className:`nf-node-row is-${E}${c?" is-dragging":""}${j?" is-drop-target":""}${h?" is-ordering":""}`,role:"row",tabIndex:0,"aria-label":`Открыть ноду ${s.node.name}`,onClick:q,onKeyDown:H,onDragOver:l=>I(l,s.node.id),onDrop:l=>z(l,s.node.id),children:[e.jsxs("div",{className:"nf-node-status",role:"cell",children:[e.jsx("i",{}),e.jsx("span",{children:us[E]})]}),e.jsxs("div",{className:"nf-node-identity-cell",role:"cell",children:[e.jsxs("div",{className:"nf-sort-controls","data-row-action":!0,children:[e.jsx(de,{label:d?"Перетащить ноду":t,openDelay:250,children:e.jsx("span",{className:"nf-sort-grip-wrap",children:e.jsx(U,{className:"nf-sort-grip",variant:"subtle",color:"gray",size:"sm",draggable:d&&!h,disabled:!d||h,"aria-label":`Перетащить ноду ${s.node.name}`,onDragStart:l=>p(l,s.node.id),onDragEnd:g,onClick:S,children:e.jsx(Fe,{size:15})})})}),e.jsxs("div",{className:"nf-sort-step-actions",children:[e.jsx(U,{variant:"subtle",color:"gray",size:"xs",disabled:!d||!o||h,"aria-label":`Переместить ${s.node.name} выше`,onClick:l=>{S(l),o&&w(s.node.id,o)},children:e.jsx(Le,{size:12})}),e.jsx(U,{variant:"subtle",color:"gray",size:"xs",disabled:!d||!a||h,"aria-label":`Переместить ${s.node.name} ниже`,onClick:l=>{S(l),a&&w(s.node.id,a)},children:e.jsx(Ne,{size:12})})]})]}),e.jsxs(ve,{className:"nf-node-identity",to:_,children:[e.jsx("strong",{children:s.node.name}),e.jsx("span",{children:s.node.address}),e.jsxs("small",{children:["ответ ",Ge(s.node.last_seen_at)]})]})]}),e.jsxs("div",{className:"nf-node-number",role:"cell",children:[e.jsx("strong",{children:K(s.routes_total)}),e.jsxs("span",{children:[s.routes_enabled," включено"]})]}),e.jsxs("div",{className:"nf-node-number",role:"cell",children:[e.jsx("strong",{children:K(y?.connections_current)}),e.jsx("span",{children:y?.connection_rate==null?"нет rate":`${K(y.connection_rate)} новых/с`})]}),e.jsx(de,{label:`Load 1 / 5 / 15: ${u.map(l=>K(l,2)).join(" · ")} · RAM ${A($.used)} / ${A($.total)}`,openDelay:350,children:e.jsxs("div",{className:"nf-node-system",role:"cell",tabIndex:0,children:[e.jsxs("div",{children:[e.jsx("small",{children:"CPU"}),e.jsx("strong",{children:Number.isFinite(C)?`${K(C)}%`:"—"})]}),e.jsxs("div",{children:[e.jsx("small",{children:"RAM"}),e.jsx("strong",{children:($.total??0)>0?`${A($.used)} / ${A($.total)}`:"—"})]})]})}),e.jsxs("div",{className:"nf-node-network",role:"cell",children:[e.jsxs("strong",{children:["↓ ",V(F)]}),e.jsxs("span",{children:["↑ ",V(P)]})]}),e.jsxs("div",{className:"nf-node-traffic",role:"cell",children:[e.jsxs("div",{children:[e.jsx("strong",{children:A(b)}),e.jsx("span",{children:N>0?`/ ${A(N)}`:"без лимита"})]}),e.jsx("div",{className:`nf-progress${N>0?"":" is-unlimited"}`,role:"img","aria-label":N>0?`Использовано ${Math.round(k)} процентов квоты`:"Трафик без лимита",children:e.jsx("i",{style:{"--nf-progress":N>0?k/100:1}})}),e.jsx("small",{children:N>0?`${Math.round(k)}%`:s.traffic_month||"нет данных"})]}),e.jsxs("div",{className:"nf-node-version",role:"cell",title:f?.haproxy_version,children:[e.jsxs("strong",{children:["HAProxy ",Ke(f?.haproxy_version)]}),e.jsxs("span",{children:["Agent ",x?.agent_version??"—"]})]}),e.jsx("div",{className:"nf-node-actions",role:"cell",children:e.jsxs(M,{position:"bottom-end",withinPortal:!0,shadow:"md",children:[e.jsx(M.Target,{children:e.jsx(U,{variant:"subtle",color:"gray","aria-label":`Действия: ${s.node.name}`,onClick:S,children:e.jsx(Ue,{size:18})})}),e.jsxs(M.Dropdown,{onClick:S,children:[e.jsx(M.Item,{leftSection:e.jsx(is,{size:16}),onClick:B,children:"Открыть ноду"}),e.jsx(M.Item,{leftSection:e.jsx(Ye,{size:16}),onClick:()=>T(O),children:"Добавить маршрут"}),e.jsx(M.Item,{leftSection:e.jsx(_e,{size:16}),onClick:()=>T(`${_}#operations`),children:"Управление нодой"})]})]})})]})});function hs({nodes:r,page:s,pageSize:o,total:a,onPageChange:d,reorderEnabled:t,reorderDisabledReason:h,orderingNodeID:c="",onReorder:j}){const p=Math.max(1,Math.ceil(a/o)),[g,I]=i.useState(""),[z,w]=i.useState(""),m=i.useRef({reorderEnabled:t,orderingNodeID:c,draggingID:g,onReorder:j});m.current={reorderEnabled:t,orderingNodeID:c,draggingID:g,onReorder:j};const T=i.useCallback((x,f)=>{const{reorderEnabled:y,orderingNodeID:u}=m.current;!y||u||(x.stopPropagation(),x.dataTransfer.effectAllowed="move",x.dataTransfer.setData("text/plain",f),m.current.draggingID=f,I(f))},[]),R=i.useCallback((x,f)=>{const{reorderEnabled:y,draggingID:u}=m.current;!y||!u||f===u||(x.preventDefault(),x.dataTransfer.dropEffect="move",w(f))},[]),_=i.useCallback((x,f)=>{x.preventDefault(),x.stopPropagation();const{reorderEnabled:y,draggingID:u,onReorder:C}=m.current,$=u||x.dataTransfer.getData("text/plain");m.current.draggingID="",I(""),w(""),y&&$&&$!==f&&C($,f)},[]),O=i.useCallback(()=>{m.current.draggingID="",I(""),w("")},[]),E=i.useCallback((x,f)=>{m.current.onReorder(x,f)},[]);return e.jsxs("div",{className:"nf-nodes-table",role:"table","aria-label":"Ноды","aria-colcount":9,"aria-rowcount":r.length+1,children:[e.jsxs("div",{className:"nf-nodes-head",role:"row",children:[e.jsx("span",{role:"columnheader",children:"Статус"}),e.jsx("span",{role:"columnheader",children:"Нода"}),e.jsx("span",{role:"columnheader",children:"Маршруты"}),e.jsx("span",{role:"columnheader",children:"Соединения"}),e.jsx("span",{role:"columnheader",children:"CPU / RAM"}),e.jsx("span",{role:"columnheader",children:"RX / TX"}),e.jsx("span",{role:"columnheader",children:"Трафик за месяц"}),e.jsx("span",{role:"columnheader",children:"HAProxy / Agent"}),e.jsx("span",{role:"columnheader","aria-label":"Действия"})]}),e.jsx("div",{className:"nf-nodes-body",role:"rowgroup",children:r.map((x,f)=>e.jsx(fs,{item:x,previousID:r[f-1]?.node.id,nextID:r[f+1]?.node.id,reorderEnabled:t,reorderDisabledReason:h,ordering:c===x.node.id,dragging:g===x.node.id,dropTarget:z===x.node.id,onDragStart:T,onDragEnd:O,onDragOver:R,onDrop:_,onMove:E},x.node.id))}),e.jsxs("footer",{className:"nf-table-footer",children:[e.jsxs("span",{children:["Показано ",a?(s-1)*o+1:0,"–",Math.min(a,s*o)," из ",a," нод"]}),e.jsx(Oe,{total:p,value:s,onChange:d,size:"sm",withEdges:!0,siblings:1,boundaries:1}),e.jsxs("span",{children:[o," / стр."]})]})]})}function he(r){return r.name?r.name:r.fallback?`Весь трафик · ${r.listener_ip||"*"}:${r.listener_port}`:r.snis[0]??`Маршрут · ${r.listener_ip||"*"}:${r.listener_port}`}function ps({routes:r}){const s=me(),o=r.slice(0,5);return e.jsxs("div",{className:"nf-ranking",children:[e.jsxs("header",{children:[e.jsx("h2",{children:"Топ маршрутов"}),e.jsx("span",{children:"RX + TX"})]}),e.jsxs("div",{className:"nf-ranking__columns","aria-hidden":"true",children:[e.jsx("span",{children:"#"}),e.jsx("span",{children:"Маршрут"}),e.jsx("span",{children:"Нода"}),e.jsx("span",{children:"Трафик"}),e.jsx("span",{children:"%"})]}),e.jsx("ol",{children:o.length?o.map((a,d)=>e.jsxs("li",{children:[e.jsx("span",{className:"nf-ranking__index",children:d+1}),e.jsxs("div",{className:"nf-ranking__route",children:[e.jsx("strong",{title:he(a),children:he(a)}),e.jsx("i",{children:e.jsx("em",{style:{width:`${Math.max(4,Math.min(100,a.share_percent))}%`}})})]}),e.jsx("span",{className:"nf-ranking__node",title:a.node_name,children:a.node_name}),e.jsx("b",{title:`За месяц: ${A(a.used_bytes)}`,children:V(a.bits_per_second)}),e.jsxs("span",{children:[Math.round(a.share_percent),"%"]})]},a.route_id)):e.jsx("li",{className:"nf-ranking__empty",children:"Маршрутов пока нет"})}),e.jsxs(ve,{to:`/traffic${be(s.search)}`,className:"nf-ranking__more",children:["Посмотреть все маршруты ",e.jsx(os,{size:16})]})]})}function js(r,s){const o=as();return es({queryKey:["overview",r,s??"all",o],queryFn:()=>ns(r,s),...Re,retry:(a,d)=>{const t="status"in Object(d)?d.status:void 0;return t!==401&&t!==404&&a<2}})}function ms(r){return r instanceof Me&&r.status===404}const te=20;function gs(r){let s=0,o=0,a=0,d=r.length>0,t=r.length>0,h=0,c=0,j=0;for(const g of r){const I=g.latest_heartbeat?.metrics,z=I?.haproxy_runtime?.connections_current;G(g)==="offline"||!Number.isFinite(z)?d=!1:s+=Number(z),o+=g.traffic_observed?g.traffic_used_bytes:0;const w=g.node.metadata,m=w&&typeof w=="object"?Number(w.traffic_limit_bytes):0;Number.isFinite(m)&&m>0?a+=m:t=!1;const T=Object.values(I?.haproxy_runtime?.backends??{});for(const R of T){const _=String(R.status??"").toUpperCase();G(g)==="offline"?j+=1:_==="UP"||_==="OPEN"?h+=1:_==="DOWN"||_==="CLOSED"||_==="MAINT"?j+=1:c+=1}}const p=h+c+j;return{connections:d?s:null,monthUsed:o,monthLimit:t?a:0,health:{percent:p?Math.round(h/p*100):null,up:h,degraded:c,down:j}}}function bs(){return e.jsxs("div",{className:"nf-overview-skeleton",children:[e.jsx(re,{height:392}),e.jsx(re,{height:392}),e.jsx(re,{height:458})]})}function Ts(){const r=ge(),[s,o]=i.useState("24h"),[a,d]=i.useState("all"),[t,h]=i.useState(""),[c,j]=i.useState("all"),[p,g]=i.useState(1),[I,z]=i.useState(!1),[w,m]=i.useState(!1),[T,R]=i.useState(!1),[_,O]=i.useState([]),[E,x]=i.useState(""),[f,y]=i.useState(""),u=js(s,a==="all"?void 0:a),C=u.data,$=i.useRef(C);a==="all"&&C&&($.current=C);const F=a!=="all"&&(ms(u.error)||!!(C&&!C.nodes.some(n=>n.node.id===a))),P=F?"all":a,b=F?$.current??C:C,N=i.useMemo(()=>b?.nodes??[],[b?.nodes]),k=i.useMemo(()=>{if(!_.length)return N;const n=new Map(_.map((v,D)=>[v,D]));return[...N].sort((v,D)=>(n.get(v.node.id)??Number.MAX_SAFE_INTEGER)-(n.get(D.node.id)??Number.MAX_SAFE_INTEGER))},[_,N]),B=P==="all"?k:k.filter(n=>n.node.id===P),S=P==="all"?void 0:B[0],Z=gs(B);let q=null,H=null;S?.rate_sampled_at?(Number.isFinite(S.rx_bits_per_second)&&(q=Number(S.rx_bits_per_second)),Number.isFinite(S.tx_bits_per_second)&&(H=Number(S.tx_bits_per_second))):P==="all"&&b?.totals.current_rate_complete===!0&&Number.isFinite(b.totals.rx_bits_per_second)&&Number.isFinite(b.totals.tx_bits_per_second)&&(q=Number(b.totals.rx_bits_per_second),H=Number(b.totals.tx_bits_per_second));const l={...Z,rx:q,tx:H,rateComplete:q!==null&&H!==null},Y=b?.traffic_history.samples??[],ye=b?.top_routes??[],L=i.useMemo(()=>k.reduce((n,v)=>(n[G(v)]+=1,n),{online:0,degraded:0,offline:0}),[k]),ee=k.filter(n=>{const v=c==="all"||G(n)===c,D=`${n.node.name} ${n.node.address}`.toLowerCase();return v&&D.includes(t.trim().toLowerCase())}),ke=ee.slice((p-1)*te,p*te),Se=Y.slice(-18).flatMap(n=>n.rx_bps===null||n.tx_bps===null?[]:[n.rx_bps+n.tx_bps]),Q=[...Y].reverse().find(n=>n.rx_bps!==null||n.tx_bps!==null),le=Q?.timestamp?Date.parse(Q.timestamp):Number.NaN,we=Math.max(45e3,(b?.traffic_history.bucket_seconds??15)*2500),Ce=!!(Q&&(!Number.isFinite(le)||Date.now()-le>we)),$e=(()=>{if(b&&u.isError||Ce)return{tone:"stale",label:"Данные устарели"};if(!Q)return{tone:"offline",label:"Нет свежих данных"};if(!l.rateComplete)return{tone:"degraded",label:"Текущие данные неполные"};if(S){const n=G(S);return n==="offline"?{tone:"offline",label:"Нода недоступна"}:n==="degraded"?{tone:"degraded",label:"Нода деградирует"}:{tone:"online",label:"Онлайн"}}return L.online===0&&L.degraded===0?{tone:"offline",label:"Ноды недоступны"}:L.degraded>0||L.offline>0?{tone:"degraded",label:"Частично доступно"}:{tone:"online",label:"Онлайн"}})(),se=n=>{j(n),g(1)};i.useEffect(()=>{const n=N.map(v=>v.node.id);O(v=>v.length===n.length&&v.every(D=>n.includes(D))?v:n)},[N]);const Ie=async(n,v)=>{if(n===v||E)return;const D=k.map(W=>W.node.id),X=[...D],ie=X.indexOf(n),ce=X.indexOf(v);if(!(ie<0||ce<0)){X.splice(ce,0,X.splice(ie,1)[0]),O(X),x(n),y("");try{await ze("/api/v1/nodes/order",{method:"PUT",body:JSON.stringify({node_ids:X})}),await u.refetch()}catch(W){O(D),y(W instanceof Error?W.message:"Порядок нод не сохранён"),u.refetch()}finally{x("")}}};return i.useEffect(()=>{F&&(d("all"),R(!0))},[F]),u.isError&&De(u.error)?e.jsx(Te,{onSuccess:()=>u.refetch()}):e.jsxs("main",{className:"nf-page nf-nodes-page",children:[e.jsx(Pe,{title:"Ноды",actions:e.jsxs(e.Fragment,{children:[e.jsx(ue,{className:"nf-top-search",placeholder:"Поиск нод...",value:t,onChange:n=>{h(n.currentTarget.value),g(1)},leftSection:e.jsx(fe,{size:16}),"aria-label":"Поиск нод"}),e.jsx(pe,{value:c,onChange:se}),e.jsx(U,{variant:"default",size:"lg",onClick:()=>u.refetch(),loading:u.isFetching,"aria-label":"Обновить",children:e.jsx(rs,{size:18})}),e.jsx(U,{variant:"default",size:"lg",onClick:()=>r("/settings"),"aria-label":"Настройки",children:e.jsx(_e,{size:18})}),e.jsx(oe,{className:"nf-primary-action",leftSection:e.jsx(xe,{size:18}),onClick:()=>m(!0),children:"Добавить ноду"})]})}),T&&e.jsx(Ae,{mb:"sm",color:"yellow",icon:e.jsx(Ve,{size:17}),title:"Источник сброшен",role:"status",withCloseButton:!0,closeButtonLabel:"Скрыть уведомление",onClose:()=>R(!1),children:"Выбранная нода больше недоступна. Показана сводка всех нод."}),u.isPending&&!b?e.jsx(bs,{}):u.isError&&!F&&!b?e.jsx(ne,{title:"Не удалось загрузить ноды",description:u.error instanceof Error?u.error.message:"Panel API недоступен",tone:"error",action:e.jsx(Qe,{onClick:()=>u.refetch()})}):k.length?e.jsxs("div",{className:"nf-nodes-content",children:[e.jsxs("div",{className:"nf-overview-grid",children:[e.jsx(ae,{className:"nf-traffic-module",title:"Трафик",actions:e.jsx(We,{className:"nf-scope-select",value:P,onChange:n=>{R(!1),d(n??"all")},data:[{value:"all",label:"Все ноды"},...k.map(({node:n})=>({value:n.id,label:n.name}))],allowDeselect:!1,"aria-label":"Источник трафика"}),children:e.jsx(ss,{samples:Y,range:s,onRangeChange:o,currentRx:l.rx,currentTx:l.tx,status:$e})}),e.jsx(ae,{className:"nf-ranking-module",children:e.jsx(ps,{routes:ye})}),e.jsx(ds,{...l,aggregateScope:P==="all",trend:Se})]}),e.jsxs(ae,{className:`nf-nodes-module${I?" is-relaxed":""}`,children:[e.jsxs("div",{className:"nf-table-toolbar",children:[e.jsx(Be,{className:"nf-status-tabs",value:c,onChange:se,label:"Фильтр состояния",items:[{value:"all",label:"Все ноды",count:k.length},{value:"online",label:"Работают",count:L.online},{value:"degraded",label:"Деградируют",count:L.degraded},{value:"offline",label:"Недоступны",count:L.offline}]}),e.jsxs("div",{className:"nf-table-actions",children:[e.jsx(ue,{placeholder:"Поиск нод...",value:t,onChange:n=>{h(n.currentTarget.value),g(1)},leftSection:e.jsx(fe,{size:16}),"aria-label":"Поиск в таблице"}),e.jsx(pe,{value:c,onChange:se,compact:!0}),e.jsx(U,{variant:"default",size:"lg",onClick:()=>z(n=>!n),"aria-label":"Переключить плотность строк","aria-pressed":I,children:e.jsx(qe,{size:18})})]})]}),f&&e.jsxs("div",{className:"nf-inline-error nf-order-error",role:"alert",children:[f,e.jsx("button",{type:"button",onClick:()=>y(""),children:"Закрыть"})]}),ee.length?e.jsx(hs,{nodes:ke,page:p,pageSize:te,total:ee.length,onPageChange:g,reorderEnabled:!t.trim()&&c==="all"&&p===1,reorderDisabledReason:t.trim()||c!=="all"?"Сбросьте поиск и фильтры, чтобы менять порядок.":"Порядок можно менять на первой странице.",orderingNodeID:E,onReorder:Ie}):e.jsx(ne,{title:"Ничего не найдено",description:"Измените поиск или фильтр состояния."})]})]}):e.jsx(ne,{title:"Нод пока нет",description:"Добавьте сервер по SSH — панель установит Node Agent и HAProxy.",action:e.jsx(oe,{leftSection:e.jsx(xe,{size:17}),onClick:()=>m(!0),children:"Добавить ноду"})}),e.jsx(He,{opened:w,onClose:()=>m(!1),onInstalled:()=>u.refetch()})]})}function pe({value:r,onChange:s,compact:o=!1}){return e.jsxs(M,{position:"bottom-end",withinPortal:!0,children:[e.jsx(M.Target,{children:e.jsx(oe,{className:`nf-status-menu-trigger${o?" is-compact":""}`,variant:"default",leftSection:e.jsx(Xe,{size:17}),rightSection:e.jsx(Ne,{size:15}),children:"Фильтры"})}),e.jsxs(M.Dropdown,{children:[e.jsx(M.Label,{children:"Состояние ноды"}),[["all","Все ноды"],["online","Работают"],["degraded","Деградируют"],["offline","Недоступны"]].map(([a,d])=>e.jsx(M.Item,{className:r===a?"is-selected":"",onClick:()=>s(a),children:d},a))]})]})}export{Ts as NodesOverviewPage}; +import{c as je,j as e,r as i,u as me,a as ge,d as be,A as U,L as ve,I as _e,b as Me,l as Re,i as De,e as Te,B as oe,f as Ae,g as ze}from"./index-fgrXogF6.js";import{T as de,I as Ne,M,P as Pe}from"./PageHeader-Fvu-o_Iq.js";import{P as Oe,d as G,m as Ee,I as Fe,a as Le,b as Ue,S as Be,c as qe,A as He,e as Xe}from"./model-Dv87zZ-k.js";import{f as V,a as A,t as Ge,b as K,s as Ke,T as ue,I as Ve,S as ne,R as Qe,c as ae,d as We}from"./format-DGDz36zr.js";import{I as J,a as xe}from"./IconPlus-D0GthIF3.js";import{I as Je,a as Ze}from"./IconArrowUp-DwKi77Ll.js";import{I as Ye,u as es,a as fe,T as ss,S as re}from"./TrafficChart-84ShhOyf.js";import{l as ns,i as as}from"./useTrafficOverview-CPWkIFeU.js";import{I as rs}from"./IconServer-DmZ16e5j.js";import"./chart-react-C4b8adjg.js";import"./IconKey-DrhZ0AMo.js";import"./chart-engine-Dbh3Q7E_.js";import"./chart-renderer-CWmX7Ukt.js";const ts=[["path",{d:"M5 12l14 0",key:"svg-0"}],["path",{d:"M13 18l6 -6",key:"svg-1"}],["path",{d:"M13 6l6 6",key:"svg-2"}]],os=je("outline","arrow-right","ArrowRight",ts);const ls=[["path",{d:"M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-0"}],["path",{d:"M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6",key:"svg-1"}]],is=je("outline","eye","Eye",ls);function cs({values:r}){const s=`nf-sparkline-${i.useId().replaceAll(":","")}`;if(r.length<2)return null;const o=Math.max(...r,1),a=Math.min(...r),d=Math.max(1,o-a),t=r.map((j,p)=>({x:p/(r.length-1)*100,y:30-(j-a)/d*24})),h=t.map(({x:j,y:p})=>`${j},${p}`).join(" "),c=`M ${t.map(({x:j,y:p})=>`${j} ${p}`).join(" L ")} L 100 36 L 0 36 Z`;return e.jsxs("svg",{className:"nf-sparkline",viewBox:"0 0 100 36",preserveAspectRatio:"none","aria-hidden":"true",children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:s,x1:"0",y1:"0",x2:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:"var(--nf-accent-strong)",stopOpacity:".3"}),e.jsx("stop",{offset:"100%",stopColor:"var(--nf-accent-strong)",stopOpacity:"0"})]})}),e.jsx("path",{className:"nf-sparkline__area",d:c,fill:`url(#${s})`}),e.jsx("polyline",{points:h})]})}function ds({rx:r,tx:s,rateComplete:o,aggregateScope:a,monthUsed:d,monthLimit:t,connections:h,health:c,trend:j}){const p=t>0?Math.min(100,d/t*100):0;return e.jsxs("div",{className:"nf-kpi-stack",children:[e.jsxs("section",{className:"nf-kpi nf-kpi--speed",children:[e.jsxs("header",{children:["Общая скорость ",e.jsx(J,{size:14}),!o&&e.jsx("span",{className:"nf-kpi-rate-state",children:"Неполные данные"})]}),e.jsxs("div",{className:"nf-speed-values",children:[e.jsxs("div",{children:[e.jsxs("strong",{children:[e.jsx(Je,{})," ",V(r)]}),e.jsx("span",{children:"RX суммарно"})]}),e.jsxs("div",{children:[e.jsxs("strong",{children:[e.jsx(Ze,{})," ",V(s)]}),e.jsx("span",{children:"TX суммарно"})]})]}),e.jsx(cs,{values:j})]}),e.jsxs("section",{className:"nf-kpi nf-kpi--traffic",children:[e.jsxs("header",{children:["Трафик за месяц ",e.jsx(J,{size:14})]}),e.jsxs("div",{className:"nf-quota-copy",children:[e.jsx("strong",{children:A(d)}),e.jsx("span",{children:t>0?`из ${A(t)}`:a?"без общего лимита":"без лимита"})]}),e.jsx("div",{className:`nf-progress${t>0?"":" is-unlimited"}`,role:"img","aria-label":t>0?`Использовано ${Math.round(p)} процентов квоты`:"Трафик без лимита",children:e.jsx("i",{style:{"--nf-progress":t>0?p/100:1}})}),e.jsx("small",{children:t>0?`${Math.round(p)}% использовано`:a?"Общий лимит не задан":"Квота не задана"})]}),e.jsxs("div",{className:"nf-kpi-pair",children:[e.jsxs("section",{className:"nf-kpi nf-kpi--connections",children:[e.jsxs("header",{children:["Соединения ",e.jsx(J,{size:14})]}),e.jsxs("div",{className:"nf-kpi__readout",children:[e.jsx("strong",{children:h===null?"—":h.toLocaleString("ru-RU")}),e.jsx("span",{children:h===null?"нет полной текущей точки":"активных · текущий срез"})]})]}),e.jsxs("section",{className:"nf-kpi nf-kpi--health",children:[e.jsxs("header",{children:["Health ",e.jsx(J,{size:14})]}),e.jsxs("div",{className:"nf-health-body",children:[e.jsx("div",{className:"nf-health-ring",style:{"--health":`${c.percent??0}%`},children:e.jsx("strong",{children:c.percent===null?"—":`${c.percent}%`})}),e.jsxs("div",{className:"nf-health-legend",children:[e.jsxs("span",{children:[e.jsx("i",{className:"is-up"}),e.jsx("b",{children:c.up})," Работает"]}),e.jsxs("span",{children:[e.jsx("i",{className:"is-warn"}),e.jsx("b",{children:c.degraded})," Деградирует"]}),e.jsxs("span",{children:[e.jsx("i",{className:"is-down"}),e.jsx("b",{children:c.down})," Недоступно"]})]})]})]})]})]})}const us={online:"Работает",degraded:"Деградирует",offline:"Недоступна"};function xs(r,s){const o=r.node.metadata,a=o&&typeof o=="object"?Number(o[s]):0;return Number.isFinite(a)?a:0}const fs=i.memo(function({item:s,previousID:o,nextID:a,reorderEnabled:d,reorderDisabledReason:t,ordering:h,dragging:c,dropTarget:j,onDragStart:p,onDragEnd:g,onDragOver:I,onDrop:z,onMove:w}){const m=me(),T=ge(),R=be(m.search),_=`/nodes/${s.node.id}${R}`,O=`/nodes/${s.node.id}/routes/new${R}`,E=G(s),x=s.latest_heartbeat,f=x?.metrics,y=f?.haproxy_runtime,u=f?.load??[],C=Number(f?.cpu_percent),$=Ee(f),F=s.rate_sampled_at?s.rx_bits_per_second:null,P=s.rate_sampled_at?s.tx_bits_per_second:null,b=s.traffic_observed?s.traffic_used_bytes:null,N=xs(s,"traffic_limit_bytes"),k=b!==null&&N>0?Math.min(100,b/N*100):0,B=()=>T(_),S=l=>l.stopPropagation(),Z=l=>l instanceof Element&&!!l.closest('a, button, input, select, textarea, [role="button"], [role="menuitem"]'),q=l=>{Z(l.target)||B()},H=l=>{l.key!=="Enter"||l.target!==l.currentTarget||(l.preventDefault(),B())};return e.jsxs("div",{className:`nf-node-row is-${E}${c?" is-dragging":""}${j?" is-drop-target":""}${h?" is-ordering":""}`,role:"row",tabIndex:0,"aria-label":`Открыть ноду ${s.node.name}`,onClick:q,onKeyDown:H,onDragOver:l=>I(l,s.node.id),onDrop:l=>z(l,s.node.id),children:[e.jsxs("div",{className:"nf-node-status",role:"cell",children:[e.jsx("i",{}),e.jsx("span",{children:us[E]})]}),e.jsxs("div",{className:"nf-node-identity-cell",role:"cell",children:[e.jsxs("div",{className:"nf-sort-controls","data-row-action":!0,children:[e.jsx(de,{label:d?"Перетащить ноду":t,openDelay:250,children:e.jsx("span",{className:"nf-sort-grip-wrap",children:e.jsx(U,{className:"nf-sort-grip",variant:"subtle",color:"gray",size:"sm",draggable:d&&!h,disabled:!d||h,"aria-label":`Перетащить ноду ${s.node.name}`,onDragStart:l=>p(l,s.node.id),onDragEnd:g,onClick:S,children:e.jsx(Fe,{size:15})})})}),e.jsxs("div",{className:"nf-sort-step-actions",children:[e.jsx(U,{variant:"subtle",color:"gray",size:"xs",disabled:!d||!o||h,"aria-label":`Переместить ${s.node.name} выше`,onClick:l=>{S(l),o&&w(s.node.id,o)},children:e.jsx(Le,{size:12})}),e.jsx(U,{variant:"subtle",color:"gray",size:"xs",disabled:!d||!a||h,"aria-label":`Переместить ${s.node.name} ниже`,onClick:l=>{S(l),a&&w(s.node.id,a)},children:e.jsx(Ne,{size:12})})]})]}),e.jsxs(ve,{className:"nf-node-identity",to:_,children:[e.jsx("strong",{children:s.node.name}),e.jsx("span",{children:s.node.address}),e.jsxs("small",{children:["ответ ",Ge(s.node.last_seen_at)]})]})]}),e.jsxs("div",{className:"nf-node-number",role:"cell",children:[e.jsx("strong",{children:K(s.routes_total)}),e.jsxs("span",{children:[s.routes_enabled," включено"]})]}),e.jsxs("div",{className:"nf-node-number",role:"cell",children:[e.jsx("strong",{children:K(y?.connections_current)}),e.jsx("span",{children:y?.connection_rate==null?"нет rate":`${K(y.connection_rate)} новых/с`})]}),e.jsx(de,{label:`Load 1 / 5 / 15: ${u.map(l=>K(l,2)).join(" · ")} · RAM ${A($.used)} / ${A($.total)}`,openDelay:350,children:e.jsxs("div",{className:"nf-node-system",role:"cell",tabIndex:0,children:[e.jsxs("div",{children:[e.jsx("small",{children:"CPU"}),e.jsx("strong",{children:Number.isFinite(C)?`${K(C)}%`:"—"})]}),e.jsxs("div",{children:[e.jsx("small",{children:"RAM"}),e.jsx("strong",{children:($.total??0)>0?`${A($.used)} / ${A($.total)}`:"—"})]})]})}),e.jsxs("div",{className:"nf-node-network",role:"cell",children:[e.jsxs("strong",{children:["↓ ",V(F)]}),e.jsxs("span",{children:["↑ ",V(P)]})]}),e.jsxs("div",{className:"nf-node-traffic",role:"cell",children:[e.jsxs("div",{children:[e.jsx("strong",{children:A(b)}),e.jsx("span",{children:N>0?`/ ${A(N)}`:"без лимита"})]}),e.jsx("div",{className:`nf-progress${N>0?"":" is-unlimited"}`,role:"img","aria-label":N>0?`Использовано ${Math.round(k)} процентов квоты`:"Трафик без лимита",children:e.jsx("i",{style:{"--nf-progress":N>0?k/100:1}})}),e.jsx("small",{children:N>0?`${Math.round(k)}%`:s.traffic_month||"нет данных"})]}),e.jsxs("div",{className:"nf-node-version",role:"cell",title:f?.haproxy_version,children:[e.jsxs("strong",{children:["HAProxy ",Ke(f?.haproxy_version)]}),e.jsxs("span",{children:["Agent ",x?.agent_version??"—"]})]}),e.jsx("div",{className:"nf-node-actions",role:"cell",children:e.jsxs(M,{position:"bottom-end",withinPortal:!0,shadow:"md",children:[e.jsx(M.Target,{children:e.jsx(U,{variant:"subtle",color:"gray","aria-label":`Действия: ${s.node.name}`,onClick:S,children:e.jsx(Ue,{size:18})})}),e.jsxs(M.Dropdown,{onClick:S,children:[e.jsx(M.Item,{leftSection:e.jsx(is,{size:16}),onClick:B,children:"Открыть ноду"}),e.jsx(M.Item,{leftSection:e.jsx(Ye,{size:16}),onClick:()=>T(O),children:"Добавить маршрут"}),e.jsx(M.Item,{leftSection:e.jsx(_e,{size:16}),onClick:()=>T(`${_}#operations`),children:"Управление нодой"})]})]})})]})});function hs({nodes:r,page:s,pageSize:o,total:a,onPageChange:d,reorderEnabled:t,reorderDisabledReason:h,orderingNodeID:c="",onReorder:j}){const p=Math.max(1,Math.ceil(a/o)),[g,I]=i.useState(""),[z,w]=i.useState(""),m=i.useRef({reorderEnabled:t,orderingNodeID:c,draggingID:g,onReorder:j});m.current={reorderEnabled:t,orderingNodeID:c,draggingID:g,onReorder:j};const T=i.useCallback((x,f)=>{const{reorderEnabled:y,orderingNodeID:u}=m.current;!y||u||(x.stopPropagation(),x.dataTransfer.effectAllowed="move",x.dataTransfer.setData("text/plain",f),m.current.draggingID=f,I(f))},[]),R=i.useCallback((x,f)=>{const{reorderEnabled:y,draggingID:u}=m.current;!y||!u||f===u||(x.preventDefault(),x.dataTransfer.dropEffect="move",w(f))},[]),_=i.useCallback((x,f)=>{x.preventDefault(),x.stopPropagation();const{reorderEnabled:y,draggingID:u,onReorder:C}=m.current,$=u||x.dataTransfer.getData("text/plain");m.current.draggingID="",I(""),w(""),y&&$&&$!==f&&C($,f)},[]),O=i.useCallback(()=>{m.current.draggingID="",I(""),w("")},[]),E=i.useCallback((x,f)=>{m.current.onReorder(x,f)},[]);return e.jsxs("div",{className:"nf-nodes-table",role:"table","aria-label":"Ноды","aria-colcount":9,"aria-rowcount":r.length+1,children:[e.jsxs("div",{className:"nf-nodes-head",role:"row",children:[e.jsx("span",{role:"columnheader",children:"Статус"}),e.jsx("span",{role:"columnheader",children:"Нода"}),e.jsx("span",{role:"columnheader",children:"Маршруты"}),e.jsx("span",{role:"columnheader",children:"Соединения"}),e.jsx("span",{role:"columnheader",children:"CPU / RAM"}),e.jsx("span",{role:"columnheader",children:"RX / TX"}),e.jsx("span",{role:"columnheader",children:"Трафик за месяц"}),e.jsx("span",{role:"columnheader",children:"HAProxy / Agent"}),e.jsx("span",{role:"columnheader","aria-label":"Действия"})]}),e.jsx("div",{className:"nf-nodes-body",role:"rowgroup",children:r.map((x,f)=>e.jsx(fs,{item:x,previousID:r[f-1]?.node.id,nextID:r[f+1]?.node.id,reorderEnabled:t,reorderDisabledReason:h,ordering:c===x.node.id,dragging:g===x.node.id,dropTarget:z===x.node.id,onDragStart:T,onDragEnd:O,onDragOver:R,onDrop:_,onMove:E},x.node.id))}),e.jsxs("footer",{className:"nf-table-footer",children:[e.jsxs("span",{children:["Показано ",a?(s-1)*o+1:0,"–",Math.min(a,s*o)," из ",a," нод"]}),e.jsx(Oe,{total:p,value:s,onChange:d,size:"sm",withEdges:!0,siblings:1,boundaries:1}),e.jsxs("span",{children:[o," / стр."]})]})]})}function he(r){return r.name?r.name:r.fallback?`Весь трафик · ${r.listener_ip||"*"}:${r.listener_port}`:r.snis[0]??`Маршрут · ${r.listener_ip||"*"}:${r.listener_port}`}function ps({routes:r}){const s=me(),o=r.slice(0,5);return e.jsxs("div",{className:"nf-ranking",children:[e.jsxs("header",{children:[e.jsx("h2",{children:"Топ маршрутов"}),e.jsx("span",{children:"RX + TX"})]}),e.jsxs("div",{className:"nf-ranking__columns","aria-hidden":"true",children:[e.jsx("span",{children:"#"}),e.jsx("span",{children:"Маршрут"}),e.jsx("span",{children:"Нода"}),e.jsx("span",{children:"Трафик"}),e.jsx("span",{children:"%"})]}),e.jsx("ol",{children:o.length?o.map((a,d)=>e.jsxs("li",{children:[e.jsx("span",{className:"nf-ranking__index",children:d+1}),e.jsxs("div",{className:"nf-ranking__route",children:[e.jsx("strong",{title:he(a),children:he(a)}),e.jsx("i",{children:e.jsx("em",{style:{width:`${Math.max(4,Math.min(100,a.share_percent))}%`}})})]}),e.jsx("span",{className:"nf-ranking__node",title:a.node_name,children:a.node_name}),e.jsx("b",{title:`За месяц: ${A(a.used_bytes)}`,children:V(a.bits_per_second)}),e.jsxs("span",{children:[Math.round(a.share_percent),"%"]})]},a.route_id)):e.jsx("li",{className:"nf-ranking__empty",children:"Маршрутов пока нет"})}),e.jsxs(ve,{to:`/traffic${be(s.search)}`,className:"nf-ranking__more",children:["Посмотреть все маршруты ",e.jsx(os,{size:16})]})]})}function js(r,s){const o=as();return es({queryKey:["overview",r,s??"all",o],queryFn:()=>ns(r,s),...Re,retry:(a,d)=>{const t="status"in Object(d)?d.status:void 0;return t!==401&&t!==404&&a<2}})}function ms(r){return r instanceof Me&&r.status===404}const te=20;function gs(r){let s=0,o=0,a=0,d=r.length>0,t=r.length>0,h=0,c=0,j=0;for(const g of r){const I=g.latest_heartbeat?.metrics,z=I?.haproxy_runtime?.connections_current;G(g)==="offline"||!Number.isFinite(z)?d=!1:s+=Number(z),o+=g.traffic_observed?g.traffic_used_bytes:0;const w=g.node.metadata,m=w&&typeof w=="object"?Number(w.traffic_limit_bytes):0;Number.isFinite(m)&&m>0?a+=m:t=!1;const T=Object.values(I?.haproxy_runtime?.backends??{});for(const R of T){const _=String(R.status??"").toUpperCase();G(g)==="offline"?j+=1:_==="UP"||_==="OPEN"?h+=1:_==="DOWN"||_==="CLOSED"||_==="MAINT"?j+=1:c+=1}}const p=h+c+j;return{connections:d?s:null,monthUsed:o,monthLimit:t?a:0,health:{percent:p?Math.round(h/p*100):null,up:h,degraded:c,down:j}}}function bs(){return e.jsxs("div",{className:"nf-overview-skeleton",children:[e.jsx(re,{height:392}),e.jsx(re,{height:392}),e.jsx(re,{height:458})]})}function Ts(){const r=ge(),[s,o]=i.useState("24h"),[a,d]=i.useState("all"),[t,h]=i.useState(""),[c,j]=i.useState("all"),[p,g]=i.useState(1),[I,z]=i.useState(!1),[w,m]=i.useState(!1),[T,R]=i.useState(!1),[_,O]=i.useState([]),[E,x]=i.useState(""),[f,y]=i.useState(""),u=js(s,a==="all"?void 0:a),C=u.data,$=i.useRef(C);a==="all"&&C&&($.current=C);const F=a!=="all"&&(ms(u.error)||!!(C&&!C.nodes.some(n=>n.node.id===a))),P=F?"all":a,b=F?$.current??C:C,N=i.useMemo(()=>b?.nodes??[],[b?.nodes]),k=i.useMemo(()=>{if(!_.length)return N;const n=new Map(_.map((v,D)=>[v,D]));return[...N].sort((v,D)=>(n.get(v.node.id)??Number.MAX_SAFE_INTEGER)-(n.get(D.node.id)??Number.MAX_SAFE_INTEGER))},[_,N]),B=P==="all"?k:k.filter(n=>n.node.id===P),S=P==="all"?void 0:B[0],Z=gs(B);let q=null,H=null;S?.rate_sampled_at?(Number.isFinite(S.rx_bits_per_second)&&(q=Number(S.rx_bits_per_second)),Number.isFinite(S.tx_bits_per_second)&&(H=Number(S.tx_bits_per_second))):P==="all"&&b?.totals.current_rate_complete===!0&&Number.isFinite(b.totals.rx_bits_per_second)&&Number.isFinite(b.totals.tx_bits_per_second)&&(q=Number(b.totals.rx_bits_per_second),H=Number(b.totals.tx_bits_per_second));const l={...Z,rx:q,tx:H,rateComplete:q!==null&&H!==null},Y=b?.traffic_history.samples??[],ye=b?.top_routes??[],L=i.useMemo(()=>k.reduce((n,v)=>(n[G(v)]+=1,n),{online:0,degraded:0,offline:0}),[k]),ee=k.filter(n=>{const v=c==="all"||G(n)===c,D=`${n.node.name} ${n.node.address}`.toLowerCase();return v&&D.includes(t.trim().toLowerCase())}),ke=ee.slice((p-1)*te,p*te),Se=Y.slice(-18).flatMap(n=>n.rx_bps===null||n.tx_bps===null?[]:[n.rx_bps+n.tx_bps]),Q=[...Y].reverse().find(n=>n.rx_bps!==null||n.tx_bps!==null),le=Q?.timestamp?Date.parse(Q.timestamp):Number.NaN,we=Math.max(45e3,(b?.traffic_history.bucket_seconds??15)*2500),Ce=!!(Q&&(!Number.isFinite(le)||Date.now()-le>we)),$e=(()=>{if(b&&u.isError||Ce)return{tone:"stale",label:"Данные устарели"};if(!Q)return{tone:"offline",label:"Нет свежих данных"};if(!l.rateComplete)return{tone:"degraded",label:"Текущие данные неполные"};if(S){const n=G(S);return n==="offline"?{tone:"offline",label:"Нода недоступна"}:n==="degraded"?{tone:"degraded",label:"Нода деградирует"}:{tone:"online",label:"Онлайн"}}return L.online===0&&L.degraded===0?{tone:"offline",label:"Ноды недоступны"}:L.degraded>0||L.offline>0?{tone:"degraded",label:"Частично доступно"}:{tone:"online",label:"Онлайн"}})(),se=n=>{j(n),g(1)};i.useEffect(()=>{const n=N.map(v=>v.node.id);O(v=>v.length===n.length&&v.every(D=>n.includes(D))?v:n)},[N]);const Ie=async(n,v)=>{if(n===v||E)return;const D=k.map(W=>W.node.id),X=[...D],ie=X.indexOf(n),ce=X.indexOf(v);if(!(ie<0||ce<0)){X.splice(ce,0,X.splice(ie,1)[0]),O(X),x(n),y("");try{await ze("/api/v1/nodes/order",{method:"PUT",body:JSON.stringify({node_ids:X})}),await u.refetch()}catch(W){O(D),y(W instanceof Error?W.message:"Порядок нод не сохранён"),u.refetch()}finally{x("")}}};return i.useEffect(()=>{F&&(d("all"),R(!0))},[F]),u.isError&&De(u.error)?e.jsx(Te,{onSuccess:()=>u.refetch()}):e.jsxs("main",{className:"nf-page nf-nodes-page",children:[e.jsx(Pe,{title:"Ноды",actions:e.jsxs(e.Fragment,{children:[e.jsx(ue,{className:"nf-top-search",placeholder:"Поиск нод...",value:t,onChange:n=>{h(n.currentTarget.value),g(1)},leftSection:e.jsx(fe,{size:16}),"aria-label":"Поиск нод"}),e.jsx(pe,{value:c,onChange:se}),e.jsx(U,{variant:"default",size:"lg",onClick:()=>u.refetch(),loading:u.isFetching,"aria-label":"Обновить",children:e.jsx(rs,{size:18})}),e.jsx(U,{variant:"default",size:"lg",onClick:()=>r("/settings"),"aria-label":"Настройки",children:e.jsx(_e,{size:18})}),e.jsx(oe,{className:"nf-primary-action",leftSection:e.jsx(xe,{size:18}),onClick:()=>m(!0),children:"Добавить ноду"})]})}),T&&e.jsx(Ae,{mb:"sm",color:"yellow",icon:e.jsx(Ve,{size:17}),title:"Источник сброшен",role:"status",withCloseButton:!0,closeButtonLabel:"Скрыть уведомление",onClose:()=>R(!1),children:"Выбранная нода больше недоступна. Показана сводка всех нод."}),u.isPending&&!b?e.jsx(bs,{}):u.isError&&!F&&!b?e.jsx(ne,{title:"Не удалось загрузить ноды",description:u.error instanceof Error?u.error.message:"Panel API недоступен",tone:"error",action:e.jsx(Qe,{onClick:()=>u.refetch()})}):k.length?e.jsxs("div",{className:"nf-nodes-content",children:[e.jsxs("div",{className:"nf-overview-grid",children:[e.jsx(ae,{className:"nf-traffic-module",title:"Трафик",actions:e.jsx(We,{className:"nf-scope-select",value:P,onChange:n=>{R(!1),d(n??"all")},data:[{value:"all",label:"Все ноды"},...k.map(({node:n})=>({value:n.id,label:n.name}))],allowDeselect:!1,"aria-label":"Источник трафика"}),children:e.jsx(ss,{samples:Y,range:s,onRangeChange:o,currentRx:l.rx,currentTx:l.tx,status:$e})}),e.jsx(ae,{className:"nf-ranking-module",children:e.jsx(ps,{routes:ye})}),e.jsx(ds,{...l,aggregateScope:P==="all",trend:Se})]}),e.jsxs(ae,{className:`nf-nodes-module${I?" is-relaxed":""}`,children:[e.jsxs("div",{className:"nf-table-toolbar",children:[e.jsx(Be,{className:"nf-status-tabs",value:c,onChange:se,label:"Фильтр состояния",items:[{value:"all",label:"Все ноды",count:k.length},{value:"online",label:"Работают",count:L.online},{value:"degraded",label:"Деградируют",count:L.degraded},{value:"offline",label:"Недоступны",count:L.offline}]}),e.jsxs("div",{className:"nf-table-actions",children:[e.jsx(ue,{placeholder:"Поиск нод...",value:t,onChange:n=>{h(n.currentTarget.value),g(1)},leftSection:e.jsx(fe,{size:16}),"aria-label":"Поиск в таблице"}),e.jsx(pe,{value:c,onChange:se,compact:!0}),e.jsx(U,{variant:"default",size:"lg",onClick:()=>z(n=>!n),"aria-label":"Переключить плотность строк","aria-pressed":I,children:e.jsx(qe,{size:18})})]})]}),f&&e.jsxs("div",{className:"nf-inline-error nf-order-error",role:"alert",children:[f,e.jsx("button",{type:"button",onClick:()=>y(""),children:"Закрыть"})]}),ee.length?e.jsx(hs,{nodes:ke,page:p,pageSize:te,total:ee.length,onPageChange:g,reorderEnabled:!t.trim()&&c==="all"&&p===1,reorderDisabledReason:t.trim()||c!=="all"?"Сбросьте поиск и фильтры, чтобы менять порядок.":"Порядок можно менять на первой странице.",orderingNodeID:E,onReorder:Ie}):e.jsx(ne,{title:"Ничего не найдено",description:"Измените поиск или фильтр состояния."})]})]}):e.jsx(ne,{title:"Нод пока нет",description:"Добавьте сервер по SSH — панель установит Node Agent и HAProxy.",action:e.jsx(oe,{leftSection:e.jsx(xe,{size:17}),onClick:()=>m(!0),children:"Добавить ноду"})}),e.jsx(He,{opened:w,onClose:()=>m(!1),onInstalled:()=>u.refetch()})]})}function pe({value:r,onChange:s,compact:o=!1}){return e.jsxs(M,{position:"bottom-end",withinPortal:!0,children:[e.jsx(M.Target,{children:e.jsx(oe,{className:`nf-status-menu-trigger${o?" is-compact":""}`,variant:"default",leftSection:e.jsx(Xe,{size:17}),rightSection:e.jsx(Ne,{size:15}),children:"Фильтры"})}),e.jsxs(M.Dropdown,{children:[e.jsx(M.Label,{children:"Состояние ноды"}),[["all","Все ноды"],["online","Работают"],["degraded","Деградируют"],["offline","Недоступны"]].map(([a,d])=>e.jsx(M.Item,{className:r===a?"is-selected":"",onClick:()=>s(a),children:d},a))]})]})}export{Ts as NodesOverviewPage}; diff --git a/internal/panel/web_dist/assets/PageHeader-C4N9uitv.js b/internal/panel/web_dist/assets/PageHeader-Fvu-o_Iq.js similarity index 99% rename from internal/panel/web_dist/assets/PageHeader-C4N9uitv.js rename to internal/panel/web_dist/assets/PageHeader-Fvu-o_Iq.js index 75eae08..ccf7b51 100644 --- a/internal/panel/web_dist/assets/PageHeader-C4N9uitv.js +++ b/internal/panel/web_dist/assets/PageHeader-Fvu-o_Iq.js @@ -1,4 +1,4 @@ -import{a3 as mt,s as W,t as Be,j as c,y as he,v as ze,ah as zt,w as Xe,H as vt,r as S,W as In,G as pt,ai as Tn,aj as Pn,a6 as Rn,ag as Ee,ak as Ce,X as En,af as Ue,a4 as $e,q as ne,p as Gt,V as ht,z as Ht,U as Ze,al as _n,o as Ut,$ as Zt,am as jn,E as Wt,R as Ve,Z as qt,C as Vn,O as kn,c as gt}from"./index-Dy6W__Vz.js";import{q as On,r as We,F as Bn,p as An,P as Ae,u as _e,v as yt,w as Fn,x as wt,y as Ln,z as Et,o as $n,A as Xt,B as Yt,D as Kn,E as Jt,G as zn,H as Gn,J as Hn,K as Un,L as Zn,M as Wn,N as qn,Q as Xn,U as Yn,V as _t,W as Jn,X as lt,Y as Qn,Z as jt}from"./format-D6_ab21F.js";function qe(e,t){let n=e;for(;(n=n.parentElement)&&!n.matches(t););return n}function er(e,t,n){for(let r=e-1;r>=0;r-=1)if(!t[r].disabled)return r;if(n){for(let r=t.length-1;r>-1;r-=1)if(!t[r].disabled)return r}return e}function tr(e,t,n){for(let r=e+1;r{n?.(i);const l=Array.from(qe(i.currentTarget,e)?.querySelectorAll(t)||[]).filter(f=>nr(i.currentTarget,f,e)),d=l.findIndex(f=>i.currentTarget===f),u=tr(d,l,r),p=er(d,l,r);switch(i.key){case"ArrowRight":break;case"ArrowLeft":break;case"ArrowUp":{i.stopPropagation(),i.preventDefault(),l[p].focus(),o&&l[p].click();break}case"ArrowDown":{i.stopPropagation(),i.preventDefault(),l[u].focus(),o&&l[u].click();break}case"Home":{i.stopPropagation(),i.preventDefault(),!l[0].disabled&&l[0].focus();break}case"End":{i.stopPropagation(),i.preventDefault();const f=l.length-1;!l[f].disabled&&l[f].focus();break}}}}function ae(e,t){return n=>{e?.(n),t?.(n)}}function rr(e,t,n){return n?Array.from(qe(n,t)?.querySelectorAll(e)||[]).findIndex(r=>r===n):null}function He(e,t,n){return t===void 0&&n===void 0?e:t!==void 0&&n===void 0?Math.max(e,t):Math.min(t===void 0&&n!==void 0?e:Math.max(e,t),n)}function en(e,t){return Array.isArray(e)?[...e].reduce((n,r)=>({...n,...en(r,t)}),{}):typeof e=="function"?e(t):e??{}}var tn={root:"m_1b7284a3"};const or=ze((e,{radius:t,shadow:n})=>({root:{"--paper-radius":t===void 0?void 0:Xe(t),"--paper-shadow":zt(n)}})),xt=mt((e,t)=>{const n=W("Paper",null,e),{classNames:r,className:o,style:a,styles:s,unstyled:i,withBorder:l,vars:d,radius:u,shadow:p,variant:f,mod:m,attributes:v,...h}=n,w=Be({name:"Paper",props:n,classes:tn,className:o,style:a,classNames:r,styles:s,unstyled:i,attributes:v,vars:d,varsResolver:or});return c.jsx(he,{ref:t,mod:[{"data-with-border":l},m],...w("root"),variant:f,...h})});xt.classes=tn;xt.displayName="@mantine/core/Paper";const[ar,be]=vt("ModalBase component was not found in tree");function sr({opened:e,transitionDuration:t}){const[n,r]=S.useState(e),o=S.useRef(-1),s=In()?0:t;return S.useEffect(()=>(e?(r(!0),window.clearTimeout(o.current)):s===0?r(!1):o.current=window.setTimeout(()=>r(!1),s),()=>window.clearTimeout(o.current)),[e,s]),n}function ir({id:e,transitionProps:t,opened:n,trapFocus:r,closeOnEscape:o,onClose:a,returnFocus:s}){const i=pt(e),[l,d]=S.useState(!1),[u,p]=S.useState(!1),f=typeof t?.duration=="number"?t?.duration:200,m=sr({opened:n,transitionDuration:f});return Tn("keydown",v=>{v.key==="Escape"&&o&&!v.isComposing&&n&&v.target?.getAttribute("data-mantine-stop-propagation")!=="true"&&a()},{capture:!0}),On({opened:n,shouldReturnFocus:r&&s}),{_id:i,titleMounted:l,bodyMounted:u,shouldLockScroll:m,setTitleMounted:d,setBodyMounted:p}}const nn=S.forwardRef(({keepMounted:e,opened:t,onClose:n,id:r,transitionProps:o,onExitTransitionEnd:a,onEnterTransitionEnd:s,trapFocus:i,closeOnEscape:l,returnFocus:d,closeOnClickOutside:u,withinPortal:p,portalProps:f,lockScroll:m,children:v,zIndex:h,shadow:w,padding:g,__vars:P,unstyled:_,removeScrollProps:j,...R},z)=>{const{_id:F,titleMounted:C,bodyMounted:V,shouldLockScroll:B,setTitleMounted:L,setBodyMounted:X}=ir({id:r,transitionProps:o,opened:t,trapFocus:i,closeOnEscape:l,onClose:n,returnFocus:d}),{key:Z,...q}=j||{};return c.jsx(We,{...f,withinPortal:p,children:c.jsx(ar,{value:{opened:t,onClose:n,closeOnClickOutside:u,onExitTransitionEnd:a,onEnterTransitionEnd:s,transitionProps:{...o,keepMounted:e},getTitleId:()=>`${F}-title`,getBodyId:()=>`${F}-body`,titleMounted:C,bodyMounted:V,setTitleMounted:L,setBodyMounted:X,trapFocus:i,closeOnEscape:l,zIndex:h,unstyled:_},children:c.jsx(Pn,{enabled:B&&m,...q,children:c.jsx(he,{ref:z,...R,__vars:{...P,"--mb-z-index":(h||Ee("modal")).toString(),"--mb-shadow":zt(w),"--mb-padding":Rn(g)},children:v})},Z)})})});nn.displayName="@mantine/core/ModalBase";var ke={title:"m_615af6c9",header:"m_b5489c3c",inner:"m_60c222c7",content:"m_fd1ab0aa",close:"m_606cb269",body:"m_5df29311"};function lr(){const e=be();return S.useEffect(()=>(e.setBodyMounted(!0),()=>e.setBodyMounted(!1)),[]),e.getBodyId()}const rn=S.forwardRef(({className:e,...t},n)=>{const r=lr(),o=be();return c.jsx(he,{ref:n,...t,id:r,className:Ce({[ke.body]:!o.unstyled},e)})});rn.displayName="@mantine/core/ModalBaseBody";const on=S.forwardRef(({className:e,onClick:t,...n},r)=>{const o=be();return c.jsx(En,{ref:r,...n,onClick:a=>{o.onClose(),t?.(a)},className:Ce({[ke.close]:!o.unstyled},e),unstyled:o.unstyled})});on.displayName="@mantine/core/ModalBaseCloseButton";const an=S.forwardRef(({transitionProps:e,className:t,innerProps:n,onKeyDown:r,style:o,...a},s)=>{const i=be();return c.jsx(Ue,{mounted:i.opened,transition:"pop",...i.transitionProps,onExited:()=>{i.onExitTransitionEnd?.(),i.transitionProps?.onExited?.()},onEntered:()=>{i.onEnterTransitionEnd?.(),i.transitionProps?.onEntered?.()},...e,children:l=>c.jsx("div",{...n,className:Ce({[ke.inner]:!i.unstyled},n.className),children:c.jsx(Bn,{active:i.opened&&i.trapFocus,innerRef:s,children:c.jsx(xt,{...a,component:"section",role:"dialog",tabIndex:-1,"aria-modal":!0,"aria-describedby":i.bodyMounted?i.getBodyId():void 0,"aria-labelledby":i.titleMounted?i.getTitleId():void 0,style:[o,l],className:Ce({[ke.content]:!i.unstyled},t),unstyled:i.unstyled,children:a.children})})})})});an.displayName="@mantine/core/ModalBaseContent";const sn=S.forwardRef(({className:e,...t},n)=>{const r=be();return c.jsx(he,{component:"header",ref:n,className:Ce({[ke.header]:!r.unstyled},e),...t})});sn.displayName="@mantine/core/ModalBaseHeader";const cr={duration:200,timingFunction:"ease",transition:"fade"};function ur(e){const t=be();return{...cr,...t.transitionProps,...e}}const ln=S.forwardRef(({onClick:e,transitionProps:t,style:n,visible:r,...o},a)=>{const s=be(),i=ur(t);return c.jsx(Ue,{mounted:r!==void 0?r:s.opened,...i,transition:"fade",children:l=>c.jsx(An,{ref:a,fixed:!0,style:[n,l],zIndex:s.zIndex,unstyled:s.unstyled,onClick:d=>{e?.(d),s.closeOnClickOutside&&s.onClose()},...o})})});ln.displayName="@mantine/core/ModalBaseOverlay";function dr(){const e=be();return S.useEffect(()=>(e.setTitleMounted(!0),()=>e.setTitleMounted(!1)),[]),e.getTitleId()}const cn=S.forwardRef(({className:e,...t},n)=>{const r=dr(),o=be();return c.jsx(he,{component:"h2",ref:n,className:Ce({[ke.title]:!o.unstyled},e),...t,id:r})});cn.displayName="@mantine/core/ModalBaseTitle";function fr({children:e}){return c.jsx(c.Fragment,{children:e})}function un({open:e,close:t,openDelay:n,closeDelay:r}){const o=S.useRef(-1),a=S.useRef(-1),s=()=>{window.clearTimeout(o.current),window.clearTimeout(a.current)},i=()=>{s(),n===0||n===void 0?e():o.current=window.setTimeout(e,n)},l=()=>{s(),r===0||r===void 0?t():a.current=window.setTimeout(t,r)};return S.useEffect(()=>s,[]),{openDropdown:i,closeDropdown:l}}function dn({style:e,size:t=16,...n}){return c.jsx("svg",{viewBox:"0 0 15 15",fill:"none",xmlns:"http://www.w3.org/2000/svg",style:{...e,width:$e(t),height:$e(t),display:"block"},...n,children:c.jsx("path",{d:"M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z",fill:"currentColor",fillRule:"evenodd",clipRule:"evenodd"})})}dn.displayName="@mantine/core/AccordionChevron";const[mr,Ie]=vt("Menu component was not found in the tree");var Te={dropdown:"m_dc9b7c9f",label:"m_9bfac126",divider:"m_efdf90cb",item:"m_99ac2aa1",itemLabel:"m_5476e0d3",itemSection:"m_8b75e504",chevron:"m_b85b0bed"};const bt=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,...i}=W("MenuDivider",null,e),l=Ie();return c.jsx(he,{ref:t,...l.getStyles("divider",{className:r,style:o,styles:a,classNames:n}),...i})});bt.classes=Te;bt.displayName="@mantine/core/MenuDivider";const St=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,onMouseEnter:i,onMouseLeave:l,onKeyDown:d,children:u,...p}=W("MenuDropdown",null,e),f=S.useRef(null),m=Ie(),v=ae(d,g=>{(g.key==="ArrowUp"||g.key==="ArrowDown")&&(g.preventDefault(),f.current?.querySelectorAll("[data-menu-item]:not(:disabled)")[0]?.focus())}),h=ae(i,()=>(m.trigger==="hover"||m.trigger==="click-hover")&&m.openDropdown()),w=ae(l,()=>(m.trigger==="hover"||m.trigger==="click-hover")&&m.closeDropdown());return c.jsxs(Ae.Dropdown,{...p,onMouseEnter:h,onMouseLeave:w,role:"menu","aria-orientation":"vertical",ref:_e(t,f),...m.getStyles("dropdown",{className:r,style:o,styles:a,classNames:n,withStaticClass:!1}),tabIndex:-1,"data-menu-dropdown":!0,onKeyDown:v,children:[m.withInitialFocusPlaceholder&&c.jsx("div",{tabIndex:-1,"data-autofocus":!0,"data-mantine-stop-propagation":!0,style:{outline:0}}),u]})});St.classes=Te;St.displayName="@mantine/core/MenuDropdown";const[vr,Ye]=Gt(),Nt=mt((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,color:i,closeMenuOnClick:l,leftSection:d,rightSection:u,children:p,disabled:f,"data-disabled":m,...v}=W("MenuItem",null,e),h=Ie(),w=Ye(),g=ht(),{dir:P}=yt(),_=S.useRef(null),j=v,R=ae(j.onClick,()=>{m||(typeof l=="boolean"?l&&h.closeDropdownImmediately():h.closeOnItemClick&&h.closeDropdownImmediately())}),z=i?g.variantColorResolver({color:i,theme:g,variant:"light"}):void 0,F=i?Ht({color:i,theme:g}):null,C=ae(j.onKeyDown,V=>{V.key==="ArrowLeft"&&w&&(w.close(),w.focusParentItem())});return c.jsxs(Ze,{onMouseDown:V=>V.preventDefault(),...v,unstyled:h.unstyled,tabIndex:h.menuItemTabIndex,...h.getStyles("item",{className:r,style:o,styles:a,classNames:n}),ref:_e(_,t),role:"menuitem",disabled:f,"data-menu-item":!0,"data-disabled":f||m||void 0,"data-mantine-stop-propagation":!0,onClick:R,onKeyDown:Qt({siblingSelector:"[data-menu-item]:not([data-disabled])",parentSelector:"[data-menu-dropdown]",activateOnFocus:!1,loop:h.loop,dir:P,orientation:"vertical",onKeyDown:C}),__vars:{"--menu-item-color":F?.isThemeColor&&F?.shade===void 0?`var(--mantine-color-${F.color}-6)`:z?.color,"--menu-item-hover":z?.hover},children:[d&&c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"left",children:d}),p&&c.jsx("div",{...h.getStyles("itemLabel",{styles:a,classNames:n}),children:p}),u&&c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"right",children:u})]})});Nt.classes=Te;Nt.displayName="@mantine/core/MenuItem";const Mt=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,...i}=W("MenuLabel",null,e),l=Ie();return c.jsx(he,{ref:t,...l.getStyles("label",{className:r,style:o,styles:a,classNames:n}),...i})});Mt.classes=Te;Mt.displayName="@mantine/core/MenuLabel";const Dt=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,onMouseEnter:i,onMouseLeave:l,onKeyDown:d,children:u,...p}=W("MenuSubDropdown",null,e),f=S.useRef(null),m=Ie(),v=Ye(),h=ae(i,v?.open),w=ae(l,v?.close);return c.jsx(Ae.Dropdown,{...p,onMouseEnter:h,onMouseLeave:w,role:"menu","aria-orientation":"vertical",ref:_e(t,f),...m.getStyles("dropdown",{className:r,style:o,styles:a,classNames:n,withStaticClass:!1}),tabIndex:-1,"data-menu-dropdown":!0,children:u})});Dt.classes=Te;Dt.displayName="@mantine/core/MenuSubDropdown";const Ct=mt((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,color:i,leftSection:l,rightSection:d,children:u,disabled:p,"data-disabled":f,closeMenuOnClick:m,...v}=W("MenuSubItem",null,e),h=Ie(),w=Ye(),g=ht(),{dir:P}=yt(),_=S.useRef(null),j=v,R=i?g.variantColorResolver({color:i,theme:g,variant:"light"}):void 0,z=i?Ht({color:i,theme:g}):null,F=ae(j.onKeyDown,L=>{L.key==="ArrowRight"&&(w?.open(),w?.focusFirstItem()),L.key==="ArrowLeft"&&w?.parentContext&&(w.parentContext.close(),w.parentContext.focusParentItem())}),C=ae(j.onClick,()=>{!f&&m&&h.closeDropdownImmediately()}),V=ae(j.onMouseEnter,w?.open),B=ae(j.onMouseLeave,w?.close);return c.jsxs(Ze,{onMouseDown:L=>L.preventDefault(),...v,unstyled:h.unstyled,tabIndex:h.menuItemTabIndex,...h.getStyles("item",{className:r,style:o,styles:a,classNames:n}),ref:_e(_,t),role:"menuitem",disabled:p,"data-menu-item":!0,"data-sub-menu-item":!0,"data-disabled":p||f||void 0,"data-mantine-stop-propagation":!0,onMouseEnter:V,onMouseLeave:B,onClick:C,onKeyDown:Qt({siblingSelector:"[data-menu-item]:not([data-disabled])",parentSelector:"[data-menu-dropdown]",activateOnFocus:!1,loop:h.loop,dir:P,orientation:"vertical",onKeyDown:F}),__vars:{"--menu-item-color":z?.isThemeColor&&z?.shade===void 0?`var(--mantine-color-${z.color}-6)`:R?.color,"--menu-item-hover":R?.hover},children:[l&&c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"left",children:l}),u&&c.jsx("div",{...h.getStyles("itemLabel",{styles:a,classNames:n}),children:u}),c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"right",children:d||c.jsx(dn,{...h.getStyles("chevron"),size:14})})]})});Ct.classes=Te;Ct.displayName="@mantine/core/MenuSubItem";function fn({children:e,refProp:t}){if(!Fn(e))throw new Error("Menu.Sub.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");return Ie(),c.jsx(Ae.Target,{refProp:t,popupType:"menu",children:e})}fn.displayName="@mantine/core/MenuSubTarget";const pr={offset:0,position:"right-start",transitionProps:{duration:0},openDelay:0,middlewares:{shift:{crossAxis:!0}}};function Fe(e){const{children:t,closeDelay:n,openDelay:r,...o}=W("MenuSub",pr,e),a=pt(),[s,{open:i,close:l}]=_n(!1),d=Ye(),{openDropdown:u,closeDropdown:p}=un({open:i,close:l,closeDelay:n,openDelay:r}),f=()=>window.setTimeout(()=>{document.getElementById(`${a}-dropdown`)?.querySelectorAll("[data-menu-item]:not([data-disabled])")[0]?.focus()},16),m=()=>window.setTimeout(()=>{document.getElementById(`${a}-target`)?.focus()},16);return c.jsx(vr,{value:{opened:s,close:p,open:u,focusFirstItem:f,focusParentItem:m,parentContext:d},children:c.jsx(Ae,{opened:s,withinPortal:!1,withArrow:!1,id:a,...o,children:t})})}Fe.extend=e=>e;Fe.displayName="@mantine/core/MenuSub";Fe.Target=fn;Fe.Dropdown=Dt;Fe.Item=Ct;const hr={refProp:"ref"},mn=S.forwardRef((e,t)=>{const{children:n,refProp:r,...o}=W("MenuTarget",hr,e),a=wt(n);if(!a)throw new Error("Menu.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const s=Ie(),i=a.props,l=ae(i.onClick,()=>{s.trigger==="click"?s.toggleDropdown():s.trigger==="click-hover"&&(s.setOpenedViaClick(!0),s.opened||s.openDropdown())}),d=ae(i.onMouseEnter,()=>(s.trigger==="hover"||s.trigger==="click-hover")&&s.openDropdown()),u=ae(i.onMouseLeave,()=>{(s.trigger==="hover"||s.trigger==="click-hover"&&!s.openedViaClick)&&s.closeDropdown()});return c.jsx(Ae.Target,{refProp:r,popupType:"menu",ref:t,...o,children:S.cloneElement(a,{onClick:l,onMouseEnter:d,onMouseLeave:u,"data-expanded":s.opened?!0:void 0})})});mn.displayName="@mantine/core/MenuTarget";const gr={trapFocus:!0,closeOnItemClick:!0,withInitialFocusPlaceholder:!0,clickOutsideEvents:["mousedown","touchstart","keydown"],loop:!0,trigger:"click",openDelay:0,closeDelay:100,menuItemTabIndex:-1};function fe(e){const t=W("Menu",gr,e),{children:n,onOpen:r,onClose:o,opened:a,defaultOpened:s,trapFocus:i,onChange:l,closeOnItemClick:d,loop:u,closeOnEscape:p,trigger:f,openDelay:m,closeDelay:v,classNames:h,styles:w,unstyled:g,variant:P,vars:_,menuItemTabIndex:j,keepMounted:R,withInitialFocusPlaceholder:z,attributes:F,...C}=t,V=Be({name:"Menu",classes:Te,props:t,classNames:h,styles:w,unstyled:g,attributes:F}),[B,L]=Ut({value:a,defaultValue:s,finalValue:!1,onChange:l}),[X,Z]=S.useState(!1),q=()=>{L(!1),Z(!1),B&&o?.()},ee=()=>{L(!0),!B&&r?.()},M=()=>{B?q():ee()},{openDropdown:N,closeDropdown:T}=un({open:ee,close:q,closeDelay:v,openDelay:m}),$=G=>rr("[data-menu-item]","[data-menu-dropdown]",G),{resolvedClassNames:O,resolvedStyles:E}=Zt({classNames:h,styles:w,props:t});return c.jsx(mr,{value:{getStyles:V,opened:B,toggleDropdown:M,getItemIndex:$,openedViaClick:X,setOpenedViaClick:Z,closeOnItemClick:d,closeDropdown:f==="click"?q:T,openDropdown:f==="click"?ee:N,closeDropdownImmediately:q,loop:u,trigger:f,unstyled:g,menuItemTabIndex:j,withInitialFocusPlaceholder:z},children:c.jsx(Ae,{returnFocus:!0,...C,opened:B,onChange:M,defaultOpened:s,trapFocus:R?!1:i,closeOnEscape:p,__staticSelector:"Menu",classNames:O,styles:E,unstyled:g,variant:P,keepMounted:R,children:n})})}fe.extend=e=>e;fe.withProps=jn(fe);fe.classes=Te;fe.displayName="@mantine/core/Menu";fe.Item=Nt;fe.Label=Mt;fe.Dropdown=St;fe.Target=mn;fe.Divider=bt;fe.Sub=Fe;var Se={root:"m_9df02822",content:"m_54c44539",inner:"m_1f958f16",header:"m_d0e2b9cd"};const[yr,Le]=vt("Modal component was not found in tree"),Je=ne((e,t)=>{const n=W("ModalBody",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(rn,{ref:t,...d.getStyles("body",{classNames:r,style:a,styles:s,className:o}),...l})});Je.classes=Se;Je.displayName="@mantine/core/ModalBody";const Qe=ne((e,t)=>{const n=W("ModalCloseButton",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(on,{ref:t,...d.getStyles("close",{classNames:r,style:a,styles:s,className:o}),...l})});Qe.classes=Se;Qe.displayName="@mantine/core/ModalCloseButton";const et=ne((e,t)=>{const n=W("ModalContent",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,children:l,__hidden:d,...u}=n,p=Le(),f=p.scrollAreaComponent||fr;return c.jsx(an,{...p.getStyles("content",{className:o,style:a,styles:s,classNames:r}),innerProps:p.getStyles("inner",{className:o,style:a,styles:s,classNames:r}),"data-full-screen":p.fullScreen||void 0,"data-modal-content":!0,"data-hidden":d||void 0,ref:t,...u,children:c.jsx(f,{style:{maxHeight:p.fullScreen?"100dvh":`calc(100dvh - (${$e(p.yOffset)} * 2))`},children:l})})});et.classes=Se;et.displayName="@mantine/core/ModalContent";const tt=ne((e,t)=>{const n=W("ModalHeader",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(sn,{ref:t,...d.getStyles("header",{classNames:r,style:a,styles:s,className:o}),...l})});tt.classes=Se;tt.displayName="@mantine/core/ModalHeader";const nt=ne((e,t)=>{const n=W("ModalOverlay",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(ln,{ref:t,...d.getStyles("overlay",{classNames:r,style:a,styles:s,className:o}),...l})});nt.classes=Se;nt.displayName="@mantine/core/ModalOverlay";const wr={__staticSelector:"Modal",closeOnClickOutside:!0,withinPortal:!0,lockScroll:!0,trapFocus:!0,returnFocus:!0,closeOnEscape:!0,keepMounted:!1,zIndex:Ee("modal"),transitionProps:{duration:200,transition:"fade-down"},yOffset:"5dvh"},xr=ze((e,{radius:t,size:n,yOffset:r,xOffset:o})=>({root:{"--modal-radius":t===void 0?void 0:Xe(t),"--modal-size":Wt(n,"modal-size"),"--modal-y-offset":$e(r),"--modal-x-offset":$e(o)}})),rt=ne((e,t)=>{const n=W("ModalRoot",wr,e),{classNames:r,className:o,style:a,styles:s,unstyled:i,vars:l,yOffset:d,scrollAreaComponent:u,radius:p,fullScreen:f,centered:m,xOffset:v,__staticSelector:h,attributes:w,...g}=n,P=Be({name:h,classes:Se,props:n,className:o,style:a,classNames:r,styles:s,unstyled:i,attributes:w,vars:l,varsResolver:xr});return c.jsx(yr,{value:{yOffset:d,scrollAreaComponent:u,getStyles:P,fullScreen:f},children:c.jsx(nn,{ref:t,...P("root"),"data-full-screen":f||void 0,"data-centered":m||void 0,"data-offset-scrollbars":u===Ln.Autosize||void 0,unstyled:i,...g})})});rt.classes=Se;rt.displayName="@mantine/core/ModalRoot";const[br,Sr]=Gt();function vn({children:e}){const[t,n]=S.useState([]),[r,o]=S.useState(Ee("modal"));return c.jsx(br,{value:{stack:t,addModal:(a,s)=>{n(i=>[...new Set([...i,a])]),o(i=>typeof s=="number"&&typeof i=="number"?Math.max(i,s):i)},removeModal:a=>n(s=>s.filter(i=>i!==a)),getZIndex:a=>`calc(${r} + ${t.indexOf(a)} + 1)`,currentId:t[t.length-1],maxZIndex:r},children:e})}vn.displayName="@mantine/core/ModalStack";const ot=ne((e,t)=>{const n=W("ModalTitle",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(cn,{ref:t,...d.getStyles("title",{classNames:r,style:a,styles:s,className:o}),...l})});ot.classes=Se;ot.displayName="@mantine/core/ModalTitle";const Nr={closeOnClickOutside:!0,withinPortal:!0,lockScroll:!0,trapFocus:!0,returnFocus:!0,closeOnEscape:!0,keepMounted:!1,zIndex:Ee("modal"),transitionProps:{duration:200,transition:"fade-down"},withOverlay:!0,withCloseButton:!0},ge=ne((e,t)=>{const{title:n,withOverlay:r,overlayProps:o,withCloseButton:a,closeButtonProps:s,children:i,radius:l,opened:d,stackId:u,zIndex:p,...f}=W("Modal",Nr,e),m=Sr(),v=!!n||a,h=m&&u?{closeOnEscape:m.currentId===u,trapFocus:m.currentId===u,zIndex:m.getZIndex(u)}:{},w=r===!1?!1:u&&m?m.currentId===u:d;return S.useEffect(()=>{m&&u&&(d?m.addModal(u,p||Ee("modal")):m.removeModal(u))},[d,u,p]),c.jsxs(rt,{ref:t,radius:l,opened:d,zIndex:m&&u?m.getZIndex(u):p,...f,...h,children:[r&&c.jsx(nt,{visible:w,transitionProps:m&&u?{duration:0}:void 0,...o}),c.jsxs(et,{radius:l,__hidden:m&&u&&d?u!==m.currentId:!1,children:[v&&c.jsxs(tt,{children:[n&&c.jsx(ot,{children:n}),a&&c.jsx(Qe,{...s})]}),c.jsx(Je,{children:i})]})]})});ge.classes=Se;ge.displayName="@mantine/core/Modal";ge.Root=rt;ge.Overlay=nt;ge.Content=et;ge.Body=Je;ge.Header=tt;ge.Title=ot;ge.CloseButton=Qe;ge.Stack=vn;function pn(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o=i?o=o+kt("0",s-i):o=(o.substring(0,s)||"0")+"."+o.substring(s),n+o}function Ot(e,t,n){if(["","-"].indexOf(e)!==-1)return e;var r=(e.indexOf(".")!==-1||n)&&t,o=It(e),a=o.beforeDecimal,s=o.afterDecimal,i=o.hasNegation,l=parseFloat("0."+(s||"0")),d=s.length<=t?"0."+s:l.toFixed(t),u=d.split("."),p=a;a&&Number(u[0])&&(p=a.split("").reverse().reduce(function(h,w,g){return h.length>g?(Number(h[0])+Number(w)).toString()+h.substring(1,h.length):w+h},u[0]));var f=yn(u[1]||"",t,n),m=i?"-":"",v=r?".":"";return""+m+p+v+f}function Re(e,t){if(e.value=e.value,e!==null){if(e.createTextRange){var n=e.createTextRange();return n.move("character",t),n.select(),!0}return e.selectionStart||e.selectionStart===0?(e.focus(),e.setSelectionRange(t,t),!0):(e.focus(),!1)}}var xn=Mr(function(e,t){for(var n=0,r=0,o=e.length,a=t.length;e[n]===t[n]&&nn&&o-r>n;)r++;return{from:{start:n,end:o-r},to:{start:n,end:a-r}}}),Pr=function(e,t){var n=Math.min(e.selectionStart,t);return{from:{start:n,end:e.selectionEnd},to:{start:n,end:t}}};function Rr(e,t,n){return Math.min(Math.max(e,t),n)}function ct(e){return Math.max(e.selectionStart,e.selectionEnd)}function Er(){return typeof navigator<"u"&&!(navigator.platform&&/iPhone|iPod/.test(navigator.platform))}function _r(e){return{from:{start:0,end:0},to:{start:0,end:e.length},lastValue:""}}function jr(e){var t=e.currentValue,n=e.formattedValue,r=e.currentValueIndex,o=e.formattedValueIndex;return t[r]===n[o]}function Vr(e,t,n,r,o,a,s){s===void 0&&(s=jr);var i=o.findIndex(function(j){return j}),l=e.slice(0,i);!t&&!n.startsWith(l)&&(t=l,n=l+n,r=r+l.length);for(var d=n.length,u=e.length,p={},f=new Array(d),m=0;m0&&f[g]===-1;)g--;var _=g===-1||f[g]===-1?0:f[g]+1;return _>P?P:r-_=0&&!n[t];)t--;t===-1&&(t=n.indexOf(!0))}else{for(;t<=o&&!n[t];)t++;t>o&&(t=n.lastIndexOf(!0))}return t===-1&&(t=o),t}function kr(e){for(var t=Array.from({length:e.length+1}).map(function(){return!0}),n=0,r=t.length;nF.length-s.length||zL||p>e.length-s.length)&&(B=p),e=e.substring(0,B),e=Fr(_?"-"+e:e,o),e=(e.match(Lr(v))||[]).join("");var X=e.indexOf(v);e=e.replace(new RegExp(gn(v),"g"),function(N,T){return T===X?".":""});var Z=It(e,o),q=Z.beforeDecimal,ee=Z.afterDecimal,M=Z.addNegation;return d.end-d.start=0;r-=1)if(!t[r].disabled)return r;if(n){for(let r=t.length-1;r>-1;r-=1)if(!t[r].disabled)return r}return e}function tr(e,t,n){for(let r=e+1;r{n?.(i);const l=Array.from(qe(i.currentTarget,e)?.querySelectorAll(t)||[]).filter(f=>nr(i.currentTarget,f,e)),d=l.findIndex(f=>i.currentTarget===f),u=tr(d,l,r),p=er(d,l,r);switch(i.key){case"ArrowRight":break;case"ArrowLeft":break;case"ArrowUp":{i.stopPropagation(),i.preventDefault(),l[p].focus(),o&&l[p].click();break}case"ArrowDown":{i.stopPropagation(),i.preventDefault(),l[u].focus(),o&&l[u].click();break}case"Home":{i.stopPropagation(),i.preventDefault(),!l[0].disabled&&l[0].focus();break}case"End":{i.stopPropagation(),i.preventDefault();const f=l.length-1;!l[f].disabled&&l[f].focus();break}}}}function ae(e,t){return n=>{e?.(n),t?.(n)}}function rr(e,t,n){return n?Array.from(qe(n,t)?.querySelectorAll(e)||[]).findIndex(r=>r===n):null}function He(e,t,n){return t===void 0&&n===void 0?e:t!==void 0&&n===void 0?Math.max(e,t):Math.min(t===void 0&&n!==void 0?e:Math.max(e,t),n)}function en(e,t){return Array.isArray(e)?[...e].reduce((n,r)=>({...n,...en(r,t)}),{}):typeof e=="function"?e(t):e??{}}var tn={root:"m_1b7284a3"};const or=ze((e,{radius:t,shadow:n})=>({root:{"--paper-radius":t===void 0?void 0:Xe(t),"--paper-shadow":zt(n)}})),xt=mt((e,t)=>{const n=W("Paper",null,e),{classNames:r,className:o,style:a,styles:s,unstyled:i,withBorder:l,vars:d,radius:u,shadow:p,variant:f,mod:m,attributes:v,...h}=n,w=Be({name:"Paper",props:n,classes:tn,className:o,style:a,classNames:r,styles:s,unstyled:i,attributes:v,vars:d,varsResolver:or});return c.jsx(he,{ref:t,mod:[{"data-with-border":l},m],...w("root"),variant:f,...h})});xt.classes=tn;xt.displayName="@mantine/core/Paper";const[ar,be]=vt("ModalBase component was not found in tree");function sr({opened:e,transitionDuration:t}){const[n,r]=S.useState(e),o=S.useRef(-1),s=In()?0:t;return S.useEffect(()=>(e?(r(!0),window.clearTimeout(o.current)):s===0?r(!1):o.current=window.setTimeout(()=>r(!1),s),()=>window.clearTimeout(o.current)),[e,s]),n}function ir({id:e,transitionProps:t,opened:n,trapFocus:r,closeOnEscape:o,onClose:a,returnFocus:s}){const i=pt(e),[l,d]=S.useState(!1),[u,p]=S.useState(!1),f=typeof t?.duration=="number"?t?.duration:200,m=sr({opened:n,transitionDuration:f});return Tn("keydown",v=>{v.key==="Escape"&&o&&!v.isComposing&&n&&v.target?.getAttribute("data-mantine-stop-propagation")!=="true"&&a()},{capture:!0}),On({opened:n,shouldReturnFocus:r&&s}),{_id:i,titleMounted:l,bodyMounted:u,shouldLockScroll:m,setTitleMounted:d,setBodyMounted:p}}const nn=S.forwardRef(({keepMounted:e,opened:t,onClose:n,id:r,transitionProps:o,onExitTransitionEnd:a,onEnterTransitionEnd:s,trapFocus:i,closeOnEscape:l,returnFocus:d,closeOnClickOutside:u,withinPortal:p,portalProps:f,lockScroll:m,children:v,zIndex:h,shadow:w,padding:g,__vars:P,unstyled:_,removeScrollProps:j,...R},z)=>{const{_id:F,titleMounted:C,bodyMounted:V,shouldLockScroll:B,setTitleMounted:L,setBodyMounted:X}=ir({id:r,transitionProps:o,opened:t,trapFocus:i,closeOnEscape:l,onClose:n,returnFocus:d}),{key:Z,...q}=j||{};return c.jsx(We,{...f,withinPortal:p,children:c.jsx(ar,{value:{opened:t,onClose:n,closeOnClickOutside:u,onExitTransitionEnd:a,onEnterTransitionEnd:s,transitionProps:{...o,keepMounted:e},getTitleId:()=>`${F}-title`,getBodyId:()=>`${F}-body`,titleMounted:C,bodyMounted:V,setTitleMounted:L,setBodyMounted:X,trapFocus:i,closeOnEscape:l,zIndex:h,unstyled:_},children:c.jsx(Pn,{enabled:B&&m,...q,children:c.jsx(he,{ref:z,...R,__vars:{...P,"--mb-z-index":(h||Ee("modal")).toString(),"--mb-shadow":zt(w),"--mb-padding":Rn(g)},children:v})},Z)})})});nn.displayName="@mantine/core/ModalBase";var ke={title:"m_615af6c9",header:"m_b5489c3c",inner:"m_60c222c7",content:"m_fd1ab0aa",close:"m_606cb269",body:"m_5df29311"};function lr(){const e=be();return S.useEffect(()=>(e.setBodyMounted(!0),()=>e.setBodyMounted(!1)),[]),e.getBodyId()}const rn=S.forwardRef(({className:e,...t},n)=>{const r=lr(),o=be();return c.jsx(he,{ref:n,...t,id:r,className:Ce({[ke.body]:!o.unstyled},e)})});rn.displayName="@mantine/core/ModalBaseBody";const on=S.forwardRef(({className:e,onClick:t,...n},r)=>{const o=be();return c.jsx(En,{ref:r,...n,onClick:a=>{o.onClose(),t?.(a)},className:Ce({[ke.close]:!o.unstyled},e),unstyled:o.unstyled})});on.displayName="@mantine/core/ModalBaseCloseButton";const an=S.forwardRef(({transitionProps:e,className:t,innerProps:n,onKeyDown:r,style:o,...a},s)=>{const i=be();return c.jsx(Ue,{mounted:i.opened,transition:"pop",...i.transitionProps,onExited:()=>{i.onExitTransitionEnd?.(),i.transitionProps?.onExited?.()},onEntered:()=>{i.onEnterTransitionEnd?.(),i.transitionProps?.onEntered?.()},...e,children:l=>c.jsx("div",{...n,className:Ce({[ke.inner]:!i.unstyled},n.className),children:c.jsx(Bn,{active:i.opened&&i.trapFocus,innerRef:s,children:c.jsx(xt,{...a,component:"section",role:"dialog",tabIndex:-1,"aria-modal":!0,"aria-describedby":i.bodyMounted?i.getBodyId():void 0,"aria-labelledby":i.titleMounted?i.getTitleId():void 0,style:[o,l],className:Ce({[ke.content]:!i.unstyled},t),unstyled:i.unstyled,children:a.children})})})})});an.displayName="@mantine/core/ModalBaseContent";const sn=S.forwardRef(({className:e,...t},n)=>{const r=be();return c.jsx(he,{component:"header",ref:n,className:Ce({[ke.header]:!r.unstyled},e),...t})});sn.displayName="@mantine/core/ModalBaseHeader";const cr={duration:200,timingFunction:"ease",transition:"fade"};function ur(e){const t=be();return{...cr,...t.transitionProps,...e}}const ln=S.forwardRef(({onClick:e,transitionProps:t,style:n,visible:r,...o},a)=>{const s=be(),i=ur(t);return c.jsx(Ue,{mounted:r!==void 0?r:s.opened,...i,transition:"fade",children:l=>c.jsx(An,{ref:a,fixed:!0,style:[n,l],zIndex:s.zIndex,unstyled:s.unstyled,onClick:d=>{e?.(d),s.closeOnClickOutside&&s.onClose()},...o})})});ln.displayName="@mantine/core/ModalBaseOverlay";function dr(){const e=be();return S.useEffect(()=>(e.setTitleMounted(!0),()=>e.setTitleMounted(!1)),[]),e.getTitleId()}const cn=S.forwardRef(({className:e,...t},n)=>{const r=dr(),o=be();return c.jsx(he,{component:"h2",ref:n,className:Ce({[ke.title]:!o.unstyled},e),...t,id:r})});cn.displayName="@mantine/core/ModalBaseTitle";function fr({children:e}){return c.jsx(c.Fragment,{children:e})}function un({open:e,close:t,openDelay:n,closeDelay:r}){const o=S.useRef(-1),a=S.useRef(-1),s=()=>{window.clearTimeout(o.current),window.clearTimeout(a.current)},i=()=>{s(),n===0||n===void 0?e():o.current=window.setTimeout(e,n)},l=()=>{s(),r===0||r===void 0?t():a.current=window.setTimeout(t,r)};return S.useEffect(()=>s,[]),{openDropdown:i,closeDropdown:l}}function dn({style:e,size:t=16,...n}){return c.jsx("svg",{viewBox:"0 0 15 15",fill:"none",xmlns:"http://www.w3.org/2000/svg",style:{...e,width:$e(t),height:$e(t),display:"block"},...n,children:c.jsx("path",{d:"M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z",fill:"currentColor",fillRule:"evenodd",clipRule:"evenodd"})})}dn.displayName="@mantine/core/AccordionChevron";const[mr,Ie]=vt("Menu component was not found in the tree");var Te={dropdown:"m_dc9b7c9f",label:"m_9bfac126",divider:"m_efdf90cb",item:"m_99ac2aa1",itemLabel:"m_5476e0d3",itemSection:"m_8b75e504",chevron:"m_b85b0bed"};const bt=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,...i}=W("MenuDivider",null,e),l=Ie();return c.jsx(he,{ref:t,...l.getStyles("divider",{className:r,style:o,styles:a,classNames:n}),...i})});bt.classes=Te;bt.displayName="@mantine/core/MenuDivider";const St=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,onMouseEnter:i,onMouseLeave:l,onKeyDown:d,children:u,...p}=W("MenuDropdown",null,e),f=S.useRef(null),m=Ie(),v=ae(d,g=>{(g.key==="ArrowUp"||g.key==="ArrowDown")&&(g.preventDefault(),f.current?.querySelectorAll("[data-menu-item]:not(:disabled)")[0]?.focus())}),h=ae(i,()=>(m.trigger==="hover"||m.trigger==="click-hover")&&m.openDropdown()),w=ae(l,()=>(m.trigger==="hover"||m.trigger==="click-hover")&&m.closeDropdown());return c.jsxs(Ae.Dropdown,{...p,onMouseEnter:h,onMouseLeave:w,role:"menu","aria-orientation":"vertical",ref:_e(t,f),...m.getStyles("dropdown",{className:r,style:o,styles:a,classNames:n,withStaticClass:!1}),tabIndex:-1,"data-menu-dropdown":!0,onKeyDown:v,children:[m.withInitialFocusPlaceholder&&c.jsx("div",{tabIndex:-1,"data-autofocus":!0,"data-mantine-stop-propagation":!0,style:{outline:0}}),u]})});St.classes=Te;St.displayName="@mantine/core/MenuDropdown";const[vr,Ye]=Gt(),Nt=mt((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,color:i,closeMenuOnClick:l,leftSection:d,rightSection:u,children:p,disabled:f,"data-disabled":m,...v}=W("MenuItem",null,e),h=Ie(),w=Ye(),g=ht(),{dir:P}=yt(),_=S.useRef(null),j=v,R=ae(j.onClick,()=>{m||(typeof l=="boolean"?l&&h.closeDropdownImmediately():h.closeOnItemClick&&h.closeDropdownImmediately())}),z=i?g.variantColorResolver({color:i,theme:g,variant:"light"}):void 0,F=i?Ht({color:i,theme:g}):null,C=ae(j.onKeyDown,V=>{V.key==="ArrowLeft"&&w&&(w.close(),w.focusParentItem())});return c.jsxs(Ze,{onMouseDown:V=>V.preventDefault(),...v,unstyled:h.unstyled,tabIndex:h.menuItemTabIndex,...h.getStyles("item",{className:r,style:o,styles:a,classNames:n}),ref:_e(_,t),role:"menuitem",disabled:f,"data-menu-item":!0,"data-disabled":f||m||void 0,"data-mantine-stop-propagation":!0,onClick:R,onKeyDown:Qt({siblingSelector:"[data-menu-item]:not([data-disabled])",parentSelector:"[data-menu-dropdown]",activateOnFocus:!1,loop:h.loop,dir:P,orientation:"vertical",onKeyDown:C}),__vars:{"--menu-item-color":F?.isThemeColor&&F?.shade===void 0?`var(--mantine-color-${F.color}-6)`:z?.color,"--menu-item-hover":z?.hover},children:[d&&c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"left",children:d}),p&&c.jsx("div",{...h.getStyles("itemLabel",{styles:a,classNames:n}),children:p}),u&&c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"right",children:u})]})});Nt.classes=Te;Nt.displayName="@mantine/core/MenuItem";const Mt=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,...i}=W("MenuLabel",null,e),l=Ie();return c.jsx(he,{ref:t,...l.getStyles("label",{className:r,style:o,styles:a,classNames:n}),...i})});Mt.classes=Te;Mt.displayName="@mantine/core/MenuLabel";const Dt=ne((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,onMouseEnter:i,onMouseLeave:l,onKeyDown:d,children:u,...p}=W("MenuSubDropdown",null,e),f=S.useRef(null),m=Ie(),v=Ye(),h=ae(i,v?.open),w=ae(l,v?.close);return c.jsx(Ae.Dropdown,{...p,onMouseEnter:h,onMouseLeave:w,role:"menu","aria-orientation":"vertical",ref:_e(t,f),...m.getStyles("dropdown",{className:r,style:o,styles:a,classNames:n,withStaticClass:!1}),tabIndex:-1,"data-menu-dropdown":!0,children:u})});Dt.classes=Te;Dt.displayName="@mantine/core/MenuSubDropdown";const Ct=mt((e,t)=>{const{classNames:n,className:r,style:o,styles:a,vars:s,color:i,leftSection:l,rightSection:d,children:u,disabled:p,"data-disabled":f,closeMenuOnClick:m,...v}=W("MenuSubItem",null,e),h=Ie(),w=Ye(),g=ht(),{dir:P}=yt(),_=S.useRef(null),j=v,R=i?g.variantColorResolver({color:i,theme:g,variant:"light"}):void 0,z=i?Ht({color:i,theme:g}):null,F=ae(j.onKeyDown,L=>{L.key==="ArrowRight"&&(w?.open(),w?.focusFirstItem()),L.key==="ArrowLeft"&&w?.parentContext&&(w.parentContext.close(),w.parentContext.focusParentItem())}),C=ae(j.onClick,()=>{!f&&m&&h.closeDropdownImmediately()}),V=ae(j.onMouseEnter,w?.open),B=ae(j.onMouseLeave,w?.close);return c.jsxs(Ze,{onMouseDown:L=>L.preventDefault(),...v,unstyled:h.unstyled,tabIndex:h.menuItemTabIndex,...h.getStyles("item",{className:r,style:o,styles:a,classNames:n}),ref:_e(_,t),role:"menuitem",disabled:p,"data-menu-item":!0,"data-sub-menu-item":!0,"data-disabled":p||f||void 0,"data-mantine-stop-propagation":!0,onMouseEnter:V,onMouseLeave:B,onClick:C,onKeyDown:Qt({siblingSelector:"[data-menu-item]:not([data-disabled])",parentSelector:"[data-menu-dropdown]",activateOnFocus:!1,loop:h.loop,dir:P,orientation:"vertical",onKeyDown:F}),__vars:{"--menu-item-color":z?.isThemeColor&&z?.shade===void 0?`var(--mantine-color-${z.color}-6)`:R?.color,"--menu-item-hover":R?.hover},children:[l&&c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"left",children:l}),u&&c.jsx("div",{...h.getStyles("itemLabel",{styles:a,classNames:n}),children:u}),c.jsx("div",{...h.getStyles("itemSection",{styles:a,classNames:n}),"data-position":"right",children:d||c.jsx(dn,{...h.getStyles("chevron"),size:14})})]})});Ct.classes=Te;Ct.displayName="@mantine/core/MenuSubItem";function fn({children:e,refProp:t}){if(!Fn(e))throw new Error("Menu.Sub.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");return Ie(),c.jsx(Ae.Target,{refProp:t,popupType:"menu",children:e})}fn.displayName="@mantine/core/MenuSubTarget";const pr={offset:0,position:"right-start",transitionProps:{duration:0},openDelay:0,middlewares:{shift:{crossAxis:!0}}};function Fe(e){const{children:t,closeDelay:n,openDelay:r,...o}=W("MenuSub",pr,e),a=pt(),[s,{open:i,close:l}]=_n(!1),d=Ye(),{openDropdown:u,closeDropdown:p}=un({open:i,close:l,closeDelay:n,openDelay:r}),f=()=>window.setTimeout(()=>{document.getElementById(`${a}-dropdown`)?.querySelectorAll("[data-menu-item]:not([data-disabled])")[0]?.focus()},16),m=()=>window.setTimeout(()=>{document.getElementById(`${a}-target`)?.focus()},16);return c.jsx(vr,{value:{opened:s,close:p,open:u,focusFirstItem:f,focusParentItem:m,parentContext:d},children:c.jsx(Ae,{opened:s,withinPortal:!1,withArrow:!1,id:a,...o,children:t})})}Fe.extend=e=>e;Fe.displayName="@mantine/core/MenuSub";Fe.Target=fn;Fe.Dropdown=Dt;Fe.Item=Ct;const hr={refProp:"ref"},mn=S.forwardRef((e,t)=>{const{children:n,refProp:r,...o}=W("MenuTarget",hr,e),a=wt(n);if(!a)throw new Error("Menu.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const s=Ie(),i=a.props,l=ae(i.onClick,()=>{s.trigger==="click"?s.toggleDropdown():s.trigger==="click-hover"&&(s.setOpenedViaClick(!0),s.opened||s.openDropdown())}),d=ae(i.onMouseEnter,()=>(s.trigger==="hover"||s.trigger==="click-hover")&&s.openDropdown()),u=ae(i.onMouseLeave,()=>{(s.trigger==="hover"||s.trigger==="click-hover"&&!s.openedViaClick)&&s.closeDropdown()});return c.jsx(Ae.Target,{refProp:r,popupType:"menu",ref:t,...o,children:S.cloneElement(a,{onClick:l,onMouseEnter:d,onMouseLeave:u,"data-expanded":s.opened?!0:void 0})})});mn.displayName="@mantine/core/MenuTarget";const gr={trapFocus:!0,closeOnItemClick:!0,withInitialFocusPlaceholder:!0,clickOutsideEvents:["mousedown","touchstart","keydown"],loop:!0,trigger:"click",openDelay:0,closeDelay:100,menuItemTabIndex:-1};function fe(e){const t=W("Menu",gr,e),{children:n,onOpen:r,onClose:o,opened:a,defaultOpened:s,trapFocus:i,onChange:l,closeOnItemClick:d,loop:u,closeOnEscape:p,trigger:f,openDelay:m,closeDelay:v,classNames:h,styles:w,unstyled:g,variant:P,vars:_,menuItemTabIndex:j,keepMounted:R,withInitialFocusPlaceholder:z,attributes:F,...C}=t,V=Be({name:"Menu",classes:Te,props:t,classNames:h,styles:w,unstyled:g,attributes:F}),[B,L]=Ut({value:a,defaultValue:s,finalValue:!1,onChange:l}),[X,Z]=S.useState(!1),q=()=>{L(!1),Z(!1),B&&o?.()},ee=()=>{L(!0),!B&&r?.()},M=()=>{B?q():ee()},{openDropdown:N,closeDropdown:T}=un({open:ee,close:q,closeDelay:v,openDelay:m}),$=G=>rr("[data-menu-item]","[data-menu-dropdown]",G),{resolvedClassNames:O,resolvedStyles:E}=Zt({classNames:h,styles:w,props:t});return c.jsx(mr,{value:{getStyles:V,opened:B,toggleDropdown:M,getItemIndex:$,openedViaClick:X,setOpenedViaClick:Z,closeOnItemClick:d,closeDropdown:f==="click"?q:T,openDropdown:f==="click"?ee:N,closeDropdownImmediately:q,loop:u,trigger:f,unstyled:g,menuItemTabIndex:j,withInitialFocusPlaceholder:z},children:c.jsx(Ae,{returnFocus:!0,...C,opened:B,onChange:M,defaultOpened:s,trapFocus:R?!1:i,closeOnEscape:p,__staticSelector:"Menu",classNames:O,styles:E,unstyled:g,variant:P,keepMounted:R,children:n})})}fe.extend=e=>e;fe.withProps=jn(fe);fe.classes=Te;fe.displayName="@mantine/core/Menu";fe.Item=Nt;fe.Label=Mt;fe.Dropdown=St;fe.Target=mn;fe.Divider=bt;fe.Sub=Fe;var Se={root:"m_9df02822",content:"m_54c44539",inner:"m_1f958f16",header:"m_d0e2b9cd"};const[yr,Le]=vt("Modal component was not found in tree"),Je=ne((e,t)=>{const n=W("ModalBody",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(rn,{ref:t,...d.getStyles("body",{classNames:r,style:a,styles:s,className:o}),...l})});Je.classes=Se;Je.displayName="@mantine/core/ModalBody";const Qe=ne((e,t)=>{const n=W("ModalCloseButton",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(on,{ref:t,...d.getStyles("close",{classNames:r,style:a,styles:s,className:o}),...l})});Qe.classes=Se;Qe.displayName="@mantine/core/ModalCloseButton";const et=ne((e,t)=>{const n=W("ModalContent",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,children:l,__hidden:d,...u}=n,p=Le(),f=p.scrollAreaComponent||fr;return c.jsx(an,{...p.getStyles("content",{className:o,style:a,styles:s,classNames:r}),innerProps:p.getStyles("inner",{className:o,style:a,styles:s,classNames:r}),"data-full-screen":p.fullScreen||void 0,"data-modal-content":!0,"data-hidden":d||void 0,ref:t,...u,children:c.jsx(f,{style:{maxHeight:p.fullScreen?"100dvh":`calc(100dvh - (${$e(p.yOffset)} * 2))`},children:l})})});et.classes=Se;et.displayName="@mantine/core/ModalContent";const tt=ne((e,t)=>{const n=W("ModalHeader",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(sn,{ref:t,...d.getStyles("header",{classNames:r,style:a,styles:s,className:o}),...l})});tt.classes=Se;tt.displayName="@mantine/core/ModalHeader";const nt=ne((e,t)=>{const n=W("ModalOverlay",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(ln,{ref:t,...d.getStyles("overlay",{classNames:r,style:a,styles:s,className:o}),...l})});nt.classes=Se;nt.displayName="@mantine/core/ModalOverlay";const wr={__staticSelector:"Modal",closeOnClickOutside:!0,withinPortal:!0,lockScroll:!0,trapFocus:!0,returnFocus:!0,closeOnEscape:!0,keepMounted:!1,zIndex:Ee("modal"),transitionProps:{duration:200,transition:"fade-down"},yOffset:"5dvh"},xr=ze((e,{radius:t,size:n,yOffset:r,xOffset:o})=>({root:{"--modal-radius":t===void 0?void 0:Xe(t),"--modal-size":Wt(n,"modal-size"),"--modal-y-offset":$e(r),"--modal-x-offset":$e(o)}})),rt=ne((e,t)=>{const n=W("ModalRoot",wr,e),{classNames:r,className:o,style:a,styles:s,unstyled:i,vars:l,yOffset:d,scrollAreaComponent:u,radius:p,fullScreen:f,centered:m,xOffset:v,__staticSelector:h,attributes:w,...g}=n,P=Be({name:h,classes:Se,props:n,className:o,style:a,classNames:r,styles:s,unstyled:i,attributes:w,vars:l,varsResolver:xr});return c.jsx(yr,{value:{yOffset:d,scrollAreaComponent:u,getStyles:P,fullScreen:f},children:c.jsx(nn,{ref:t,...P("root"),"data-full-screen":f||void 0,"data-centered":m||void 0,"data-offset-scrollbars":u===Ln.Autosize||void 0,unstyled:i,...g})})});rt.classes=Se;rt.displayName="@mantine/core/ModalRoot";const[br,Sr]=Gt();function vn({children:e}){const[t,n]=S.useState([]),[r,o]=S.useState(Ee("modal"));return c.jsx(br,{value:{stack:t,addModal:(a,s)=>{n(i=>[...new Set([...i,a])]),o(i=>typeof s=="number"&&typeof i=="number"?Math.max(i,s):i)},removeModal:a=>n(s=>s.filter(i=>i!==a)),getZIndex:a=>`calc(${r} + ${t.indexOf(a)} + 1)`,currentId:t[t.length-1],maxZIndex:r},children:e})}vn.displayName="@mantine/core/ModalStack";const ot=ne((e,t)=>{const n=W("ModalTitle",null,e),{classNames:r,className:o,style:a,styles:s,vars:i,...l}=n,d=Le();return c.jsx(cn,{ref:t,...d.getStyles("title",{classNames:r,style:a,styles:s,className:o}),...l})});ot.classes=Se;ot.displayName="@mantine/core/ModalTitle";const Nr={closeOnClickOutside:!0,withinPortal:!0,lockScroll:!0,trapFocus:!0,returnFocus:!0,closeOnEscape:!0,keepMounted:!1,zIndex:Ee("modal"),transitionProps:{duration:200,transition:"fade-down"},withOverlay:!0,withCloseButton:!0},ge=ne((e,t)=>{const{title:n,withOverlay:r,overlayProps:o,withCloseButton:a,closeButtonProps:s,children:i,radius:l,opened:d,stackId:u,zIndex:p,...f}=W("Modal",Nr,e),m=Sr(),v=!!n||a,h=m&&u?{closeOnEscape:m.currentId===u,trapFocus:m.currentId===u,zIndex:m.getZIndex(u)}:{},w=r===!1?!1:u&&m?m.currentId===u:d;return S.useEffect(()=>{m&&u&&(d?m.addModal(u,p||Ee("modal")):m.removeModal(u))},[d,u,p]),c.jsxs(rt,{ref:t,radius:l,opened:d,zIndex:m&&u?m.getZIndex(u):p,...f,...h,children:[r&&c.jsx(nt,{visible:w,transitionProps:m&&u?{duration:0}:void 0,...o}),c.jsxs(et,{radius:l,__hidden:m&&u&&d?u!==m.currentId:!1,children:[v&&c.jsxs(tt,{children:[n&&c.jsx(ot,{children:n}),a&&c.jsx(Qe,{...s})]}),c.jsx(Je,{children:i})]})]})});ge.classes=Se;ge.displayName="@mantine/core/Modal";ge.Root=rt;ge.Overlay=nt;ge.Content=et;ge.Body=Je;ge.Header=tt;ge.Title=ot;ge.CloseButton=Qe;ge.Stack=vn;function pn(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o=i?o=o+kt("0",s-i):o=(o.substring(0,s)||"0")+"."+o.substring(s),n+o}function Ot(e,t,n){if(["","-"].indexOf(e)!==-1)return e;var r=(e.indexOf(".")!==-1||n)&&t,o=It(e),a=o.beforeDecimal,s=o.afterDecimal,i=o.hasNegation,l=parseFloat("0."+(s||"0")),d=s.length<=t?"0."+s:l.toFixed(t),u=d.split("."),p=a;a&&Number(u[0])&&(p=a.split("").reverse().reduce(function(h,w,g){return h.length>g?(Number(h[0])+Number(w)).toString()+h.substring(1,h.length):w+h},u[0]));var f=yn(u[1]||"",t,n),m=i?"-":"",v=r?".":"";return""+m+p+v+f}function Re(e,t){if(e.value=e.value,e!==null){if(e.createTextRange){var n=e.createTextRange();return n.move("character",t),n.select(),!0}return e.selectionStart||e.selectionStart===0?(e.focus(),e.setSelectionRange(t,t),!0):(e.focus(),!1)}}var xn=Mr(function(e,t){for(var n=0,r=0,o=e.length,a=t.length;e[n]===t[n]&&nn&&o-r>n;)r++;return{from:{start:n,end:o-r},to:{start:n,end:a-r}}}),Pr=function(e,t){var n=Math.min(e.selectionStart,t);return{from:{start:n,end:e.selectionEnd},to:{start:n,end:t}}};function Rr(e,t,n){return Math.min(Math.max(e,t),n)}function ct(e){return Math.max(e.selectionStart,e.selectionEnd)}function Er(){return typeof navigator<"u"&&!(navigator.platform&&/iPhone|iPod/.test(navigator.platform))}function _r(e){return{from:{start:0,end:0},to:{start:0,end:e.length},lastValue:""}}function jr(e){var t=e.currentValue,n=e.formattedValue,r=e.currentValueIndex,o=e.formattedValueIndex;return t[r]===n[o]}function Vr(e,t,n,r,o,a,s){s===void 0&&(s=jr);var i=o.findIndex(function(j){return j}),l=e.slice(0,i);!t&&!n.startsWith(l)&&(t=l,n=l+n,r=r+l.length);for(var d=n.length,u=e.length,p={},f=new Array(d),m=0;m0&&f[g]===-1;)g--;var _=g===-1||f[g]===-1?0:f[g]+1;return _>P?P:r-_=0&&!n[t];)t--;t===-1&&(t=n.indexOf(!0))}else{for(;t<=o&&!n[t];)t++;t>o&&(t=n.lastIndexOf(!0))}return t===-1&&(t=o),t}function kr(e){for(var t=Array.from({length:e.length+1}).map(function(){return!0}),n=0,r=t.length;nF.length-s.length||zL||p>e.length-s.length)&&(B=p),e=e.substring(0,B),e=Fr(_?"-"+e:e,o),e=(e.match(Lr(v))||[]).join("");var X=e.indexOf(v);e=e.replace(new RegExp(gn(v),"g"),function(N,T){return T===X?".":""});var Z=It(e,o),q=Z.beforeDecimal,ee=Z.afterDecimal,M=Z.addNegation;return d.end-d.start({height:0,overflow:"hidden",...e?{}:{display:"none"}});function ai({transitionDuration:e,transitionTimingFunction:s="ease",onTransitionEnd:n=()=>{},opened:a,keepMounted:i=!1}){const h=C.useRef(null),l=ri(i),[d,u]=C.useState(a?{}:l),p=o=>{jn.flushSync(()=>u(o))},r=o=>{p(v=>({...v,...o}))};function m(o){const v=e||ii(o);return{transition:`height ${v}ms ${s}, opacity ${v}ms ${s}`}}yn(()=>{typeof ot=="function"&&ot(a?()=>{r({willChange:"height",display:"block",overflow:"hidden"}),ot(()=>{const o=Vt(h);r({...m(o),height:o})})}:()=>{const o=Vt(h);r({...m(o),willChange:"height",height:o}),ot(()=>r({height:bs,overflow:"hidden"}))})},[a]);const g=o=>{if(!(o.target!==h.current||o.propertyName!=="height"))if(a){const v=Vt(h);v===d.height?p({}):r({height:v}),n()}else d.height===bs&&(p(l),n())};function f({style:o={},refKey:v="ref",...P}={}){const $=P[v],j={"aria-hidden":!a,...P,[v]:Wn(h,$),onTransitionEnd:g,style:{boxSizing:"border-box",...o,...d}};return Pn.version.startsWith("18")?a||(j.inert=""):j.inert=!a,j}return f}const oi={transitionDuration:200,transitionTimingFunction:"ease",animateOpacity:!0},dt=Ye((e,s)=>{const{children:n,in:a,transitionDuration:i,transitionTimingFunction:h,style:l,onTransitionEnd:d,animateOpacity:u,keepMounted:p,...r}=Ke("Collapse",oi,e),m=wn(),g=kn(),o=(m.respectReducedMotion?g:!1)?0:i,v=ai({opened:a,transitionDuration:o,transitionTimingFunction:h,onTransitionEnd:d,keepMounted:p});return o===0?a?t.jsx(pt,{...r,children:n}):null:t.jsx(pt,{...v({style:{opacity:a||!u?1:0,transition:u?`opacity ${o}ms ${h}`:"none",...qn(l,m)},ref:s,...r}),children:n})});dt.displayName="@mantine/core/Collapse";const[li,ns]=Ss();var At={root:"m_7cda1cd6","root--default":"m_44da308b","root--contrast":"m_e3a01f8",label:"m_1e0e6180",remove:"m_ae386778",group:"m_1dcfd90b"};const[ci,di]=Ss(),ui=Ms((e,{gap:s},{size:n})=>({group:{"--pg-gap":s!==void 0?It(s):It(n,"pg-gap")}})),is=Ye((e,s)=>{const n=Ke("PillGroup",null,e),{classNames:a,className:i,style:h,styles:l,unstyled:d,vars:u,size:p,disabled:r,attributes:m,...g}=n,o=ns()?.size||p||void 0,v=Et({name:"PillGroup",classes:At,props:n,className:i,style:h,classNames:a,styles:l,unstyled:d,attributes:m,vars:u,varsResolver:ui,stylesCtx:{size:o},rootSelector:"group"});return t.jsx(ci,{value:{size:o,disabled:r},children:t.jsx(pt,{ref:s,size:o,...v("group"),...g})})});is.classes=At;is.displayName="@mantine/core/PillGroup";const pi={variant:"default"},hi=Ms((e,{radius:s},{size:n})=>({root:{"--pill-fz":It(n,"pill-fz"),"--pill-height":It(n,"pill-height"),"--pill-radius":s===void 0?void 0:Nn(s)}})),ht=Ye((e,s)=>{const n=Ke("Pill",pi,e),{classNames:a,className:i,style:h,styles:l,unstyled:d,vars:u,variant:p,children:r,withRemoveButton:m,onRemove:g,removeButtonProps:f,radius:o,size:v,disabled:P,mod:$,attributes:j,...N}=n,x=di(),E=ns(),_=v||x?.size||void 0,b=E?.variant==="filled"?"contrast":p||"default",M=Et({name:"Pill",classes:At,props:n,className:i,style:h,classNames:a,styles:l,unstyled:d,attributes:j,vars:u,varsResolver:hi,stylesCtx:{size:_}});return t.jsxs(pt,{component:"span",ref:s,variant:b,size:_,...M("root",{variant:b}),mod:[{"with-remove":m&&!P,disabled:P||x?.disabled},$],...N,children:[t.jsx("span",{...M("label"),children:r}),m&&t.jsx($n,{variant:"transparent",radius:o,tabIndex:-1,"aria-hidden":!0,unstyled:d,...f,...M("remove",{className:f?.className,style:f?.style}),onMouseDown:I=>{I.preventDefault(),I.stopPropagation(),f?.onMouseDown?.(I)},onClick:I=>{I.stopPropagation(),g?.(),f?.onClick?.(I)}})]})});ht.classes=At;ht.displayName="@mantine/core/Pill";ht.Group=is;var Ls={field:"m_45c4369d"};const mi={type:"visible"},rs=Ye((e,s)=>{const n=Ke("PillsInputField",mi,e),{classNames:a,className:i,style:h,styles:l,unstyled:d,vars:u,type:p,disabled:r,id:m,pointer:g,mod:f,attributes:o,...v}=n,P=ns(),$=In(),j=Et({name:"PillsInputField",classes:Ls,props:n,className:i,style:h,classNames:a,styles:l,unstyled:d,attributes:o,rootSelector:"field"}),N=r||P?.disabled;return t.jsx(pt,{component:"input",ref:As(s,P?.fieldRef),"data-type":p,disabled:N,mod:[{disabled:N,pointer:g},f],...j("field"),...v,id:$?.inputId||m,"aria-invalid":P?.hasError,"aria-describedby":$?.describedBy,type:"text",onMouseDown:x=>!g&&x.stopPropagation()})});rs.classes=Ls;rs.displayName="@mantine/core/PillsInputField";const fi={size:"sm"},Mt=Ye((e,s)=>{const n=Ke("PillsInput",fi,e),{children:a,onMouseDown:i,onClick:h,size:l,disabled:d,__staticSelector:u,error:p,variant:r,...m}=n,g=C.useRef(null);return t.jsx(li,{value:{fieldRef:g,size:l,disabled:d,hasError:!!p,variant:r},children:t.jsx(Ts,{size:l,error:p,variant:r,component:"div",ref:s,"data-no-overflow":!0,onMouseDown:f=>{f.preventDefault(),i?.(f),g.current?.focus()},onClick:f=>{f.preventDefault(),f.currentTarget.closest("fieldset")?.disabled||(g.current?.focus(),h?.(f))},...m,multiline:!0,disabled:d,__staticSelector:u||"PillsInput",withAria:!1,children:a})})});Mt.displayName="@mantine/core/PillsInput";Mt.Field=rs;function bi({data:e,value:s}){const n=s.map(i=>i.trim().toLowerCase());return e.reduce((i,h)=>(Gn(h)?i.push({group:h.group,items:h.items.filter(l=>n.indexOf(l.label.toLowerCase().trim())===-1)}):n.indexOf(h.label.toLowerCase().trim())===-1&&i.push(h),i),[])}function gi(e,s){return e?s.split(new RegExp(`[${e.join("")}]`)).map(n=>n.trim()).filter(n=>n!==""):[s]}function gs({splitChars:e,allowDuplicates:s,maxTags:n,value:a,currentTags:i,isDuplicate:h,onDuplicate:l}){const d=gi(e,a),u=[];if(s)u.push(...i,...d);else{u.push(...i);for(const p of d)(h?m=>h(m,u):m=>u.some(g=>g.toLowerCase()===m.toLowerCase()))(p)?l?.(p):u.push(p)}return n?u.slice(0,n):u}const xi={maxTags:1/0,acceptValueOnBlur:!0,splitChars:[","],hiddenInputValuesDivider:",",openOnFocus:!0,size:"sm"},Tt=Ye((e,s)=>{const n=Ke("TagsInput",xi,e),{classNames:a,className:i,style:h,styles:l,unstyled:d,vars:u,size:p,value:r,defaultValue:m,onChange:g,onKeyDown:f,maxTags:o,allowDuplicates:v,onDuplicate:P,variant:$,data:j,dropdownOpened:N,defaultDropdownOpened:x,onDropdownOpen:E,onDropdownClose:_,selectFirstOptionOnChange:b,selectFirstOptionOnDropdownOpen:M,onOptionSubmit:I,comboboxProps:ue,filter:ie,limit:Z,withScrollArea:K,maxDropdownHeight:G,searchValue:pe,defaultSearchValue:le,onSearchChange:k,readOnly:X,disabled:z,splitChars:U,onFocus:Ee,onBlur:xe,onPaste:F,radius:W,rightSection:re,rightSectionWidth:_e,rightSectionPointerEvents:ae,rightSectionProps:H,leftSection:he,leftSectionWidth:y,leftSectionPointerEvents:w,leftSectionProps:V,inputContainer:D,inputWrapperOrder:S,withAsterisk:se,required:J,labelProps:ve,descriptionProps:De,errorProps:Y,wrapperProps:Fe,description:B,label:Qe,error:Lt,withErrorStyles:Ze,name:Ft,form:gt,id:be,clearable:Be,clearButtonProps:et,hiddenInputProps:ye,hiddenInputValuesDivider:ne,mod:Bt,renderOption:qe,onRemove:ze,onClear:tt,scrollAreaProps:st,acceptValueOnBlur:xt,isDuplicate:Pe,openOnFocus:_t,attributes:nt,...vt}=n,it=Sn(be),rt=Xn(j),qt=Yn(rt),yt=C.useRef(null),at=As(yt,s),oe=Kn({opened:N,defaultOpened:x,onDropdownOpen:()=>{E?.(),M&&oe.selectFirstOption()},onDropdownClose:()=>{_?.(),oe.resetSelectedOption()}}),{styleProps:zt,rest:{type:Pt,autoComplete:jt,...wt}}=Mn(vt),[O,me]=ps({value:r,defaultValue:m,finalValue:[],onChange:g}),[c,A]=ps({value:pe,defaultValue:le,finalValue:"",onChange:k}),Q=T=>{A(T),oe.resetSelectedOption()},L=Et({name:"TagsInput",classes:{},props:n,classNames:a,styles:l,unstyled:d}),{resolvedClassNames:je,resolvedStyles:q}=Tn({props:n,styles:l,classNames:a}),ee=T=>{if((Pe?Pe(T,O):O.some(ke=>ke.toLowerCase()===T.toLowerCase()))&&(P?.(T),!v)){Q("");return}O.length0&&me([...O,T]))},He=T=>{if(f?.(T),T.isPropagationStopped())return;const we=c.trim(),{length:ke}=we;if(U.includes(T.key)&&ke>0&&(me(gs({splitChars:U,allowDuplicates:v,maxTags:o,value:c,currentTags:O,isDuplicate:Pe,onDuplicate:P})),Q(""),T.preventDefault()),T.key==="Enter"&&ke>0&&!T.nativeEvent.isComposing){if(T.preventDefault(),!!document.querySelector(`#${oe.listId} [data-combobox-option][data-combobox-selected]`))return;ee(we)}T.key==="Backspace"&&ke===0&&O.length>0&&!T.nativeEvent.isComposing&&!X&&(ze?.(O[O.length-1]),me(O.slice(0,O.length-1)))},Ht=T=>{if(F?.(T),T.preventDefault(),T.clipboardData){const we=T.clipboardData.getData("text/plain");me(gs({splitChars:U,allowDuplicates:v,maxTags:o,value:`${c}${we}`,currentTags:O,isDuplicate:Pe,onDuplicate:P})),Q("")}},_n=O.map((T,we)=>t.jsx(ht,{withRemoveButton:!X,onRemove:()=>{const ke=O.slice();ke.splice(we,1),me(ke),ze?.(T)},unstyled:d,disabled:z,attributes:nt,...L("pill"),children:T},`${T}-${we}`));C.useEffect(()=>{b&&oe.selectFirstOption()},[b,O,c]);const vn=t.jsx(Ue.ClearButton,{...et,onClear:()=>{me([]),Q(""),yt.current?.focus(),oe.openDropdown(),tt?.()}});return t.jsxs(t.Fragment,{children:[t.jsxs(Ue,{store:oe,classNames:je,styles:q,unstyled:d,size:p,readOnly:X,__staticSelector:"TagsInput",attributes:nt,onOptionSubmit:T=>{I?.(T),Q(""),O.length0&&!z&&!X,rightSectionWidth:_e,rightSectionPointerEvents:ae,rightSectionProps:H,leftSection:he,leftSectionWidth:y,leftSectionPointerEvents:w,leftSectionProps:V,inputContainer:D,inputWrapperOrder:S,withAsterisk:se,required:J,labelProps:ve,descriptionProps:De,errorProps:Y,wrapperProps:Fe,description:B,label:Qe,error:Lt,withErrorStyles:Ze,__stylesApiProps:{...n,multiline:!0},id:it,mod:Bt,attributes:nt,children:t.jsxs(ht.Group,{disabled:z,unstyled:d,...L("pillsList"),children:[_n,t.jsx(Ue.EventsTarget,{autoComplete:jt,children:t.jsx(Mt.Field,{...wt,ref:at,...L("inputField"),unstyled:d,onKeyDown:He,onFocus:T=>{Ee?.(T),_t&&oe.openDropdown()},onBlur:T=>{xe?.(T),xt&&ee(c),oe.closeDropdown()},onPaste:Ht,value:c,onChange:T=>Q(T.currentTarget.value),required:J&&O.length===0,disabled:z,readOnly:X,id:it})})]})})}),t.jsx(Jn,{data:bi({data:rt,value:O}),hidden:X||z,filter:ie,search:c,limit:Z,hiddenWhenEmpty:!0,withScrollArea:K,maxDropdownHeight:G,unstyled:d,labelId:Qe?`${it}-label`:void 0,"aria-label":Qe?void 0:vt["aria-label"],renderOption:qe,scrollAreaProps:st})]}),t.jsx(Ue.HiddenInput,{name:Ft,form:gt,value:O,valuesDivider:ne,disabled:z,...ye})]})});Tt.classes={...Ts.classes,...Ue.classes};Tt.displayName="@mantine/core/TagsInput";const _i=[["path",{d:"M5 12l14 0",key:"svg-0"}],["path",{d:"M5 12l6 6",key:"svg-1"}],["path",{d:"M5 12l6 -6",key:"svg-2"}]],vi=Dt("outline","arrow-left","ArrowLeft",_i);const yi=[["path",{d:"M7 8l-4 4l4 4",key:"svg-0"}],["path",{d:"M17 8l4 4l-4 4",key:"svg-1"}],["path",{d:"M14 4l-4 16",key:"svg-2"}]],Pi=Dt("outline","code","Code",yi);const ji=[["path",{d:"M16 3l4 4l-4 4",key:"svg-0"}],["path",{d:"M10 7l10 0",key:"svg-1"}],["path",{d:"M8 13l-4 4l4 4",key:"svg-2"}],["path",{d:"M4 17l9 0",key:"svg-3"}]],wi=Dt("outline","switch-horizontal","SwitchHorizontal",ji);const ki=[["path",{d:"M21 12a9 9 0 1 0 -9 9",key:"svg-0"}],["path",{d:"M3.6 9h16.8",key:"svg-1"}],["path",{d:"M3.6 15h7.9",key:"svg-2"}],["path",{d:"M11.5 3a17 17 0 0 0 0 18",key:"svg-3"}],["path",{d:"M12.5 3a16.984 16.984 0 0 1 2.574 8.62",key:"svg-4"}],["path",{d:"M15 18a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-5"}],["path",{d:"M20.2 20.2l1.8 1.8",key:"svg-6"}]],$i=Dt("outline","world-search","WorldSearch",ki);function Fs(e,s){const n=/^v?(\d+)\.(\d+)\.(\d+)/.exec((e??"").trim());if(!n)return!0;const a=n.slice(1).map(Number),i=s.split(".").map(Number);for(let h=0;h<3;h+=1)if(a[h]!==i[h])return a[h]>i[h];return!0}const Ve=(e,s)=>e===""||!(Number(e)>0)?s:Number(e);function Ni(e){if(!e.some(p=>Ve(p.cost,0)>0||p.ipWeights.some(r=>Ve(r.cost,0)>0)))return null;const n=p=>Ve(p.weight,1)/Ve(p.cost,1),a=(p,r)=>Ve(r.weight===""?p.weight:r.weight,1)/Ve(r.cost===""?p.cost:r.cost,1),i=[];e.forEach(p=>{i.push(n(p)),p.ipWeights.forEach(r=>i.push(a(p,r)))});const h=Math.min(...i),l=Math.max(...i);let d=256/l;for(let p=1;p<=256;p++){const r=p/h;if(l*r>256+1e-9)break;if(i.every(m=>Math.abs(m*r-Math.round(m*r))<1e-6*Math.max(1,m*r))){d=r;break}}const u=p=>Math.min(256,Math.max(1,Math.round(p*d)));return e.map(p=>{const r=u(n(p));return{...p,weight:r===1?"":r,cost:"",ipWeights:p.ipWeights.map(m=>{const g=u(a(p,m));return{...m,weight:g===r?"":g,cost:""}})}})}const Bs=1024**3,Nt=1024**4,Ii=Number.MAX_SAFE_INTEGER,Si=new RegExp("^(?!-)[a-z0-9-]{1,63}(?n.trim().toLowerCase()));return s.size===1?s.has("0.0.0.0/0"):s.size===2&&s.has("0.0.0.0/0")&&s.has("::/0")}const Ce="1h",zs=20,Ai=[{value:"algorithm",label:"По алгоритму",description:"Каждое новое соединение получает сервер по алгоритму."},{value:"hash",label:"Закреплять по IP",description:"Сервер определяется IP клиента, алгоритм не нужен."},{value:"table",label:"Запоминать клиента",description:"Первый сервер выбирает алгоритм, дальше клиент остаётся на нём."}];function Ri(e){return e==="source"?"hash":e==="source_table"?"table":"algorithm"}function Oi(e){return e==="hash"?"source":e==="table"?"source_table":"none"}const Li=["1m","5m","15m","30m","1h","12h","24h"],Fi=60,Bi=168*3600;function os(e){const s=/^([1-9]\d{0,6})([smhd])$/.exec(e.trim().toLowerCase());return s?Number(s[1])*{s:1,m:60,h:3600,d:86400}[s[2]]:null}function Hs(e){const s=/^([1-9]\d{0,6})([smhd])$/.exec(e.trim().toLowerCase());if(!s)return{amount:"",unit:"m"};const n=Number(s[1]);return s[2]==="d"?{amount:n*24,unit:"h"}:{amount:n,unit:s[2]}}const Vs={s:"сек",m:"мин",h:"ч"};function qi(e){const{amount:s,unit:n}=Hs(e);return`${s} ${Vs[n]}`}const Se={k:1024,m:1024*1024},Rt={k:1e4,m:10},zi=228;function Us(e){const s=/^([1-9]\d{0,4})([km])$/.exec(e.trim().toLowerCase());return s?{amount:Number(s[1]),unit:s[2]}:{amount:"",unit:"k"}}function Ws(e){if(e==="")return!0;const{amount:s,unit:n}=Us(e);return s!==""&&s>=1&&s<=Rt[n]}const Gs="1m",Ot=Rt.m*Se.m;function Ct(e){const{amount:s,unit:n}=Us(e||Gs);return s===""?0:s*Se[n]}function Hi(e,s){const a=e&&Number.isFinite(e)&&e>0?Math.floor(e/268435456)*268435456:0;if(a<=0)return Gs;const i=Math.max(1,Math.floor(s));let h=Math.floor(Math.floor(Math.floor(a/20)/228)/i);return h=Math.max(h,100*Se.k),h>=Ot?`${Rt.m}m`:`${Math.floor(h/Se.k)}k`}function Xs(e){return e.enabled&&e.sticky_mode==="source_table"&&!e.sticky_table_entries&&e.balance_mode!=="failover"}function Ys(e,s){return Hi(s,e.filter(Xs).length+1)}function xs(e){if(e===""||!Number.isFinite(e)||e<=0)return"";const s=Math.min(Math.ceil(e),Ot);if(s%Se.m===0)return`${s/Se.m}m`;const n=Math.ceil(s/Se.k);return n<=Rt.k?`${n}k`:`${Math.ceil(s/Se.m)}m`}function Ks(e){return e.toLocaleString("ru-RU").replace(/\u00a0/g," ")}function Vi(e,s){if(!s)return"Авто: 1 000 000, RAM ноды неизвестна";const n=Math.round(Ct(e)/1e3)*1e3;return`Авто: ~${Ks(n)} клиентов (5% RAM ноды), ${Js(e)} при полной таблице`}function Js(e){const s=Ct(e);if(s===0)return"";const n=s*zi/(1024*1024);return n>=1024?`≈${(n/1024).toFixed(1).replace(".",",")} ГБ`:n>=10?`≈${Math.round(n)} МБ`:`≈${n.toFixed(1).replace(".",",")} МБ`}const Jt=[{value:"roundrobin",label:"По кругу",description:"Серверы получают клиентов по очереди, с учётом веса."},{value:"random",label:"Случайно",description:"Случайный сервер с учётом веса."},{value:"leastconn",label:"Меньше соединений",description:"Сервер, где сейчас меньше всего соединений."},{value:"leastping",label:"Меньше задержка",description:"Больше трафика серверам с меньшей задержкой (как leastLoad в Xray)."}];function Qs(e){return e==="static-rr"?"roundrobin":e}function Ui(e){return e?os(e)??"":""}const Wi=["leastconn","roundrobin"];function Gi(e){const s=e.sticky_mode??"";return s===""?e.sticky_enabled?"source":null:Wi.includes(s)?"none":s==="sni"?"source":s==="none"||s==="source"||s==="source_table"?s:null}function Xi(e){const s=e.balance_algorithm??"";if(s)return s;const n=e.sticky_mode??"";return n==="leastconn"?"leastconn":n==="roundrobin"?"roundrobin":null}const _s=[{value:"hourly",label:"Каждый час",description:"Сбрасывается в начале следующего часа."},{value:"daily",label:"Ежедневно",description:"Сбрасывается в 00:00 UTC."},{value:"calendar_month",label:"Календарный месяц",description:"Сбрасывается первого числа в 00:00 UTC."},{value:"monthly_from_creation",label:"Месяц от создания",description:"Окно начинается в дату создания маршрута."}];function Zs(e){return e.name?.trim()?e.name.trim():e.fallback?`tcp-${e.listener_port}`:e.snis[0]??e.hostname??`route-${e.listener_port}`}function Yi(e){const s=new Set(e.map(n=>n.name.trim()));for(let n=e.length+1;;n+=1)if(!s.has(`srv${n}`))return`srv${n}`}function en(e="srv1"){return{_key:St(),name:e,targetType:"tcp",host:"",port:443,unixSocketPath:"",backup:!1,dnsPool:!1,preferredIP:"",weight:"",cost:"",ipWeights:[]}}function vs(){return{name:"",matchMode:"sni",listenerIP:"*",listenerPort:443,snis:[],acceptProxyEnabled:!1,acceptProxyFrom:[],targetMode:"ip",targetHost:"",targetPort:443,unixSocketPath:"",healthCheck:!0,proxyProtocol:"none",servers:[en()],balanceMode:"pool",stickyMode:null,stickyTTL:Ce,legacyTarget:null,stickyHash:"",stickyHashBalanceFactor:"",stickyTableEntries:"",stickyIPv6Prefix:0,clientIPv6:!0,balanceAlgorithm:null,balanceRandomDraws:"",leastpingTolerancePct:"",leastpingToleranceMs:"",slowstart:"",quotaEnabled:!1,quotaValue:"",quotaUnit:"GiB",quotaPeriod:"calendar_month",quotaAction:"observe",expertOverride:"",clientBandwidthEnabled:!1,clientUploadMbps:"",clientDownloadMbps:"",shaperMode:"haproxy"}}function tn(e){const s=e.quota_bytes??0,n=s>=Nt&&s%Nt===0,a=e.listener_ip||"*",i=e.match_mode==="sni"?"sni":"fallback",h=e.target_host??"",l=e.target_type==="unix"?"unix":te(h)?"ip":"domain";let d,u=null;(e.servers??[]).length>0?d=(e.servers??[]).slice().sort((o,v)=>o.position-v.position).map(o=>({_key:o.id||St(),name:o.name,targetType:o.target_type==="unix"?"unix":"tcp",host:o.host??"",port:o.port||443,unixSocketPath:o.unix_socket_path??"",backup:!!o.backup,dnsPool:!!o.dns_pool,preferredIP:o.preferred_ip??"",weight:o.weight||"",cost:o.cost||"",ipWeights:(o.ip_weights??[]).map(v=>({ip:v.ip,weight:v.weight||"",cost:v.cost||""}))})):(u={targetType:e.target_type==="unix"?"unix":"tcp",host:h,port:e.target_port||443,unixSocketPath:e.unix_socket_path??"",dnsPool:!!e.dns_pool},d=[{_key:St(),name:"srv1",targetType:u.targetType,host:u.host,port:u.port,unixSocketPath:u.unixSocketPath,backup:!1,dnsPool:u.dnsPool,preferredIP:"",weight:"",cost:"",ipWeights:[]}]);const p=e.accept_proxy_from??[],m=qs(p)?[]:p,g=e.balance_mode==="failover"||d.some(o=>o.backup)?"failover":"pool";g==="failover"&&d.length>1&&!d.some(o=>o.backup)&&(d=rn(d));const f={name:Zs(e),matchMode:i,listenerIP:a,listenerPort:e.listener_port,snis:e.snis??[],acceptProxyEnabled:p.length>0,acceptProxyFrom:m,targetMode:l,targetHost:h,targetPort:e.target_port||443,unixSocketPath:e.unix_socket_path??"",healthCheck:e.health_check??!0,proxyProtocol:["none","v1","v2"].includes(e.proxy_protocol)?e.proxy_protocol:"none",servers:d,balanceMode:g,stickyMode:Gi(e),stickyTTL:e.sticky_ttl||Ce,stickyHash:e.sticky_hash==="map-based"?"map-based":"",stickyHashBalanceFactor:e.sticky_hash_balance_factor||"",stickyTableEntries:Ws(e.sticky_table_entries??"")?e.sticky_table_entries??"":"",stickyIPv6Prefix:e.sticky_ipv6_prefix||0,clientIPv6:e.client_ipv6??!0,balanceAlgorithm:Xi(e),balanceRandomDraws:e.balance_random_draws||"",leastpingTolerancePct:Ji(e),leastpingToleranceMs:e.leastping_tolerance_ms||"",slowstart:e.slowstart||"",legacyTarget:u,quotaEnabled:s>0,quotaValue:s>0?s/(n?Nt:Bs):"",quotaUnit:n?"TiB":"GiB",quotaPeriod:["hourly","daily","calendar_month","monthly_from_creation"].includes(e.quota_period)?e.quota_period:"calendar_month",quotaAction:e.quota_action==="block_new"?"block_new":"observe",clientBandwidthEnabled:e.client_upload_mbps!==null||e.client_download_mbps!==null,clientUploadMbps:e.client_upload_mbps??"",clientDownloadMbps:e.client_download_mbps??"",shaperMode:e.shaper_mode==="kernel"?"kernel":"haproxy",expertOverride:e.custom_fragment??""};if(mn(f)){const o=Ni(f.servers);o&&(f.servers=o)}return f}function te(e){const s=e.trim();return Mi.test(s)||s.includes(":")&&Kt.test(s)}function sn(e){const s=e.trim().replace(/\.$/,"");return s!==""&&s.split(".").every(n=>/^\d+$/.test(n))}function Ki(e){const s=e.trim();return te(s)||ds(s)}function nn(e){return e.servers.length>=2||e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function Ji(e){const s=e.balance_tolerance??e.leastping_tolerance;return typeof s!="number"?"":e.balance_algorithm==="leastping"||e.balance_algorithm==="leastconn"&&s>0?Math.round(s*100):""}function de(e){return nn(e)?e.balanceMode:"pool"}const ft="1.1.0";function Qi(e){return Fs(e,ft)}function Xe(e,s){return e.servers.length>1&&de(e)==="failover"&&!!e.servers[s]?.backup}function Zi(e){return e.every((s,n)=>s.backup===n>0)}function rn(e){return e.map((s,n)=>s.backup===n>0?s:{...s,backup:n>0,preferredIP:n>0?"":s.preferredIP})}function bt(e,s){const n=e.servers[s];return s===0&&!!n&&n.targetType==="tcp"&&n.dnsPool&&de(e)==="failover"&&!Xe(e,0)}function Je(e){return de(e)!=="pool"?!1:e.servers.length>=2||e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function an(e){return e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function ys(e){return an(e)?"source":"none"}function Oe(e){return Je(e)?e.stickyMode??ys(e):ys(e)}function Ps(e){return Oe(e)==="source_table"?"leastconn":"roundrobin"}function Le(e){return Oe(e)==="source"?Ps(e):e.balanceAlgorithm??Ps(e)}function ls(e){return e.healthCheck||e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function er(e){return e.clientBandwidthEnabled&&(e.clientUploadMbps!==""||e.clientDownloadMbps!=="")}function cs(e){if(e.servers.length!==1)return{kind:"servers"};const[s]=e.servers,n=s.weight===""&&s.cost===""&&bn(s.ipWeights,Qt(e)).length===0;if(s.targetType==="unix"||!s.dnsPool)return n?{kind:"legacy",dnsPool:!1}:{kind:"servers"};const a=e.legacyTarget,i=bt(e,0)&&s.preferredIP.trim()!=="";return n&&a&&a.dnsPool&&a.targetType==="tcp"&&!i&&a.host.trim().toLowerCase()===s.host.trim().toLowerCase()&&a.port===Number(s.port)?{kind:"legacy",dnsPool:!0}:{kind:"servers"}}function ds(e){const s=e.trim().replace(/\.$/,"").toLowerCase();return s.length>0&&s.length<=253&&!sn(s)&&s.split(".").every(n=>Si.test(n))}function on(e){for(let s=0;s=55296&&n<=56319){const a=e.charCodeAt(s+1);if(!(a>=56320&&a<=57343))return!1;s+=1}else if(n>=56320&&n<=57343)return!1}return!0}function tr(e){const s=new TextEncoder().encode(e).length;return!on(e)||s<2||s>107||!e.startsWith("/")||!/^[A-Za-z0-9/._-]+$/.test(e)||e.endsWith("/")||e.includes("//")?!1:e.slice(1).split("/").every(n=>n!==""&&n!=="."&&n!=="..")}function sr(e,s,n,a){return s!==a?!1:e===n||(e==="*"||e==="0.0.0.0"||e==="::")||(n==="*"||n==="0.0.0.0"||n==="::")}function ln(e,s,n,a){return e.toLowerCase()===n.toLowerCase()&&s===a}function cn(e){const s=e.trim();if(!s)return!1;if(s.includes(":")){const n=s.indexOf("/");if(n===-1)return Kt.test(s);const a=s.slice(0,n),i=s.slice(n+1);if(!Kt.test(a))return!1;const h=Number(i);return Number.isInteger(h)&&h>=0&&h<=128&&String(h)===i}return Ti.test(s)}const js=32;function mt(e){const s=e.trim();return!cn(s)&&!s.includes("/")&&!s.includes(":")&&ds(s)}function dn(e){return cn(e)||mt(e)}function un(e){const s=e.trim();return mt(s)?s.replace(/\.$/,"").toLowerCase():s}function us(e){if(!e.quotaEnabled||e.quotaValue==="")return null;const s=e.quotaUnit==="TiB"?Nt:Bs;return Math.round(Number(e.quotaValue)*s)}function nr(e){const s=new TextEncoder;if(s.encode(e).length>8192)return[{field:"expert",message:"Экспертный слой превышает 8192 байт."}];if(!on(e))return[{field:"expert",message:"Экспертный слой должен быть корректным UTF-8."}];const n=e.replace(/\r\n/g,` +`);if(/[\u0000-\u0008\u000b-\u001f\u007f]/.test(n))return[{field:"expert",message:"Экспертный слой содержит управляющий символ."}];if(n.includes("\\"))return[{field:"expert",message:"Перенос и экранирование директив через \\ запрещены."}];const a=[];let i=!1;for(const h of n.split(` +`)){if(s.encode(h).length>512)return[{field:"expert",message:"Одна из директив длиннее 512 байт."}];const l=h.trim();if(!l){a.length>0&&(i=!0);continue}const d=l.split(/\s+/)[0].toLowerCase();if(Ci.has(d))return[{field:"expert",message:`Секция ${d} управляется NodeFlow и не может быть переопределена.`}];i&&(a.push(""),i=!1),a.push(` ${l}`)}return s.encode(a.join(` +`)).length>8192?[{field:"expert",message:"Экспертный слой превышает 8192 байт после нормализации."}]:[]}function ir(e){const s=[];if(de(e)!=="pool"||!Je(e))return s;const n=(l,d)=>s.push({field:l,message:d}),a=(l,d,u,p=!0)=>l===""||Number.isFinite(l)&&l>=d&&l<=u&&(!p||Number.isInteger(l)),i=Oe(e),h=Le(e);if(i!=="source"&&(h==="random"&&!a(e.balanceRandomDraws,1,5)&&n("balanceRandomDraws","Выборок — от 1 до 5."),h==="leastping"&&(a(e.leastpingTolerancePct,0,100)||n("leastpingTolerancePct","Толерантность — целое число от 0 до 100 %."),a(e.leastpingToleranceMs,0,1e3)||n("leastpingToleranceMs","Толерантность в мс — от 0 до 1000.")),h==="leastconn"&&!a(e.leastpingTolerancePct,0,100)&&n("leastpingTolerancePct","Толерантность — целое число от 0 до 100 %.")),i==="source"&&e.stickyHash!=="map-based"&&!a(e.stickyHashBalanceFactor,101,1e3)&&n("stickyHashBalanceFactor","Лимит перегрузки — от 101 до 1000 % или пусто."),e.clientIPv6&&(i==="source"||i==="source_table")&&e.stickyIPv6Prefix!==0&&!a(e.stickyIPv6Prefix,32,128)&&n("stickyIPv6Prefix","Префикс IPv6 — от /32 до /128."),i==="source_table"){const l=os(e.stickyTTL||Ce);(l===null||lBi)&&n("stickyTTL","Помнить — от 1 минуты до 168 часов."),Ws(e.stickyTableEntries)||n("stickyTableEntries",`Макс. клиентов — от 1 до ${Ks(Ot)}.`)}return s}function ws(e,s,n){const a=[],i=(m,g)=>a.push({field:m,message:g}),h=Number(e.listenerPort),l=e.listenerIP.trim()||"*",d=l==="*"||l==="0.0.0.0"||l==="::",u=e.snis.map(m=>m.trim().replace(/\.$/,"").toLowerCase()).filter(Boolean);if(e.name.trim()?e.name.trim().length>80&&i("name","Имя маршрута не должно превышать 80 символов."):i("name","Укажите имя маршрута. Оно видно только оператору."),!d&&!te(l)&&i("listenerIP","Адрес listener должен быть * или корректным IP."),(!Number.isInteger(h)||h<1||h>65535)&&i("listenerPort","Порт listener должен быть от 1 до 65535."),e.matchMode==="sni"&&(u.length||i("snis","Добавьте хотя бы один SNI."),u.length>64&&i("snis","Можно указать не больше 64 SNI."),u.some(m=>!ds(m))&&i("snis","Каждый SNI должен быть корректным DNS-именем."),new Set(u).size!==u.length&&i("snis","SNI внутри маршрута не должны повторяться.")),e.acceptProxyEnabled)if(e.acceptProxyFrom.length>256)i("acceptProxyFrom","Список не должен превышать 256 записей.");else{for(const g of e.acceptProxyFrom)if(!dn(g)){i("acceptProxyFrom",`Некорректный адрес, подсеть или домен: ${g}`);break}new Set(e.acceptProxyFrom.filter(mt).map(un)).size>js&&i("acceptProxyFrom",`Не больше ${js} доменов в списке.`)}if(e.servers.length===0)i("servers","Добавьте хотя бы один сервер назначения.");else if(e.servers.length>16)i("servers","Не более 16 серверов.");else{const m=e.servers.map(f=>f.name.trim()).filter(Boolean),g=e.servers.find(f=>/_pref$/i.test(f.name.trim()));g&&i("servers",`Имя сервера ${g.name.trim()} не должно оканчиваться на _pref.`),new Set(m).size!==m.length&&i("servers","Имена серверов не должны повторяться."),e.servers.forEach((f,o)=>{if(!f.name.trim()){i("servers",`Сервер ${o+1}: укажите имя.`);return}if(Ei.test(f.name.trim())||i("servers",`Сервер ${o+1}: имя — буквы, цифры, _, - (до ${as} символов).`),f.targetType==="tcp"){const v=Number(f.port),P=f.host.trim();P?sn(P)&&!te(P)?i("servers",`Сервер ${o+1}: ${P} — некорректный IPv4-адрес.`):Ki(P)||i("servers",`Сервер ${o+1}: адрес должен быть IP или доменом.`):i("servers",`Сервер ${o+1}: укажите адрес.`),(!Number.isInteger(v)||v<1||v>65535)&&i("servers",`Сервер ${o+1}: некорректный порт.`),f.dnsPool&&te(f.host.trim())&&i("servers",`Сервер ${o+1}: DNS-пул недоступен для IP-адресов.`),bt(e,o)&&f.preferredIP.trim()&&!te(f.preferredIP.trim())&&i("servers",`Сервер ${o+1}: основной IP — некорректный адрес.`)}else tr(f.unixSocketPath.trim())||i("servers",`Сервер ${o+1}: некорректный путь Unix socket.`);if(f.weight!==""&&(!Number.isInteger(Number(f.weight))||Number(f.weight)<1||Number(f.weight)>256)&&i("servers",`Сервер ${o+1}: вес — целое число от 1 до 256.`),Qt(e)&&f.cost!==""&&(!Number.isFinite(Number(f.cost))||Number(f.cost)<=0||Number(f.cost)>100)&&i("servers",`Сервер ${o+1}: стоимость — число больше 0 и не больше 100.`),f.ipWeights.length>0){const v=Le(e),P=Oe(e);f.dnsPool||i("servers",`Сервер ${o+1}: вес и стоимость IP доступны только для DNS-пула.`),f.ipWeights.length>32&&i("servers",`Сервер ${o+1}: не более 32 отдельных IP.`);const $=f.ipWeights.map(N=>N.ip.trim().toLowerCase());new Set($).size!==$.length&&i("servers",`Сервер ${o+1}: IP не должны повторяться.`),f.ipWeights.some(N=>!te(N.ip))&&i("servers",`Сервер ${o+1}: некорректный IP в списке отдельных IP.`),f.ipWeights.some(N=>N.weight!==""&&(!Number.isInteger(N.weight)||N.weight<1||N.weight>256))&&i("servers",`Сервер ${o+1}: вес IP — целое число от 1 до 256.`),Qt(e)&&f.ipWeights.some(N=>N.cost!==""&&(!Number.isFinite(N.cost)||N.cost<.01||N.cost>100))&&i("servers",`Сервер ${o+1}: стоимость IP — число от 0,01 до 100.`),f.ipWeights.some(N=>N.weight!=="")&&(v==="static-rr"||P==="source"&&e.stickyHash==="map-based")&&i("servers",`Сервер ${o+1}: вес IP не работает с фиксированными весами — включите «Веса меняются на лету» или «Стабильное» распределение.`)}}),de(e)==="failover"&&e.servers.length>1&&(e.servers.every(f=>f.backup)?i("servers","Отметьте хотя бы один сервер как «Основной»."):e.servers.some(f=>f.backup)||i("servers","Отметьте хотя бы один сервер как «Резерв» или выберите режим «Пул»."))}const p=us(e);if(e.quotaEnabled&&(e.quotaValue===""||Number(e.quotaValue)<=0||!Number.isFinite(p)||Number(p)>Ii)&&i("quota","Лимит должен быть положительным числом в безопасном диапазоне."),e.quotaAction==="block_new"&&!e.quotaEnabled&&i("quota","Блокировка новых соединений требует включённого лимита."),e.quotaEnabled&&e.quotaAction==="block_new"&&e.servers.length>0){const m=cs(e);(m.kind==="servers"||m.dnsPool)&&i("quota","Блокировка новых соединений доступна только для одного сервера без DNS-пула. Выберите «Только уведомить».")}if(e.clientBandwidthEnabled)for(const[m,g,f]of[["clientUploadMbps",e.clientUploadMbps,"Лимит upload"],["clientDownloadMbps",e.clientDownloadMbps,"Лимит download"]])g!==""&&(!Number.isSafeInteger(g)||g<1||g>1e6)&&i(m,`${f} должен быть целым числом от 1 до 1 000 000 Mbps либо пустым.`);e.slowstart&&!ls(e)&&i("servers","Плавный ввод требует включённой проверки здоровья.");const r=e.slowstart?os(e.slowstart):0;(r===null||r>600)&&i("slowstart","Плавный ввод — от 1 до 600 секунд."),a.push(...ir(e)),a.push(...nr(e.expertOverride));for(const m of s.filter(g=>g.id!==n&&!g.delete_pending&&g.deployment_state!=="deleting")){if(!Number.isInteger(h)||!sr(l,h,m.listener_ip||"*",m.listener_port))continue;if(!ln(l,h,m.listener_ip||"*",m.listener_port)){i("listener",`Порт ${h} уже слушается ${m.listener_ip||"*"}. Нельзя смешивать wildcard и конкретный IP.`);continue}const f=e.matchMode!=="sni";if(f&&m.fallback&&i("listener",`Для ${l}:${h} уже есть фолбэк-маршрут.`),!f&&!m.fallback){const v=u.find(P=>(m.snis??[]).map($=>$.toLowerCase()).includes(P));v&&i("snis",`SNI ${v} уже назначен другому маршруту на ${l}:${h}.`)}const o=m.enabled&&(m.client_upload_mbps!==null||m.client_download_mbps!==null);if(er(e)&&o){const v=m.shaper_mode==="kernel",P=Zs(m);if(e.shaperMode==="kernel"!==v)i("bandwidth",`На ${l}:${h} маршрут ${P} ограничивает скорость через ${v?"ядро":"HAProxy"}; режимы на одном listener смешивать нельзя.`);else if(v){const $=e.clientUploadMbps===""?null:e.clientUploadMbps,j=e.clientDownloadMbps===""?null:e.clientDownloadMbps;($!==m.client_upload_mbps||j!==m.client_download_mbps)&&i("bandwidth",`Лимиты ядра на ${l}:${h} должны совпадать с маршрутом ${P} (↑${m.client_upload_mbps??"—"} / ↓${m.client_download_mbps??"—"} Mbps).`)}}}return a}function pn(e){return e.acceptProxyEnabled?e.acceptProxyFrom.length===0?[...Di]:e.acceptProxyFrom.filter(dn).map(un):[]}function hn(e){return de(e)==="pool"&&Je(e)&&Le(e)==="leastping"}function mn(e){return de(e)==="pool"&&Je(e)&&Le(e)==="leastconn"}function Qt(e){return hn(e)}const fn="1.1.1";function rr(e){return Fs(e,fn)}function ar(e){if(!e.some(d=>d.cost>0||d.ip_weights.some(u=>(u.cost??0)>0)))return null;const n=(d,u)=>(d>0?d:1)/(u>0?u:1),a=(d,u)=>n(d.weight>0?d.weight:u.weight,(d.cost??0)>0?d.cost??0:u.cost);let i=0;e.forEach(d=>{i=Math.max(i,n(d.weight,d.cost)),d.ip_weights.forEach(u=>{i=Math.max(i,a(u,d))})});const h=Math.min(100,256/i),l=d=>Math.min(256,Math.max(1,Math.round(d)));return{servers:e.map(d=>l(n(d.weight,d.cost)*h)),ips:e.map(d=>Object.fromEntries(d.ip_weights.map(u=>[u.ip,l(a(u,d)*h)])))}}function bn(e,s){return e.flatMap(n=>{const a=n.weight===""?0:Number(n.weight),i=s&&n.cost!==""?Math.round(Number(n.cost)*100)/100:0;return!a&&!i?[]:[i?{ip:n.ip.trim(),weight:a,cost:i}:{ip:n.ip.trim(),weight:a}]})}function We(e,s,n){const a=e.matchMode!=="sni",i=a?[]:e.snis.map(_=>_.trim().replace(/\.$/,"").toLowerCase()).filter(Boolean),h=pn(e),l=de(e),d=cs(e),u=l==="pool",p=u?Oe(e):"",m=u&&Je(e)?Le(e):"",g=hn(e),f=mn(e),o=g,v=e.servers[0],P=v?.targetType==="unix",$=P?"":v?.host.trim()??"",j=P?0:Number(v?.port??443),N=P?v?.unixSocketPath.trim()??"":"",x=l==="failover"&&d.kind==="servers"&&!Zi(e.servers.map((_,b)=>({backup:Xe(e,b)}))),E=d.kind==="legacy"?[]:e.servers.map((_,b)=>({position:b+1,name:_.name.trim(),target_type:_.targetType,host:_.targetType==="tcp"?_.host.trim():"",port:_.targetType==="tcp"?Number(_.port):0,unix_socket_path:_.targetType==="unix"?_.unixSocketPath.trim():"",backup:Xe(e,b),dns_pool:_.targetType==="tcp"&&_.dnsPool,preferred_ip:bt(e,b)?_.preferredIP.trim():"",weight:_.weight===""?0:Number(_.weight),cost:o&&_.cost!==""?Number(_.cost):0,ip_weights:_.targetType==="tcp"&&_.dnsPool?bn(_.ipWeights,o):[]}));return{...n?{expected_version:n}:{},name:e.name.trim(),hostname:i[0]??"",listener_ip:e.listenerIP.trim()||"*",listener_port:Number(e.listenerPort),match_mode:e.matchMode,snis:i,fallback:a,target_type:P?"unix":"tcp",target_host:$,target_port:j,dns_pool:d.kind==="legacy"&&d.dnsPool,unix_socket_path:N,health_check:ls(e),proxy_protocol:e.proxyProtocol,quota_bytes:us(e),quota_action:e.quotaEnabled?e.quotaAction:"observe",quota_period:e.quotaPeriod,client_upload_mbps:!e.clientBandwidthEnabled||e.clientUploadMbps===""?null:e.clientUploadMbps,client_download_mbps:!e.clientBandwidthEnabled||e.clientDownloadMbps===""?null:e.clientDownloadMbps,enabled:s,custom_fragment:e.expertOverride,accept_proxy_from:h,servers:E,sticky_enabled:p==="source"||p==="source_table",sticky_mode:p,...p==="source_table"?{sticky_ttl:e.stickyTTL||Ce}:{},sticky_hash:p==="source"?e.stickyHash:"",sticky_hash_balance_factor:p==="source"&&e.stickyHash!=="map-based"?Number(e.stickyHashBalanceFactor||0):0,sticky_table_entries:p==="source_table"?e.stickyTableEntries:"",sticky_ipv6_prefix:e.clientIPv6&&(p==="source"||p==="source_table")?e.stickyIPv6Prefix:0,client_ipv6:e.clientIPv6,balance_algorithm:m,balance_random_draws:m==="random"?Number(e.balanceRandomDraws||2):0,balance_tolerance:g?Math.round(e.leastpingTolerancePct===""?zs:Number(e.leastpingTolerancePct))/100:f&&e.leastpingTolerancePct!==""?Math.round(Number(e.leastpingTolerancePct))/100:0,leastping_tolerance_ms:g?Number(e.leastpingToleranceMs||0):0,slowstart:e.slowstart,...x?{}:{balance_mode:l},shaper_mode:e.shaperMode}}function kt(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"route_preview"}function lt(e,s){return e.includes(":")?`[${e}]:${s}`:`${e}:${s}`}const Ut=" check inter 5s fall 3 rise 2 resolvers nf_dns init-addr last,none resolve-opts prevent-dup-ip hash-key addr";function or(e,s,n){const a=e.listenerIP.trim()||"*",i=Number(e.listenerPort)||443,h=s.filter(y=>y.enabled&&ln(y.listener_ip||"*",y.listener_port,a,i)),l=We(e,!0),d=[...h,l],u=`nf_listener_${i}_${kt(a==="*"?"any":a)}`,p=kt(e.name),r=cs(e),m=l.servers.length===1?l.servers[0]:null,g=m&&!m.preferred_ip&&!m.weight&&!m.cost&&!m.ip_weights.length?{kind:"legacy",dnsPool:m.dns_pool}:r,f=l.health_check,o=["# Managed by NodeFlow — preview"];e.servers.some(y=>y.targetType==="tcp"&&(y.dnsPool||y.host.trim()!==""&&!te(y.host.trim())))&&o.push("resolvers nf_dns"," nameserver adguard_local 127.0.0.1:53"," # … остальные nameserver и hold-параметры",""),l.sticky_mode==="source_table"&&o.push("peers nf_peers"," bind unix@/run/haproxy/nf_peers.sock"," server nf_local",""),o.push(`frontend ${u}`,` bind ${a}:${i}`," mode tcp");const P=pn(e);if(e.acceptProxyEnabled&&qs(P))o.push(" tcp-request connection expect-proxy layer4");else if(P.length>0){const y=[...new Set(P)].sort(),w=y.filter(mt),V=y.filter(D=>!mt(D));if(w.length>0){const D=`/etc/haproxy/nodeflow/pp-trusted-${u}.acl`;o.push(` # nf-pp-trusted file=${D} domains=${w.join(",")}`,` acl nf_pp_trusted src -f ${D}`,` tcp-request connection expect-proxy layer4 if ${V.length?`{ src ${V.join(" ")} } || `:""}nf_pp_trusted`)}else o.push(` tcp-request connection expect-proxy layer4 if { src ${V.join(" ")} }`)}const $=l.client_download_mbps!==null?l.client_download_mbps*125e3:null,j=l.client_upload_mbps!==null?l.client_upload_mbps*125e3:null,N=$!==null||j!==null,x=e.shaperMode==="kernel",E=!x&&N;x&&N&&o.push(` # nf-kernel-shaper listen=${a} port=${i} download_bps=${$??0} upload_bps=${j??0}`);const _=l.client_ipv6,b=_?"ipv6":"ip",M=_?"src,ipmask(32,64)":"src";E&&$!==null&&o.push(` filter bwlim-out nf_bw_download_${p} limit ${$} key ${M} table nf_bw_download_table_${p} min-size 2896`),E&&j!==null&&o.push(` filter bwlim-in nf_bw_upload_${p} limit ${j} key ${M} table nf_bw_upload_table_${p} min-size 2896`);const I=d.filter(y=>!y.fallback);I.length&&o.push(" tcp-request inspect-delay 5s"," tcp-request content accept if { req.ssl_hello_type 1 }");const ue=I.indexOf(l),ie=ue>=0?` if nf_sni_${ue+1}`:I.length?` if ${I.map((y,w)=>`!nf_sni_${w+1}`).join(" ")}`:"";E&&$!==null&&o.push(` tcp-request content set-bandwidth-limit nf_bw_download_${p}${ie}`),E&&j!==null&&o.push(` tcp-request content set-bandwidth-limit nf_bw_upload_${p}${ie}`),I.forEach((y,w)=>{const V=(y.snis??[]).length?y.snis:["sni.example.com"];o.push(` acl nf_sni_${w+1} req.ssl_sni -i ${V.join(" ")}`),o.push(` use_backend nf_be_${kt(y===l?e.name:V[0])} if nf_sni_${w+1}`)});const Z=d.find(y=>y.fallback);Z&&o.push(` default_backend nf_be_${kt(Z===l?e.name:Z.snis?.[0]||`tcp_${Z.listener_port}`)}`),o.push("",`backend nf_be_${p}`," mode tcp");const K=g.kind==="legacy"&&g.dnsPool,G=l.sticky_mode;if(G==="source"){const y=l.sticky_ipv6_prefix;!_||y===0||y===128?o.push(" balance source"):o.push(` balance hash src,ipmask(32,${y})`);const w=l.sticky_hash==="map-based"?"map-based":"consistent";o.push(` hash-type ${w} sdbm avalanche`),w==="consistent"&&l.sticky_hash_balance_factor&&o.push(` hash-balance-factor ${l.sticky_hash_balance_factor}`)}else if(G==="none"||G==="source_table"||G===""){const y=l.balance_algorithm;if(y==="static-rr"?o.push(" balance static-rr"):y==="random"?o.push(` balance random(${l.balance_random_draws||2})`):y==="leastconn"&&!(l.balance_tolerance>0&&g.kind==="servers")&&o.push(" balance leastconn"),G==="source_table"){const w=l.sticky_table_entries||Ys(s,n);o.push(` stick-table type ${b} size ${w} expire ${l.sticky_ttl||Ce} peers nf_peers`),o.push(_?` stick on src,ipmask(32,${l.sticky_ipv6_prefix||64})`:" stick on src"),o.push(" option redispatch")}}const pe=l.balance_algorithm==="leastping"&&G!=="source",le=g.kind==="servers"?l.servers:[],k=l.balance_algorithm==="leastconn"&&G!=="source"&&le.length>0,X=k&&l.balance_tolerance>0,z=pe||X,U=k?ar(le):null,Ee=y=>z||U?(y.ip_weights?.length??0)>0:(y.ip_weights??[]).some(w=>w.weight>0),xe=le.some(Ee);if(z||xe){const y=pe?"leastping":X?"leastconn":"static",w=(z?l.balance_tolerance:0).toFixed(2),V=pe&&l.leastping_tolerance_ms||0;o.push(` # nf-weights backend=nf_be_${p} algo=${y} tolerance=${w} tolerance_ms=${V}`),le.forEach((D,S)=>{if(!z&&!Ee(D))return;const se=D.weight||1,J=(D.cost||0).toFixed(2);if(D.dns_pool){if(D.preferred_ip&&!D.backup&&S===0&&e.balanceMode==="failover"&&o.push(` # nf-weight server=${D.name}_pref base=${se} cost=${J}`),!z&&U){const Y=(D.ip_weights??[]).map(Fe=>`${Fe.ip}=${U.ips[S][Fe.ip]}`).join(",");o.push(` # nf-weight template=${D.name}_ slots=32 base=${U.servers[S]} cost=0.00${Y?` ips=${Y}`:""}`);return}const ve=(D.ip_weights??[]).filter(Y=>Y.weight>0).map(Y=>`${Y.ip}=${Y.weight}`).join(","),De=z?(D.ip_weights??[]).filter(Y=>(Y.cost??0)>0).map(Y=>`${Y.ip}=${(Y.cost??0).toFixed(2)}`).join(","):"";o.push(` # nf-weight template=${D.name}_ slots=32 base=${se} cost=${J}${ve?` ips=${ve}`:""}${De?` ipcosts=${De}`:""}`)}else o.push(` # nf-weight server=${D.name} base=${se} cost=${J}`)})}f&&o.push(" option tcp-check"),e.quotaEnabled&&o.push(` # quota ${Qn(us(e)??0)} · ${e.quotaPeriod} · ${e.quotaAction}`),e.expertOverride.trim()&&(o.push(" # ── expert override: backend directives only ──"),e.expertOverride.split(` +`).forEach(y=>o.push(` ${y.trimStart()}`)),o.push(" # ── end expert override ──"));const F=e.proxyProtocol==="v1"?" send-proxy":e.proxyProtocol==="v2"?" send-proxy-v2":"",W=e.proxyProtocol!=="none"&&f?" check-send-proxy":"",re=f?" check inter 5s fall 3 rise 2":"",_e=(y,w)=>y.trim()||w,ae=y=>Number(y)||443,H=e.slowstart&&f?` slowstart ${e.slowstart}`:"",he=y=>y?` weight ${y}`:"";if(g.kind==="legacy"){const y=e.servers[0];if(K)o.push(` server-template nf_srv_${p}_ 32 ${lt(_e(y.host,"pool.example.com"),ae(y.port))}${H}${Ut}${F}${W}`);else if(y?.targetType==="unix")o.push(` server nf_srv_${p} ${y.unixSocketPath.trim()||"/run/service.sock"}${H}${re}${F}${W}`);else{const w=_e(y?.host??"","10.0.0.1"),V=te(w)?"":" resolvers nf_dns init-addr last,none";o.push(` server nf_srv_${p} ${lt(w,ae(y?.port??443))}${H}${re}${V}${F}${W}`)}}else{const y=l.servers;y.some(w=>w.dns_pool&&(w.backup||w.preferred_ip!==""))&&o.push(" option allbackups"),y.forEach((w,V)=>{const D=w.name||`srv${V+1}`,S=w.backup?" backup":"",se=he(U?U.servers[V]:w.weight);if(w.dns_pool){const J=lt(_e(w.host,"pool.example.com"),ae(w.port));w.preferred_ip&&!w.backup?(o.push(` server ${D}_pref ${lt(w.preferred_ip,ae(w.port))}${se}${H}${re}${F}${W}`),o.push(` server-template ${D}_ 32 ${J}${se}${H}${Ut}${F}${W} backup`)):o.push(` server-template ${D}_ 32 ${J}${se}${H}${Ut}${F}${W}${S}`)}else if(w.target_type==="unix")o.push(` server ${D} ${w.unix_socket_path||"/run/service.sock"}${se}${H}${re}${F}${W}${S}`);else{const J=_e(w.host,"10.0.0.1"),ve=te(J)?"":" resolvers nf_dns init-addr last,none";o.push(` server ${D} ${lt(J,ae(w.port))}${se}${H}${re}${ve}${F}${W}${S}`)}})}return E&&$!==null&&o.push("",`backend nf_bw_download_table_${p}`,` stick-table type ${b} size 1m expire 1h store bytes_out_rate(1s)`),E&&j!==null&&o.push("",`backend nf_bw_upload_table_${p}`,` stick-table type ${b} size 1m expire 1h store bytes_in_rate(1s)`),{config:o.join(` +`),merged:h.length}}function Wt(e,s){const n=Math.abs(e)%100,a=n%10;return n>10&&n<20?s[2]:a>1&&a<5?s[1]:a===1?s[0]:s[2]}function ks({id:e,index:s,title:n,summary:a,aside:i,children:h,className:l=""}){return t.jsxs("section",{className:`nf-re-section ${l}`.trim(),"aria-labelledby":`${e}-title`,children:[t.jsxs("header",{className:"nf-re-section__head",children:[s&&t.jsx("span",{className:"nf-re-section__index","aria-hidden":"true",children:s}),t.jsx("h2",{id:`${e}-title`,children:n}),a&&t.jsx("span",{className:"nf-re-section__summary",children:a}),i&&t.jsx("span",{className:"nf-re-section__aside",children:i})]}),t.jsx("div",{className:"nf-re-section__body",children:h})]})}function Zt({title:e,hint:s,id:n,stableHint:a=!1}){return t.jsxs("div",{className:`nf-re-block-head${a?" has-stable-hint":""}`,children:[t.jsx("h3",{id:n,children:e}),s&&t.jsx("p",{title:a&&typeof s=="string"?s:void 0,children:s})]})}function ct({children:e,className:s="",layout:n="fixed",...a}){return t.jsx("div",{className:`nf-setgrid nf-setgrid--${n} ${s}`.trim(),...a,children:e})}function R({id:e,label:s,hint:n,aside:a,error:i,children:h,group:l=!1,field:d,grow:u=!1,inline:p=!1,area:r,wide:m=!1,stableHint:g=!1,inactive:f=!1}){const o=["nf-setting-row",u&&"is-grow",p&&"is-inline",m&&"is-wide",g&&"has-stable-hint",f&&"is-inactive"].filter(Boolean).join(" ");return t.jsxs("div",{className:o,"data-field":d,style:r?{gridArea:r}:void 0,children:[t.jsx("div",{className:"nf-setting-row__label",children:l?t.jsx("span",{id:`${e}-label`,children:s}):t.jsx("label",{htmlFor:e,id:`${e}-label`,children:s})}),t.jsx("div",{className:"nf-setting-row__control",children:t.jsxs("div",{className:"nf-setting-row__line",children:[h,a&&t.jsx("span",{className:"nf-setting-row__aside",id:`${e}-aside`,title:typeof a=="string"?a:void 0,children:a})]})}),t.jsx("small",{className:`nf-setting-row__hint${i?" is-error":""}`,id:`${e}-hint`,role:i?"alert":void 0,children:i??n})]})}function lr(){return t.jsx("div",{className:"nf-setgrid__divider","aria-hidden":"true"})}function Gt({children:e,tone:s="info"}){return t.jsxs("p",{className:`nf-re-note${s==="warning"?" is-warning":""} nf-setgrid__note`,children:[t.jsx(ss,{size:14,"aria-hidden":"true"}),t.jsx("span",{children:e})]})}function cr({children:e,tone:s="info",icon:n}){return t.jsxs("p",{className:`nf-re-note${s==="warning"?" is-warning":""}`,children:[n??t.jsx(ss,{size:14,"aria-hidden":"true"}),t.jsx("span",{children:e})]})}function dr({children:e,cards:s=!1}){return t.jsx("div",{className:`nf-re-options${s?" is-cards":""}`,children:e})}function $s({title:e,hint:s,control:n,children:a,open:i=!1,disabled:h=!1,field:l}){return t.jsxs("div",{className:`nf-re-option${i?" is-open":""}${h?" is-disabled":""}`,"data-field":l,children:[t.jsxs("div",{className:"nf-re-option__main",children:[t.jsxs("div",{className:"nf-re-option__text",children:[t.jsx("strong",{children:e}),s&&t.jsx("p",{children:s})]}),t.jsx("div",{className:"nf-re-option__control",children:n})]}),a&&t.jsx(dt,{in:i,children:t.jsx("div",{className:"nf-re-option__body",children:a})})]})}function ur({value:e,onValue:s,...n}){const[a,i]=C.useState(e),[h,l]=C.useState(!1);return t.jsx(Me,{...n,value:h?a:e,onFocus:d=>{l(!0),i(e),n.onFocus?.(d)},onBlur:d=>{l(!1),n.onBlur?.(d)},onChange:d=>{i(d),d===""?s(""):typeof d=="number"&&Number.isFinite(d)&&s(d)}})}function ce({unit:e,wide:s=!1,className:n="",...a}){const i=e?Math.max(28,e.length*7+16):void 0;return t.jsx(ur,{hideControls:!0,size:"sm",...a,className:`nf-num${s?" nf-num--wide":""} ${n}`.trim(),rightSection:e?t.jsx("span",{className:"nf-num__unit","aria-hidden":"true",children:e}):void 0,rightSectionWidth:i,rightSectionPointerEvents:"none"})}const pr="kernel_shaper_requires_agent_1_1",Xt=`Ядерный шейпер требует Node Agent ${ft} на этой ноде`,ut=new URLSearchParams(window.location.search).get("demo")==="1"||!1;function hr(e,s){return e.find(n=>s.includes(n.field))?.message}const mr={name:"имя",snis:"SNI",listenerPort:"порт",listenerIP:"IP ноды",listener:"порт",quota:"лимит трафика",clientUploadMbps:"скорость",clientDownloadMbps:"скорость",bandwidth:"скорость"};function fr(e){const s=[];for(const a of e){const i=a.field==="servers"?/адрес|путь/i.test(a.message)?"адрес сервера":"серверы":mr[a.field];i&&!s.includes(i)&&s.push(i)}return s.length?`Заполните ${s.length>1?`${s.slice(0,-1).join(", ")} и ${s.at(-1)}`:s[0]}`:"Проверьте поля формы"}function br(e,s){return e==="draft"?s?"Черновик сохранён":"Маршрут создан как выключенный черновик":e==="apply"?"Изменения отправлены на ноду":"Маршрут создан и отправлен на включение"}async function gr(e,s){if(ut){const{demoNodeBundles:d,mergeDemoRoutes:u}=await es(async()=>{const{demoNodeBundles:g,mergeDemoRoutes:f}=await import("./demo-k0hjezoN.js");return{demoNodeBundles:g,mergeDemoRoutes:f}},[]),p=structuredClone(d.find(({node:g})=>g.id===e)??d[0]);p.node.id=e,p.routes=u(e,p.routes.map(g=>({...g,node_id:e})));const r=s?p.routes.find(g=>g.id===s):void 0,m=p.operational?.latest_heartbeat;return{node:p.node,routes:p.routes,route:r,agentVersion:m?.agent_version,memoryTotalBytes:m?.metrics?.memory_total_bytes}}const[n,a,i]=await Promise.all([Ie(`/api/v1/nodes/${e}`),Ie(`/api/v1/nodes/${e}/routes`),Ie(`/api/v1/nodes/${e}/operational`).catch(()=>null)]),h=s?await Ie(`/api/v1/nodes/${e}/routes/${s}`):void 0,l=i?.latest_heartbeat;return{node:n,routes:a,route:h,agentVersion:l?.agent_version,memoryTotalBytes:l?.metrics?.memory_total_bytes}}function Ns(e,s){return We(e,s.enabled).servers.length>0&&!(s.servers??[]).length?e:tn({...s,name:e.name})}async function Is(e,s){try{return await Ie(`/api/v1/nodes/${e}/routes/${s.id}`)}catch(n){if(Cs(n))throw n;return s}}const $t={host:"",loading:!1,addresses:[],error:"",done:!1};async function xr(e){if(ut){const{demoResolveDNS:s}=await es(async()=>{const{demoResolveDNS:n}=await import("./demo-k0hjezoN.js");return{demoResolveDNS:n}},[]);return s(e)}return Fn(e)}function gn(e){const[s,n]=C.useState($t),a=e.trim(),i=a!==""&&!te(a),h=s.host===a?s:$t;return{host:a,canResolve:i,current:h,run:async()=>{if(i){n({...$t,host:a,loading:!0});try{const d=await xr(a);n({host:a,loading:!1,done:!0,addresses:d.addresses??[],error:d.addresses?.length?"":d.error||"Домен не вернул ни одного адреса."})}catch(d){const u=d instanceof Ds&&d.code==="invalid_host"?"Некорректное имя домена.":d instanceof Error?d.message:"Не удалось получить адреса.";n({...$t,host:a,done:!0,error:u})}}}}}function xn({canResolve:e,loading:s,disabled:n=!1,onClick:a}){return t.jsx(ge,{label:"Сначала укажите домен в поле «Адрес»",disabled:e,openDelay:200,children:t.jsx("span",{className:"nf-inline-flex",children:t.jsx(fe,{variant:"default",size:"sm",leftSection:t.jsx($i,{size:14}),onClick:a,loading:s,disabled:!e||n,children:"IP домена"})})})}function _r({server:e,hasOtherServers:s,error:n,onChange:a}){const{host:i,canResolve:h,current:l,run:d}=gn(e.host),u=e.preferredIP.trim(),p=u!==""&&!te(u),r=`preferred-${e._key}`;return t.jsxs("div",{className:"nf-srv-sub",children:[t.jsxs("div",{className:"nf-srv-sub__head",children:[t.jsx("label",{className:"nf-srv-sub__title",htmlFor:r,children:"Основной IP"}),t.jsx("span",{className:"nf-srv-sub__hint",id:`${r}-hint`,children:s?"Весь трафик на этот IP; если он недоступен — на все IP домена и резервные серверы.":"Весь трафик на этот IP; если он недоступен — на все IP домена."})]}),t.jsxs("div",{className:"nf-srv-sub__controls",children:[t.jsx(Te,{id:r,size:"sm",className:"nf-srv-sub__ip",placeholder:"не задан",value:e.preferredIP,onChange:m=>a(m.currentTarget.value),error:p||n?!0:void 0,"aria-describedby":`${r}-hint`}),t.jsx(xn,{canResolve:h,loading:l.loading,onClick:()=>{d()}})]}),(p||n)&&t.jsx("p",{className:"nf-cell-error",children:p?"Некорректный IP-адрес.":n}),l.done&&(l.error?t.jsxs("p",{className:"nf-srv-sub__warning",children:[t.jsx(Re,{size:13,"aria-hidden":"true"}),l.error]}):t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"nf-ip-chips",role:"group","aria-label":`IP-адреса ${i}`,children:l.addresses.map(m=>{const g=m===u;return t.jsxs("button",{type:"button",className:`nf-ip-chip${g?" is-selected":""}`,"aria-pressed":g,onClick:()=>a(g?"":m),children:[g&&t.jsx(ts,{size:12,"aria-hidden":"true"}),m]},m)})}),t.jsx("p",{className:"nf-srv-sub__note",children:"Адреса получены с хоста панели — нода может видеть другие."})]}))]})}const vr="Доля новых клиентов для этого IP: 2 — вдвое больше, чем у IP с весом 1. Пусто — вес сервера (по умолчанию 1).",yr="Множитель задержки этого IP: 2 — IP кажется вдвое медленнее и выбирается реже. Пусто — стоимость сервера (по умолчанию 1).",Pr="Новые клиенты делятся пропорционально весу: 4 ядра против 2 — вес 2 у 4-ядерного, и он получит вдвое больше клиентов. При «Запоминании» уже закреплённые клиенты остаются на своём IP.",jr="Чем меньше задержка × стоимость, тем больше клиентов получает IP; вес задаёт долю при равной задержке. Под мощность сервера: 4 ядра против 2 — вес 2 у 4-ядерного.",wr="Доля IP пропорциональна весу. Например, 4 ядра против 2: вес 2 у 4-ядерного — он получит вдвое больше клиентов.";function kr({server:e,agentAllowed:s,showCost:n,connections:a,weightsFixed:i,error:h,onChange:l}){const{host:d,canResolve:u,current:p,run:r}=gn(e.host),[m,g]=C.useState(""),f=new Set(e.ipWeights.map(b=>b.ip)),o=e.ipWeights.length>=32,v=m.trim(),P=v!==""&&!te(v),$=v!==""&&f.has(v),j=e.name.trim()||d,N=b=>{f.has(b)||o||l([...e.ipWeights,{ip:b,weight:"",cost:""}])},x=()=>{!v||P||$||(N(v),g(""))},E=(b,M)=>{l(e.ipWeights.map(I=>I.ip===b?{...I,...M}:I))},_=b=>l(e.ipWeights.filter(M=>M.ip!==b));return t.jsxs("div",{className:"nf-srv-sub",children:[t.jsxs("div",{className:"nf-srv-sub__head",children:[t.jsx("span",{className:"nf-srv-sub__title",children:n?"Вес и стоимость отдельных IP":"Вес отдельных IP"}),t.jsxs("span",{className:"nf-srv-sub__hint",children:["Пусто — как у сервера.",i?" Сейчас веса фиксированы и не применятся.":""]})]}),!s&&t.jsxs("p",{className:"nf-srv-sub__warning is-error",children:[t.jsx(Rs,{size:13,"aria-hidden":"true"}),"Веса отдельных IP применяет агент ноды — обновите Node Agent до ",ft," или новее."]}),t.jsxs("div",{className:"nf-srv-sub__body",children:[e.ipWeights.length>0&&!i&&t.jsx("p",{className:"nf-srv-sub__note",children:a?Pr:n?jr:wr}),e.ipWeights.length>0&&t.jsxs("div",{className:`nf-ipw${n?" has-cost":""}`,role:"table","aria-label":`Отдельные IP ${j}`,children:[t.jsxs("div",{className:"nf-ipw__row is-head",role:"row",children:[t.jsx("span",{role:"columnheader",children:"IP"}),t.jsx("span",{role:"columnheader",children:t.jsx(ge,{label:vr,multiline:!0,w:260,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Вес"})})}),n&&t.jsx("span",{role:"columnheader",children:t.jsx(ge,{label:yr,multiline:!0,w:260,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Стоимость"})})}),t.jsx("span",{role:"columnheader","aria-label":"Удалить"})]}),e.ipWeights.map(b=>t.jsxs("div",{className:"nf-ipw__row",role:"row",children:[t.jsx("span",{className:"nf-ipw__ip",role:"cell",title:b.ip,children:b.ip}),t.jsx("span",{role:"cell",children:t.jsx(Me,{size:"sm",value:b.weight,min:1,max:256,allowDecimal:!1,hideControls:!0,inputMode:"numeric",placeholder:e.weight===""?"1":String(e.weight),disabled:i&&b.weight==="",error:i&&b.weight!==""?!0:void 0,onChange:M=>E(b.ip,{weight:M===""?"":Number(M)}),"aria-label":`Вес ${b.ip}`})}),n&&t.jsx("span",{role:"cell",children:t.jsx(Me,{size:"sm",value:b.cost,min:.01,max:100,decimalScale:2,hideControls:!0,inputMode:"decimal",placeholder:e.cost===""?"1":String(e.cost),onChange:M=>E(b.ip,{cost:M===""?"":Number(M)}),"aria-label":`Стоимость ${b.ip}`})}),t.jsx("span",{role:"cell",className:"nf-ipw__action",children:t.jsx(Es,{variant:"subtle",color:"gray",size:36,onClick:()=>_(b.ip),"aria-label":`Убрать ${b.ip}`,children:t.jsx(Os,{size:14})})})]},b.ip))]}),t.jsxs("div",{className:"nf-srv-sub__controls",children:[t.jsx(Te,{size:"sm",className:"nf-srv-sub__ip",placeholder:"IP-адрес",value:m,onChange:b=>g(b.currentTarget.value),onKeyDown:b=>{b.key==="Enter"&&(b.preventDefault(),x())},error:P||$?!0:void 0,"aria-label":`Добавить IP для ${j}`,disabled:o}),t.jsx(fe,{variant:"default",size:"sm",leftSection:t.jsx(Yt,{size:14}),onClick:x,disabled:!v||P||$||o,children:"Добавить"}),t.jsx(xn,{canResolve:u,loading:p.loading,disabled:o,onClick:()=>{r()}})]})]}),(P||$)&&t.jsx("p",{className:"nf-cell-error",children:P?"Некорректный IP-адрес.":"Этот IP уже в списке."}),h&&t.jsx("p",{className:"nf-cell-error",children:h}),p.done&&(p.error?t.jsxs("p",{className:"nf-srv-sub__warning",children:[t.jsx(Re,{size:13,"aria-hidden":"true"}),p.error]}):t.jsx("div",{className:"nf-ip-chips",role:"group","aria-label":`IP-адреса ${d}`,children:p.addresses.map(b=>t.jsxs("button",{type:"button",className:`nf-ip-chip${f.has(b)?" is-selected":""}`,disabled:f.has(b)||o,onClick:()=>N(b),children:[f.has(b)?t.jsx(ts,{size:12,"aria-hidden":"true"}):t.jsx(Yt,{size:12,"aria-hidden":"true"}),b]},b))}))]})}const $r={role:"0px",name:"minmax(88px, 180px)",type:"minmax(108px, 140px)",host:"minmax(120px, 1fr)",port:"minmax(72px, 96px)",dns:"minmax(56px, 80px)",weight:"minmax(64px, 72px)",cost:"minmax(72px, 88px)",actions:"36px"};function Nr(e){return/^имя/i.test(e)?"name":e.includes("основной IP")?"preferred":/(вес|стоимость) IP|отдельных IP|IP не должны|IP в списке|вес и стоимость IP/.test(e)?"ipweights":e.includes("DNS-пул")?"dns":/адрес|IPv4/.test(e)?"host":e.includes("Unix")?"unix":e.includes("порт")?"port":e.startsWith("вес")?"weight":e.startsWith("стоимость")?"cost":"row"}function Ir(e){const s=new Map,n=[];for(const a of e){const i=/^Сервер (\d+): (.+)$/.exec(a);if(!i){n.push(a);continue}const h=Number(i[1])-1,l=i[2],d=s.get(h)??[];d.push({cell:Nr(l),message:l.charAt(0).toUpperCase()+l.slice(1)}),s.set(h,d)}return{perServer:s,general:n}}function Sr({servers:e,balanceMode:s,poolSettings:n,onChange:a,errors:i}){const h=e.length>=16,l=de({servers:e,balanceMode:s}),d={servers:e,balanceMode:l},u=l==="failover"&&e.length>1,p=e.length>1,{perServer:r,general:m}=Ir(i),g=!!n?.showCost,f=g?["name","type","host","port","dns","weight","cost","actions"]:["name","type","host","port","dns","weight","actions"],o=_=>(_==="role"?f.indexOf("weight"):f.indexOf(_))+1,v={"--srv-cols":f.map(_=>$r[_]).join(" "),"--srv-sub-start":String(o("name"))},P=!!n,$="Нужно два сервера или DNS-пул в режиме «Пул»",j=(_,b)=>{a(e.map((M,I)=>I===_?{...M,...b}:M))},N=_=>{const b=e.filter((M,I)=>I!==_);b.length>0&&b.every(M=>M.backup)&&(b[0]={...b[0],backup:!1}),a(b)},x=(_,b)=>{j(_,b?{backup:b,preferredIP:""}:{backup:b})},E=(_,b)=>{const M=_+b;if(M<0||M>=e.length)return;const I=[...e];[I[_],I[M]]=[I[M],I[_]],a(I)};return t.jsxs("div",{className:"nf-servers",children:[t.jsxs("div",{className:`nf-srv-table${u?" is-failover":""}`,style:v,children:[t.jsxs("div",{className:"nf-srv-table__head","aria-hidden":"true",children:[t.jsx("span",{className:"is-field",children:"Имя"}),t.jsx("span",{className:"is-field",children:"Тип"}),t.jsx("span",{className:"is-field",children:"Адрес"}),t.jsx("span",{className:"is-field",children:"Порт"}),t.jsx("span",{className:"is-center",children:t.jsx(ge,{label:"HAProxy резолвит домен и распределяет трафик по всем его IP. Только для домена.",multiline:!0,w:240,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"DNS-пул"})})}),u?t.jsx("span",{className:"nf-srv-table__role-head",children:"Роль"}):t.jsxs(t.Fragment,{children:[t.jsx("span",{className:`is-field${P?"":" is-off"}`,children:t.jsx(ge,{label:P?"Доля новых клиентов относительно других серверов: 2 — вдвое больше, чем у сервера с весом 1. Пусто — 1.":`Вес: ${$.toLowerCase()}.`,multiline:!0,w:220,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Вес"})})}),g&&t.jsx("span",{className:"is-field",children:t.jsx(ge,{label:"Множитель задержки: 2 — сервер кажется вдвое медленнее. Пусто — 1.",multiline:!0,w:220,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Стоимость"})})})]}),t.jsx("span",{})]}),e.map((_,b)=>{const M=_.host.trim()!==""&&te(_.host),I=_.targetType==="tcp",ue=_.name.trim()||`сервер ${b+1}`,ie=Xe(d,b),Z=r.get(b)??[],K=k=>Z.find(X=>X.cell===k)?.message,G=Z.filter(k=>k.cell!=="preferred"&&k.cell!=="ipweights"),pe=I&&bt({servers:e,balanceMode:l},b),le=I&&_.dnsPool&&n;return t.jsxs("div",{className:`nf-srv-row${ie?" is-backup":""}${Z.length?" has-error":""}`,children:[t.jsx(Te,{className:"nf-srv-row__name",label:"Имя",placeholder:"srv1",maxLength:as,value:_.name,onChange:k=>j(b,{name:k.currentTarget.value}),error:K("name")?!0:void 0}),t.jsx(Ge,{className:"nf-srv-row__type",label:"Тип",value:_.targetType,onChange:k=>j(b,{targetType:k??"tcp",dnsPool:!1,preferredIP:""}),allowDeselect:!1,data:[{value:"tcp",label:"IP / домен"},{value:"unix",label:"Unix socket"}]}),I?t.jsxs(t.Fragment,{children:[t.jsx(Te,{className:"nf-srv-row__host",label:"Адрес",placeholder:"IP или домен",value:_.host,onChange:k=>j(b,{host:k.currentTarget.value}),error:K("host")?!0:void 0}),t.jsx(Me,{className:"nf-srv-row__port",label:"Порт",value:_.port,onChange:k=>j(b,{port:k===""?"":Number(k)}),min:1,max:65535,allowDecimal:!1,hideControls:!0,inputMode:"numeric",error:K("port")?!0:void 0}),t.jsx(ge,{label:"DNS-пул доступен только для домена",disabled:!M,openDelay:150,children:t.jsxs("div",{className:"nf-srv-row__dns",children:[t.jsx(Ae,{size:"sm","aria-label":`DNS-пул для ${ue}: все IP домена`,checked:_.dnsPool,disabled:M&&!_.dnsPool,error:K("dns")?!0:void 0,onChange:k=>j(b,{dnsPool:k.currentTarget.checked,preferredIP:k.currentTarget.checked?_.preferredIP:""})}),t.jsx("span",{className:"nf-srv-row__dns-label","aria-hidden":"true",children:"DNS-пул"})]})})]}):t.jsx(Te,{className:"nf-srv-row__unix",label:"Путь socket",placeholder:"/run/service.sock",value:_.unixSocketPath,onChange:k=>j(b,{unixSocketPath:k.currentTarget.value}),error:K("unix")?!0:void 0}),u?t.jsx("div",{className:"nf-srv-row__role",children:t.jsxs("span",{className:`nf-role-badge${ie?" is-backup":""}`,children:[t.jsx("b",{children:b+1}),ie?"Резерв":"Основной"]})}):t.jsxs(t.Fragment,{children:[t.jsx(ge,{label:$,disabled:P,openDelay:200,children:t.jsx("div",{className:"nf-srv-row__weight",children:t.jsx(Me,{label:"Вес",placeholder:P?"1":"—",value:P?_.weight:"",onChange:k=>j(b,{weight:k===""?"":Number(k)}),min:1,max:256,allowDecimal:!1,hideControls:!0,inputMode:"numeric",disabled:!P,error:P&&K("weight")?!0:void 0})})}),g&&t.jsx("div",{className:"nf-srv-row__cost",children:t.jsx(Me,{label:"Стоимость",placeholder:"1",value:_.cost,onChange:k=>j(b,{cost:k===""?"":Number(k)}),min:.01,max:100,decimalScale:2,hideControls:!0,inputMode:"decimal",error:K("cost")?!0:void 0})})]}),t.jsx("div",{className:"nf-srv-row__actions",children:t.jsxs($e,{position:"bottom-end",withinPortal:!0,shadow:"md",width:210,children:[t.jsx($e.Target,{children:t.jsx(Es,{variant:"subtle",color:"gray",size:36,"aria-label":`Действия: ${ue}`,children:t.jsx(ni,{size:16})})}),t.jsxs($e.Dropdown,{children:[u&&t.jsxs(t.Fragment,{children:[t.jsx($e.Item,{leftSection:t.jsx(ti,{size:14}),disabled:b===0,onClick:()=>E(b,-1),children:"Выше"}),t.jsx($e.Item,{leftSection:t.jsx(si,{size:14}),disabled:b===e.length-1,onClick:()=>E(b,1),children:"Ниже"}),t.jsx($e.Item,{leftSection:t.jsx(wi,{size:14}),onClick:()=>x(b,!_.backup),children:_.backup?"Сделать основным":"Сделать резервным"}),t.jsx($e.Divider,{})]}),t.jsx($e.Item,{color:"red",leftSection:t.jsx(Os,{size:14}),disabled:!p,onClick:()=>N(b),children:"Удалить сервер"})]})]})}),G.map(k=>{const X=k.cell==="row"?"name":k.cell==="unix"?"host":k.cell;return t.jsx("p",{className:"nf-cell-error nf-srv-row__error",style:{gridColumn:`${Math.max(1,o(X))} / -1`},children:k.message},`${k.cell}-${k.message}`)}),pe&&t.jsx(_r,{server:_,hasOtherServers:e.length>1,error:K("preferred"),onChange:k=>j(b,{preferredIP:k})}),le&&t.jsx(kr,{server:_,agentAllowed:n.agentAllowed,showCost:n.showCost,connections:n.connections,weightsFixed:n.weightsFixed,error:K("ipweights"),onChange:k=>j(b,{ipWeights:k})})]},_._key)})]}),m.length>0&&t.jsx("div",{className:"nf-servers__errors",role:"alert","data-invalid":"true",tabIndex:-1,children:m.map(_=>t.jsxs("p",{className:"nf-cell-error",children:[t.jsx(Re,{size:13,"aria-hidden":"true"}),_]},_))}),t.jsxs("div",{className:"nf-servers__footer",children:[t.jsx(fe,{variant:"default",size:"sm",leftSection:t.jsx(Yt,{size:14}),disabled:h,onClick:()=>a([...e,{...en(Yi(e)),backup:e.length>0}]),children:"Добавить сервер"}),h&&t.jsx("span",{className:"nf-muted",children:"Максимум — 16 серверов."})]})]})}function Mr(e){const s=e.servers,n=s.length===1;if(de(e)==="pool")return n?"Нагрузка делится между всеми IP домена.":"Нагрузка делится между всеми серверами и всеми IP доменов с DNS-пулом.";const a=bt(e,0)&&s[0].preferredIP.trim()!=="";if(n)return a?"Трафик идёт на основной IP; если он упал — делится между всеми IP домена.":"Задайте основной IP — он получит весь трафик, остальные IP домена станут резервом.";const i=a||s.some((u,p)=>Xe(e,p)&&u.targetType==="tcp"&&u.dnsPool),h=s.filter((u,p)=>!Xe(e,p)).length,l=h>1?"Трафик делится между основными серверами":"Трафик идёт на основной сервер",d=h>1?"если все основные упали":"если он упал";return i?`${l}; ${d} — делится между всеми резервными сразу.`:`${l}; резервные включаются по порядку, ${d}.`}function Tr({draft:e,update:s,agent110:n,agentVersion:a,autoTableEntries:i,memoryKnown:h,showError:l}){const d=Oe(e),u=Ri(d),p=Le(e),r=Qs(p),m=Hs(e.stickyTTL||Ce),g=e.stickyTableEntries==="",f=Ct(e.stickyTableEntries||i),o=u==="hash"?128:64,v=l(["stickyTTL"]),P=l(["stickyTableEntries"]),$=Js(e.stickyTableEntries||i),j=t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-algorithm",stableHint:!0,label:u==="table"?"Первый сервер":"Алгоритм",hint:u==="table"?"Как выбрать сервер для нового клиента.":Jt.find(x=>x.value===r)?.description,children:t.jsx(Ge,{id:"dist-algorithm",className:"nf-select-md",size:"sm",value:r,onChange:x=>{x&&s("balanceAlgorithm",x)},allowDeselect:!1,data:Jt.map(({value:x,label:E})=>({value:x,label:E,disabled:x==="leastping"&&!n})),"aria-describedby":"dist-algorithm-hint"})}),r==="roundrobin"&&t.jsx(R,{id:"dist-dynamic",label:"Веса на лету",hint:"Выкл — веса фиксированы: вес IP и плавный ввод не действуют.",children:t.jsx(Ae,{id:"dist-dynamic",checked:p!=="static-rr",onChange:x=>s("balanceAlgorithm",x.currentTarget.checked?"roundrobin":"static-rr"),"aria-describedby":"dist-dynamic-hint"})}),r==="random"&&t.jsx(R,{id:"dist-draws",label:"Выборок",hint:"Из стольких случайных серверов берётся менее загруженный.",error:l(["balanceRandomDraws"]),children:t.jsx(ce,{id:"dist-draws",value:e.balanceRandomDraws,onValue:x=>s("balanceRandomDraws",x),placeholder:"2",min:1,max:5,allowDecimal:!1,inputMode:"numeric",error:l(["balanceRandomDraws"])?!0:void 0,"aria-describedby":"dist-draws-hint"})}),r==="leastconn"&&t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-tolerance",label:"Толерантность",hint:"Серверы, где соединений на единицу веса больше минимума не более чем на столько, считаются равными.",aside:"Пусто — 0",error:l(["leastpingTolerancePct"]),children:t.jsx(ce,{id:"dist-tolerance",unit:"%",value:e.leastpingTolerancePct,onValue:x=>s("leastpingTolerancePct",x),placeholder:"0",min:0,max:100,allowDecimal:!1,inputMode:"numeric",error:l(["leastpingTolerancePct"])?!0:void 0,"aria-describedby":"dist-tolerance-hint"})}),t.jsxs(Gt,{children:["Вес — в таблице серверов. Толерантность больше 0 применяет агент ноды каждые 5 с.",rr(a)?"":` Нужен Node Agent ${fn}, на ноде ${a??"неизвестно"}.`]})]}),r==="leastping"&&t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-tolerance",label:"Толерантность",hint:"Кто медленнее лучшего не больше чем на столько — получает полный вес.",error:l(["leastpingTolerancePct"]),children:t.jsx(ce,{id:"dist-tolerance",unit:"%",value:e.leastpingTolerancePct,onValue:x=>s("leastpingTolerancePct",x),placeholder:String(zs),min:0,max:100,allowDecimal:!1,inputMode:"numeric",error:l(["leastpingTolerancePct"])?!0:void 0,"aria-describedby":"dist-tolerance-hint"})}),t.jsx(R,{id:"dist-floor",label:"Толерантность не меньше",hint:"Разница до стольких мс не в счёт. Пусто — выкл.",error:l(["leastpingToleranceMs"]),children:t.jsx(ce,{id:"dist-floor",unit:"мс",value:e.leastpingToleranceMs,onValue:x=>s("leastpingToleranceMs",x),placeholder:"выкл",min:0,max:1e3,allowDecimal:!1,inputMode:"numeric",error:l(["leastpingToleranceMs"])?!0:void 0,"aria-describedby":"dist-floor-hint"})}),t.jsxs(Gt,{children:["Задержку меряет проверка здоровья, агент ноды обновляет веса каждые 5 с. Стоимость — в таблице серверов.",n?"":` Нужен Node Agent ${ft}, на ноде ${a??"неизвестно"}.`]})]})]}),N=t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-ipv6-clients",group:!0,label:"IPv6-клиенты",hint:"Выключите, если на ноде нет IPv6: таблица будет только для IPv4.",children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:e.clientIPv6?"on":"off",onChange:x=>s("clientIPv6",x==="on"),data:[{value:"on",label:"Вкл"},{value:"off",label:"Выкл"}],"aria-labelledby":"dist-ipv6-clients-label","aria-describedby":"dist-ipv6-clients-hint"})}),t.jsx(R,{id:"dist-ipv6",stableHint:!0,label:"Подсеть IPv6-клиента",inactive:!e.clientIPv6,hint:"Все адреса из одной подсети считаются одним клиентом; /128 — каждый адрес отдельно.",aside:`Пусто — /${o}`,error:e.clientIPv6?l(["stickyIPv6Prefix"]):void 0,children:t.jsx(ce,{id:"dist-ipv6",value:!e.clientIPv6||e.stickyIPv6Prefix===0?"":e.stickyIPv6Prefix,onValue:x=>s("stickyIPv6Prefix",x===""||u==="hash"&&x===128?0:x),placeholder:String(o),min:32,max:128,allowDecimal:!1,inputMode:"numeric",leftSection:"/",disabled:!e.clientIPv6,error:e.clientIPv6&&l(["stickyIPv6Prefix"])?!0:void 0,"aria-describedby":"dist-ipv6-hint"})})]});return t.jsxs("div",{className:"nf-re-block nf-dist",children:[t.jsx(Zt,{title:"Распределение клиентов",hint:"Какой сервер получает клиент: выбирается заново или всегда тот же.",id:"dist-choice-label"}),t.jsx("div",{className:"nf-choice-cards",role:"radiogroup","aria-labelledby":"dist-choice-label",children:Ai.map(x=>{const E=x.value===u;return t.jsxs("button",{type:"button",role:"radio","aria-checked":E,className:`nf-choice-card${E?" is-selected":""}`,onClick:()=>s("stickyMode",Oi(x.value)),children:[t.jsx("span",{className:"nf-choice-card__radio","aria-hidden":"true"}),t.jsx("strong",{children:x.label}),t.jsx("small",{children:x.description})]},x.value)})}),t.jsxs(ct,{"data-choice":u,children:[u==="algorithm"&&j,u==="hash"&&t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-hash",group:!0,stableHint:!0,label:"Распределение",hint:e.stickyHash==="map-based"?"Ровнее, но при смене серверов переезжают почти все.":"При смене серверов переезжают только их клиенты.",children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:e.stickyHash==="map-based"?"even":"stable",onChange:x=>s("stickyHash",x==="even"?"map-based":""),data:[{value:"stable",label:"Стабильное"},{value:"even",label:"Ровное"}],"aria-labelledby":"dist-hash-label","aria-describedby":"dist-hash-hint"})}),t.jsx(R,{id:"dist-factor",stableHint:!0,inactive:e.stickyHash==="map-based",label:"Лимит перегрузки",hint:e.stickyHash==="map-based"?"Только для стабильного распределения.":"Не больше этого % от средней нагрузки. Пусто — выкл.",error:e.stickyHash!=="map-based"?l(["stickyHashBalanceFactor"]):void 0,children:t.jsx(ce,{id:"dist-factor",unit:"%",value:e.stickyHash==="map-based"?"":e.stickyHashBalanceFactor,onValue:x=>s("stickyHashBalanceFactor",x),placeholder:"выкл",min:101,max:1e3,allowDecimal:!1,inputMode:"numeric",disabled:e.stickyHash==="map-based",error:e.stickyHash!=="map-based"&&l(["stickyHashBalanceFactor"])?!0:void 0,"aria-describedby":"dist-factor-hint"})}),N]}),u==="table"&&t.jsxs(t.Fragment,{children:[t.jsxs(R,{id:"dist-ttl",label:"Помнить",hint:"Сколько клиент держится за сервер после последнего соединения.",error:v,children:[t.jsxs("div",{className:"nf-combo",children:[t.jsx(ce,{id:"dist-ttl",value:m.amount,onValue:x=>s("stickyTTL",x===""?Ce:`${x}${m.unit}`),min:1,allowDecimal:!1,inputMode:"numeric",error:v?!0:void 0,"aria-describedby":"dist-ttl-hint"}),t.jsx(Ge,{className:"nf-select-unit",size:"sm",value:m.unit,onChange:x=>{x&&m.amount!==""&&s("stickyTTL",`${m.amount}${x}`)},allowDeselect:!1,data:(m.unit==="s"?["s","m","h"]:["m","h"]).map(x=>({value:x,label:Vs[x]})),"aria-label":"Единица времени"})]}),t.jsx("div",{className:"nf-picks",role:"group","aria-label":"Быстрый выбор срока",children:Li.map(x=>{const E=(e.stickyTTL||Ce)===x;return t.jsx("button",{type:"button",className:`nf-pick${E?" is-selected":""}`,"aria-pressed":E,onClick:()=>s("stickyTTL",x),children:qi(x)},x)})})]}),t.jsxs(R,{id:"dist-table",wide:!0,stableHint:!0,group:g,label:"Клиентов в памяти",hint:"Память занимается по мере прихода клиентов; запись удаляется через «Помнить» без соединений. Когда места нет, самые старые забываются.",aside:g?Vi(i,h):$?`${$} при заполнении`:void 0,error:P,children:[t.jsx(Ne,{className:"nf-seg",size:"sm",value:g?"auto":"manual",onChange:x=>s("stickyTableEntries",x==="auto"?"":xs(Ct(i))),data:[{value:"auto",label:"Авто"},{value:"manual",label:"Задать"}],"aria-labelledby":"dist-table-label"}),t.jsx(ce,{wide:!0,unit:"клиентов",id:"dist-table",value:f||"",onValue:x=>{x!==""&&s("stickyTableEntries",xs(x))},min:1,max:Ot,allowDecimal:!1,inputMode:"numeric",thousandSeparator:" ",disabled:g,error:P?!0:void 0,"aria-describedby":"dist-table-hint dist-table-aside"})]}),N,t.jsx(lr,{}),j]}),u!=="algorithm"&&t.jsxs(Gt,{children:[u==="table"?"Таблица переживает перезагрузку HAProxy. ":"","IP клиента берётся из PROXY protocol, если он приходит, иначе — адрес соединения."]})]})]})}function zr(){const{nodeId:e="",routeId:s}=Cn(),n=En(),a=Dn(),i=An(),h=C.useRef(null),l=C.useRef(!1),d=C.useRef(null),[u,p]=C.useState(null),[r,m]=C.useState(vs),[g,f]=C.useState(""),[o,v]=C.useState(!0),[P,$]=C.useState(null),[j,N]=C.useState(!1),[x,E]=C.useState(null),[_,b]=C.useState("enable"),[M,I]=C.useState(""),[ue,ie]=C.useState(""),[,Z]=C.useState(!1),[K,G]=C.useState(!1),[pe,le]=C.useState(!1),[k,X]=C.useState(""),z=async()=>{v(!0),$(null),I("");try{const c=await gr(e,s),A=c.route?tn(c.route):vs();p(c),m(A),le(!!A.expertOverride);const Q=!!A.expertOverride||A.quotaEnabled||A.clientBandwidthEnabled||A.shaperMode==="kernel";Z(!!A.expertOverride),G(Q),f(JSON.stringify(A))}catch(c){$(c)}finally{v(!1)}};C.useEffect(()=>{if(s&&d.current===s){d.current=null;return}z()},[e,s]);const U=u?.routes??[],Ee=C.useMemo(()=>ws(r,[],u?.route?.id),[r,u?.route?.id]),xe=C.useMemo(()=>ws(r,U,u?.route?.id),[r,U,u?.route?.id]),F=_==="draft"?Ee:xe,W=u?.memoryTotalBytes,re=C.useMemo(()=>or(r,U.filter(c=>c.id!==u?.route?.id),W),[r,U,u?.route?.id,W]),_e=C.useMemo(()=>{const c=u?.route;return c&&Xs({...c,enabled:!0})&&c.sticky_table_entries_effective?c.sticky_table_entries_effective:Ys(U.filter(A=>A.id!==u?.route?.id),W)},[U,u?.route,W]),ae=!!g&&JSON.stringify(r)!==g,H=Rn(({currentLocation:c,nextLocation:A})=>!l.current&&ae&&!x&&c.pathname!==A.pathname);C.useEffect(()=>{l.current=!1},[a.key]);const he=!!u?.route,y=!!u?.route?.enabled,w=ut?"?demo=1":a.search,V=`/nodes/${encodeURIComponent(e)}${w}`,D=c=>`/nodes/${encodeURIComponent(e)}/routes/${encodeURIComponent(c)}/edit${w}`;On(c=>{!ae||x||(c.preventDefault(),c.returnValue="")});const S=(c,A)=>{m(Q=>({...Q,[c]:A})),ie(""),I(""),c==="shaperMode"&&X("")},se=()=>n(V),J=()=>{window.requestAnimationFrame(()=>window.requestAnimationFrame(()=>{const c=h.current?.querySelector('[aria-invalid="true"], [data-invalid="true"]');c?.focus({preventScroll:!0}),c?.scrollIntoView({block:"center",behavior:"smooth"})}))},ve=()=>{N(!0),F.some(c=>["quota","clientUploadMbps","clientDownloadMbps","bandwidth"].includes(c.field))&&G(!0),F.some(c=>c.field==="expert")&&Z(!0),J()},De=async c=>{b(c),N(!0),I(""),ie("");const A=c==="draft"?Ee:xe;if(A.length){A.some(L=>L.field==="expert")&&Z(!0),J();return}if(!u)return;E(c);let Q=!1;try{let L;if(ut){await new Promise(ee=>window.setTimeout(ee,420)),L={id:u.route?.id??St(),node_id:e,version:(u.route?.version??0)+1,...We(r,c!=="draft"),listener_port:Number(r.listenerPort),target_port:r.servers[0]?.targetType==="unix"?0:Number(r.servers[0]?.port??443),deployed:c!=="draft",deployment_state:c==="draft"?"draft":"pending",created_at:u.route?.created_at??new Date().toISOString(),updated_at:new Date().toISOString()};const{upsertDemoRoute:q}=await es(async()=>{const{upsertDemoRoute:ee}=await import("./demo-k0hjezoN.js");return{upsertDemoRoute:ee}},[]);q(e,L)}else if(u.route)L=await Ie(`/api/v1/nodes/${e}/routes/${u.route.id}`,{method:"PUT",body:JSON.stringify(We(r,c==="apply"||c==="enable",u.route.version))});else{const q=await Is(e,await Ie(`/api/v1/nodes/${e}/routes`,{method:"POST",body:JSON.stringify(We(r,!1))})),ee=Ns(r,q);Q=!0,d.current=q.id,p(He=>He&&{...He,route:q,routes:[...He.routes.filter(Ht=>Ht.id!==q.id),q]}),m(ee),f(JSON.stringify(ee)),l.current=!0,n(D(q.id),{replace:!0}),c==="draft"?L=q:L=await Ie(`/api/v1/nodes/${e}/routes/${q.id}`,{method:"PUT",body:JSON.stringify(We(r,!0,q.version))})}ut||(L=await Is(e,L),i.invalidateQueries({queryKey:["node-detail",e]}));const je=Ns(r,L);p(q=>q&&{...q,route:L,routes:[...q.routes.filter(ee=>ee.id!==L.id),L]}),m(je),f(JSON.stringify(je)),ie(br(c,he)),!he&&!Q&&(l.current=!0,n(D(L.id),{replace:!0}))}catch(L){const je=L instanceof Error?L.message:"Маршрут не сохранён",q=L instanceof Ds&&L.code===pr;q&&(X(`${Xt}. Выберите HAProxy или обновите агент.`),G(!0));const ee=q?`${Xt}.`:je.includes("version")?"Маршрут изменился в другой вкладке. Обновите данные и повторите.":je;I(Q?`Черновик сохранён, но включить маршрут не удалось: ${ee}`:ee)}finally{E(null)}},Y=c=>{c.preventDefault(),De(y?"apply":"enable")},Fe=()=>{H.state==="blocked"&&H.proceed()};if(o)return t.jsx("main",{className:"nf-page nf-route-editor-page",children:t.jsxs("div",{className:"nf-route-editor-loading",children:[t.jsx(Bn,{visible:!0}),t.jsx("span",{children:"Загружаем маршруты ноды и проверяем конфликты портов…"})]})});if(P&&Cs(P))return t.jsx(Ln,{onSuccess:z});if(P||!u)return t.jsx("main",{className:"nf-page",children:t.jsx(Zn,{title:"Редактор не загрузился",description:P instanceof Error?P.message:"Нода или маршрут не найдены",tone:"error",action:t.jsxs(t.Fragment,{children:[t.jsx(fe,{variant:"default",onClick:()=>n(`/nodes${w}`),children:"К нодам"}),t.jsx(fe,{onClick:z,children:"Повторить"})]})})});const B=c=>j?hr(F,c):void 0,Qe=j?F.filter(c=>c.field==="servers").map(c=>c.message):[],Lt=_s.find(c=>c.value===r.quotaPeriod)?.description,Ze=F.length===0,Ft=Ze?"valid":j?"invalid":"incomplete",gt=r.listenerIP==="*"||r.listenerIP==="0.0.0.0"||r.listenerIP==="::",be=gt?"all":"specific",Be=an(r),et=Je(r),ye=Oe(r),ne=nn(r),Bt=de(r),qe=Le(r),ze=ls(r),tt=Qi(u.agentVersion),st=tt,xt=!!k||!st&&r.shaperMode==="kernel",Pe=k||(st?"":`${Xt} (сейчас ${u.agentVersion}).${r.shaperMode==="kernel"?" Выберите HAProxy.":""}`),_t=ye!=="source"&&qe==="static-rr"||ye==="source"&&r.stickyHash==="map-based",nt=et?{showCost:ye!=="source"&&qe==="leastping",connections:ye!=="source"&&qe==="leastconn",weightsFixed:_t,agentAllowed:tt}:null,vt=`${gt?"*":r.listenerIP||"—"}:${r.listenerPort||"—"}`,it=[r.matchMode==="sni"?r.snis.length?`SNI · ${r.snis.length} ${Wt(r.snis.length,["домен","домена","доменов"])}`:"SNI":"Фолбэк",vt,r.acceptProxyEnabled?"принимает PROXY":""].filter(Boolean).join(" · "),rt=Jt.find(c=>c.value===Qs(qe))?.label.toLowerCase(),qt=et?ye==="source"?"закрепление по IP":ye==="source_table"?`запоминание · ${rt}`:rt:"",yt=[`${r.servers.length} ${Wt(r.servers.length,["сервер","сервера","серверов"])}`,Be?"DNS-пул":"",ne?Bt==="pool"?"пул":"основной + резервные":"",qt??""].filter(Boolean).join(" · "),at=[];if(r.quotaEnabled&&r.quotaValue!==""&&at.push(`лимит ${r.quotaValue} ${r.quotaUnit}`),r.clientBandwidthEnabled){const c=[];r.clientUploadMbps!==""&&c.push(`↑${r.clientUploadMbps}`),r.clientDownloadMbps!==""&&c.push(`↓${r.clientDownloadMbps}`),c.length&&at.push(`скорость ${c.join(" ")} Мбит/с${r.shaperMode==="kernel"?" · ядро":""}`)}const oe=at.join(" · ")||"Лимит трафика и скорости не заданы",zt=j&&F.some(c=>["quota","clientUploadMbps","clientDownloadMbps","bandwidth"].includes(c.field)),Pt=K||zt,jt=y?"apply":"enable",wt=j?F.length:0,O=!j&&xe.length>0?fr(xe):"",me=x?{tone:"busy",text:"Сохраняем…"}:M?{tone:"error",text:"Не сохранено"}:ue&&!ae?{tone:"saved",text:ue}:ae?{tone:"dirty",text:"Есть несохранённые изменения"}:{tone:"clean",text:he?"Изменений нет":"Новый маршрут"};return t.jsxs("main",{className:"nf-page nf-route-editor-page",children:[t.jsx(zn,{className:"nf-route-editor-header",breadcrumb:t.jsxs(t.Fragment,{children:[t.jsx(hs,{to:`/nodes${w}`,children:"Ноды"}),t.jsx("span",{children:"/"}),t.jsx(hs,{to:V,children:u.node.name}),t.jsx("span",{children:"/"}),t.jsx("span",{"aria-current":"page",children:he?"Маршрут":"Новый маршрут"})]}),backAction:t.jsx(fe,{variant:"subtle",color:"gray",px:6,onClick:se,"aria-label":"Назад к ноде",children:t.jsx(vi,{size:20})}),title:he?r.name.trim()||"Без имени":"Новый маршрут",badge:t.jsxs("span",{className:`nf-route-state-badge${y?" is-enabled":""}`,children:[t.jsx("i",{"aria-hidden":"true"}),t.jsx("span",{className:"nf-visually-hidden",children:"Состояние: "}),y?"Включён":he?"Выключен":"Черновик"]})}),t.jsxs("form",{ref:h,className:"nf-route-editor-layout",onSubmit:Y,noValidate:!0,"aria-busy":!!x,children:[t.jsxs(fs,{className:"nf-route-editor-form",children:[t.jsx(ks,{id:"route-listener",index:"1",title:"Подключение",summary:it,children:t.jsxs(ct,{layout:"connection",children:[t.jsx(R,{id:"route-name",area:"name",label:"Имя маршрута",hint:"Видно только оператору.",error:B(["name"]),children:t.jsx(Te,{id:"route-name",className:"nf-input-md",placeholder:"api-internal-tls",value:r.name,onChange:c=>S("name",c.currentTarget.value),error:B(["name"])?!0:void 0,required:!0,maxLength:80,"aria-describedby":"route-name-hint"})}),t.jsx(R,{id:"route-match",area:"match",group:!0,label:"Выбор маршрута",hint:r.matchMode==="sni"?"По SNI; порт можно делить.":"Всё, что не совпало по SNI.",children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:r.matchMode,onChange:c=>S("matchMode",c),data:[{value:"sni",label:"По SNI"},{value:"fallback",label:"Фолбэк"}],"aria-labelledby":"route-match-label","aria-describedby":"route-match-hint"})}),t.jsxs(R,{id:"route-listen",area:"listen",group:!0,label:"Слушать",hint:be==="all"?"Все адреса ноды.":"Один адрес ноды.",error:B(["listenerIP","listener"]),children:[t.jsx(Ne,{className:"nf-seg",size:"sm",value:be,onChange:c=>{S("listenerIP",c==="all"?"*":u.node.address||"")},data:[{value:"all",label:"Все IP"},{value:"specific",label:"Один IP"}],"aria-labelledby":"route-listen-label"}),t.jsx(Te,{className:"nf-listen-ip",placeholder:be==="specific"?"203.0.113.1":"все адреса",value:be==="specific"?r.listenerIP:"",onChange:c=>S("listenerIP",c.currentTarget.value),error:be==="specific"&&B(["listenerIP","listener"])?!0:void 0,disabled:be!=="specific","aria-label":"IP-адрес listener",required:be==="specific"})]}),t.jsx(R,{id:"route-port",area:"port",label:"Порт",hint:"TCP на ноде.",error:B(["listenerPort"]),children:t.jsx(Me,{id:"route-port",className:"nf-num",hideControls:!0,value:r.listenerPort,onChange:c=>S("listenerPort",c===""?"":Number(c)),error:B(["listenerPort"])?!0:void 0,min:1,max:65535,allowDecimal:!1,inputMode:"numeric",required:!0,"aria-describedby":"route-port-hint"})}),r.matchMode==="sni"?t.jsx(R,{id:"route-sni",area:"sni",grow:!0,label:"Домены SNI",hint:"Enter, пробел или запятая — следующий домен.",error:B(["snis"]),children:t.jsx(Tt,{id:"route-sni",className:"nf-route-sni-input",classNames:{pill:"nf-route-sni-pill",pillsList:"nf-route-sni-pills",inputField:"nf-route-sni-field"},placeholder:r.snis.length?"":"api.example.com",value:r.snis,onChange:c=>S("snis",c),error:B(["snis"])?!0:void 0,splitChars:[","," "],clearable:!0,required:!0,"aria-describedby":"route-sni-hint"})}):t.jsx(R,{id:"route-sni",area:"sni",grow:!0,inactive:!0,label:"Домены SNI",hint:"Фолбэк получает соединения без совпавшего SNI.",children:t.jsx(Te,{id:"route-sni",className:"nf-route-sni-input",placeholder:"не нужны для фолбэка",value:"",disabled:!0,"aria-describedby":"route-sni-hint"})}),t.jsx(R,{id:"route-accept-proxy",area:"proxy",inline:!0,label:"Принимать PROXY protocol",hint:"Прокси перед нодой передаёт IP клиента.",children:t.jsx(Ae,{id:"route-accept-proxy",checked:r.acceptProxyEnabled,onChange:c=>{const A=c.currentTarget.checked;S("acceptProxyEnabled",A),A||S("acceptProxyFrom",[])},"aria-describedby":"route-accept-proxy-hint"})}),t.jsx(dt,{in:r.acceptProxyEnabled,className:"nf-setgrid__collapse",children:t.jsxs("div",{className:"nf-setgrid__collapse-body",children:[t.jsx(R,{id:"route-accept-from",grow:!0,label:"Доверенные адреса",hint:"IP, подсети или домены (IP домена обновляются сами). Пусто — ждать PROXY от всех.",error:B(["acceptProxyFrom"]),children:t.jsx(Tt,{id:"route-accept-from",className:"nf-input-lg",placeholder:r.acceptProxyFrom.length?"":"10.0.0.0/8",value:r.acceptProxyFrom,onChange:c=>S("acceptProxyFrom",c),error:B(["acceptProxyFrom"])?!0:void 0,splitChars:[","," "],clearable:!0,"aria-describedby":"route-accept-from-hint"})}),r.acceptProxyFrom.length===0&&t.jsxs("p",{className:"nf-inline-warning",role:"note",children:[t.jsx(Rs,{size:14,"aria-hidden":"true"}),t.jsx("span",{children:"Клиенты без PROXY protocol не подключатся к этому порту — это действует на все маршруты порта."})]})]})})]})}),t.jsxs(ks,{id:"route-target",index:"2",title:"Назначение",summary:yt,children:[t.jsxs("div",{className:"nf-re-block",children:[t.jsxs("div",{className:"nf-re-block-row nf-re-block-row--servers",children:[t.jsx(Zt,{title:"Серверы",hint:ne?Mr(r):"Добавьте второй сервер или DNS-пул, чтобы делить нагрузку.",stableHint:!0}),t.jsx(ge,{label:"Нужно два сервера или DNS-пул",disabled:ne,openDelay:200,children:t.jsx("span",{className:"nf-inline-flex nf-balance-mode",children:t.jsx(Ne,{className:"nf-seg nf-seg--fixed",size:"sm",value:ne?r.balanceMode:"pool",disabled:!ne,onChange:c=>{const A=c;S("balanceMode",A),A==="failover"&&r.balanceMode!=="failover"&&S("servers",rn(r.servers))},data:[{value:"pool",label:"Пул"},{value:"failover",label:"Основной + резервные"}],"aria-label":"Как распределять трафик"})})})]}),t.jsx(Sr,{servers:r.servers,balanceMode:r.balanceMode,poolSettings:nt,onChange:c=>S("servers",c),errors:Qe})]}),t.jsx(dt,{in:et,children:t.jsx(Tr,{draft:r,update:S,agent110:tt,agentVersion:u.agentVersion,autoTableEntries:_e,memoryKnown:!!(W&&W>0),showError:B})}),t.jsxs("div",{className:"nf-re-block nf-re-block--aside",children:[t.jsx(Zt,{title:"Соединение с серверами",hint:"Как нода подключается к серверам."}),t.jsxs(ct,{children:[t.jsx(R,{id:"route-health",inline:!0,stableHint:!0,label:"Проверка здоровья",hint:Be?"Для DNS-пула включена всегда.":"TCP каждые 5 с; недоступный сервер исключается.",children:t.jsx(Ae,{id:"route-health",checked:r.healthCheck||Be,disabled:Be,onChange:c=>S("healthCheck",c.currentTarget.checked),"aria-describedby":"route-health-hint"})}),t.jsx(R,{id:"route-proxy-out",group:!0,stableHint:!0,label:"PROXY protocol к серверу",hint:r.proxyProtocol==="none"?"Передать IP клиента; сервер должен принимать PROXY.":`Без поддержки PROXY на сервере соединения не пройдут.${ze?" Проверка тоже шлёт заголовок.":""}`,children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:r.proxyProtocol,onChange:c=>S("proxyProtocol",c),data:[{value:"none",label:"Нет"},{value:"v1",label:"v1"},{value:"v2",label:"v2"}],"aria-labelledby":"route-proxy-out-label","aria-describedby":"route-proxy-out-hint"})}),t.jsx(R,{id:"route-slowstart",stableHint:!0,label:"Плавный ввод после восстановления",inactive:!ne,hint:ne?ze?_t?"Не действует: веса фиксированы.":"Трафик на вернувшийся сервер растёт постепенно. Пусто — сразу.":"Требует проверки здоровья.":"Нужно два сервера или DNS-пул.",error:ne?B(["slowstart"]):void 0,children:t.jsx(ce,{id:"route-slowstart",unit:"с",value:ne?Ui(r.slowstart):"",onValue:c=>S("slowstart",c===""?"":`${c}s`),placeholder:"выкл",min:1,max:600,allowDecimal:!1,inputMode:"numeric",disabled:!ze||!ne,error:ne&&B(["slowstart"])?!0:void 0,"aria-describedby":"route-slowstart-hint"})})]})]})]}),t.jsxs("section",{className:`nf-re-section nf-re-section--disclosure${Pt?" is-open":""}`,"aria-labelledby":"route-additional-title",children:[t.jsxs("button",{type:"button",className:"nf-re-section__head nf-re-section__toggle",onClick:()=>G(c=>!c),"aria-expanded":Pt,"aria-controls":"route-additional-body",children:[t.jsx("span",{className:"nf-re-section__index","aria-hidden":"true",children:"3"}),t.jsx("h2",{id:"route-additional-title",children:"Дополнительно"}),t.jsx("span",{className:"nf-re-section__summary",children:oe}),t.jsx(Hn,{className:"nf-re-section__chevron",size:16,"aria-hidden":"true"})]}),t.jsx(dt,{in:Pt,children:t.jsx("div",{className:"nf-re-section__body",id:"route-additional-body",children:t.jsxs(dr,{cards:!0,children:[t.jsx($s,{title:"Лимит трафика",hint:"Счётчик трафика маршрута со сбросом по расписанию.",open:r.quotaEnabled,control:t.jsx(Ae,{checked:r.quotaEnabled,onChange:c=>S("quotaEnabled",c.currentTarget.checked),"aria-label":"Лимит трафика"}),children:t.jsxs(ct,{children:[t.jsx(R,{id:"route-quota",label:"Лимит",error:B(["quota"]),children:t.jsxs("div",{className:"nf-combo",children:[t.jsx(Me,{id:"route-quota",className:"nf-num nf-num--wide",hideControls:!0,value:r.quotaValue,onChange:c=>S("quotaValue",c===""?"":Number(c)),error:B(["quota"])?!0:void 0,min:.001,decimalScale:3,inputMode:"decimal",required:r.quotaEnabled}),t.jsx(Ge,{className:"nf-select-unit",value:r.quotaUnit,onChange:c=>S("quotaUnit",c??"GiB"),allowDeselect:!1,data:["GiB","TiB"],"aria-label":"Единица лимита"})]})}),t.jsx(R,{id:"route-quota-period",stableHint:!0,label:"Сброс",hint:Lt,children:t.jsx(Ge,{id:"route-quota-period",className:"nf-select-md",value:r.quotaPeriod,onChange:c=>S("quotaPeriod",c??"calendar_month"),allowDeselect:!1,data:_s.map(({value:c,label:A})=>({value:c,label:A}))})}),t.jsx(R,{id:"route-quota-action",stableHint:!0,label:"При достижении",hint:r.quotaAction==="block_new"?"Новые соединения не пройдут; активные сессии не разрываются.":"Панель подсветит превышение, трафик продолжит идти.",children:t.jsx(Ge,{id:"route-quota-action",className:"nf-select-md",value:r.quotaAction,onChange:c=>S("quotaAction",c??"observe"),allowDeselect:!1,data:[{value:"observe",label:"Только уведомить"},{value:"block_new",label:"Блокировать новые"}]})})]})}),t.jsx($s,{title:"Ограничение скорости",hint:"На IP клиента, для всех его соединений в маршруте.",open:r.clientBandwidthEnabled,control:t.jsx(Ae,{checked:r.clientBandwidthEnabled,onChange:c=>S("clientBandwidthEnabled",c.currentTarget.checked),"aria-label":"Ограничение скорости"}),children:t.jsxs(ct,{children:[t.jsx(R,{id:"route-up",label:"От клиента",hint:"Пусто — без лимита.",error:B(["clientUploadMbps","bandwidth"]),children:t.jsx(ce,{id:"route-up",wide:!0,unit:"Мбит/с",placeholder:"без лимита",value:r.clientUploadMbps,onValue:c=>S("clientUploadMbps",c),error:B(["clientUploadMbps","bandwidth"])?!0:void 0,min:1,max:1e6,allowDecimal:!1,inputMode:"numeric"})}),t.jsx(R,{id:"route-down",label:"К клиенту",hint:"Пусто — без лимита.",error:B(["clientDownloadMbps"]),children:t.jsx(ce,{id:"route-down",wide:!0,unit:"Мбит/с",placeholder:"без лимита",value:r.clientDownloadMbps,onValue:c=>S("clientDownloadMbps",c),error:B(["clientDownloadMbps","bandwidth"])?!0:void 0,min:1,max:1e6,allowDecimal:!1,inputMode:"numeric"})}),t.jsxs(R,{id:"route-shaper",group:!0,stableHint:!0,label:"Где ограничивать",hint:r.shaperMode==="kernel"?"nftables на ноде, splice сохраняется. Маршруты порта должны иметь одинаковые лимиты.":"Точно по маршруту (SNI), но отключает splice на этом порту.",error:Pe&&xt?Pe:void 0,children:[t.jsx(Ne,{className:"nf-seg",size:"sm",value:r.shaperMode,onChange:c=>S("shaperMode",c),data:[{value:"haproxy",label:"HAProxy"},{value:"kernel",label:"Ядро (nftables)",disabled:!st&&r.shaperMode!=="kernel"}],"aria-labelledby":"route-shaper-label","aria-describedby":"route-shaper-hint"}),Pe&&!xt&&t.jsxs("span",{className:"nf-setting-row__aside",children:["Ядро: нужен Node Agent ",ft,", на ноде ",u.agentVersion??"неизвестно"]})]})]})})]})})})]}),t.jsxs("div",{className:"nf-re-footer",children:[j&&F.length>0&&t.jsx(ms,{className:"nf-route-error-summary",color:"red",icon:t.jsx(Re,{size:18}),title:`Нужно исправить: ${F.length}`,role:"alert",children:t.jsx("ul",{children:F.slice(0,5).map((c,A)=>t.jsx("li",{children:c.message},`${c.field}-${A}`))})}),M&&t.jsx(ms,{color:"red",icon:t.jsx(Re,{size:18}),role:"alert",children:M})]}),t.jsxs("footer",{className:`nf-save-bar is-${me.tone}`,children:[t.jsxs("div",{className:"nf-save-bar__status",role:"status","aria-live":"polite",children:[t.jsx("i",{"aria-hidden":"true"}),t.jsx("span",{children:me.text}),O&&t.jsx("span",{className:"nf-save-bar__hint",children:O}),wt>0&&t.jsxs("button",{type:"button",className:"nf-save-bar__errors",onClick:ve,children:[t.jsx(Re,{size:14,"aria-hidden":"true"}),"Нужно исправить: ",wt]})]}),t.jsxs("div",{className:"nf-save-bar__actions",children:[!y&&t.jsx(fe,{variant:"default",onClick:()=>{De("draft")},loading:x==="draft",disabled:!!(x&&x!=="draft"),children:"Сохранить черновик"}),t.jsx(fe,{type:"submit",loading:x===jt,disabled:!!(x&&x!==jt),children:y?"Сохранить и применить":"Сохранить и включить"})]})]})]}),t.jsx("aside",{className:"nf-route-preview-column","aria-label":"Предпросмотр HAProxy",children:t.jsx(fs,{className:"nf-route-preview-surface",children:t.jsxs("section",{className:"nf-re-section nf-route-preview is-open","aria-labelledby":"route-preview-title",children:[t.jsxs("div",{className:"nf-re-section__head",children:[t.jsx("span",{className:"nf-re-section__index","aria-hidden":"true",children:t.jsx(Pi,{size:13})}),t.jsx("h2",{id:"route-preview-title",children:"Предпросмотр HAProxy"}),t.jsxs("span",{className:`nf-preview-validation is-${Ft}`,role:"status",children:[t.jsxs("span",{children:[Ze?t.jsx(ts,{size:14}):j?t.jsx(Re,{size:14}):t.jsx(ss,{size:14}),Ze?"Форма заполнена верно":j?`Ошибок: ${F.length}`:"Заполните обязательные поля"]}),t.jsxs("small",{children:[re.merged?`Общий frontend с ${re.merged} ${Wt(re.merged,["маршрутом","маршрутами","маршрутами"])}`:"Отдельный frontend",r.expertOverride.trim()?" · есть ручные директивы":""]})]})]}),t.jsxs("div",{className:"nf-re-section__body nf-preview-body",id:"route-preview-body",children:[t.jsxs(cr,{icon:t.jsx(Vn,{size:14,"aria-hidden":"true"}),children:["Перед применением Agent проверит конфиг через ",t.jsx("code",{children:"haproxy -c"}),"; UFW меняется только по политике ноды. Активные соединения не разрываются."]}),t.jsxs("div",{className:"nf-code-editor","aria-label":"Предпросмотр HAProxy, только чтение",children:[t.jsxs("div",{className:"nf-code-editor__bar",children:[t.jsxs("span",{children:[t.jsx("i",{}),t.jsx("i",{}),t.jsx("i",{})]}),t.jsx("b",{children:"haproxy.cfg"}),t.jsx("em",{children:"только чтение"})]}),t.jsx("pre",{children:t.jsx("code",{children:re.config})})]}),t.jsxs("section",{className:"nf-preview-expert","aria-labelledby":"route-expert-title",children:[t.jsxs("div",{className:"nf-preview-expert__head",children:[t.jsxs("span",{children:[t.jsx("strong",{id:"route-expert-title",children:"Ручные директивы backend"}),t.jsx("small",{children:"Секции global, frontend, listen, backend и resolvers запрещены."})]}),t.jsx(Ae,{checked:pe,onChange:c=>{le(c.currentTarget.checked),c.currentTarget.checked||S("expertOverride","")},"aria-label":"Разрешить ручные директивы"})]}),pe&&t.jsx(ei,{"aria-label":"Директивы backend",value:r.expertOverride,onChange:c=>S("expertOverride",c.currentTarget.value),error:B(["expert"]),placeholder:`timeout connect 5s +maxconn 2000`,autosize:!0,minRows:8,maxRows:20,classNames:{input:"nf-code-input"}})]})]})]})})})]}),t.jsx(Un,{opened:H.state==="blocked",onClose:()=>H.state==="blocked"&&H.reset(),title:"Выйти без сохранения?",size:"sm",closeOnClickOutside:!0,closeOnEscape:!0,classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:t.jsxs("div",{className:"nf-confirm-dialog",children:[t.jsx("p",{children:"Изменения маршрута будут потеряны. HAProxy и UFW не изменятся."}),t.jsxs("div",{children:[t.jsx(fe,{variant:"default",onClick:()=>H.state==="blocked"&&H.reset(),children:"Продолжить"}),t.jsx(fe,{color:"red",onClick:Fe,children:"Выйти"})]})]})})]})}export{zr as RouteEditorPage}; diff --git a/internal/panel/web_dist/assets/RouteEditorPage-PVwzgvr8.js b/internal/panel/web_dist/assets/RouteEditorPage-PVwzgvr8.js deleted file mode 100644 index 5849f74..0000000 --- a/internal/panel/web_dist/assets/RouteEditorPage-PVwzgvr8.js +++ /dev/null @@ -1,7 +0,0 @@ -import{r as C,O as _n,R as vn,Q as yn,q as Xe,s as Ye,V as Pn,W as jn,j as t,y as ut,p as Ns,t as Ct,v as Is,E as Nt,X as wn,w as kn,Y as $n,Z as Ss,G as Nn,F as In,o as ds,$ as Sn,c as Et,n as Tn,a as Mn,u as Cn,k as En,a0 as Dn,a1 as An,i as Ts,e as Rn,B as fe,L as us,f as ps,M as Oe,A as Ms,_ as Qt,g as Ie,b as Cs,a2 as On}from"./index-Dy6W__Vz.js";import{r as It,L as Ln}from"./uuid-CHFAcSZK.js";import{g as Fn,N as Te,P as Bn,T as be,I as qn,c as Zt,a as zn,b as Hn,M as $e}from"./PageHeader-C4N9uitv.js";import{m as Vn,u as Es,i as Un,h as Wn,j as Gn,k as Xn,l as Ve,O as Yn,a as Kn,S as Jn,c as hs,T as Me,I as Ds,d as We}from"./format-D6_ab21F.js";import{I as es,S as Re,T as Qn,a as Xt}from"./IconPlus-N6bDt4BE.js";import{S as Ne,a as Zn,I as er}from"./IconArrowUp-Cj3lrfzR.js";import{I as tr}from"./IconDots-B4BXVaDG.js";import{I as As}from"./IconTrash-CZzjtN_Z.js";import"./chart-react-C4b8adjg.js";function sr(e){if(!e||typeof e=="string")return 0;const s=e/36;return Math.round((4+15*s**.25+s/5)*10)}function Ht(e){return e?.current?e.current.scrollHeight:"auto"}const at=typeof window<"u"&&window.requestAnimationFrame,ms=0,nr=e=>({height:0,overflow:"hidden",...e?{}:{display:"none"}});function rr({transitionDuration:e,transitionTimingFunction:s="ease",onTransitionEnd:n=()=>{},opened:i,keepMounted:r=!1}){const p=C.useRef(null),a=nr(r),[d,u]=C.useState(i?{}:a),b=l=>{yn.flushSync(()=>u(l))},o=l=>{b(v=>({...v,...l}))};function m(l){const v=e||sr(l);return{transition:`height ${v}ms ${s}, opacity ${v}ms ${s}`}}_n(()=>{typeof at=="function"&&at(i?()=>{o({willChange:"height",display:"block",overflow:"hidden"}),at(()=>{const l=Ht(p);o({...m(l),height:l})})}:()=>{const l=Ht(p);o({...m(l),willChange:"height",height:l}),at(()=>o({height:ms,overflow:"hidden"}))})},[i]);const x=l=>{if(!(l.target!==p.current||l.propertyName!=="height"))if(i){const v=Ht(p);v===d.height?b({}):o({height:v}),n()}else d.height===ms&&(b(a),n())};function h({style:l={},refKey:v="ref",...P}={}){const $=P[v],j={"aria-hidden":!i,...P,[v]:Vn(p,$),onTransitionEnd:x,style:{boxSizing:"border-box",...l,...d}};return vn.version.startsWith("18")?i||(j.inert=""):j.inert=!i,j}return h}const ir={transitionDuration:200,transitionTimingFunction:"ease",animateOpacity:!0},ct=Xe((e,s)=>{const{children:n,in:i,transitionDuration:r,transitionTimingFunction:p,style:a,onTransitionEnd:d,animateOpacity:u,keepMounted:b,...o}=Ye("Collapse",ir,e),m=Pn(),x=jn(),l=(m.respectReducedMotion?x:!1)?0:r,v=rr({opened:i,transitionDuration:l,transitionTimingFunction:p,onTransitionEnd:d,keepMounted:b});return l===0?i?t.jsx(ut,{...o,children:n}):null:t.jsx(ut,{...v({style:{opacity:i||!u?1:0,transition:u?`opacity ${l}ms ${p}`:"none",...Fn(a,m)},ref:s,...o}),children:n})});ct.displayName="@mantine/core/Collapse";const[ar,ts]=Ns();var Dt={root:"m_7cda1cd6","root--default":"m_44da308b","root--contrast":"m_e3a01f8",label:"m_1e0e6180",remove:"m_ae386778",group:"m_1dcfd90b"};const[or,lr]=Ns(),cr=Is((e,{gap:s},{size:n})=>({group:{"--pg-gap":s!==void 0?Nt(s):Nt(n,"pg-gap")}})),ss=Xe((e,s)=>{const n=Ye("PillGroup",null,e),{classNames:i,className:r,style:p,styles:a,unstyled:d,vars:u,size:b,disabled:o,attributes:m,...x}=n,l=ts()?.size||b||void 0,v=Ct({name:"PillGroup",classes:Dt,props:n,className:r,style:p,classNames:i,styles:a,unstyled:d,attributes:m,vars:u,varsResolver:cr,stylesCtx:{size:l},rootSelector:"group"});return t.jsx(or,{value:{size:l,disabled:o},children:t.jsx(ut,{ref:s,size:l,...v("group"),...x})})});ss.classes=Dt;ss.displayName="@mantine/core/PillGroup";const dr={variant:"default"},ur=Is((e,{radius:s},{size:n})=>({root:{"--pill-fz":Nt(n,"pill-fz"),"--pill-height":Nt(n,"pill-height"),"--pill-radius":s===void 0?void 0:kn(s)}})),pt=Xe((e,s)=>{const n=Ye("Pill",dr,e),{classNames:i,className:r,style:p,styles:a,unstyled:d,vars:u,variant:b,children:o,withRemoveButton:m,onRemove:x,removeButtonProps:h,radius:l,size:v,disabled:P,mod:$,attributes:j,...N}=n,g=lr(),E=ts(),_=v||g?.size||void 0,f=E?.variant==="filled"?"contrast":b||"default",T=Ct({name:"Pill",classes:Dt,props:n,className:r,style:p,classNames:i,styles:a,unstyled:d,attributes:j,vars:u,varsResolver:ur,stylesCtx:{size:_}});return t.jsxs(ut,{component:"span",ref:s,variant:f,size:_,...T("root",{variant:f}),mod:[{"with-remove":m&&!P,disabled:P||g?.disabled},$],...N,children:[t.jsx("span",{...T("label"),children:o}),m&&t.jsx(wn,{variant:"transparent",radius:l,tabIndex:-1,"aria-hidden":!0,unstyled:d,...h,...T("remove",{className:h?.className,style:h?.style}),onMouseDown:I=>{I.preventDefault(),I.stopPropagation(),h?.onMouseDown?.(I)},onClick:I=>{I.stopPropagation(),x?.(),h?.onClick?.(I)}})]})});pt.classes=Dt;pt.displayName="@mantine/core/Pill";pt.Group=ss;var Rs={field:"m_45c4369d"};const pr={type:"visible"},ns=Xe((e,s)=>{const n=Ye("PillsInputField",pr,e),{classNames:i,className:r,style:p,styles:a,unstyled:d,vars:u,type:b,disabled:o,id:m,pointer:x,mod:h,attributes:l,...v}=n,P=ts(),$=$n(),j=Ct({name:"PillsInputField",classes:Rs,props:n,className:r,style:p,classNames:i,styles:a,unstyled:d,attributes:l,rootSelector:"field"}),N=o||P?.disabled;return t.jsx(ut,{component:"input",ref:Es(s,P?.fieldRef),"data-type":b,disabled:N,mod:[{disabled:N,pointer:x},h],...j("field"),...v,id:$?.inputId||m,"aria-invalid":P?.hasError,"aria-describedby":$?.describedBy,type:"text",onMouseDown:g=>!x&&g.stopPropagation()})});ns.classes=Rs;ns.displayName="@mantine/core/PillsInputField";const hr={size:"sm"},St=Xe((e,s)=>{const n=Ye("PillsInput",hr,e),{children:i,onMouseDown:r,onClick:p,size:a,disabled:d,__staticSelector:u,error:b,variant:o,...m}=n,x=C.useRef(null);return t.jsx(ar,{value:{fieldRef:x,size:a,disabled:d,hasError:!!b,variant:o},children:t.jsx(Ss,{size:a,error:b,variant:o,component:"div",ref:s,"data-no-overflow":!0,onMouseDown:h=>{h.preventDefault(),r?.(h),x.current?.focus()},onClick:h=>{h.preventDefault(),h.currentTarget.closest("fieldset")?.disabled||(x.current?.focus(),p?.(h))},...m,multiline:!0,disabled:d,__staticSelector:u||"PillsInput",withAria:!1,children:i})})});St.displayName="@mantine/core/PillsInput";St.Field=ns;function mr({data:e,value:s}){const n=s.map(r=>r.trim().toLowerCase());return e.reduce((r,p)=>(Un(p)?r.push({group:p.group,items:p.items.filter(a=>n.indexOf(a.label.toLowerCase().trim())===-1)}):n.indexOf(p.label.toLowerCase().trim())===-1&&r.push(p),r),[])}function fr(e,s){return e?s.split(new RegExp(`[${e.join("")}]`)).map(n=>n.trim()).filter(n=>n!==""):[s]}function fs({splitChars:e,allowDuplicates:s,maxTags:n,value:i,currentTags:r,isDuplicate:p,onDuplicate:a}){const d=fr(e,i),u=[];if(s)u.push(...r,...d);else{u.push(...r);for(const b of d)(p?m=>p(m,u):m=>u.some(x=>x.toLowerCase()===m.toLowerCase()))(b)?a?.(b):u.push(b)}return n?u.slice(0,n):u}const br={maxTags:1/0,acceptValueOnBlur:!0,splitChars:[","],hiddenInputValuesDivider:",",openOnFocus:!0,size:"sm"},Tt=Xe((e,s)=>{const n=Ye("TagsInput",br,e),{classNames:i,className:r,style:p,styles:a,unstyled:d,vars:u,size:b,value:o,defaultValue:m,onChange:x,onKeyDown:h,maxTags:l,allowDuplicates:v,onDuplicate:P,variant:$,data:j,dropdownOpened:N,defaultDropdownOpened:g,onDropdownOpen:E,onDropdownClose:_,selectFirstOptionOnChange:f,selectFirstOptionOnDropdownOpen:T,onOptionSubmit:I,comboboxProps:ue,filter:re,limit:Z,withScrollArea:K,maxDropdownHeight:G,searchValue:pe,defaultSearchValue:le,onSearchChange:k,readOnly:X,disabled:z,splitChars:U,onFocus:Ee,onBlur:xe,onPaste:F,radius:W,rightSection:ie,rightSectionWidth:_e,rightSectionPointerEvents:ae,rightSectionProps:H,leftSection:he,leftSectionWidth:y,leftSectionPointerEvents:w,leftSectionProps:V,inputContainer:D,inputWrapperOrder:S,withAsterisk:se,required:J,labelProps:ve,descriptionProps:De,errorProps:Y,wrapperProps:Be,description:B,label:Je,error:Ot,withErrorStyles:Qe,name:Lt,form:bt,id:ge,clearable:qe,clearButtonProps:Ze,hiddenInputProps:ye,hiddenInputValuesDivider:ne,mod:Ft,renderOption:Ae,onRemove:ze,onClear:et,scrollAreaProps:tt,acceptValueOnBlur:gt,isDuplicate:Pe,openOnFocus:xt,attributes:st,..._t}=n,nt=Nn(ge),rt=Wn(j),Bt=Gn(rt),vt=C.useRef(null),it=Es(vt,s),oe=Xn({opened:N,defaultOpened:g,onDropdownOpen:()=>{E?.(),T&&oe.selectFirstOption()},onDropdownClose:()=>{_?.(),oe.resetSelectedOption()}}),{styleProps:qt,rest:{type:yt,autoComplete:Pt,...jt}}=In(_t),[O,me]=ds({value:o,defaultValue:m,finalValue:[],onChange:x}),[c,A]=ds({value:pe,defaultValue:le,finalValue:"",onChange:k}),Q=M=>{A(M),oe.resetSelectedOption()},L=Ct({name:"TagsInput",classes:{},props:n,classNames:i,styles:a,unstyled:d}),{resolvedClassNames:je,resolvedStyles:q}=Sn({props:n,styles:a,classNames:i}),ee=M=>{if((Pe?Pe(M,O):O.some(ke=>ke.toLowerCase()===M.toLowerCase()))&&(P?.(M),!v)){Q("");return}O.length0&&me([...O,M]))},He=M=>{if(h?.(M),M.isPropagationStopped())return;const we=c.trim(),{length:ke}=we;if(U.includes(M.key)&&ke>0&&(me(fs({splitChars:U,allowDuplicates:v,maxTags:l,value:c,currentTags:O,isDuplicate:Pe,onDuplicate:P})),Q(""),M.preventDefault()),M.key==="Enter"&&ke>0&&!M.nativeEvent.isComposing){if(M.preventDefault(),!!document.querySelector(`#${oe.listId} [data-combobox-option][data-combobox-selected]`))return;ee(we)}M.key==="Backspace"&&ke===0&&O.length>0&&!M.nativeEvent.isComposing&&!X&&(ze?.(O[O.length-1]),me(O.slice(0,O.length-1)))},zt=M=>{if(F?.(M),M.preventDefault(),M.clipboardData){const we=M.clipboardData.getData("text/plain");me(fs({splitChars:U,allowDuplicates:v,maxTags:l,value:`${c}${we}`,currentTags:O,isDuplicate:Pe,onDuplicate:P})),Q("")}},gn=O.map((M,we)=>t.jsx(pt,{withRemoveButton:!X,onRemove:()=>{const ke=O.slice();ke.splice(we,1),me(ke),ze?.(M)},unstyled:d,disabled:z,attributes:st,...L("pill"),children:M},`${M}-${we}`));C.useEffect(()=>{f&&oe.selectFirstOption()},[f,O,c]);const xn=t.jsx(Ve.ClearButton,{...Ze,onClear:()=>{me([]),Q(""),vt.current?.focus(),oe.openDropdown(),et?.()}});return t.jsxs(t.Fragment,{children:[t.jsxs(Ve,{store:oe,classNames:je,styles:q,unstyled:d,size:b,readOnly:X,__staticSelector:"TagsInput",attributes:st,onOptionSubmit:M=>{I?.(M),Q(""),O.length0&&!z&&!X,rightSectionWidth:_e,rightSectionPointerEvents:ae,rightSectionProps:H,leftSection:he,leftSectionWidth:y,leftSectionPointerEvents:w,leftSectionProps:V,inputContainer:D,inputWrapperOrder:S,withAsterisk:se,required:J,labelProps:ve,descriptionProps:De,errorProps:Y,wrapperProps:Be,description:B,label:Je,error:Ot,withErrorStyles:Qe,__stylesApiProps:{...n,multiline:!0},id:nt,mod:Ft,attributes:st,children:t.jsxs(pt.Group,{disabled:z,unstyled:d,...L("pillsList"),children:[gn,t.jsx(Ve.EventsTarget,{autoComplete:Pt,children:t.jsx(St.Field,{...jt,ref:it,...L("inputField"),unstyled:d,onKeyDown:He,onFocus:M=>{Ee?.(M),xt&&oe.openDropdown()},onBlur:M=>{xe?.(M),gt&&ee(c),oe.closeDropdown()},onPaste:zt,value:c,onChange:M=>Q(M.currentTarget.value),required:J&&O.length===0,disabled:z,readOnly:X,id:nt})})]})})}),t.jsx(Yn,{data:mr({data:rt,value:O}),hidden:X||z,filter:re,search:c,limit:Z,hiddenWhenEmpty:!0,withScrollArea:K,maxDropdownHeight:G,unstyled:d,labelId:Je?`${nt}-label`:void 0,"aria-label":Je?void 0:_t["aria-label"],renderOption:Ae,scrollAreaProps:tt})]}),t.jsx(Ve.HiddenInput,{name:Lt,form:bt,value:O,valuesDivider:ne,disabled:z,...ye})]})});Tt.classes={...Ss.classes,...Ve.classes};Tt.displayName="@mantine/core/TagsInput";const gr=[["path",{d:"M5 12l14 0",key:"svg-0"}],["path",{d:"M5 12l6 6",key:"svg-1"}],["path",{d:"M5 12l6 -6",key:"svg-2"}]],xr=Et("outline","arrow-left","ArrowLeft",gr);const _r=[["path",{d:"M7 8l-4 4l4 4",key:"svg-0"}],["path",{d:"M17 8l4 4l-4 4",key:"svg-1"}],["path",{d:"M14 4l-4 16",key:"svg-2"}]],vr=Et("outline","code","Code",_r);const yr=[["path",{d:"M16 3l4 4l-4 4",key:"svg-0"}],["path",{d:"M10 7l10 0",key:"svg-1"}],["path",{d:"M8 13l-4 4l4 4",key:"svg-2"}],["path",{d:"M4 17l9 0",key:"svg-3"}]],Pr=Et("outline","switch-horizontal","SwitchHorizontal",yr);const jr=[["path",{d:"M21 12a9 9 0 1 0 -9 9",key:"svg-0"}],["path",{d:"M3.6 9h16.8",key:"svg-1"}],["path",{d:"M3.6 15h7.9",key:"svg-2"}],["path",{d:"M11.5 3a17 17 0 0 0 0 18",key:"svg-3"}],["path",{d:"M12.5 3a16.984 16.984 0 0 1 2.574 8.62",key:"svg-4"}],["path",{d:"M15 18a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-5"}],["path",{d:"M20.2 20.2l1.8 1.8",key:"svg-6"}]],wr=Et("outline","world-search","WorldSearch",jr);function Os(e,s){const n=/^v?(\d+)\.(\d+)\.(\d+)/.exec((e??"").trim());if(!n)return!0;const i=n.slice(1).map(Number),r=s.split(".").map(Number);for(let p=0;p<3;p+=1)if(i[p]!==r[p])return i[p]>r[p];return!0}const Ls=1024**3,$t=1024**4,kr=Number.MAX_SAFE_INTEGER,$r=new RegExp("^(?!-)[a-z0-9-]{1,63}(?n.trim().toLowerCase()));return s.size===1?s.has("0.0.0.0/0"):s.size===2&&s.has("0.0.0.0/0")&&s.has("::/0")}const Ce="1h",Bs=20,Cr=[{value:"algorithm",label:"По алгоритму",description:"Каждое новое соединение получает сервер по алгоритму."},{value:"hash",label:"Закреплять по IP",description:"Сервер определяется IP клиента, алгоритм не нужен."},{value:"table",label:"Запоминать клиента",description:"Первый сервер выбирает алгоритм, дальше клиент остаётся на нём."}];function Er(e){return e==="source"?"hash":e==="source_table"?"table":"algorithm"}function Dr(e){return e==="hash"?"source":e==="table"?"source_table":"none"}const Ar=["1m","5m","15m","30m","1h","12h","24h"],Rr=60,Or=168*3600;function is(e){const s=/^([1-9]\d{0,6})([smhd])$/.exec(e.trim().toLowerCase());return s?Number(s[1])*{s:1,m:60,h:3600,d:86400}[s[2]]:null}function qs(e){const s=/^([1-9]\d{0,6})([smhd])$/.exec(e.trim().toLowerCase());if(!s)return{amount:"",unit:"m"};const n=Number(s[1]);return s[2]==="d"?{amount:n*24,unit:"h"}:{amount:n,unit:s[2]}}const zs={s:"сек",m:"мин",h:"ч"};function Lr(e){const{amount:s,unit:n}=qs(e);return`${s} ${zs[n]}`}const Se={k:1024,m:1024*1024},At={k:1e4,m:10},Fr=228;function Hs(e){const s=/^([1-9]\d{0,4})([km])$/.exec(e.trim().toLowerCase());return s?{amount:Number(s[1]),unit:s[2]}:{amount:"",unit:"k"}}function Vs(e){if(e==="")return!0;const{amount:s,unit:n}=Hs(e);return s!==""&&s>=1&&s<=At[n]}const Us="1m",Rt=At.m*Se.m;function Mt(e){const{amount:s,unit:n}=Hs(e||Us);return s===""?0:s*Se[n]}function Br(e,s){const i=e&&Number.isFinite(e)&&e>0?Math.floor(e/268435456)*268435456:0;if(i<=0)return Us;const r=Math.max(1,Math.floor(s));let p=Math.floor(Math.floor(Math.floor(i/20)/228)/r);return p=Math.max(p,100*Se.k),p>=Rt?`${At.m}m`:`${Math.floor(p/Se.k)}k`}function Ws(e){return e.enabled&&e.sticky_mode==="source_table"&&!e.sticky_table_entries&&e.balance_mode!=="failover"}function Gs(e,s){return Br(s,e.filter(Ws).length+1)}function bs(e){if(e===""||!Number.isFinite(e)||e<=0)return"";const s=Math.min(Math.ceil(e),Rt);if(s%Se.m===0)return`${s/Se.m}m`;const n=Math.ceil(s/Se.k);return n<=At.k?`${n}k`:`${Math.ceil(s/Se.m)}m`}function Xs(e){return e.toLocaleString("ru-RU").replace(/\u00a0/g," ")}function qr(e,s){if(!s)return"Авто: 1 000 000, RAM ноды неизвестна";const n=Math.round(Mt(e)/1e3)*1e3;return`Авто: ~${Xs(n)} клиентов (5% RAM ноды), ${Ys(e)} при полной таблице`}function Ys(e){const s=Mt(e);if(s===0)return"";const n=s*Fr/(1024*1024);return n>=1024?`≈${(n/1024).toFixed(1).replace(".",",")} ГБ`:n>=10?`≈${Math.round(n)} МБ`:`≈${n.toFixed(1).replace(".",",")} МБ`}const Kt=[{value:"roundrobin",label:"По кругу",description:"Серверы получают клиентов по очереди, с учётом веса."},{value:"random",label:"Случайно",description:"Случайный сервер с учётом веса."},{value:"leastconn",label:"Меньше соединений",description:"Сервер, где сейчас меньше всего соединений."},{value:"leastping",label:"Меньше задержка",description:"Больше трафика серверам с меньшей задержкой (как leastLoad в Xray)."}];function Ks(e){return e==="static-rr"?"roundrobin":e}function zr(e){return e?is(e)??"":""}const Hr=["leastconn","roundrobin"];function Vr(e){const s=e.sticky_mode??"";return s===""?e.sticky_enabled?"source":null:Hr.includes(s)?"none":s==="sni"?"source":s==="none"||s==="source"||s==="source_table"?s:null}function Ur(e){const s=e.balance_algorithm??"";if(s)return s;const n=e.sticky_mode??"";return n==="leastconn"?"leastconn":n==="roundrobin"?"roundrobin":null}const gs=[{value:"hourly",label:"Каждый час",description:"Сбрасывается в начале следующего часа."},{value:"daily",label:"Ежедневно",description:"Сбрасывается в 00:00 UTC."},{value:"calendar_month",label:"Календарный месяц",description:"Сбрасывается первого числа в 00:00 UTC."},{value:"monthly_from_creation",label:"Месяц от создания",description:"Окно начинается в дату создания маршрута."}];function Js(e){return e.name?.trim()?e.name.trim():e.fallback?`tcp-${e.listener_port}`:e.snis[0]??e.hostname??`route-${e.listener_port}`}function Wr(e){const s=new Set(e.map(n=>n.name.trim()));for(let n=e.length+1;;n+=1)if(!s.has(`srv${n}`))return`srv${n}`}function Qs(e="srv1"){return{_key:It(),name:e,targetType:"tcp",host:"",port:443,unixSocketPath:"",backup:!1,dnsPool:!1,preferredIP:"",weight:"",cost:"",ipWeights:[]}}function xs(){return{name:"",matchMode:"sni",listenerIP:"*",listenerPort:443,snis:[],acceptProxyEnabled:!1,acceptProxyFrom:[],targetMode:"ip",targetHost:"",targetPort:443,unixSocketPath:"",healthCheck:!0,proxyProtocol:"none",servers:[Qs()],balanceMode:"pool",stickyMode:null,stickyTTL:Ce,legacyTarget:null,stickyHash:"",stickyHashBalanceFactor:"",stickyTableEntries:"",stickyIPv6Prefix:0,clientIPv6:!0,balanceAlgorithm:null,balanceRandomDraws:"",leastpingTolerancePct:"",leastpingToleranceMs:"",slowstart:"",quotaEnabled:!1,quotaValue:"",quotaUnit:"GiB",quotaPeriod:"calendar_month",quotaAction:"observe",expertOverride:"",clientBandwidthEnabled:!1,clientUploadMbps:"",clientDownloadMbps:"",shaperMode:"haproxy"}}function Zs(e){const s=e.quota_bytes??0,n=s>=$t&&s%$t===0,i=e.listener_ip||"*",r=e.match_mode==="sni"?"sni":"fallback",p=e.target_host??"",a=e.target_type==="unix"?"unix":te(p)?"ip":"domain";let d,u=null;(e.servers??[]).length>0?d=(e.servers??[]).slice().sort((h,l)=>h.position-l.position).map(h=>({_key:h.id||It(),name:h.name,targetType:h.target_type==="unix"?"unix":"tcp",host:h.host??"",port:h.port||443,unixSocketPath:h.unix_socket_path??"",backup:!!h.backup,dnsPool:!!h.dns_pool,preferredIP:h.preferred_ip??"",weight:h.weight||"",cost:h.cost||"",ipWeights:(h.ip_weights??[]).map(l=>({ip:l.ip,weight:l.weight||"",cost:l.cost||""}))})):(u={targetType:e.target_type==="unix"?"unix":"tcp",host:p,port:e.target_port||443,unixSocketPath:e.unix_socket_path??"",dnsPool:!!e.dns_pool},d=[{_key:It(),name:"srv1",targetType:u.targetType,host:u.host,port:u.port,unixSocketPath:u.unixSocketPath,backup:!1,dnsPool:u.dnsPool,preferredIP:"",weight:"",cost:"",ipWeights:[]}]);const b=e.accept_proxy_from??[],m=Fs(b)?[]:b,x=e.balance_mode==="failover"||d.some(h=>h.backup)?"failover":"pool";return x==="failover"&&d.length>1&&!d.some(h=>h.backup)&&(d=sn(d)),{name:Js(e),matchMode:r,listenerIP:i,listenerPort:e.listener_port,snis:e.snis??[],acceptProxyEnabled:b.length>0,acceptProxyFrom:m,targetMode:a,targetHost:p,targetPort:e.target_port||443,unixSocketPath:e.unix_socket_path??"",healthCheck:e.health_check??!0,proxyProtocol:["none","v1","v2"].includes(e.proxy_protocol)?e.proxy_protocol:"none",servers:d,balanceMode:x,stickyMode:Vr(e),stickyTTL:e.sticky_ttl||Ce,stickyHash:e.sticky_hash==="map-based"?"map-based":"",stickyHashBalanceFactor:e.sticky_hash_balance_factor||"",stickyTableEntries:Vs(e.sticky_table_entries??"")?e.sticky_table_entries??"":"",stickyIPv6Prefix:e.sticky_ipv6_prefix||0,clientIPv6:e.client_ipv6??!0,balanceAlgorithm:Ur(e),balanceRandomDraws:e.balance_random_draws||"",leastpingTolerancePct:Xr(e),leastpingToleranceMs:e.leastping_tolerance_ms||"",slowstart:e.slowstart||"",legacyTarget:u,quotaEnabled:s>0,quotaValue:s>0?s/(n?$t:Ls):"",quotaUnit:n?"TiB":"GiB",quotaPeriod:["hourly","daily","calendar_month","monthly_from_creation"].includes(e.quota_period)?e.quota_period:"calendar_month",quotaAction:e.quota_action==="block_new"?"block_new":"observe",clientBandwidthEnabled:e.client_upload_mbps!==null||e.client_download_mbps!==null,clientUploadMbps:e.client_upload_mbps??"",clientDownloadMbps:e.client_download_mbps??"",shaperMode:e.shaper_mode==="kernel"?"kernel":"haproxy",expertOverride:e.custom_fragment??""}}function te(e){const s=e.trim();return Nr.test(s)||s.includes(":")&&Yt.test(s)}function en(e){const s=e.trim().replace(/\.$/,"");return s!==""&&s.split(".").every(n=>/^\d+$/.test(n))}function Gr(e){const s=e.trim();return te(s)||ls(s)}function tn(e){return e.servers.length>=2||e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function Xr(e){const s=e.balance_tolerance??e.leastping_tolerance;return typeof s!="number"?"":e.balance_algorithm==="leastping"||e.balance_algorithm==="leastconn"&&s>0?Math.round(s*100):""}function de(e){return tn(e)?e.balanceMode:"pool"}const mt="1.1.0";function Yr(e){return Os(e,mt)}function Ge(e,s){return e.servers.length>1&&de(e)==="failover"&&!!e.servers[s]?.backup}function Kr(e){return e.every((s,n)=>s.backup===n>0)}function sn(e){return e.map((s,n)=>s.backup===n>0?s:{...s,backup:n>0,preferredIP:n>0?"":s.preferredIP})}function ft(e,s){const n=e.servers[s];return s===0&&!!n&&n.targetType==="tcp"&&n.dnsPool&&de(e)==="failover"&&!Ge(e,0)}function Ke(e){return de(e)!=="pool"?!1:e.servers.length>=2||e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function nn(e){return e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function _s(e){return nn(e)?"source":"none"}function Le(e){return Ke(e)?e.stickyMode??_s(e):_s(e)}function vs(e){return Le(e)==="source_table"?"leastconn":"roundrobin"}function Fe(e){return Le(e)==="source"?vs(e):e.balanceAlgorithm??vs(e)}function as(e){return e.healthCheck||e.servers.some(s=>s.targetType==="tcp"&&s.dnsPool)}function Jr(e){return e.clientBandwidthEnabled&&(e.clientUploadMbps!==""||e.clientDownloadMbps!=="")}function os(e){if(e.servers.length!==1)return{kind:"servers"};const[s]=e.servers,n=s.weight===""&&s.cost===""&&mn(s.ipWeights,si(e)).length===0;if(s.targetType==="unix"||!s.dnsPool)return n?{kind:"legacy",dnsPool:!1}:{kind:"servers"};const i=e.legacyTarget,r=ft(e,0)&&s.preferredIP.trim()!=="";return n&&i&&i.dnsPool&&i.targetType==="tcp"&&!r&&i.host.trim().toLowerCase()===s.host.trim().toLowerCase()&&i.port===Number(s.port)?{kind:"legacy",dnsPool:!0}:{kind:"servers"}}function ls(e){const s=e.trim().replace(/\.$/,"").toLowerCase();return s.length>0&&s.length<=253&&!en(s)&&s.split(".").every(n=>$r.test(n))}function rn(e){for(let s=0;s=55296&&n<=56319){const i=e.charCodeAt(s+1);if(!(i>=56320&&i<=57343))return!1;s+=1}else if(n>=56320&&n<=57343)return!1}return!0}function Qr(e){const s=new TextEncoder().encode(e).length;return!rn(e)||s<2||s>107||!e.startsWith("/")||!/^[A-Za-z0-9/._-]+$/.test(e)||e.endsWith("/")||e.includes("//")?!1:e.slice(1).split("/").every(n=>n!==""&&n!=="."&&n!=="..")}function Zr(e,s,n,i){return s!==i?!1:e===n||(e==="*"||e==="0.0.0.0"||e==="::")||(n==="*"||n==="0.0.0.0"||n==="::")}function an(e,s,n,i){return e.toLowerCase()===n.toLowerCase()&&s===i}function on(e){const s=e.trim();if(!s)return!1;if(s.includes(":")){const n=s.indexOf("/");if(n===-1)return Yt.test(s);const i=s.slice(0,n),r=s.slice(n+1);if(!Yt.test(i))return!1;const p=Number(r);return Number.isInteger(p)&&p>=0&&p<=128&&String(p)===r}return Ir.test(s)}const ys=32;function ht(e){const s=e.trim();return!on(s)&&!s.includes("/")&&!s.includes(":")&&ls(s)}function ln(e){return on(e)||ht(e)}function cn(e){const s=e.trim();return ht(s)?s.replace(/\.$/,"").toLowerCase():s}function cs(e){if(!e.quotaEnabled||e.quotaValue==="")return null;const s=e.quotaUnit==="TiB"?$t:Ls;return Math.round(Number(e.quotaValue)*s)}function ei(e){const s=new TextEncoder;if(s.encode(e).length>8192)return[{field:"expert",message:"Экспертный слой превышает 8192 байт."}];if(!rn(e))return[{field:"expert",message:"Экспертный слой должен быть корректным UTF-8."}];const n=e.replace(/\r\n/g,` -`);if(/[\u0000-\u0008\u000b-\u001f\u007f]/.test(n))return[{field:"expert",message:"Экспертный слой содержит управляющий символ."}];if(n.includes("\\"))return[{field:"expert",message:"Перенос и экранирование директив через \\ запрещены."}];const i=[];let r=!1;for(const p of n.split(` -`)){if(s.encode(p).length>512)return[{field:"expert",message:"Одна из директив длиннее 512 байт."}];const a=p.trim();if(!a){i.length>0&&(r=!0);continue}const d=a.split(/\s+/)[0].toLowerCase();if(Sr.has(d))return[{field:"expert",message:`Секция ${d} управляется NodeFlow и не может быть переопределена.`}];r&&(i.push(""),r=!1),i.push(` ${a}`)}return s.encode(i.join(` -`)).length>8192?[{field:"expert",message:"Экспертный слой превышает 8192 байт после нормализации."}]:[]}function ti(e){const s=[];if(de(e)!=="pool"||!Ke(e))return s;const n=(a,d)=>s.push({field:a,message:d}),i=(a,d,u,b=!0)=>a===""||Number.isFinite(a)&&a>=d&&a<=u&&(!b||Number.isInteger(a)),r=Le(e),p=Fe(e);if(r!=="source"&&(p==="random"&&!i(e.balanceRandomDraws,1,5)&&n("balanceRandomDraws","Выборок — от 1 до 5."),p==="leastping"&&(i(e.leastpingTolerancePct,0,100)||n("leastpingTolerancePct","Толерантность — целое число от 0 до 100 %."),i(e.leastpingToleranceMs,0,1e3)||n("leastpingToleranceMs","Толерантность в мс — от 0 до 1000.")),p==="leastconn"&&!i(e.leastpingTolerancePct,0,100)&&n("leastpingTolerancePct","Толерантность — целое число от 0 до 100 %.")),r==="source"&&e.stickyHash!=="map-based"&&!i(e.stickyHashBalanceFactor,101,1e3)&&n("stickyHashBalanceFactor","Лимит перегрузки — от 101 до 1000 % или пусто."),e.clientIPv6&&(r==="source"||r==="source_table")&&e.stickyIPv6Prefix!==0&&!i(e.stickyIPv6Prefix,32,128)&&n("stickyIPv6Prefix","Префикс IPv6 — от /32 до /128."),r==="source_table"){const a=is(e.stickyTTL||Ce);(a===null||aOr)&&n("stickyTTL","Помнить — от 1 минуты до 168 часов."),Vs(e.stickyTableEntries)||n("stickyTableEntries",`Макс. клиентов — от 1 до ${Xs(Rt)}.`)}return s}function Ps(e,s,n){const i=[],r=(m,x)=>i.push({field:m,message:x}),p=Number(e.listenerPort),a=e.listenerIP.trim()||"*",d=a==="*"||a==="0.0.0.0"||a==="::",u=e.snis.map(m=>m.trim().replace(/\.$/,"").toLowerCase()).filter(Boolean);if(e.name.trim()?e.name.trim().length>80&&r("name","Имя маршрута не должно превышать 80 символов."):r("name","Укажите имя маршрута. Оно видно только оператору."),!d&&!te(a)&&r("listenerIP","Адрес listener должен быть * или корректным IP."),(!Number.isInteger(p)||p<1||p>65535)&&r("listenerPort","Порт listener должен быть от 1 до 65535."),e.matchMode==="sni"&&(u.length||r("snis","Добавьте хотя бы один SNI."),u.length>64&&r("snis","Можно указать не больше 64 SNI."),u.some(m=>!ls(m))&&r("snis","Каждый SNI должен быть корректным DNS-именем."),new Set(u).size!==u.length&&r("snis","SNI внутри маршрута не должны повторяться.")),e.acceptProxyEnabled)if(e.acceptProxyFrom.length>256)r("acceptProxyFrom","Список не должен превышать 256 записей.");else{for(const x of e.acceptProxyFrom)if(!ln(x)){r("acceptProxyFrom",`Некорректный адрес, подсеть или домен: ${x}`);break}new Set(e.acceptProxyFrom.filter(ht).map(cn)).size>ys&&r("acceptProxyFrom",`Не больше ${ys} доменов в списке.`)}if(e.servers.length===0)r("servers","Добавьте хотя бы один сервер назначения.");else if(e.servers.length>16)r("servers","Не более 16 серверов.");else{const m=e.servers.map(h=>h.name.trim()).filter(Boolean),x=e.servers.find(h=>/_pref$/i.test(h.name.trim()));x&&r("servers",`Имя сервера ${x.name.trim()} не должно оканчиваться на _pref.`),new Set(m).size!==m.length&&r("servers","Имена серверов не должны повторяться."),e.servers.forEach((h,l)=>{if(!h.name.trim()){r("servers",`Сервер ${l+1}: укажите имя.`);return}if(Tr.test(h.name.trim())||r("servers",`Сервер ${l+1}: имя — буквы, цифры, _, - (до ${rs} символов).`),h.targetType==="tcp"){const v=Number(h.port),P=h.host.trim();P?en(P)&&!te(P)?r("servers",`Сервер ${l+1}: ${P} — некорректный IPv4-адрес.`):Gr(P)||r("servers",`Сервер ${l+1}: адрес должен быть IP или доменом.`):r("servers",`Сервер ${l+1}: укажите адрес.`),(!Number.isInteger(v)||v<1||v>65535)&&r("servers",`Сервер ${l+1}: некорректный порт.`),h.dnsPool&&te(h.host.trim())&&r("servers",`Сервер ${l+1}: DNS-пул недоступен для IP-адресов.`),ft(e,l)&&h.preferredIP.trim()&&!te(h.preferredIP.trim())&&r("servers",`Сервер ${l+1}: основной IP — некорректный адрес.`)}else Qr(h.unixSocketPath.trim())||r("servers",`Сервер ${l+1}: некорректный путь Unix socket.`);if(h.weight!==""&&(!Number.isInteger(Number(h.weight))||Number(h.weight)<1||Number(h.weight)>256)&&r("servers",`Сервер ${l+1}: вес — целое число от 1 до 256.`),h.cost!==""&&(!Number.isFinite(Number(h.cost))||Number(h.cost)<=0||Number(h.cost)>100)&&r("servers",`Сервер ${l+1}: стоимость — число больше 0 и не больше 100.`),h.ipWeights.length>0){const v=Fe(e),P=Le(e);h.dnsPool||r("servers",`Сервер ${l+1}: вес и стоимость IP доступны только для DNS-пула.`),h.ipWeights.length>32&&r("servers",`Сервер ${l+1}: не более 32 отдельных IP.`);const $=h.ipWeights.map(N=>N.ip.trim().toLowerCase());new Set($).size!==$.length&&r("servers",`Сервер ${l+1}: IP не должны повторяться.`),h.ipWeights.some(N=>!te(N.ip))&&r("servers",`Сервер ${l+1}: некорректный IP в списке отдельных IP.`),h.ipWeights.some(N=>N.weight!==""&&(!Number.isInteger(N.weight)||N.weight<1||N.weight>256))&&r("servers",`Сервер ${l+1}: вес IP — целое число от 1 до 256.`),h.ipWeights.some(N=>N.cost!==""&&(!Number.isFinite(N.cost)||N.cost<.01||N.cost>100))&&r("servers",`Сервер ${l+1}: стоимость IP — число от 0,01 до 100.`),h.ipWeights.some(N=>N.weight!=="")&&(v==="static-rr"||P==="source"&&e.stickyHash==="map-based")&&r("servers",`Сервер ${l+1}: вес IP не работает с фиксированными весами — включите «Веса меняются на лету» или «Стабильное» распределение.`)}}),de(e)==="failover"&&e.servers.length>1&&(e.servers.every(h=>h.backup)?r("servers","Отметьте хотя бы один сервер как «Основной»."):e.servers.some(h=>h.backup)||r("servers","Отметьте хотя бы один сервер как «Резерв» или выберите режим «Пул»."))}const b=cs(e);if(e.quotaEnabled&&(e.quotaValue===""||Number(e.quotaValue)<=0||!Number.isFinite(b)||Number(b)>kr)&&r("quota","Лимит должен быть положительным числом в безопасном диапазоне."),e.quotaAction==="block_new"&&!e.quotaEnabled&&r("quota","Блокировка новых соединений требует включённого лимита."),e.quotaEnabled&&e.quotaAction==="block_new"&&e.servers.length>0){const m=os(e);(m.kind==="servers"||m.dnsPool)&&r("quota","Блокировка новых соединений доступна только для одного сервера без DNS-пула. Выберите «Только уведомить».")}if(e.clientBandwidthEnabled)for(const[m,x,h]of[["clientUploadMbps",e.clientUploadMbps,"Лимит upload"],["clientDownloadMbps",e.clientDownloadMbps,"Лимит download"]])x!==""&&(!Number.isSafeInteger(x)||x<1||x>1e6)&&r(m,`${h} должен быть целым числом от 1 до 1 000 000 Mbps либо пустым.`);e.slowstart&&!as(e)&&r("servers","Плавный ввод требует включённой проверки здоровья.");const o=e.slowstart?is(e.slowstart):0;(o===null||o>600)&&r("slowstart","Плавный ввод — от 1 до 600 секунд."),i.push(...ti(e)),i.push(...ei(e.expertOverride));for(const m of s.filter(x=>x.id!==n&&!x.delete_pending&&x.deployment_state!=="deleting")){if(!Number.isInteger(p)||!Zr(a,p,m.listener_ip||"*",m.listener_port))continue;if(!an(a,p,m.listener_ip||"*",m.listener_port)){r("listener",`Порт ${p} уже слушается ${m.listener_ip||"*"}. Нельзя смешивать wildcard и конкретный IP.`);continue}const h=e.matchMode!=="sni";if(h&&m.fallback&&r("listener",`Для ${a}:${p} уже есть фолбэк-маршрут.`),!h&&!m.fallback){const v=u.find(P=>(m.snis??[]).map($=>$.toLowerCase()).includes(P));v&&r("snis",`SNI ${v} уже назначен другому маршруту на ${a}:${p}.`)}const l=m.enabled&&(m.client_upload_mbps!==null||m.client_download_mbps!==null);if(Jr(e)&&l){const v=m.shaper_mode==="kernel",P=Js(m);if(e.shaperMode==="kernel"!==v)r("bandwidth",`На ${a}:${p} маршрут ${P} ограничивает скорость через ${v?"ядро":"HAProxy"}; режимы на одном listener смешивать нельзя.`);else if(v){const $=e.clientUploadMbps===""?null:e.clientUploadMbps,j=e.clientDownloadMbps===""?null:e.clientDownloadMbps;($!==m.client_upload_mbps||j!==m.client_download_mbps)&&r("bandwidth",`Лимиты ядра на ${a}:${p} должны совпадать с маршрутом ${P} (↑${m.client_upload_mbps??"—"} / ↓${m.client_download_mbps??"—"} Mbps).`)}}}return i}function dn(e){return e.acceptProxyEnabled?e.acceptProxyFrom.length===0?[...Mr]:e.acceptProxyFrom.filter(ln).map(cn):[]}function un(e){return de(e)==="pool"&&Ke(e)&&Fe(e)==="leastping"}function pn(e){return de(e)==="pool"&&Ke(e)&&Fe(e)==="leastconn"}function si(e){return un(e)||pn(e)}const hn="1.1.1";function ni(e){return Os(e,hn)}function ri(e){if(!e.some(d=>d.cost>0||d.ip_weights.some(u=>(u.cost??0)>0)))return null;const n=(d,u)=>(d>0?d:1)/(u>0?u:1),i=(d,u)=>n(d.weight>0?d.weight:u.weight,(d.cost??0)>0?d.cost??0:u.cost);let r=0;e.forEach(d=>{r=Math.max(r,n(d.weight,d.cost)),d.ip_weights.forEach(u=>{r=Math.max(r,i(u,d))})});const p=Math.min(100,256/r),a=d=>Math.min(256,Math.max(1,Math.round(d)));return{servers:e.map(d=>a(n(d.weight,d.cost)*p)),ips:e.map(d=>Object.fromEntries(d.ip_weights.map(u=>[u.ip,a(i(u,d)*p)])))}}function mn(e,s){return e.flatMap(n=>{const i=n.weight===""?0:Number(n.weight),r=s&&n.cost!==""?Math.round(Number(n.cost)*100)/100:0;return!i&&!r?[]:[r?{ip:n.ip.trim(),weight:i,cost:r}:{ip:n.ip.trim(),weight:i}]})}function Ue(e,s,n){const i=e.matchMode!=="sni",r=i?[]:e.snis.map(_=>_.trim().replace(/\.$/,"").toLowerCase()).filter(Boolean),p=dn(e),a=de(e),d=os(e),u=a==="pool",b=u?Le(e):"",m=u&&Ke(e)?Fe(e):"",x=un(e),h=pn(e),l=x||h,v=e.servers[0],P=v?.targetType==="unix",$=P?"":v?.host.trim()??"",j=P?0:Number(v?.port??443),N=P?v?.unixSocketPath.trim()??"":"",g=a==="failover"&&d.kind==="servers"&&!Kr(e.servers.map((_,f)=>({backup:Ge(e,f)}))),E=d.kind==="legacy"?[]:e.servers.map((_,f)=>({position:f+1,name:_.name.trim(),target_type:_.targetType,host:_.targetType==="tcp"?_.host.trim():"",port:_.targetType==="tcp"?Number(_.port):0,unix_socket_path:_.targetType==="unix"?_.unixSocketPath.trim():"",backup:Ge(e,f),dns_pool:_.targetType==="tcp"&&_.dnsPool,preferred_ip:ft(e,f)?_.preferredIP.trim():"",weight:_.weight===""?0:Number(_.weight),cost:l&&_.cost!==""?Number(_.cost):0,ip_weights:_.targetType==="tcp"&&_.dnsPool?mn(_.ipWeights,l):[]}));return{...n?{expected_version:n}:{},name:e.name.trim(),hostname:r[0]??"",listener_ip:e.listenerIP.trim()||"*",listener_port:Number(e.listenerPort),match_mode:e.matchMode,snis:r,fallback:i,target_type:P?"unix":"tcp",target_host:$,target_port:j,dns_pool:d.kind==="legacy"&&d.dnsPool,unix_socket_path:N,health_check:as(e),proxy_protocol:e.proxyProtocol,quota_bytes:cs(e),quota_action:e.quotaEnabled?e.quotaAction:"observe",quota_period:e.quotaPeriod,client_upload_mbps:!e.clientBandwidthEnabled||e.clientUploadMbps===""?null:e.clientUploadMbps,client_download_mbps:!e.clientBandwidthEnabled||e.clientDownloadMbps===""?null:e.clientDownloadMbps,enabled:s,custom_fragment:e.expertOverride,accept_proxy_from:p,servers:E,sticky_enabled:b==="source"||b==="source_table",sticky_mode:b,...b==="source_table"?{sticky_ttl:e.stickyTTL||Ce}:{},sticky_hash:b==="source"?e.stickyHash:"",sticky_hash_balance_factor:b==="source"&&e.stickyHash!=="map-based"?Number(e.stickyHashBalanceFactor||0):0,sticky_table_entries:b==="source_table"?e.stickyTableEntries:"",sticky_ipv6_prefix:e.clientIPv6&&(b==="source"||b==="source_table")?e.stickyIPv6Prefix:0,client_ipv6:e.clientIPv6,balance_algorithm:m,balance_random_draws:m==="random"?Number(e.balanceRandomDraws||2):0,balance_tolerance:x?Math.round(e.leastpingTolerancePct===""?Bs:Number(e.leastpingTolerancePct))/100:h&&e.leastpingTolerancePct!==""?Math.round(Number(e.leastpingTolerancePct))/100:0,leastping_tolerance_ms:x?Number(e.leastpingToleranceMs||0):0,slowstart:e.slowstart,...g?{}:{balance_mode:a},shaper_mode:e.shaperMode}}function wt(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"route_preview"}function ot(e,s){return e.includes(":")?`[${e}]:${s}`:`${e}:${s}`}const Vt=" check inter 5s fall 3 rise 2 resolvers nf_dns init-addr last,none resolve-opts prevent-dup-ip hash-key addr";function ii(e,s,n){const i=e.listenerIP.trim()||"*",r=Number(e.listenerPort)||443,p=s.filter(y=>y.enabled&&an(y.listener_ip||"*",y.listener_port,i,r)),a=Ue(e,!0),d=[...p,a],u=`nf_listener_${r}_${wt(i==="*"?"any":i)}`,b=wt(e.name),o=os(e),m=a.servers.length===1?a.servers[0]:null,x=m&&!m.preferred_ip&&!m.weight&&!m.cost&&!m.ip_weights.length?{kind:"legacy",dnsPool:m.dns_pool}:o,h=a.health_check,l=["# Managed by NodeFlow — preview"];e.servers.some(y=>y.targetType==="tcp"&&(y.dnsPool||y.host.trim()!==""&&!te(y.host.trim())))&&l.push("resolvers nf_dns"," nameserver adguard_local 127.0.0.1:53"," # … остальные nameserver и hold-параметры",""),a.sticky_mode==="source_table"&&l.push("peers nf_peers"," bind unix@/run/haproxy/nf_peers.sock"," server nf_local",""),l.push(`frontend ${u}`,` bind ${i}:${r}`," mode tcp");const P=dn(e);if(e.acceptProxyEnabled&&Fs(P))l.push(" tcp-request connection expect-proxy layer4");else if(P.length>0){const y=[...new Set(P)].sort(),w=y.filter(ht),V=y.filter(D=>!ht(D));if(w.length>0){const D=`/etc/haproxy/nodeflow/pp-trusted-${u}.acl`;l.push(` # nf-pp-trusted file=${D} domains=${w.join(",")}`,` acl nf_pp_trusted src -f ${D}`,` tcp-request connection expect-proxy layer4 if ${V.length?`{ src ${V.join(" ")} } || `:""}nf_pp_trusted`)}else l.push(` tcp-request connection expect-proxy layer4 if { src ${V.join(" ")} }`)}const $=a.client_download_mbps!==null?a.client_download_mbps*125e3:null,j=a.client_upload_mbps!==null?a.client_upload_mbps*125e3:null,N=$!==null||j!==null,g=e.shaperMode==="kernel",E=!g&&N;g&&N&&l.push(` # nf-kernel-shaper listen=${i} port=${r} download_bps=${$??0} upload_bps=${j??0}`);const _=a.client_ipv6,f=_?"ipv6":"ip",T=_?"src,ipmask(32,64)":"src";E&&$!==null&&l.push(` filter bwlim-out nf_bw_download_${b} limit ${$} key ${T} table nf_bw_download_table_${b} min-size 2896`),E&&j!==null&&l.push(` filter bwlim-in nf_bw_upload_${b} limit ${j} key ${T} table nf_bw_upload_table_${b} min-size 2896`);const I=d.filter(y=>!y.fallback);I.length&&l.push(" tcp-request inspect-delay 5s"," tcp-request content accept if { req.ssl_hello_type 1 }");const ue=I.indexOf(a),re=ue>=0?` if nf_sni_${ue+1}`:I.length?` if ${I.map((y,w)=>`!nf_sni_${w+1}`).join(" ")}`:"";E&&$!==null&&l.push(` tcp-request content set-bandwidth-limit nf_bw_download_${b}${re}`),E&&j!==null&&l.push(` tcp-request content set-bandwidth-limit nf_bw_upload_${b}${re}`),I.forEach((y,w)=>{const V=(y.snis??[]).length?y.snis:["sni.example.com"];l.push(` acl nf_sni_${w+1} req.ssl_sni -i ${V.join(" ")}`),l.push(` use_backend nf_be_${wt(y===a?e.name:V[0])} if nf_sni_${w+1}`)});const Z=d.find(y=>y.fallback);Z&&l.push(` default_backend nf_be_${wt(Z===a?e.name:Z.snis?.[0]||`tcp_${Z.listener_port}`)}`),l.push("",`backend nf_be_${b}`," mode tcp");const K=x.kind==="legacy"&&x.dnsPool,G=a.sticky_mode;if(G==="source"){const y=a.sticky_ipv6_prefix;!_||y===0||y===128?l.push(" balance source"):l.push(` balance hash src,ipmask(32,${y})`);const w=a.sticky_hash==="map-based"?"map-based":"consistent";l.push(` hash-type ${w} sdbm avalanche`),w==="consistent"&&a.sticky_hash_balance_factor&&l.push(` hash-balance-factor ${a.sticky_hash_balance_factor}`)}else if(G==="none"||G==="source_table"||G===""){const y=a.balance_algorithm;if(y==="static-rr"?l.push(" balance static-rr"):y==="random"?l.push(` balance random(${a.balance_random_draws||2})`):y==="leastconn"&&!(a.balance_tolerance>0&&x.kind==="servers")&&l.push(" balance leastconn"),G==="source_table"){const w=a.sticky_table_entries||Gs(s,n);l.push(` stick-table type ${f} size ${w} expire ${a.sticky_ttl||Ce} peers nf_peers`),l.push(_?` stick on src,ipmask(32,${a.sticky_ipv6_prefix||64})`:" stick on src"),l.push(" option redispatch")}}const pe=a.balance_algorithm==="leastping"&&G!=="source",le=x.kind==="servers"?a.servers:[],k=a.balance_algorithm==="leastconn"&&G!=="source"&&le.length>0,X=k&&a.balance_tolerance>0,z=pe||X,U=k?ri(le):null,Ee=y=>z||U?(y.ip_weights?.length??0)>0:(y.ip_weights??[]).some(w=>w.weight>0),xe=le.some(Ee);if(z||xe){const y=pe?"leastping":X?"leastconn":"static",w=(z?a.balance_tolerance:0).toFixed(2),V=pe&&a.leastping_tolerance_ms||0;l.push(` # nf-weights backend=nf_be_${b} algo=${y} tolerance=${w} tolerance_ms=${V}`),le.forEach((D,S)=>{if(!z&&!Ee(D))return;const se=D.weight||1,J=(D.cost||0).toFixed(2);if(D.dns_pool){if(D.preferred_ip&&!D.backup&&S===0&&e.balanceMode==="failover"&&l.push(` # nf-weight server=${D.name}_pref base=${se} cost=${J}`),!z&&U){const Y=(D.ip_weights??[]).map(Be=>`${Be.ip}=${U.ips[S][Be.ip]}`).join(",");l.push(` # nf-weight template=${D.name}_ slots=32 base=${U.servers[S]} cost=0.00${Y?` ips=${Y}`:""}`);return}const ve=(D.ip_weights??[]).filter(Y=>Y.weight>0).map(Y=>`${Y.ip}=${Y.weight}`).join(","),De=z?(D.ip_weights??[]).filter(Y=>(Y.cost??0)>0).map(Y=>`${Y.ip}=${(Y.cost??0).toFixed(2)}`).join(","):"";l.push(` # nf-weight template=${D.name}_ slots=32 base=${se} cost=${J}${ve?` ips=${ve}`:""}${De?` ipcosts=${De}`:""}`)}else l.push(` # nf-weight server=${D.name} base=${se} cost=${J}`)})}h&&l.push(" option tcp-check"),e.quotaEnabled&&l.push(` # quota ${Kn(cs(e)??0)} · ${e.quotaPeriod} · ${e.quotaAction}`),e.expertOverride.trim()&&(l.push(" # ── expert override: backend directives only ──"),e.expertOverride.split(` -`).forEach(y=>l.push(` ${y.trimStart()}`)),l.push(" # ── end expert override ──"));const F=e.proxyProtocol==="v1"?" send-proxy":e.proxyProtocol==="v2"?" send-proxy-v2":"",W=e.proxyProtocol!=="none"&&h?" check-send-proxy":"",ie=h?" check inter 5s fall 3 rise 2":"",_e=(y,w)=>y.trim()||w,ae=y=>Number(y)||443,H=e.slowstart&&h?` slowstart ${e.slowstart}`:"",he=y=>y?` weight ${y}`:"";if(x.kind==="legacy"){const y=e.servers[0];if(K)l.push(` server-template nf_srv_${b}_ 32 ${ot(_e(y.host,"pool.example.com"),ae(y.port))}${H}${Vt}${F}${W}`);else if(y?.targetType==="unix")l.push(` server nf_srv_${b} ${y.unixSocketPath.trim()||"/run/service.sock"}${H}${ie}${F}${W}`);else{const w=_e(y?.host??"","10.0.0.1"),V=te(w)?"":" resolvers nf_dns init-addr last,none";l.push(` server nf_srv_${b} ${ot(w,ae(y?.port??443))}${H}${ie}${V}${F}${W}`)}}else{const y=a.servers;y.some(w=>w.dns_pool&&(w.backup||w.preferred_ip!==""))&&l.push(" option allbackups"),y.forEach((w,V)=>{const D=w.name||`srv${V+1}`,S=w.backup?" backup":"",se=he(U?U.servers[V]:w.weight);if(w.dns_pool){const J=ot(_e(w.host,"pool.example.com"),ae(w.port));w.preferred_ip&&!w.backup?(l.push(` server ${D}_pref ${ot(w.preferred_ip,ae(w.port))}${se}${H}${ie}${F}${W}`),l.push(` server-template ${D}_ 32 ${J}${se}${H}${Vt}${F}${W} backup`)):l.push(` server-template ${D}_ 32 ${J}${se}${H}${Vt}${F}${W}${S}`)}else if(w.target_type==="unix")l.push(` server ${D} ${w.unix_socket_path||"/run/service.sock"}${se}${H}${ie}${F}${W}${S}`);else{const J=_e(w.host,"10.0.0.1"),ve=te(J)?"":" resolvers nf_dns init-addr last,none";l.push(` server ${D} ${ot(J,ae(w.port))}${se}${H}${ie}${ve}${F}${W}${S}`)}})}return E&&$!==null&&l.push("",`backend nf_bw_download_table_${b}`,` stick-table type ${f} size 1m expire 1h store bytes_out_rate(1s)`),E&&j!==null&&l.push("",`backend nf_bw_upload_table_${b}`,` stick-table type ${f} size 1m expire 1h store bytes_in_rate(1s)`),{config:l.join(` -`),merged:p.length}}function Ut(e,s){const n=Math.abs(e)%100,i=n%10;return n>10&&n<20?s[2]:i>1&&i<5?s[1]:i===1?s[0]:s[2]}function js({id:e,index:s,title:n,summary:i,aside:r,children:p,className:a=""}){return t.jsxs("section",{className:`nf-re-section ${a}`.trim(),"aria-labelledby":`${e}-title`,children:[t.jsxs("header",{className:"nf-re-section__head",children:[s&&t.jsx("span",{className:"nf-re-section__index","aria-hidden":"true",children:s}),t.jsx("h2",{id:`${e}-title`,children:n}),i&&t.jsx("span",{className:"nf-re-section__summary",children:i}),r&&t.jsx("span",{className:"nf-re-section__aside",children:r})]}),t.jsx("div",{className:"nf-re-section__body",children:p})]})}function Jt({title:e,hint:s,id:n,stableHint:i=!1}){return t.jsxs("div",{className:`nf-re-block-head${i?" has-stable-hint":""}`,children:[t.jsx("h3",{id:n,children:e}),s&&t.jsx("p",{title:i&&typeof s=="string"?s:void 0,children:s})]})}function lt({children:e,className:s="",layout:n="fixed",...i}){return t.jsx("div",{className:`nf-setgrid nf-setgrid--${n} ${s}`.trim(),...i,children:e})}function R({id:e,label:s,hint:n,aside:i,error:r,children:p,group:a=!1,field:d,grow:u=!1,inline:b=!1,area:o,wide:m=!1,stableHint:x=!1,inactive:h=!1}){const l=["nf-setting-row",u&&"is-grow",b&&"is-inline",m&&"is-wide",x&&"has-stable-hint",h&&"is-inactive"].filter(Boolean).join(" ");return t.jsxs("div",{className:l,"data-field":d,style:o?{gridArea:o}:void 0,children:[t.jsx("div",{className:"nf-setting-row__label",children:a?t.jsx("span",{id:`${e}-label`,children:s}):t.jsx("label",{htmlFor:e,id:`${e}-label`,children:s})}),t.jsx("div",{className:"nf-setting-row__control",children:t.jsxs("div",{className:"nf-setting-row__line",children:[p,i&&t.jsx("span",{className:"nf-setting-row__aside",id:`${e}-aside`,title:typeof i=="string"?i:void 0,children:i})]})}),t.jsx("small",{className:`nf-setting-row__hint${r?" is-error":""}`,id:`${e}-hint`,role:r?"alert":void 0,children:r??n})]})}function ai(){return t.jsx("div",{className:"nf-setgrid__divider","aria-hidden":"true"})}function Wt({children:e,tone:s="info"}){return t.jsxs("p",{className:`nf-re-note${s==="warning"?" is-warning":""} nf-setgrid__note`,children:[t.jsx(es,{size:14,"aria-hidden":"true"}),t.jsx("span",{children:e})]})}function oi({children:e,tone:s="info",icon:n}){return t.jsxs("p",{className:`nf-re-note${s==="warning"?" is-warning":""}`,children:[n??t.jsx(es,{size:14,"aria-hidden":"true"}),t.jsx("span",{children:e})]})}function li({children:e,cards:s=!1}){return t.jsx("div",{className:`nf-re-options${s?" is-cards":""}`,children:e})}function ws({title:e,hint:s,control:n,children:i,open:r=!1,disabled:p=!1,field:a}){return t.jsxs("div",{className:`nf-re-option${r?" is-open":""}${p?" is-disabled":""}`,"data-field":a,children:[t.jsxs("div",{className:"nf-re-option__main",children:[t.jsxs("div",{className:"nf-re-option__text",children:[t.jsx("strong",{children:e}),s&&t.jsx("p",{children:s})]}),t.jsx("div",{className:"nf-re-option__control",children:n})]}),i&&t.jsx(ct,{in:r,children:t.jsx("div",{className:"nf-re-option__body",children:i})})]})}function ci({value:e,onValue:s,...n}){const[i,r]=C.useState(e),[p,a]=C.useState(!1);return t.jsx(Te,{...n,value:p?i:e,onFocus:d=>{a(!0),r(e),n.onFocus?.(d)},onBlur:d=>{a(!1),n.onBlur?.(d)},onChange:d=>{r(d),d===""?s(""):typeof d=="number"&&Number.isFinite(d)&&s(d)}})}function ce({unit:e,wide:s=!1,className:n="",...i}){const r=e?Math.max(28,e.length*7+16):void 0;return t.jsx(ci,{hideControls:!0,size:"sm",...i,className:`nf-num${s?" nf-num--wide":""} ${n}`.trim(),rightSection:e?t.jsx("span",{className:"nf-num__unit","aria-hidden":"true",children:e}):void 0,rightSectionWidth:r,rightSectionPointerEvents:"none"})}const di="kernel_shaper_requires_agent_1_1",Gt=`Ядерный шейпер требует Node Agent ${mt} на этой ноде`,dt=new URLSearchParams(window.location.search).get("demo")==="1"||!1;function ui(e,s){return e.find(n=>s.includes(n.field))?.message}const pi={name:"имя",snis:"SNI",listenerPort:"порт",listenerIP:"IP ноды",listener:"порт",quota:"лимит трафика",clientUploadMbps:"скорость",clientDownloadMbps:"скорость",bandwidth:"скорость"};function hi(e){const s=[];for(const i of e){const r=i.field==="servers"?/адрес|путь/i.test(i.message)?"адрес сервера":"серверы":pi[i.field];r&&!s.includes(r)&&s.push(r)}return s.length?`Заполните ${s.length>1?`${s.slice(0,-1).join(", ")} и ${s.at(-1)}`:s[0]}`:"Проверьте поля формы"}function mi(e,s){return e==="draft"?s?"Черновик сохранён":"Маршрут создан как выключенный черновик":e==="apply"?"Изменения отправлены на ноду":"Маршрут создан и отправлен на включение"}async function fi(e,s){if(dt){const{demoNodeBundles:d,mergeDemoRoutes:u}=await Qt(async()=>{const{demoNodeBundles:x,mergeDemoRoutes:h}=await import("./demo-42aef_vS.js");return{demoNodeBundles:x,mergeDemoRoutes:h}},[]),b=structuredClone(d.find(({node:x})=>x.id===e)??d[0]);b.node.id=e,b.routes=u(e,b.routes.map(x=>({...x,node_id:e})));const o=s?b.routes.find(x=>x.id===s):void 0,m=b.operational?.latest_heartbeat;return{node:b.node,routes:b.routes,route:o,agentVersion:m?.agent_version,memoryTotalBytes:m?.metrics?.memory_total_bytes}}const[n,i,r]=await Promise.all([Ie(`/api/v1/nodes/${e}`),Ie(`/api/v1/nodes/${e}/routes`),Ie(`/api/v1/nodes/${e}/operational`).catch(()=>null)]),p=s?await Ie(`/api/v1/nodes/${e}/routes/${s}`):void 0,a=r?.latest_heartbeat;return{node:n,routes:i,route:p,agentVersion:a?.agent_version,memoryTotalBytes:a?.metrics?.memory_total_bytes}}function ks(e,s){return Ue(e,s.enabled).servers.length>0&&!(s.servers??[]).length?e:Zs({...s,name:e.name})}async function $s(e,s){try{return await Ie(`/api/v1/nodes/${e}/routes/${s.id}`)}catch(n){if(Ts(n))throw n;return s}}const kt={host:"",loading:!1,addresses:[],error:"",done:!1};async function bi(e){if(dt){const{demoResolveDNS:s}=await Qt(async()=>{const{demoResolveDNS:n}=await import("./demo-42aef_vS.js");return{demoResolveDNS:n}},[]);return s(e)}return On(e)}function fn(e){const[s,n]=C.useState(kt),i=e.trim(),r=i!==""&&!te(i),p=s.host===i?s:kt;return{host:i,canResolve:r,current:p,run:async()=>{if(r){n({...kt,host:i,loading:!0});try{const d=await bi(i);n({host:i,loading:!1,done:!0,addresses:d.addresses??[],error:d.addresses?.length?"":d.error||"Домен не вернул ни одного адреса."})}catch(d){const u=d instanceof Cs&&d.code==="invalid_host"?"Некорректное имя домена.":d instanceof Error?d.message:"Не удалось получить адреса.";n({...kt,host:i,done:!0,error:u})}}}}}function bn({canResolve:e,loading:s,disabled:n=!1,onClick:i}){return t.jsx(be,{label:"Сначала укажите домен в поле «Адрес»",disabled:e,openDelay:200,children:t.jsx("span",{className:"nf-inline-flex",children:t.jsx(fe,{variant:"default",size:"sm",leftSection:t.jsx(wr,{size:14}),onClick:i,loading:s,disabled:!e||n,children:"IP домена"})})})}function gi({server:e,hasOtherServers:s,error:n,onChange:i}){const{host:r,canResolve:p,current:a,run:d}=fn(e.host),u=e.preferredIP.trim(),b=u!==""&&!te(u),o=`preferred-${e._key}`;return t.jsxs("div",{className:"nf-srv-sub",children:[t.jsxs("div",{className:"nf-srv-sub__head",children:[t.jsx("label",{className:"nf-srv-sub__title",htmlFor:o,children:"Основной IP"}),t.jsx("span",{className:"nf-srv-sub__hint",id:`${o}-hint`,children:s?"Весь трафик на этот IP; если он недоступен — на все IP домена и резервные серверы.":"Весь трафик на этот IP; если он недоступен — на все IP домена."})]}),t.jsxs("div",{className:"nf-srv-sub__controls",children:[t.jsx(Me,{id:o,size:"sm",className:"nf-srv-sub__ip",placeholder:"не задан",value:e.preferredIP,onChange:m=>i(m.currentTarget.value),error:b||n?!0:void 0,"aria-describedby":`${o}-hint`}),t.jsx(bn,{canResolve:p,loading:a.loading,onClick:()=>{d()}})]}),(b||n)&&t.jsx("p",{className:"nf-cell-error",children:b?"Некорректный IP-адрес.":n}),a.done&&(a.error?t.jsxs("p",{className:"nf-srv-sub__warning",children:[t.jsx(Oe,{size:13,"aria-hidden":"true"}),a.error]}):t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"nf-ip-chips",role:"group","aria-label":`IP-адреса ${r}`,children:a.addresses.map(m=>{const x=m===u;return t.jsxs("button",{type:"button",className:`nf-ip-chip${x?" is-selected":""}`,"aria-pressed":x,onClick:()=>i(x?"":m),children:[x&&t.jsx(Zt,{size:12,"aria-hidden":"true"}),m]},m)})}),t.jsx("p",{className:"nf-srv-sub__note",children:"Адреса получены с хоста панели — нода может видеть другие."})]}))]})}const xi="Доля новых клиентов для этого IP: 2 — вдвое больше, чем у IP с весом 1. Пусто — вес сервера (по умолчанию 1).",_i="Сколько весит одно соединение на этом IP: 2 — каждое соединение считается за два, и IP получает вдвое меньше клиентов. Пусто — стоимость сервера (по умолчанию 1).",vi="Множитель задержки этого IP: 2 — IP кажется вдвое медленнее и выбирается реже. Пусто — стоимость сервера (по умолчанию 1).",yi="Стоимость учитывают алгоритмы «Меньше соединений» и «Меньше задержка».",Pi="Доля IP = вес ÷ стоимость. Например, 4 ядра против 2: вес 2 у 4-ядерного (или стоимость 2 у 2-ядерного) — он получит вдвое больше клиентов. При «Запоминании» уже закреплённые клиенты остаются на своём IP.",ji="Чем меньше задержка × стоимость, тем больше клиентов получает IP; вес задаёт долю при равной задержке. Под мощность сервера: 4 ядра против 2 — вес 2 у 4-ядерного.",wi="Доля IP пропорциональна весу. Например, 4 ядра против 2: вес 2 у 4-ядерного — он получит вдвое больше клиентов.";function ki({server:e,agentAllowed:s,showCost:n,connections:i,weightsFixed:r,error:p,onChange:a}){const{host:d,canResolve:u,current:b,run:o}=fn(e.host),[m,x]=C.useState(""),h=new Set(e.ipWeights.map(f=>f.ip)),l=e.ipWeights.length>=32,v=m.trim(),P=v!==""&&!te(v),$=v!==""&&h.has(v),j=e.name.trim()||d,N=f=>{h.has(f)||l||a([...e.ipWeights,{ip:f,weight:"",cost:""}])},g=()=>{!v||P||$||(N(v),x(""))},E=(f,T)=>{a(e.ipWeights.map(I=>I.ip===f?{...I,...T}:I))},_=f=>a(e.ipWeights.filter(T=>T.ip!==f));return t.jsxs("div",{className:"nf-srv-sub",children:[t.jsxs("div",{className:"nf-srv-sub__head",children:[t.jsx("span",{className:"nf-srv-sub__title",children:"Вес и стоимость отдельных IP"}),t.jsxs("span",{className:"nf-srv-sub__hint",children:["Пусто — как у сервера.",r?" Сейчас веса фиксированы и не применятся.":""]})]}),!s&&t.jsxs("p",{className:"nf-srv-sub__warning is-error",children:[t.jsx(Ds,{size:13,"aria-hidden":"true"}),"Веса отдельных IP применяет агент ноды — обновите Node Agent до ",mt," или новее."]}),t.jsxs("div",{className:"nf-srv-sub__body",children:[e.ipWeights.length>0&&!r&&t.jsx("p",{className:"nf-srv-sub__note",children:i?Pi:n?ji:wi}),e.ipWeights.length>0&&t.jsxs("div",{className:"nf-ipw has-cost",role:"table","aria-label":`Отдельные IP ${j}`,children:[t.jsxs("div",{className:"nf-ipw__row is-head",role:"row",children:[t.jsx("span",{role:"columnheader",children:"IP"}),t.jsx("span",{role:"columnheader",children:t.jsx(be,{label:xi,multiline:!0,w:260,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Вес"})})}),t.jsx("span",{role:"columnheader",className:n?void 0:"is-off",children:t.jsx(be,{label:n?i?_i:vi:yi,multiline:!0,w:260,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Стоимость"})})}),t.jsx("span",{role:"columnheader","aria-label":"Удалить"})]}),e.ipWeights.map(f=>t.jsxs("div",{className:"nf-ipw__row",role:"row",children:[t.jsx("span",{className:"nf-ipw__ip",role:"cell",title:f.ip,children:f.ip}),t.jsx("span",{role:"cell",children:t.jsx(Te,{size:"sm",value:f.weight,min:1,max:256,allowDecimal:!1,hideControls:!0,inputMode:"numeric",placeholder:e.weight===""?"1":String(e.weight),disabled:r&&f.weight==="",error:r&&f.weight!==""?!0:void 0,onChange:T=>E(f.ip,{weight:T===""?"":Number(T)}),"aria-label":`Вес ${f.ip}`})}),t.jsx("span",{role:"cell",children:t.jsx(Te,{size:"sm",value:n?f.cost:"",min:.01,max:100,decimalScale:2,hideControls:!0,inputMode:"decimal",placeholder:n?e.cost===""?"1":String(e.cost):"—",disabled:!n,onChange:T=>E(f.ip,{cost:T===""?"":Number(T)}),"aria-label":`Стоимость ${f.ip}`})}),t.jsx("span",{role:"cell",className:"nf-ipw__action",children:t.jsx(Ms,{variant:"subtle",color:"gray",size:36,onClick:()=>_(f.ip),"aria-label":`Убрать ${f.ip}`,children:t.jsx(As,{size:14})})})]},f.ip))]}),t.jsxs("div",{className:"nf-srv-sub__controls",children:[t.jsx(Me,{size:"sm",className:"nf-srv-sub__ip",placeholder:"IP-адрес",value:m,onChange:f=>x(f.currentTarget.value),onKeyDown:f=>{f.key==="Enter"&&(f.preventDefault(),g())},error:P||$?!0:void 0,"aria-label":`Добавить IP для ${j}`,disabled:l}),t.jsx(fe,{variant:"default",size:"sm",leftSection:t.jsx(Xt,{size:14}),onClick:g,disabled:!v||P||$||l,children:"Добавить"}),t.jsx(bn,{canResolve:u,loading:b.loading,disabled:l,onClick:()=>{o()}})]})]}),(P||$)&&t.jsx("p",{className:"nf-cell-error",children:P?"Некорректный IP-адрес.":"Этот IP уже в списке."}),p&&t.jsx("p",{className:"nf-cell-error",children:p}),b.done&&(b.error?t.jsxs("p",{className:"nf-srv-sub__warning",children:[t.jsx(Oe,{size:13,"aria-hidden":"true"}),b.error]}):t.jsx("div",{className:"nf-ip-chips",role:"group","aria-label":`IP-адреса ${d}`,children:b.addresses.map(f=>t.jsxs("button",{type:"button",className:`nf-ip-chip${h.has(f)?" is-selected":""}`,disabled:h.has(f)||l,onClick:()=>N(f),children:[h.has(f)?t.jsx(Zt,{size:12,"aria-hidden":"true"}):t.jsx(Xt,{size:12,"aria-hidden":"true"}),f]},f))}))]})}const $i={role:"0px",name:"minmax(88px, 180px)",type:"minmax(108px, 140px)",host:"minmax(120px, 1fr)",port:"minmax(72px, 96px)",dns:"minmax(56px, 80px)",weight:"minmax(64px, 72px)",cost:"minmax(72px, 88px)",actions:"36px"};function Ni(e){return/^имя/i.test(e)?"name":e.includes("основной IP")?"preferred":/(вес|стоимость) IP|отдельных IP|IP не должны|IP в списке|вес и стоимость IP/.test(e)?"ipweights":e.includes("DNS-пул")?"dns":/адрес|IPv4/.test(e)?"host":e.includes("Unix")?"unix":e.includes("порт")?"port":e.startsWith("вес")?"weight":e.startsWith("стоимость")?"cost":"row"}function Ii(e){const s=new Map,n=[];for(const i of e){const r=/^Сервер (\d+): (.+)$/.exec(i);if(!r){n.push(i);continue}const p=Number(r[1])-1,a=r[2],d=s.get(p)??[];d.push({cell:Ni(a),message:a.charAt(0).toUpperCase()+a.slice(1)}),s.set(p,d)}return{perServer:s,general:n}}function Si({servers:e,balanceMode:s,poolSettings:n,onChange:i,errors:r}){const p=e.length>=16,a=de({servers:e,balanceMode:s}),d={servers:e,balanceMode:a},u=a==="failover"&&e.length>1,b=e.length>1,{perServer:o,general:m}=Ii(r),x=["name","type","host","port","dns","weight","cost","actions"],h=_=>(_==="role"?x.indexOf("weight"):x.indexOf(_))+1,l={"--srv-cols":x.map(_=>$i[_]).join(" "),"--srv-sub-start":String(h("name"))},v=!!n,P=!!n?.showCost,$="Нужно два сервера или DNS-пул в режиме «Пул»",j=(_,f)=>{i(e.map((T,I)=>I===_?{...T,...f}:T))},N=_=>{const f=e.filter((T,I)=>I!==_);f.length>0&&f.every(T=>T.backup)&&(f[0]={...f[0],backup:!1}),i(f)},g=(_,f)=>{j(_,f?{backup:f,preferredIP:""}:{backup:f})},E=(_,f)=>{const T=_+f;if(T<0||T>=e.length)return;const I=[...e];[I[_],I[T]]=[I[T],I[_]],i(I)};return t.jsxs("div",{className:"nf-servers",children:[t.jsxs("div",{className:`nf-srv-table${u?" is-failover":""}`,style:l,children:[t.jsxs("div",{className:"nf-srv-table__head","aria-hidden":"true",children:[t.jsx("span",{className:"is-field",children:"Имя"}),t.jsx("span",{className:"is-field",children:"Тип"}),t.jsx("span",{className:"is-field",children:"Адрес"}),t.jsx("span",{className:"is-field",children:"Порт"}),t.jsx("span",{className:"is-center",children:t.jsx(be,{label:"HAProxy резолвит домен и распределяет трафик по всем его IP. Только для домена.",multiline:!0,w:240,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"DNS-пул"})})}),u?t.jsx("span",{className:"nf-srv-table__role-head",children:"Роль"}):t.jsxs(t.Fragment,{children:[t.jsx("span",{className:`is-field${v?"":" is-off"}`,children:t.jsx(be,{label:v?"Доля новых клиентов относительно других серверов: 2 — вдвое больше, чем у сервера с весом 1. Пусто — 1.":`Вес: ${$.toLowerCase()}.`,multiline:!0,w:220,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Вес"})})}),t.jsx("span",{className:`is-field${P?"":" is-off"}`,children:t.jsx(be,{label:P?n?.connections?"Каждое соединение считается за столько: 2 — сервер получает вдвое меньше клиентов. Пусто — 1.":"Множитель задержки: 2 — сервер кажется вдвое медленнее. Пусто — 1.":"Стоимость учитывают алгоритмы «Меньше соединений» и «Меньше задержка».",multiline:!0,w:220,openDelay:150,children:t.jsx("span",{className:"nf-help-term",children:"Стоимость"})})})]}),t.jsx("span",{})]}),e.map((_,f)=>{const T=_.host.trim()!==""&&te(_.host),I=_.targetType==="tcp",ue=_.name.trim()||`сервер ${f+1}`,re=Ge(d,f),Z=o.get(f)??[],K=k=>Z.find(X=>X.cell===k)?.message,G=Z.filter(k=>k.cell!=="preferred"&&k.cell!=="ipweights"),pe=I&&ft({servers:e,balanceMode:a},f),le=I&&_.dnsPool&&n;return t.jsxs("div",{className:`nf-srv-row${re?" is-backup":""}${Z.length?" has-error":""}`,children:[t.jsx(Me,{className:"nf-srv-row__name",label:"Имя",placeholder:"srv1",maxLength:rs,value:_.name,onChange:k=>j(f,{name:k.currentTarget.value}),error:K("name")?!0:void 0}),t.jsx(We,{className:"nf-srv-row__type",label:"Тип",value:_.targetType,onChange:k=>j(f,{targetType:k??"tcp",dnsPool:!1,preferredIP:""}),allowDeselect:!1,data:[{value:"tcp",label:"IP / домен"},{value:"unix",label:"Unix socket"}]}),I?t.jsxs(t.Fragment,{children:[t.jsx(Me,{className:"nf-srv-row__host",label:"Адрес",placeholder:"IP или домен",value:_.host,onChange:k=>j(f,{host:k.currentTarget.value}),error:K("host")?!0:void 0}),t.jsx(Te,{className:"nf-srv-row__port",label:"Порт",value:_.port,onChange:k=>j(f,{port:k===""?"":Number(k)}),min:1,max:65535,allowDecimal:!1,hideControls:!0,inputMode:"numeric",error:K("port")?!0:void 0}),t.jsx(be,{label:"DNS-пул доступен только для домена",disabled:!T,openDelay:150,children:t.jsxs("div",{className:"nf-srv-row__dns",children:[t.jsx(Re,{size:"sm","aria-label":`DNS-пул для ${ue}: все IP домена`,checked:_.dnsPool,disabled:T&&!_.dnsPool,error:K("dns")?!0:void 0,onChange:k=>j(f,{dnsPool:k.currentTarget.checked,preferredIP:k.currentTarget.checked?_.preferredIP:""})}),t.jsx("span",{className:"nf-srv-row__dns-label","aria-hidden":"true",children:"DNS-пул"})]})})]}):t.jsx(Me,{className:"nf-srv-row__unix",label:"Путь socket",placeholder:"/run/service.sock",value:_.unixSocketPath,onChange:k=>j(f,{unixSocketPath:k.currentTarget.value}),error:K("unix")?!0:void 0}),u?t.jsx("div",{className:"nf-srv-row__role",children:t.jsxs("span",{className:`nf-role-badge${re?" is-backup":""}`,children:[t.jsx("b",{children:f+1}),re?"Резерв":"Основной"]})}):t.jsxs(t.Fragment,{children:[t.jsx(be,{label:$,disabled:v,openDelay:200,children:t.jsx("div",{className:"nf-srv-row__weight",children:t.jsx(Te,{label:"Вес",placeholder:v?"1":"—",value:v?_.weight:"",onChange:k=>j(f,{weight:k===""?"":Number(k)}),min:1,max:256,allowDecimal:!1,hideControls:!0,inputMode:"numeric",disabled:!v,error:v&&K("weight")?!0:void 0})})}),t.jsx(be,{label:"Стоимость учитывают алгоритмы «Меньше соединений» и «Меньше задержка»",disabled:P,openDelay:200,children:t.jsx("div",{className:"nf-srv-row__cost",children:t.jsx(Te,{label:"Стоимость",placeholder:P?"1":"—",value:P?_.cost:"",onChange:k=>j(f,{cost:k===""?"":Number(k)}),min:.01,max:100,decimalScale:2,hideControls:!0,inputMode:"decimal",disabled:!P,error:P&&K("cost")?!0:void 0})})})]}),t.jsx("div",{className:"nf-srv-row__actions",children:t.jsxs($e,{position:"bottom-end",withinPortal:!0,shadow:"md",width:210,children:[t.jsx($e.Target,{children:t.jsx(Ms,{variant:"subtle",color:"gray",size:36,"aria-label":`Действия: ${ue}`,children:t.jsx(tr,{size:16})})}),t.jsxs($e.Dropdown,{children:[u&&t.jsxs(t.Fragment,{children:[t.jsx($e.Item,{leftSection:t.jsx(Zn,{size:14}),disabled:f===0,onClick:()=>E(f,-1),children:"Выше"}),t.jsx($e.Item,{leftSection:t.jsx(er,{size:14}),disabled:f===e.length-1,onClick:()=>E(f,1),children:"Ниже"}),t.jsx($e.Item,{leftSection:t.jsx(Pr,{size:14}),onClick:()=>g(f,!_.backup),children:_.backup?"Сделать основным":"Сделать резервным"}),t.jsx($e.Divider,{})]}),t.jsx($e.Item,{color:"red",leftSection:t.jsx(As,{size:14}),disabled:!b,onClick:()=>N(f),children:"Удалить сервер"})]})]})}),G.map(k=>{const X=k.cell==="row"?"name":k.cell==="unix"?"host":k.cell;return t.jsx("p",{className:"nf-cell-error nf-srv-row__error",style:{gridColumn:`${Math.max(1,h(X))} / -1`},children:k.message},`${k.cell}-${k.message}`)}),pe&&t.jsx(gi,{server:_,hasOtherServers:e.length>1,error:K("preferred"),onChange:k=>j(f,{preferredIP:k})}),le&&t.jsx(ki,{server:_,agentAllowed:n.agentAllowed,showCost:n.showCost,connections:n.connections,weightsFixed:n.weightsFixed,error:K("ipweights"),onChange:k=>j(f,{ipWeights:k})})]},_._key)})]}),m.length>0&&t.jsx("div",{className:"nf-servers__errors",role:"alert","data-invalid":"true",tabIndex:-1,children:m.map(_=>t.jsxs("p",{className:"nf-cell-error",children:[t.jsx(Oe,{size:13,"aria-hidden":"true"}),_]},_))}),t.jsxs("div",{className:"nf-servers__footer",children:[t.jsx(fe,{variant:"default",size:"sm",leftSection:t.jsx(Xt,{size:14}),disabled:p,onClick:()=>i([...e,{...Qs(Wr(e)),backup:e.length>0}]),children:"Добавить сервер"}),p&&t.jsx("span",{className:"nf-muted",children:"Максимум — 16 серверов."})]})]})}function Ti(e){const s=e.servers,n=s.length===1;if(de(e)==="pool")return n?"Нагрузка делится между всеми IP домена.":"Нагрузка делится между всеми серверами и всеми IP доменов с DNS-пулом.";const i=ft(e,0)&&s[0].preferredIP.trim()!=="";if(n)return i?"Трафик идёт на основной IP; если он упал — делится между всеми IP домена.":"Задайте основной IP — он получит весь трафик, остальные IP домена станут резервом.";const r=i||s.some((u,b)=>Ge(e,b)&&u.targetType==="tcp"&&u.dnsPool),p=s.filter((u,b)=>!Ge(e,b)).length,a=p>1?"Трафик делится между основными серверами":"Трафик идёт на основной сервер",d=p>1?"если все основные упали":"если он упал";return r?`${a}; ${d} — делится между всеми резервными сразу.`:`${a}; резервные включаются по порядку, ${d}.`}function Mi({draft:e,update:s,agent110:n,agentVersion:i,autoTableEntries:r,memoryKnown:p,showError:a}){const d=Le(e),u=Er(d),b=Fe(e),o=Ks(b),m=qs(e.stickyTTL||Ce),x=e.stickyTableEntries==="",h=Mt(e.stickyTableEntries||r),l=u==="hash"?128:64,v=a(["stickyTTL"]),P=a(["stickyTableEntries"]),$=Ys(e.stickyTableEntries||r),j=t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-algorithm",stableHint:!0,label:u==="table"?"Первый сервер":"Алгоритм",hint:u==="table"?"Как выбрать сервер для нового клиента.":Kt.find(g=>g.value===o)?.description,children:t.jsx(We,{id:"dist-algorithm",className:"nf-select-md",size:"sm",value:o,onChange:g=>{g&&s("balanceAlgorithm",g)},allowDeselect:!1,data:Kt.map(({value:g,label:E})=>({value:g,label:E,disabled:g==="leastping"&&!n})),"aria-describedby":"dist-algorithm-hint"})}),o==="roundrobin"&&t.jsx(R,{id:"dist-dynamic",label:"Веса на лету",hint:"Выкл — веса фиксированы: вес IP и плавный ввод не действуют.",children:t.jsx(Re,{id:"dist-dynamic",checked:b!=="static-rr",onChange:g=>s("balanceAlgorithm",g.currentTarget.checked?"roundrobin":"static-rr"),"aria-describedby":"dist-dynamic-hint"})}),o==="random"&&t.jsx(R,{id:"dist-draws",label:"Выборок",hint:"Из стольких случайных серверов берётся менее загруженный.",error:a(["balanceRandomDraws"]),children:t.jsx(ce,{id:"dist-draws",value:e.balanceRandomDraws,onValue:g=>s("balanceRandomDraws",g),placeholder:"2",min:1,max:5,allowDecimal:!1,inputMode:"numeric",error:a(["balanceRandomDraws"])?!0:void 0,"aria-describedby":"dist-draws-hint"})}),o==="leastconn"&&t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-tolerance",label:"Толерантность",hint:"Серверы, где соединений (с учётом стоимости) больше минимума не более чем на столько, считаются равными.",aside:"Пусто — 0",error:a(["leastpingTolerancePct"]),children:t.jsx(ce,{id:"dist-tolerance",unit:"%",value:e.leastpingTolerancePct,onValue:g=>s("leastpingTolerancePct",g),placeholder:"0",min:0,max:100,allowDecimal:!1,inputMode:"numeric",error:a(["leastpingTolerancePct"])?!0:void 0,"aria-describedby":"dist-tolerance-hint"})}),t.jsxs(Wt,{children:["Стоимость — в таблице серверов. Толерантность больше 0 применяет агент ноды каждые 5 с.",ni(i)?"":` Нужен Node Agent ${hn}, на ноде ${i??"неизвестно"}.`]})]}),o==="leastping"&&t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-tolerance",label:"Толерантность",hint:"Кто медленнее лучшего не больше чем на столько — получает полный вес.",error:a(["leastpingTolerancePct"]),children:t.jsx(ce,{id:"dist-tolerance",unit:"%",value:e.leastpingTolerancePct,onValue:g=>s("leastpingTolerancePct",g),placeholder:String(Bs),min:0,max:100,allowDecimal:!1,inputMode:"numeric",error:a(["leastpingTolerancePct"])?!0:void 0,"aria-describedby":"dist-tolerance-hint"})}),t.jsx(R,{id:"dist-floor",label:"Толерантность не меньше",hint:"Разница до стольких мс не в счёт. Пусто — выкл.",error:a(["leastpingToleranceMs"]),children:t.jsx(ce,{id:"dist-floor",unit:"мс",value:e.leastpingToleranceMs,onValue:g=>s("leastpingToleranceMs",g),placeholder:"выкл",min:0,max:1e3,allowDecimal:!1,inputMode:"numeric",error:a(["leastpingToleranceMs"])?!0:void 0,"aria-describedby":"dist-floor-hint"})}),t.jsxs(Wt,{children:["Задержку меряет проверка здоровья, агент ноды обновляет веса каждые 5 с. Стоимость — в таблице серверов.",n?"":` Нужен Node Agent ${mt}, на ноде ${i??"неизвестно"}.`]})]})]}),N=t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-ipv6-clients",group:!0,label:"IPv6-клиенты",hint:"Выключите, если на ноде нет IPv6: таблица будет только для IPv4.",children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:e.clientIPv6?"on":"off",onChange:g=>s("clientIPv6",g==="on"),data:[{value:"on",label:"Вкл"},{value:"off",label:"Выкл"}],"aria-labelledby":"dist-ipv6-clients-label","aria-describedby":"dist-ipv6-clients-hint"})}),t.jsx(R,{id:"dist-ipv6",stableHint:!0,label:"Подсеть IPv6-клиента",inactive:!e.clientIPv6,hint:"Все адреса из одной подсети считаются одним клиентом; /128 — каждый адрес отдельно.",aside:`Пусто — /${l}`,error:e.clientIPv6?a(["stickyIPv6Prefix"]):void 0,children:t.jsx(ce,{id:"dist-ipv6",value:!e.clientIPv6||e.stickyIPv6Prefix===0?"":e.stickyIPv6Prefix,onValue:g=>s("stickyIPv6Prefix",g===""||u==="hash"&&g===128?0:g),placeholder:String(l),min:32,max:128,allowDecimal:!1,inputMode:"numeric",leftSection:"/",disabled:!e.clientIPv6,error:e.clientIPv6&&a(["stickyIPv6Prefix"])?!0:void 0,"aria-describedby":"dist-ipv6-hint"})})]});return t.jsxs("div",{className:"nf-re-block nf-dist",children:[t.jsx(Jt,{title:"Распределение клиентов",hint:"Какой сервер получает клиент: выбирается заново или всегда тот же.",id:"dist-choice-label"}),t.jsx("div",{className:"nf-choice-cards",role:"radiogroup","aria-labelledby":"dist-choice-label",children:Cr.map(g=>{const E=g.value===u;return t.jsxs("button",{type:"button",role:"radio","aria-checked":E,className:`nf-choice-card${E?" is-selected":""}`,onClick:()=>s("stickyMode",Dr(g.value)),children:[t.jsx("span",{className:"nf-choice-card__radio","aria-hidden":"true"}),t.jsx("strong",{children:g.label}),t.jsx("small",{children:g.description})]},g.value)})}),t.jsxs(lt,{"data-choice":u,children:[u==="algorithm"&&j,u==="hash"&&t.jsxs(t.Fragment,{children:[t.jsx(R,{id:"dist-hash",group:!0,stableHint:!0,label:"Распределение",hint:e.stickyHash==="map-based"?"Ровнее, но при смене серверов переезжают почти все.":"При смене серверов переезжают только их клиенты.",children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:e.stickyHash==="map-based"?"even":"stable",onChange:g=>s("stickyHash",g==="even"?"map-based":""),data:[{value:"stable",label:"Стабильное"},{value:"even",label:"Ровное"}],"aria-labelledby":"dist-hash-label","aria-describedby":"dist-hash-hint"})}),t.jsx(R,{id:"dist-factor",stableHint:!0,inactive:e.stickyHash==="map-based",label:"Лимит перегрузки",hint:e.stickyHash==="map-based"?"Только для стабильного распределения.":"Не больше этого % от средней нагрузки. Пусто — выкл.",error:e.stickyHash!=="map-based"?a(["stickyHashBalanceFactor"]):void 0,children:t.jsx(ce,{id:"dist-factor",unit:"%",value:e.stickyHash==="map-based"?"":e.stickyHashBalanceFactor,onValue:g=>s("stickyHashBalanceFactor",g),placeholder:"выкл",min:101,max:1e3,allowDecimal:!1,inputMode:"numeric",disabled:e.stickyHash==="map-based",error:e.stickyHash!=="map-based"&&a(["stickyHashBalanceFactor"])?!0:void 0,"aria-describedby":"dist-factor-hint"})}),N]}),u==="table"&&t.jsxs(t.Fragment,{children:[t.jsxs(R,{id:"dist-ttl",label:"Помнить",hint:"Сколько клиент держится за сервер после последнего соединения.",error:v,children:[t.jsxs("div",{className:"nf-combo",children:[t.jsx(ce,{id:"dist-ttl",value:m.amount,onValue:g=>s("stickyTTL",g===""?Ce:`${g}${m.unit}`),min:1,allowDecimal:!1,inputMode:"numeric",error:v?!0:void 0,"aria-describedby":"dist-ttl-hint"}),t.jsx(We,{className:"nf-select-unit",size:"sm",value:m.unit,onChange:g=>{g&&m.amount!==""&&s("stickyTTL",`${m.amount}${g}`)},allowDeselect:!1,data:(m.unit==="s"?["s","m","h"]:["m","h"]).map(g=>({value:g,label:zs[g]})),"aria-label":"Единица времени"})]}),t.jsx("div",{className:"nf-picks",role:"group","aria-label":"Быстрый выбор срока",children:Ar.map(g=>{const E=(e.stickyTTL||Ce)===g;return t.jsx("button",{type:"button",className:`nf-pick${E?" is-selected":""}`,"aria-pressed":E,onClick:()=>s("stickyTTL",g),children:Lr(g)},g)})})]}),t.jsxs(R,{id:"dist-table",wide:!0,stableHint:!0,group:x,label:"Клиентов в памяти",hint:"Память занимается по мере прихода клиентов; запись удаляется через «Помнить» без соединений. Когда места нет, самые старые забываются.",aside:x?qr(r,p):$?`${$} при заполнении`:void 0,error:P,children:[t.jsx(Ne,{className:"nf-seg",size:"sm",value:x?"auto":"manual",onChange:g=>s("stickyTableEntries",g==="auto"?"":bs(Mt(r))),data:[{value:"auto",label:"Авто"},{value:"manual",label:"Задать"}],"aria-labelledby":"dist-table-label"}),t.jsx(ce,{wide:!0,unit:"клиентов",id:"dist-table",value:h||"",onValue:g=>{g!==""&&s("stickyTableEntries",bs(g))},min:1,max:Rt,allowDecimal:!1,inputMode:"numeric",thousandSeparator:" ",disabled:x,error:P?!0:void 0,"aria-describedby":"dist-table-hint dist-table-aside"})]}),N,t.jsx(ai,{}),j]}),u!=="algorithm"&&t.jsxs(Wt,{children:[u==="table"?"Таблица переживает перезагрузку HAProxy. ":"","IP клиента берётся из PROXY protocol, если он приходит, иначе — адрес соединения."]})]})]})}function zi(){const{nodeId:e="",routeId:s}=Tn(),n=Mn(),i=Cn(),r=En(),p=C.useRef(null),a=C.useRef(!1),d=C.useRef(null),[u,b]=C.useState(null),[o,m]=C.useState(xs),[x,h]=C.useState(""),[l,v]=C.useState(!0),[P,$]=C.useState(null),[j,N]=C.useState(!1),[g,E]=C.useState(null),[_,f]=C.useState("enable"),[T,I]=C.useState(""),[ue,re]=C.useState(""),[,Z]=C.useState(!1),[K,G]=C.useState(!1),[pe,le]=C.useState(!1),[k,X]=C.useState(""),z=async()=>{v(!0),$(null),I("");try{const c=await fi(e,s),A=c.route?Zs(c.route):xs();b(c),m(A),le(!!A.expertOverride);const Q=!!A.expertOverride||A.quotaEnabled||A.clientBandwidthEnabled||A.shaperMode==="kernel";Z(!!A.expertOverride),G(Q),h(JSON.stringify(A))}catch(c){$(c)}finally{v(!1)}};C.useEffect(()=>{if(s&&d.current===s){d.current=null;return}z()},[e,s]);const U=u?.routes??[],Ee=C.useMemo(()=>Ps(o,[],u?.route?.id),[o,u?.route?.id]),xe=C.useMemo(()=>Ps(o,U,u?.route?.id),[o,U,u?.route?.id]),F=_==="draft"?Ee:xe,W=u?.memoryTotalBytes,ie=C.useMemo(()=>ii(o,U.filter(c=>c.id!==u?.route?.id),W),[o,U,u?.route?.id,W]),_e=C.useMemo(()=>{const c=u?.route;return c&&Ws({...c,enabled:!0})&&c.sticky_table_entries_effective?c.sticky_table_entries_effective:Gs(U.filter(A=>A.id!==u?.route?.id),W)},[U,u?.route,W]),ae=!!x&&JSON.stringify(o)!==x,H=Dn(({currentLocation:c,nextLocation:A})=>!a.current&&ae&&!g&&c.pathname!==A.pathname);C.useEffect(()=>{a.current=!1},[i.key]);const he=!!u?.route,y=!!u?.route?.enabled,w=dt?"?demo=1":i.search,V=`/nodes/${encodeURIComponent(e)}${w}`,D=c=>`/nodes/${encodeURIComponent(e)}/routes/${encodeURIComponent(c)}/edit${w}`;An(c=>{!ae||g||(c.preventDefault(),c.returnValue="")});const S=(c,A)=>{m(Q=>({...Q,[c]:A})),re(""),I(""),c==="shaperMode"&&X("")},se=()=>n(V),J=()=>{window.requestAnimationFrame(()=>window.requestAnimationFrame(()=>{const c=p.current?.querySelector('[aria-invalid="true"], [data-invalid="true"]');c?.focus({preventScroll:!0}),c?.scrollIntoView({block:"center",behavior:"smooth"})}))},ve=()=>{N(!0),F.some(c=>["quota","clientUploadMbps","clientDownloadMbps","bandwidth"].includes(c.field))&&G(!0),F.some(c=>c.field==="expert")&&Z(!0),J()},De=async c=>{f(c),N(!0),I(""),re("");const A=c==="draft"?Ee:xe;if(A.length){A.some(L=>L.field==="expert")&&Z(!0),J();return}if(!u)return;E(c);let Q=!1;try{let L;if(dt){await new Promise(ee=>window.setTimeout(ee,420)),L={id:u.route?.id??It(),node_id:e,version:(u.route?.version??0)+1,...Ue(o,c!=="draft"),listener_port:Number(o.listenerPort),target_port:o.servers[0]?.targetType==="unix"?0:Number(o.servers[0]?.port??443),deployed:c!=="draft",deployment_state:c==="draft"?"draft":"pending",created_at:u.route?.created_at??new Date().toISOString(),updated_at:new Date().toISOString()};const{upsertDemoRoute:q}=await Qt(async()=>{const{upsertDemoRoute:ee}=await import("./demo-42aef_vS.js");return{upsertDemoRoute:ee}},[]);q(e,L)}else if(u.route)L=await Ie(`/api/v1/nodes/${e}/routes/${u.route.id}`,{method:"PUT",body:JSON.stringify(Ue(o,c==="apply"||c==="enable",u.route.version))});else{const q=await $s(e,await Ie(`/api/v1/nodes/${e}/routes`,{method:"POST",body:JSON.stringify(Ue(o,!1))})),ee=ks(o,q);Q=!0,d.current=q.id,b(He=>He&&{...He,route:q,routes:[...He.routes.filter(zt=>zt.id!==q.id),q]}),m(ee),h(JSON.stringify(ee)),a.current=!0,n(D(q.id),{replace:!0}),c==="draft"?L=q:L=await Ie(`/api/v1/nodes/${e}/routes/${q.id}`,{method:"PUT",body:JSON.stringify(Ue(o,!0,q.version))})}dt||(L=await $s(e,L),r.invalidateQueries({queryKey:["node-detail",e]}));const je=ks(o,L);b(q=>q&&{...q,route:L,routes:[...q.routes.filter(ee=>ee.id!==L.id),L]}),m(je),h(JSON.stringify(je)),re(mi(c,he)),!he&&!Q&&(a.current=!0,n(D(L.id),{replace:!0}))}catch(L){const je=L instanceof Error?L.message:"Маршрут не сохранён",q=L instanceof Cs&&L.code===di;q&&(X(`${Gt}. Выберите HAProxy или обновите агент.`),G(!0));const ee=q?`${Gt}.`:je.includes("version")?"Маршрут изменился в другой вкладке. Обновите данные и повторите.":je;I(Q?`Черновик сохранён, но включить маршрут не удалось: ${ee}`:ee)}finally{E(null)}},Y=c=>{c.preventDefault(),De(y?"apply":"enable")},Be=()=>{H.state==="blocked"&&H.proceed()};if(l)return t.jsx("main",{className:"nf-page nf-route-editor-page",children:t.jsxs("div",{className:"nf-route-editor-loading",children:[t.jsx(Ln,{visible:!0}),t.jsx("span",{children:"Загружаем маршруты ноды и проверяем конфликты портов…"})]})});if(P&&Ts(P))return t.jsx(Rn,{onSuccess:z});if(P||!u)return t.jsx("main",{className:"nf-page",children:t.jsx(Jn,{title:"Редактор не загрузился",description:P instanceof Error?P.message:"Нода или маршрут не найдены",tone:"error",action:t.jsxs(t.Fragment,{children:[t.jsx(fe,{variant:"default",onClick:()=>n(`/nodes${w}`),children:"К нодам"}),t.jsx(fe,{onClick:z,children:"Повторить"})]})})});const B=c=>j?ui(F,c):void 0,Je=j?F.filter(c=>c.field==="servers").map(c=>c.message):[],Ot=gs.find(c=>c.value===o.quotaPeriod)?.description,Qe=F.length===0,Lt=Qe?"valid":j?"invalid":"incomplete",bt=o.listenerIP==="*"||o.listenerIP==="0.0.0.0"||o.listenerIP==="::",ge=bt?"all":"specific",qe=nn(o),Ze=Ke(o),ye=Le(o),ne=tn(o),Ft=de(o),Ae=Fe(o),ze=as(o),et=Yr(u.agentVersion),tt=et,gt=!!k||!tt&&o.shaperMode==="kernel",Pe=k||(tt?"":`${Gt} (сейчас ${u.agentVersion}).${o.shaperMode==="kernel"?" Выберите HAProxy.":""}`),xt=ye!=="source"&&Ae==="static-rr"||ye==="source"&&o.stickyHash==="map-based",st=Ze?{showCost:ye!=="source"&&(Ae==="leastping"||Ae==="leastconn"),connections:ye!=="source"&&Ae==="leastconn",weightsFixed:xt,agentAllowed:et}:null,_t=`${bt?"*":o.listenerIP||"—"}:${o.listenerPort||"—"}`,nt=[o.matchMode==="sni"?o.snis.length?`SNI · ${o.snis.length} ${Ut(o.snis.length,["домен","домена","доменов"])}`:"SNI":"Фолбэк",_t,o.acceptProxyEnabled?"принимает PROXY":""].filter(Boolean).join(" · "),rt=Kt.find(c=>c.value===Ks(Ae))?.label.toLowerCase(),Bt=Ze?ye==="source"?"закрепление по IP":ye==="source_table"?`запоминание · ${rt}`:rt:"",vt=[`${o.servers.length} ${Ut(o.servers.length,["сервер","сервера","серверов"])}`,qe?"DNS-пул":"",ne?Ft==="pool"?"пул":"основной + резервные":"",Bt??""].filter(Boolean).join(" · "),it=[];if(o.quotaEnabled&&o.quotaValue!==""&&it.push(`лимит ${o.quotaValue} ${o.quotaUnit}`),o.clientBandwidthEnabled){const c=[];o.clientUploadMbps!==""&&c.push(`↑${o.clientUploadMbps}`),o.clientDownloadMbps!==""&&c.push(`↓${o.clientDownloadMbps}`),c.length&&it.push(`скорость ${c.join(" ")} Мбит/с${o.shaperMode==="kernel"?" · ядро":""}`)}const oe=it.join(" · ")||"Лимит трафика и скорости не заданы",qt=j&&F.some(c=>["quota","clientUploadMbps","clientDownloadMbps","bandwidth"].includes(c.field)),yt=K||qt,Pt=y?"apply":"enable",jt=j?F.length:0,O=!j&&xe.length>0?hi(xe):"",me=g?{tone:"busy",text:"Сохраняем…"}:T?{tone:"error",text:"Не сохранено"}:ue&&!ae?{tone:"saved",text:ue}:ae?{tone:"dirty",text:"Есть несохранённые изменения"}:{tone:"clean",text:he?"Изменений нет":"Новый маршрут"};return t.jsxs("main",{className:"nf-page nf-route-editor-page",children:[t.jsx(Bn,{className:"nf-route-editor-header",breadcrumb:t.jsxs(t.Fragment,{children:[t.jsx(us,{to:`/nodes${w}`,children:"Ноды"}),t.jsx("span",{children:"/"}),t.jsx(us,{to:V,children:u.node.name}),t.jsx("span",{children:"/"}),t.jsx("span",{"aria-current":"page",children:he?"Маршрут":"Новый маршрут"})]}),backAction:t.jsx(fe,{variant:"subtle",color:"gray",px:6,onClick:se,"aria-label":"Назад к ноде",children:t.jsx(xr,{size:20})}),title:he?o.name.trim()||"Без имени":"Новый маршрут",badge:t.jsxs("span",{className:`nf-route-state-badge${y?" is-enabled":""}`,children:[t.jsx("i",{"aria-hidden":"true"}),t.jsx("span",{className:"nf-visually-hidden",children:"Состояние: "}),y?"Включён":he?"Выключен":"Черновик"]})}),t.jsxs("form",{ref:p,className:"nf-route-editor-layout",onSubmit:Y,noValidate:!0,"aria-busy":!!g,children:[t.jsxs(hs,{className:"nf-route-editor-form",children:[t.jsx(js,{id:"route-listener",index:"1",title:"Подключение",summary:nt,children:t.jsxs(lt,{layout:"connection",children:[t.jsx(R,{id:"route-name",area:"name",label:"Имя маршрута",hint:"Видно только оператору.",error:B(["name"]),children:t.jsx(Me,{id:"route-name",className:"nf-input-md",placeholder:"api-internal-tls",value:o.name,onChange:c=>S("name",c.currentTarget.value),error:B(["name"])?!0:void 0,required:!0,maxLength:80,"aria-describedby":"route-name-hint"})}),t.jsx(R,{id:"route-match",area:"match",group:!0,label:"Выбор маршрута",hint:o.matchMode==="sni"?"По SNI; порт можно делить.":"Всё, что не совпало по SNI.",children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:o.matchMode,onChange:c=>S("matchMode",c),data:[{value:"sni",label:"По SNI"},{value:"fallback",label:"Фолбэк"}],"aria-labelledby":"route-match-label","aria-describedby":"route-match-hint"})}),t.jsxs(R,{id:"route-listen",area:"listen",group:!0,label:"Слушать",hint:ge==="all"?"Все адреса ноды.":"Один адрес ноды.",error:B(["listenerIP","listener"]),children:[t.jsx(Ne,{className:"nf-seg",size:"sm",value:ge,onChange:c=>{S("listenerIP",c==="all"?"*":u.node.address||"")},data:[{value:"all",label:"Все IP"},{value:"specific",label:"Один IP"}],"aria-labelledby":"route-listen-label"}),t.jsx(Me,{className:"nf-listen-ip",placeholder:ge==="specific"?"203.0.113.1":"все адреса",value:ge==="specific"?o.listenerIP:"",onChange:c=>S("listenerIP",c.currentTarget.value),error:ge==="specific"&&B(["listenerIP","listener"])?!0:void 0,disabled:ge!=="specific","aria-label":"IP-адрес listener",required:ge==="specific"})]}),t.jsx(R,{id:"route-port",area:"port",label:"Порт",hint:"TCP на ноде.",error:B(["listenerPort"]),children:t.jsx(Te,{id:"route-port",className:"nf-num",hideControls:!0,value:o.listenerPort,onChange:c=>S("listenerPort",c===""?"":Number(c)),error:B(["listenerPort"])?!0:void 0,min:1,max:65535,allowDecimal:!1,inputMode:"numeric",required:!0,"aria-describedby":"route-port-hint"})}),o.matchMode==="sni"?t.jsx(R,{id:"route-sni",area:"sni",grow:!0,label:"Домены SNI",hint:"Enter, пробел или запятая — следующий домен.",error:B(["snis"]),children:t.jsx(Tt,{id:"route-sni",className:"nf-route-sni-input",classNames:{pill:"nf-route-sni-pill",pillsList:"nf-route-sni-pills",inputField:"nf-route-sni-field"},placeholder:o.snis.length?"":"api.example.com",value:o.snis,onChange:c=>S("snis",c),error:B(["snis"])?!0:void 0,splitChars:[","," "],clearable:!0,required:!0,"aria-describedby":"route-sni-hint"})}):t.jsx(R,{id:"route-sni",area:"sni",grow:!0,inactive:!0,label:"Домены SNI",hint:"Фолбэк получает соединения без совпавшего SNI.",children:t.jsx(Me,{id:"route-sni",className:"nf-route-sni-input",placeholder:"не нужны для фолбэка",value:"",disabled:!0,"aria-describedby":"route-sni-hint"})}),t.jsx(R,{id:"route-accept-proxy",area:"proxy",inline:!0,label:"Принимать PROXY protocol",hint:"Прокси перед нодой передаёт IP клиента.",children:t.jsx(Re,{id:"route-accept-proxy",checked:o.acceptProxyEnabled,onChange:c=>{const A=c.currentTarget.checked;S("acceptProxyEnabled",A),A||S("acceptProxyFrom",[])},"aria-describedby":"route-accept-proxy-hint"})}),t.jsx(ct,{in:o.acceptProxyEnabled,className:"nf-setgrid__collapse",children:t.jsxs("div",{className:"nf-setgrid__collapse-body",children:[t.jsx(R,{id:"route-accept-from",grow:!0,label:"Доверенные адреса",hint:"IP, подсети или домены (IP домена обновляются сами). Пусто — ждать PROXY от всех.",error:B(["acceptProxyFrom"]),children:t.jsx(Tt,{id:"route-accept-from",className:"nf-input-lg",placeholder:o.acceptProxyFrom.length?"":"10.0.0.0/8",value:o.acceptProxyFrom,onChange:c=>S("acceptProxyFrom",c),error:B(["acceptProxyFrom"])?!0:void 0,splitChars:[","," "],clearable:!0,"aria-describedby":"route-accept-from-hint"})}),o.acceptProxyFrom.length===0&&t.jsxs("p",{className:"nf-inline-warning",role:"note",children:[t.jsx(Ds,{size:14,"aria-hidden":"true"}),t.jsx("span",{children:"Клиенты без PROXY protocol не подключатся к этому порту — это действует на все маршруты порта."})]})]})})]})}),t.jsxs(js,{id:"route-target",index:"2",title:"Назначение",summary:vt,children:[t.jsxs("div",{className:"nf-re-block",children:[t.jsxs("div",{className:"nf-re-block-row nf-re-block-row--servers",children:[t.jsx(Jt,{title:"Серверы",hint:ne?Ti(o):"Добавьте второй сервер или DNS-пул, чтобы делить нагрузку.",stableHint:!0}),t.jsx(be,{label:"Нужно два сервера или DNS-пул",disabled:ne,openDelay:200,children:t.jsx("span",{className:"nf-inline-flex nf-balance-mode",children:t.jsx(Ne,{className:"nf-seg nf-seg--fixed",size:"sm",value:ne?o.balanceMode:"pool",disabled:!ne,onChange:c=>{const A=c;S("balanceMode",A),A==="failover"&&o.balanceMode!=="failover"&&S("servers",sn(o.servers))},data:[{value:"pool",label:"Пул"},{value:"failover",label:"Основной + резервные"}],"aria-label":"Как распределять трафик"})})})]}),t.jsx(Si,{servers:o.servers,balanceMode:o.balanceMode,poolSettings:st,onChange:c=>S("servers",c),errors:Je})]}),t.jsx(ct,{in:Ze,children:t.jsx(Mi,{draft:o,update:S,agent110:et,agentVersion:u.agentVersion,autoTableEntries:_e,memoryKnown:!!(W&&W>0),showError:B})}),t.jsxs("div",{className:"nf-re-block nf-re-block--aside",children:[t.jsx(Jt,{title:"Соединение с серверами",hint:"Как нода подключается к серверам."}),t.jsxs(lt,{children:[t.jsx(R,{id:"route-health",inline:!0,stableHint:!0,label:"Проверка здоровья",hint:qe?"Для DNS-пула включена всегда.":"TCP каждые 5 с; недоступный сервер исключается.",children:t.jsx(Re,{id:"route-health",checked:o.healthCheck||qe,disabled:qe,onChange:c=>S("healthCheck",c.currentTarget.checked),"aria-describedby":"route-health-hint"})}),t.jsx(R,{id:"route-proxy-out",group:!0,stableHint:!0,label:"PROXY protocol к серверу",hint:o.proxyProtocol==="none"?"Передать IP клиента; сервер должен принимать PROXY.":`Без поддержки PROXY на сервере соединения не пройдут.${ze?" Проверка тоже шлёт заголовок.":""}`,children:t.jsx(Ne,{className:"nf-seg",size:"sm",value:o.proxyProtocol,onChange:c=>S("proxyProtocol",c),data:[{value:"none",label:"Нет"},{value:"v1",label:"v1"},{value:"v2",label:"v2"}],"aria-labelledby":"route-proxy-out-label","aria-describedby":"route-proxy-out-hint"})}),t.jsx(R,{id:"route-slowstart",stableHint:!0,label:"Плавный ввод после восстановления",inactive:!ne,hint:ne?ze?xt?"Не действует: веса фиксированы.":"Трафик на вернувшийся сервер растёт постепенно. Пусто — сразу.":"Требует проверки здоровья.":"Нужно два сервера или DNS-пул.",error:ne?B(["slowstart"]):void 0,children:t.jsx(ce,{id:"route-slowstart",unit:"с",value:ne?zr(o.slowstart):"",onValue:c=>S("slowstart",c===""?"":`${c}s`),placeholder:"выкл",min:1,max:600,allowDecimal:!1,inputMode:"numeric",disabled:!ze||!ne,error:ne&&B(["slowstart"])?!0:void 0,"aria-describedby":"route-slowstart-hint"})})]})]})]}),t.jsxs("section",{className:`nf-re-section nf-re-section--disclosure${yt?" is-open":""}`,"aria-labelledby":"route-additional-title",children:[t.jsxs("button",{type:"button",className:"nf-re-section__head nf-re-section__toggle",onClick:()=>G(c=>!c),"aria-expanded":yt,"aria-controls":"route-additional-body",children:[t.jsx("span",{className:"nf-re-section__index","aria-hidden":"true",children:"3"}),t.jsx("h2",{id:"route-additional-title",children:"Дополнительно"}),t.jsx("span",{className:"nf-re-section__summary",children:oe}),t.jsx(qn,{className:"nf-re-section__chevron",size:16,"aria-hidden":"true"})]}),t.jsx(ct,{in:yt,children:t.jsx("div",{className:"nf-re-section__body",id:"route-additional-body",children:t.jsxs(li,{cards:!0,children:[t.jsx(ws,{title:"Лимит трафика",hint:"Счётчик трафика маршрута со сбросом по расписанию.",open:o.quotaEnabled,control:t.jsx(Re,{checked:o.quotaEnabled,onChange:c=>S("quotaEnabled",c.currentTarget.checked),"aria-label":"Лимит трафика"}),children:t.jsxs(lt,{children:[t.jsx(R,{id:"route-quota",label:"Лимит",error:B(["quota"]),children:t.jsxs("div",{className:"nf-combo",children:[t.jsx(Te,{id:"route-quota",className:"nf-num nf-num--wide",hideControls:!0,value:o.quotaValue,onChange:c=>S("quotaValue",c===""?"":Number(c)),error:B(["quota"])?!0:void 0,min:.001,decimalScale:3,inputMode:"decimal",required:o.quotaEnabled}),t.jsx(We,{className:"nf-select-unit",value:o.quotaUnit,onChange:c=>S("quotaUnit",c??"GiB"),allowDeselect:!1,data:["GiB","TiB"],"aria-label":"Единица лимита"})]})}),t.jsx(R,{id:"route-quota-period",stableHint:!0,label:"Сброс",hint:Ot,children:t.jsx(We,{id:"route-quota-period",className:"nf-select-md",value:o.quotaPeriod,onChange:c=>S("quotaPeriod",c??"calendar_month"),allowDeselect:!1,data:gs.map(({value:c,label:A})=>({value:c,label:A}))})}),t.jsx(R,{id:"route-quota-action",stableHint:!0,label:"При достижении",hint:o.quotaAction==="block_new"?"Новые соединения не пройдут; активные сессии не разрываются.":"Панель подсветит превышение, трафик продолжит идти.",children:t.jsx(We,{id:"route-quota-action",className:"nf-select-md",value:o.quotaAction,onChange:c=>S("quotaAction",c??"observe"),allowDeselect:!1,data:[{value:"observe",label:"Только уведомить"},{value:"block_new",label:"Блокировать новые"}]})})]})}),t.jsx(ws,{title:"Ограничение скорости",hint:"На IP клиента, для всех его соединений в маршруте.",open:o.clientBandwidthEnabled,control:t.jsx(Re,{checked:o.clientBandwidthEnabled,onChange:c=>S("clientBandwidthEnabled",c.currentTarget.checked),"aria-label":"Ограничение скорости"}),children:t.jsxs(lt,{children:[t.jsx(R,{id:"route-up",label:"От клиента",hint:"Пусто — без лимита.",error:B(["clientUploadMbps","bandwidth"]),children:t.jsx(ce,{id:"route-up",wide:!0,unit:"Мбит/с",placeholder:"без лимита",value:o.clientUploadMbps,onValue:c=>S("clientUploadMbps",c),error:B(["clientUploadMbps","bandwidth"])?!0:void 0,min:1,max:1e6,allowDecimal:!1,inputMode:"numeric"})}),t.jsx(R,{id:"route-down",label:"К клиенту",hint:"Пусто — без лимита.",error:B(["clientDownloadMbps"]),children:t.jsx(ce,{id:"route-down",wide:!0,unit:"Мбит/с",placeholder:"без лимита",value:o.clientDownloadMbps,onValue:c=>S("clientDownloadMbps",c),error:B(["clientDownloadMbps","bandwidth"])?!0:void 0,min:1,max:1e6,allowDecimal:!1,inputMode:"numeric"})}),t.jsxs(R,{id:"route-shaper",group:!0,stableHint:!0,label:"Где ограничивать",hint:o.shaperMode==="kernel"?"nftables на ноде, splice сохраняется. Маршруты порта должны иметь одинаковые лимиты.":"Точно по маршруту (SNI), но отключает splice на этом порту.",error:Pe&>?Pe:void 0,children:[t.jsx(Ne,{className:"nf-seg",size:"sm",value:o.shaperMode,onChange:c=>S("shaperMode",c),data:[{value:"haproxy",label:"HAProxy"},{value:"kernel",label:"Ядро (nftables)",disabled:!tt&&o.shaperMode!=="kernel"}],"aria-labelledby":"route-shaper-label","aria-describedby":"route-shaper-hint"}),Pe&&!gt&&t.jsxs("span",{className:"nf-setting-row__aside",children:["Ядро: нужен Node Agent ",mt,", на ноде ",u.agentVersion??"неизвестно"]})]})]})})]})})})]}),t.jsxs("div",{className:"nf-re-footer",children:[j&&F.length>0&&t.jsx(ps,{className:"nf-route-error-summary",color:"red",icon:t.jsx(Oe,{size:18}),title:`Нужно исправить: ${F.length}`,role:"alert",children:t.jsx("ul",{children:F.slice(0,5).map((c,A)=>t.jsx("li",{children:c.message},`${c.field}-${A}`))})}),T&&t.jsx(ps,{color:"red",icon:t.jsx(Oe,{size:18}),role:"alert",children:T})]}),t.jsxs("footer",{className:`nf-save-bar is-${me.tone}`,children:[t.jsxs("div",{className:"nf-save-bar__status",role:"status","aria-live":"polite",children:[t.jsx("i",{"aria-hidden":"true"}),t.jsx("span",{children:me.text}),O&&t.jsx("span",{className:"nf-save-bar__hint",children:O}),jt>0&&t.jsxs("button",{type:"button",className:"nf-save-bar__errors",onClick:ve,children:[t.jsx(Oe,{size:14,"aria-hidden":"true"}),"Нужно исправить: ",jt]})]}),t.jsxs("div",{className:"nf-save-bar__actions",children:[!y&&t.jsx(fe,{variant:"default",onClick:()=>{De("draft")},loading:g==="draft",disabled:!!(g&&g!=="draft"),children:"Сохранить черновик"}),t.jsx(fe,{type:"submit",loading:g===Pt,disabled:!!(g&&g!==Pt),children:y?"Сохранить и применить":"Сохранить и включить"})]})]})]}),t.jsx("aside",{className:"nf-route-preview-column","aria-label":"Предпросмотр HAProxy",children:t.jsx(hs,{className:"nf-route-preview-surface",children:t.jsxs("section",{className:"nf-re-section nf-route-preview is-open","aria-labelledby":"route-preview-title",children:[t.jsxs("div",{className:"nf-re-section__head",children:[t.jsx("span",{className:"nf-re-section__index","aria-hidden":"true",children:t.jsx(vr,{size:13})}),t.jsx("h2",{id:"route-preview-title",children:"Предпросмотр HAProxy"}),t.jsxs("span",{className:`nf-preview-validation is-${Lt}`,role:"status",children:[t.jsxs("span",{children:[Qe?t.jsx(Zt,{size:14}):j?t.jsx(Oe,{size:14}):t.jsx(es,{size:14}),Qe?"Форма заполнена верно":j?`Ошибок: ${F.length}`:"Заполните обязательные поля"]}),t.jsxs("small",{children:[ie.merged?`Общий frontend с ${ie.merged} ${Ut(ie.merged,["маршрутом","маршрутами","маршрутами"])}`:"Отдельный frontend",o.expertOverride.trim()?" · есть ручные директивы":""]})]})]}),t.jsxs("div",{className:"nf-re-section__body nf-preview-body",id:"route-preview-body",children:[t.jsxs(oi,{icon:t.jsx(zn,{size:14,"aria-hidden":"true"}),children:["Перед применением Agent проверит конфиг через ",t.jsx("code",{children:"haproxy -c"}),"; UFW меняется только по политике ноды. Активные соединения не разрываются."]}),t.jsxs("div",{className:"nf-code-editor","aria-label":"Предпросмотр HAProxy, только чтение",children:[t.jsxs("div",{className:"nf-code-editor__bar",children:[t.jsxs("span",{children:[t.jsx("i",{}),t.jsx("i",{}),t.jsx("i",{})]}),t.jsx("b",{children:"haproxy.cfg"}),t.jsx("em",{children:"только чтение"})]}),t.jsx("pre",{children:t.jsx("code",{children:ie.config})})]}),t.jsxs("section",{className:"nf-preview-expert","aria-labelledby":"route-expert-title",children:[t.jsxs("div",{className:"nf-preview-expert__head",children:[t.jsxs("span",{children:[t.jsx("strong",{id:"route-expert-title",children:"Ручные директивы backend"}),t.jsx("small",{children:"Секции global, frontend, listen, backend и resolvers запрещены."})]}),t.jsx(Re,{checked:pe,onChange:c=>{le(c.currentTarget.checked),c.currentTarget.checked||S("expertOverride","")},"aria-label":"Разрешить ручные директивы"})]}),pe&&t.jsx(Qn,{"aria-label":"Директивы backend",value:o.expertOverride,onChange:c=>S("expertOverride",c.currentTarget.value),error:B(["expert"]),placeholder:`timeout connect 5s -maxconn 2000`,autosize:!0,minRows:8,maxRows:20,classNames:{input:"nf-code-input"}})]})]})]})})})]}),t.jsx(Hn,{opened:H.state==="blocked",onClose:()=>H.state==="blocked"&&H.reset(),title:"Выйти без сохранения?",size:"sm",closeOnClickOutside:!0,closeOnEscape:!0,classNames:{content:"nf-dialog",header:"nf-dialog__header",body:"nf-dialog__body"},children:t.jsxs("div",{className:"nf-confirm-dialog",children:[t.jsx("p",{children:"Изменения маршрута будут потеряны. HAProxy и UFW не изменятся."}),t.jsxs("div",{children:[t.jsx(fe,{variant:"default",onClick:()=>H.state==="blocked"&&H.reset(),children:"Продолжить"}),t.jsx(fe,{color:"red",onClick:Be,children:"Выйти"})]})]})})]})}export{zi as RouteEditorPage}; diff --git a/internal/panel/web_dist/assets/SettingsPage-Cn7Tfg_U.js b/internal/panel/web_dist/assets/SettingsPage-B9rk-cjR.js similarity index 98% rename from internal/panel/web_dist/assets/SettingsPage-Cn7Tfg_U.js rename to internal/panel/web_dist/assets/SettingsPage-B9rk-cjR.js index fe7d6b7..c5e9b47 100644 --- a/internal/panel/web_dist/assets/SettingsPage-Cn7Tfg_U.js +++ b/internal/panel/web_dist/assets/SettingsPage-B9rk-cjR.js @@ -1,4 +1,4 @@ -import{r as l,q as bs,s as se,t as Ue,j as e,y as pe,v as js,C as Un,a3 as Hn,a4 as q,w as Vn,p as Gn,V as Kn,O as hs,a5 as Wn,o as Xn,E as Me,a6 as Jn,c as ie,u as Qn,k as Yn,a7 as fs,g as K,i as Zn,e as et,B as A,M as Z,a8 as st,a9 as je,aa as rn,f as ee,L as nt,I as tt,ab as _e,ac as at,ad as rt,ae as ot,A as Us,b as ss,m as Hs,_ as lt}from"./index-Dy6W__Vz.js";import{L as ct,r as it}from"./uuid-CHFAcSZK.js";import{u as on,n as dt,o as ut,S as ns,c as fe,d as Te,P as ts,T as Vs,t as ht,a as ze}from"./format-D6_ab21F.js";import{e as Be,N as ft,a as Gs,I as we,M as Se,P as mt,c as as,b as rs,T as De}from"./PageHeader-C4N9uitv.js";import{h as Ks,r as Ce,I as os,p as Ws,a as ls}from"./platform-C19YEZOH.js";import{a as pt,I as xt}from"./IconServer-BpOSndTX.js";import{G as Xs,I as gt}from"./IconKey-D6H2eVar.js";import{I as Js}from"./IconTrash-CZzjtN_Z.js";import"./chart-react-C4b8adjg.js";function bt(t={timeout:2e3}){const[n,a]=l.useState(null),[o,r]=l.useState(!1),[d,i]=l.useState(null),u=m=>{window.clearTimeout(d),i(window.setTimeout(()=>r(!1),t.timeout)),r(m)};return{copy:m=>{"clipboard"in navigator?navigator.clipboard.writeText(m).then(()=>u(!0)).catch(b=>a(b)):a(new Error("useClipboard: navigator.clipboard is not supported"))},reset:()=>{r(!1),a(null),window.clearTimeout(d)},error:n,copied:o}}function ln(t){return{x:Be(t.x,0,1),y:Be(t.y,0,1)}}function cn(t,n,a="ltr"){const o=l.useRef(!1),r=l.useRef(!1),d=l.useRef(0),[i,u]=l.useState(!1),f=l.useRef(null);return l.useEffect(()=>{o.current=!0},[]),{ref:l.useCallback(m=>{if(f.current&&(f.current(),f.current=null),!m)return;const b=({x:h,y:W})=>{cancelAnimationFrame(d.current),d.current=requestAnimationFrame(()=>{if(o.current&&m){m.style.userSelect="none";const z=m.getBoundingClientRect();if(z.width&&z.height){const B=Be((h-z.left)/z.width,0,1);t({x:a==="ltr"?B:1-B,y:Be((W-z.top)/z.height,0,1)})}}})},_=()=>{document.addEventListener("mousemove",S),document.addEventListener("mouseup",N),document.addEventListener("touchmove",v,{passive:!1}),document.addEventListener("touchend",N)},w=()=>{document.removeEventListener("mousemove",S),document.removeEventListener("mouseup",N),document.removeEventListener("touchmove",v),document.removeEventListener("touchend",N)},$=()=>{!r.current&&o.current&&(r.current=!0,typeof n?.onScrubStart=="function"&&n.onScrubStart(),u(!0),_())},N=()=>{r.current&&o.current&&(r.current=!1,u(!1),w(),setTimeout(()=>{typeof n?.onScrubEnd=="function"&&n.onScrubEnd()},0))},j=h=>{$(),h.preventDefault(),S(h)},S=h=>b({x:h.clientX,y:h.clientY}),k=h=>{h.cancelable&&h.preventDefault(),$(),v(h)},v=h=>{h.cancelable&&h.preventDefault(),b({x:h.changedTouches[0].clientX,y:h.changedTouches[0].clientY})};m.addEventListener("mousedown",j),m.addEventListener("touchstart",k,{passive:!1}),f.current=()=>{m.removeEventListener("mousedown",j),m.removeEventListener("touchstart",k)}},[a,t]),active:i}}var dn={root:"m_b183c0a2"};const jt=js((t,{color:n})=>({root:{"--code-bg":n?Un(n,t):void 0}})),me=bs((t,n)=>{const a=se("Code",null,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,color:x,block:m,variant:b,mod:_,attributes:w,...$}=a,N=Ue({name:"Code",props:a,classes:dn,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:w,vars:f,varsResolver:jt});return e.jsx(pe,{component:m?"pre":"code",variant:b,ref:n,mod:[{block:m},_],...N("root"),...$,dir:"ltr"})});me.classes=dn;me.displayName="@mantine/core/Code";var un={root:"m_de3d2490",colorOverlay:"m_862f3d1b",shadowOverlay:"m_98ae7f22",alphaOverlay:"m_95709ac0",childrenOverlay:"m_93e74e3"};const Qs={withShadow:!0},vt=js((t,{radius:n,size:a})=>({root:{"--cs-radius":n===void 0?void 0:Vn(n),"--cs-size":q(a)}})),He=Hn((t,n)=>{const a=se("ColorSwatch",Qs,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,color:x,size:m,radius:b,withShadow:_,children:w,variant:$,attributes:N,...j}=se("ColorSwatch",Qs,a),S=Ue({name:"ColorSwatch",props:a,classes:un,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:N,vars:f,varsResolver:vt});return e.jsxs(pe,{ref:n,variant:$,size:m,...S("root",{focusable:!0}),...j,children:[e.jsx("span",{...S("alphaOverlay")}),_&&e.jsx("span",{...S("shadowOverlay")}),e.jsx("span",{...S("colorOverlay",{style:{backgroundColor:x}})}),e.jsx("span",{...S("childrenOverlay"),children:w})]})});He.classes=un;He.displayName="@mantine/core/ColorSwatch";const[yt,vs]=Gn(null);var ys={wrapper:"m_fee9c77",preview:"m_9dddfbac",body:"m_bffecc3e",sliders:"m_3283bb96",thumb:"m_40d572ba",swatch:"m_d8ee6fd8",swatches:"m_5711e686",saturation:"m_202a296e",saturationOverlay:"m_11b3db02",slider:"m_d856d47d",sliderOverlay:"m_8f327113"};const _s=l.forwardRef(({position:t,...n},a)=>e.jsx(pe,{ref:a,__vars:{"--thumb-y-offset":`${t.y*100}%`,"--thumb-x-offset":`${t.x*100}%`},...n}));_s.displayName="@mantine/core/ColorPickerThumb";const ws=bs((t,n)=>{const a=se("ColorSlider",null,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,onChange:x,onChangeEnd:m,maxValue:b,round:_,size:w="md",focusable:$=!0,value:N,overlays:j,thumbColor:S="transparent",onScrubStart:k,onScrubEnd:v,__staticSelector:h="ColorPicker",attributes:W,...z}=a,B=Ue({name:h,classes:ys,props:a,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:W}),Q=vs()?.getStyles||B,Y=Kn(),[F,U]=l.useState({y:0,x:N/b}),O=l.useRef(F),H=C=>_?Math.round(C*b):C*b,{ref:ne}=cn(({x:C,y:E})=>{O.current={x:C,y:E},x?.(H(C))},{onScrubEnd:()=>{const{x:C}=O.current;m?.(H(C)),v?.()},onScrubStart:k});hs(()=>{U({y:0,x:N/b})},[N]);const I=(C,E)=>{C.preventDefault();const P=ln(E);x?.(H(P.x)),m?.(H(P.x))},te=C=>{switch(C.key){case"ArrowRight":{I(C,{x:F.x+.05,y:F.y});break}case"ArrowLeft":{I(C,{x:F.x-.05,y:F.y});break}}},X=j.map((C,E)=>l.createElement("div",{...Q("sliderOverlay"),style:C,key:E}));return e.jsxs(pe,{...z,ref:on(ne,n),...Q("slider"),role:"slider","aria-valuenow":N,"aria-valuemax":b,"aria-valuemin":0,tabIndex:$?0:-1,onKeyDown:te,"data-focus-ring":Y.focusRing,__vars:{"--cp-thumb-size":`var(--cp-thumb-size-${w})`},children:[X,e.jsx(_s,{position:F,...Q("thumb",{style:{top:q(1),background:S}})})]})});ws.displayName="@mantine/core/ColorSlider";function L(t,n=0,a=10**n){return Math.round(a*t)/a}function _t({h:t,s:n,l:a,a:o}){const r=n*((a<50?a:100-a)/100);return{h:t,s:r>0?2*r/(a+r)*100:0,v:a+r,a:o}}const wt={grad:360/400,turn:360,rad:360/(Math.PI*2)};function St(t,n="deg"){return Number(t)*(wt[n]||1)}const Nt=/hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;function Ys(t){const n=Nt.exec(t);return n?_t({h:St(n[1],n[2]),s:Number(n[3]),l:Number(n[4]),a:n[5]===void 0?1:Number(n[5])/(n[6]?100:1)}):{h:0,s:0,v:0,a:1}}function ms({r:t,g:n,b:a,a:o}){const r=Math.max(t,n,a),d=r-Math.min(t,n,a),i=d?r===t?(n-a)/d:r===n?2+(a-t)/d:4+(t-n)/d:0;return{h:L(60*(i<0?i+6:i),3),s:L(r?d/r*100:0,3),v:L(r/255*100,3),a:o}}function ps(t){const n=t[0]==="#"?t.slice(1):t;return n.length===3?ms({r:parseInt(n[0]+n[0],16),g:parseInt(n[1]+n[1],16),b:parseInt(n[2]+n[2],16),a:1}):ms({r:parseInt(n.slice(0,2),16),g:parseInt(n.slice(2,4),16),b:parseInt(n.slice(4,6),16),a:1})}function Ct(t){const n=t[0]==="#"?t.slice(1):t,a=i=>L(parseInt(i,16)/255,3);if(n.length===4){const i=n.slice(0,3),u=a(n[3]+n[3]);return{...ps(i),a:u}}const o=n.slice(0,6),r=a(n.slice(6,8));return{...ps(o),a:r}}const kt=/rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;function Zs(t){const n=kt.exec(t);return n?ms({r:Number(n[1])/(n[2]?100/255:1),g:Number(n[3])/(n[4]?100/255:1),b:Number(n[5])/(n[6]?100/255:1),a:n[7]===void 0?1:Number(n[7])/(n[8]?100:1)}):{h:0,s:0,v:0,a:1}}const hn={hex:/^#?([0-9A-F]{3}){1,2}$/i,hexa:/^#?([0-9A-F]{4}){1,2}$/i,rgb:/^rgb\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i,rgba:/^rgba\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i,hsl:/hsl\(\s*(\d+)\s*,\s*(\d+(?:\.\d+)?%)\s*,\s*(\d+(?:\.\d+)?%)\)/i,hsla:/^hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*(\d*(?:\.\d+)?)\)$/i},$t={hex:ps,hexa:Ct,rgb:Zs,rgba:Zs,hsl:Ys,hsla:Ys};function Et(t){for(const[,n]of Object.entries(hn))if(n.test(t))return!0;return!1}function Oe(t){if(typeof t!="string")return{h:0,s:0,v:0,a:1};if(t==="transparent")return{h:0,s:0,v:0,a:0};const n=t.trim();for(const[a,o]of Object.entries(hn))if(o.test(n))return $t[a](n);return{h:0,s:0,v:0,a:1}}const fn=l.forwardRef((t,n)=>{const{value:a,onChange:o,onChangeEnd:r,color:d,...i}=se("AlphaSlider",null,t);return e.jsx(ws,{...i,ref:n,value:a,onChange:u=>o?.(L(u,2)),onChangeEnd:u=>r?.(L(u,2)),maxValue:1,round:!1,"data-alpha":!0,overlays:[{backgroundImage:"linear-gradient(45deg, var(--slider-checkers) 25%, transparent 25%), linear-gradient(-45deg, var(--slider-checkers) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--slider-checkers) 75%), linear-gradient(-45deg, var(--mantine-color-body) 75%, var(--slider-checkers) 75%)",backgroundSize:`${q(8)} ${q(8)}`,backgroundPosition:`0 0, 0 ${q(4)}, ${q(4)} ${q(-4)}, ${q(-4)} 0`},{backgroundImage:`linear-gradient(90deg, transparent, ${d})`},{boxShadow:`rgba(0, 0, 0, .1) 0 0 0 ${q(1)} inset, rgb(0, 0, 0, .15) 0 0 ${q(4)} inset`}]})});fn.displayName="@mantine/core/AlphaSlider";function mn({h:t,s:n,v:a,a:o}){const r=t/360*6,d=n/100,i=a/100,u=Math.floor(r),f=i*(1-d),x=i*(1-(r-u)*d),m=i*(1-(1-r+u)*d),b=u%6;return{r:L([i,x,f,f,m,i][b]*255),g:L([m,i,i,x,f,f][b]*255),b:L([f,f,m,i,i,x][b]*255),a:L(o,2)}}function en(t,n){const{r:a,g:o,b:r,a:d}=mn(t);return n?`rgba(${a}, ${o}, ${r}, ${L(d,2)})`:`rgb(${a}, ${o}, ${r})`}function sn({h:t,s:n,v:a,a:o},r){const d=(200-n)*a/100,i={h:Math.round(t),s:Math.round(d>0&&d<200?n*a/100/(d<=100?d:200-d)*100:0),l:Math.round(d/2)};return r?`hsla(${i.h}, ${i.s}%, ${i.l}%, ${L(o,2)})`:`hsl(${i.h}, ${i.s}%, ${i.l}%)`}function Le(t){const n=t.toString(16);return n.length<2?`0${n}`:n}function pn(t){const{r:n,g:a,b:o}=mn(t);return`#${Le(n)}${Le(a)}${Le(o)}`}function Rt(t){const n=Math.round(t.a*255);return`${pn(t)}${Le(n)}`}const cs={hex:pn,hexa:t=>Rt(t),rgb:t=>en(t,!1),rgba:t=>en(t,!0),hsl:t=>sn(t,!1),hsla:t=>sn(t,!0)};function ce(t,n){return n?t in cs?cs[t](n):cs.hex(n):"#000000"}const xn=l.forwardRef((t,n)=>{const{value:a,onChange:o,onChangeEnd:r,color:d,...i}=se("HueSlider",{},t);return e.jsx(ws,{...i,ref:n,value:a,onChange:o,onChangeEnd:r,maxValue:360,thumbColor:`hsl(${a}, 100%, 50%)`,round:!0,"data-hue":!0,overlays:[{backgroundImage:"linear-gradient(to right,hsl(0,100%,50%),hsl(60,100%,50%),hsl(120,100%,50%),hsl(170,100%,50%),hsl(240,100%,50%),hsl(300,100%,50%),hsl(360,100%,50%))"},{boxShadow:`rgba(0, 0, 0, .1) 0 0 0 ${q(1)} inset, rgb(0, 0, 0, .15) 0 0 ${q(4)} inset`}]})});xn.displayName="@mantine/core/HueSlider";function gn({className:t,onChange:n,onChangeEnd:a,value:o,saturationLabel:r,focusable:d=!0,size:i,color:u,onScrubStart:f,onScrubEnd:x,...m}){const{getStyles:b}=vs(),[_,w]=l.useState({x:o.s/100,y:1-o.v/100}),$=l.useRef(_),{ref:N}=cn(({x:k,y:v})=>{$.current={x:k,y:v},n({s:Math.round(k*100),v:Math.round((1-v)*100)})},{onScrubEnd:()=>{const{x:k,y:v}=$.current;a({s:Math.round(k*100),v:Math.round((1-v)*100)}),x?.()},onScrubStart:f});l.useEffect(()=>{w({x:o.s/100,y:1-o.v/100})},[o.s,o.v]);const j=(k,v)=>{k.preventDefault();const h=ln(v);n({s:Math.round(h.x*100),v:Math.round((1-h.y)*100)}),a({s:Math.round(h.x*100),v:Math.round((1-h.y)*100)})},S=k=>{switch(k.key){case"ArrowUp":{j(k,{y:_.y-.05,x:_.x});break}case"ArrowDown":{j(k,{y:_.y+.05,x:_.x});break}case"ArrowRight":{j(k,{x:_.x+.05,y:_.y});break}case"ArrowLeft":{j(k,{x:_.x-.05,y:_.y});break}}};return e.jsxs(pe,{...b("saturation"),ref:N,...m,role:"slider","aria-label":r,"aria-valuenow":_.x,"aria-valuetext":ce("rgba",o),tabIndex:d?0:-1,onKeyDown:S,children:[e.jsx("div",{...b("saturationOverlay",{style:{backgroundColor:`hsl(${o.h}, 100%, 50%)`}})}),e.jsx("div",{...b("saturationOverlay",{style:{backgroundImage:"linear-gradient(90deg, #fff, transparent)"}})}),e.jsx("div",{...b("saturationOverlay",{style:{backgroundImage:"linear-gradient(0deg, #000, transparent)"}})}),e.jsx(_s,{position:_,...b("thumb",{style:{backgroundColor:u}})})]})}gn.displayName="@mantine/core/Saturation";const bn=l.forwardRef(({className:t,datatype:n,setValue:a,onChangeEnd:o,size:r,focusable:d,data:i,swatchesPerRow:u,value:f,...x},m)=>{const b=vs(),_=i.map((w,$)=>l.createElement(He,{...b.getStyles("swatch"),unstyled:b.unstyled,component:"button",type:"button",color:w,key:$,radius:"sm",onClick:()=>{a(w),o?.(w)},"aria-label":w,tabIndex:d?0:-1,"data-swatch":!0},f===w&&e.jsx(dt,{size:"35%",color:Wn(w)<.5?"white":"black"})));return e.jsx(pe,{...b.getStyles("swatches"),ref:m,...x,children:_})});bn.displayName="@mantine/core/Swatches";const It={swatchesPerRow:7,withPicker:!0,focusable:!0,size:"md",__staticSelector:"ColorPicker"},Pt=js((t,{size:n,swatchesPerRow:a})=>({wrapper:{"--cp-preview-size":Me(n,"cp-preview-size"),"--cp-width":Me(n,"cp-width"),"--cp-body-spacing":Jn(n),"--cp-swatch-size":`${100/a}%`,"--cp-thumb-size":Me(n,"cp-thumb-size"),"--cp-saturation-height":Me(n,"cp-saturation-height")}})),Ss=bs((t,n)=>{const a=se("ColorPicker",It,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,format:x="hex",value:m,defaultValue:b,onChange:_,onChangeEnd:w,withPicker:$,size:N,saturationLabel:j,hueLabel:S,alphaLabel:k,focusable:v,swatches:h,swatchesPerRow:W,fullWidth:z,onColorSwatchClick:B,__staticSelector:ke,mod:Q,attributes:Y,...F}=a,U=Ue({name:ke,props:a,classes:ys,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:Y,rootSelector:"wrapper",vars:f,varsResolver:Pt}),O=l.useRef(x||"hex"),H=l.useRef(""),ne=l.useRef(-1),I=l.useRef(!1),te=x==="hexa"||x==="rgba"||x==="hsla",[X,C,E]=Xn({value:m,defaultValue:b,finalValue:"#FFFFFF",onChange:_}),[P,xe]=l.useState(Oe(X)),de=()=>{window.clearTimeout(ne.current),I.current=!0},ue=()=>{window.clearTimeout(ne.current),ne.current=window.setTimeout(()=>{I.current=!1},200)},ae=g=>{xe(D=>{const re={...D,...g};return H.current=ce(O.current,re),re}),C(H.current)};return hs(()=>{typeof m=="string"&&Et(m)&&!I.current&&xe(Oe(m))},[m]),hs(()=>{O.current=x||"hex",C(ce(O.current,P))},[x]),e.jsx(yt,{value:{getStyles:U,unstyled:u},children:e.jsxs(pe,{ref:n,...U("wrapper"),size:N,mod:[{"full-width":z},Q],...F,children:[$&&e.jsxs(e.Fragment,{children:[e.jsx(gn,{value:P,onChange:ae,onChangeEnd:({s:g,v:D})=>w?.(ce(O.current,{...P,s:g,v:D})),color:X,size:N,focusable:v,saturationLabel:j,onScrubStart:de,onScrubEnd:ue}),e.jsxs("div",{...U("body"),children:[e.jsxs("div",{...U("sliders"),children:[e.jsx(xn,{value:P.h,onChange:g=>ae({h:g}),onChangeEnd:g=>w?.(ce(O.current,{...P,h:g})),size:N,focusable:v,"aria-label":S,onScrubStart:de,onScrubEnd:ue}),te&&e.jsx(fn,{value:P.a,onChange:g=>ae({a:g}),onChangeEnd:g=>{w?.(ce(O.current,{...P,a:g}))},size:N,color:ce("hex",P),focusable:v,"aria-label":k,onScrubStart:de,onScrubEnd:ue})]}),te&&e.jsx(He,{color:X,radius:"sm",size:"var(--cp-preview-size)",...U("preview")})]})]}),Array.isArray(h)&&e.jsx(bn,{data:h,swatchesPerRow:W,focusable:v,setValue:C,value:X,onChangeEnd:g=>{const D=ce(x,Oe(g));B?.(D),w?.(D),E||xe(Oe(g))}})]})})});Ss.classes=ys;Ss.displayName="@mantine/core/ColorPicker";const At={timeout:1e3};function jn(t){const{children:n,timeout:a,value:o,...r}=se("CopyButton",At,t),d=bt({timeout:a}),i=()=>d.copy(o);return e.jsx(e.Fragment,{children:n({copy:i,copied:d.copied,...r})})}jn.displayName="@mantine/core/CopyButton";const Mt={multiple:!1},vn=l.forwardRef((t,n)=>{const{onChange:a,children:o,multiple:r,accept:d,name:i,form:u,resetRef:f,disabled:x,capture:m,inputProps:b,..._}=se("FileButton",Mt,t),w=l.useRef(null),$=()=>{!x&&w.current?.click()},N=S=>{if(S.currentTarget.files===null)return a(r?[]:null);a(r?Array.from(S.currentTarget.files):S.currentTarget.files[0]||null)};return ut(f,()=>{w.current&&(w.current.value="")}),e.jsxs(e.Fragment,{children:[e.jsx("input",{style:{display:"none"},type:"file",accept:d,multiple:r,onChange:N,ref:on(n,w),name:i,form:u,capture:m,...b}),o({onClick:$,..._})]})});vn.displayName="@mantine/core/FileButton";const Tt=[["path",{d:"M3 7a2 2 0 1 0 4 0a2 2 0 1 0 -4 0",key:"svg-0"}],["path",{d:"M14 15a2 2 0 1 0 4 0a2 2 0 1 0 -4 0",key:"svg-1"}],["path",{d:"M15 6a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-2"}],["path",{d:"M3 18a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-3"}],["path",{d:"M9 17l5 -1.5",key:"svg-4"}],["path",{d:"M6.5 8.5l7.81 5.37",key:"svg-5"}],["path",{d:"M7 7l8 -1",key:"svg-6"}]],zt=ie("outline","chart-dots-3","ChartDots3",Tt);const Dt=[["path",{d:"M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0",key:"svg-0"}],["path",{d:"M9 12l2 2l4 -4",key:"svg-1"}]],Ot=ie("outline","circle-check","CircleCheck",Dt);const qt=[["path",{d:"M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666",key:"svg-0"}],["path",{d:"M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1",key:"svg-1"}]],Lt=ie("outline","copy","Copy",qt);const Bt=[["path",{d:"M12 8l0 4l2 2",key:"svg-0"}],["path",{d:"M3.05 11a9 9 0 1 1 .5 4m-.5 5v-5h5",key:"svg-1"}]],Ft=ie("outline","history","History",Bt);const Ut=[["path",{d:"M12 21a9 9 0 0 1 0 -18c4.97 0 9 3.582 9 8c0 1.06 -.474 2.078 -1.318 2.828c-.844 .75 -1.989 1.172 -3.182 1.172h-2.5a2 2 0 0 0 -1 3.75a1.3 1.3 0 0 1 -1 2.25",key:"svg-0"}],["path",{d:"M7.5 10.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-1"}],["path",{d:"M11.5 7.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-2"}],["path",{d:"M15.5 10.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-3"}]],Ht=ie("outline","palette","Palette",Ut);const Vt=[["path",{d:"M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3",key:"svg-0"}],["path",{d:"M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3",key:"svg-1"}],["path",{d:"M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-2"}]],nn=ie("outline","rocket","Rocket",Vt);const Gt=[["path",{d:"M12 3a12 12 0 0 0 8.5 3a12 12 0 0 1 -8.5 15a12 12 0 0 1 -8.5 -15a12 12 0 0 0 8.5 -3",key:"svg-0"}],["path",{d:"M11 11a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-1"}],["path",{d:"M12 12l0 2.5",key:"svg-2"}]],Kt=ie("outline","shield-lock","ShieldLock",Gt);const Wt=[["path",{d:"M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0",key:"svg-0"}],["path",{d:"M3.6 9h16.8",key:"svg-1"}],["path",{d:"M3.6 15h16.8",key:"svg-2"}],["path",{d:"M11.5 3a17 17 0 0 0 0 18",key:"svg-3"}],["path",{d:"M12.5 3a17 17 0 0 1 0 18",key:"svg-4"}]],Xt=ie("outline","world","World",Wt);function Ne({id:t,label:n,hint:a,children:o,group:r=!1}){return e.jsxs("div",{className:"nf-cfg-field",children:[e.jsxs("div",{className:"nf-cfg-field__label",children:[r?e.jsx("span",{id:`${t}-label`,children:n}):e.jsx("label",{htmlFor:t,id:`${t}-label`,children:n}),a&&e.jsx("small",{id:`${t}-hint`,children:a})]}),o]})}function is({children:t}){return e.jsx("div",{className:"nf-cfg-fields",children:t})}function ds({unit:t,...n}){return e.jsx(ft,{...n,className:`nf-cfg-number ${n.className??""}`.trim(),hideControls:!0,allowDecimal:!1,allowNegative:!1,rightSection:e.jsx("span",{className:"nf-cfg-number__unit",children:t}),rightSectionPointerEvents:"none",rightSectionWidth:t.length>3?64:48})}function qe({tone:t="muted",children:n,title:a}){return e.jsx("span",{className:`nf-cfg-pill is-${t}`,title:a,children:n})}function us({children:t,mono:n=!0}){return e.jsx("span",{className:`nf-cfg-value${n?" is-mono":""}`,children:t})}const Jt=new Intl.DateTimeFormat("ru-RU",{day:"numeric",month:"short",year:"numeric"}),Qt=new Intl.DateTimeFormat("ru-RU",{day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"});function Yt(t){const n=new Date(t);return Number.isNaN(n.getTime())?"—":Jt.format(n)}function tn(t){const n=new Date(t);return Number.isNaN(n.getTime())?"—":Qt.format(n)}function Zt(t){const n=new Map,a=[...t].sort((r,d)=>d.sequence-r.sequence),o=r=>`${r.os.trim().toLowerCase()}/${r.arch.trim().toLowerCase()}`;return a.forEach((r,d)=>{const i=a.slice(0,d).filter(x=>o(x)===o(r)).reverse(),u=i.find(x=>x.sha256===r.sha256);if(u){n.set(r.id,{kind:"same",sequence:u.sequence});return}const f=i.find(x=>x.version===r.version);f&&n.set(r.id,{kind:"rebuilt",sequence:f.sequence})}),n}function ea(t){return t>=1960?3:t>=1e3?2:1}function sa(t,n){const a=["appearance","security","addresses"];return t===3?{columns:[["agent","versions"],a,["metrics"]],below:[]}:t===2?n==="below"?{columns:[["agent","versions"],a],below:["metrics"]}:{columns:n==="left"?[["agent","versions","metrics"],a]:[["agent","versions"],[...a,"metrics"]],below:[]}:{columns:[["agent","versions","appearance","addresses","security","metrics"]],below:[]}}const an=64*1024*1024,xs={public_url:"https://panel.example.com",web_port:8080,agent_port:4200,theme:"rose",accent:fs,session_timeout_minutes:30,max_sessions:5,audit_retention_days:90},na=["#22C55E","#C27087","#45C7D8","#E7B84B"];function yn(t){return["green","rose","cyan","amber"].includes(t.theme)?t.theme:je(t.accent)==="#22C55E"?"green":"rose"}function ta(t){return{...t,theme:yn(t)}}const G=new URLSearchParams(window.location.search).get("demo")==="1"||!1;async function aa(){const{demoNodeBundles:t}=await lt(async()=>{const{demoNodeBundles:u}=await import("./demo-42aef_vS.js");return{demoNodeBundles:u}},[]),n=Date.now(),a=864e5,r=[[22,"2.0.0",8470528,.1,"9c3e71a4f0b25d68e1c7a93f4b0d2e86c5f17a39b2e4d60c8f1a7b35e92d04c6"],[21,"1.1.2",8462336,.2,"25f449ad85c1be0d9a7f1c3e0b54a2d7e61f9c08a3b7d42e95f06c1d8a2b3e47"],[20,"1.1.2",8462336,.25,"25f449ad85c1be0d9a7f1c3e0b54a2d7e61f9c08a3b7d42e95f06c1d8a2b3e47"],[19,"1.1.1",8451840,.4,"47c24b0b96e3a1f7d05c2b8e9f4a6d13c7b25e80f9a1d4c6b3e72a05f8d91c2b"],[18,"1.1.0",8441344,1.2,"a68a075355d2e8b1c47f09a3e6b5d21c8f7a4e90b3c6d15f2a8e7b40c9d31f6a"],[17,"1.1.0",8441344,1.3,"6e8654c4c4f1a0b9d73e25c8a6f4b1e09d7c3a52f8e6b14d0c9a7e35b2f81d4c"],[16,"1.0.5",7749632,56,"a8d400cff41e7b2c9d05a6f3e8b1c47d2a9f60e3b5c8d71f4a2e9b06c3d85f1a"],[15,"1.0.4",7749632,63,"84e063ebb7a2f5c1d98e40b6a3f7c2e15d9b08a4f6e3c71b2d5a8e94f0c6b3d2"],[14,"1.0.2",7749632,64,"be71d6c2219f3a8e5b0c7d4f1a6e2b98c3d05f7a4e1b6c92d8f3a50e7b4c1d6f"],[13,"0.5.0",7738880,67,"e5a975f060b8c3d1e7f4a2b95c0d6e83f1a7b4c29d5e0f6a3b8c71d4e2f95a0b"],[12,"0.4.9-dev",7738880,68,"a76ab9c9a9d2e5f1b8c4a07e3d6f92b5c1e8a4d73f0b6c29e5a1d8f4b7c03e6d"],[11,"0.4.8-dev",7738880,68.2,"fd19989d4e7a3c1b6f02d8e5a9c4b71f3e6d0a28b5c9f14e7d3a6b80c2f5e19a"]].map(([u,f,x,m,b])=>({id:`00000000-0000-4000-8000-${String(u).padStart(12,"0")}`,version:f,os:"linux",arch:"amd64",sha256:b,size_bytes:x,sequence:u,signature:"verified",created_at:new Date(n-m*a).toISOString()})),d=u=>r.find(f=>f.sequence===(u===0?22:16)),i=t.map((u,f)=>({node:u.node,operational:u.operational&&u.operational.latest_heartbeat?{...u.operational,latest_heartbeat:{...u.operational.latest_heartbeat,agent_version:d(f).version}}:u.operational,update:{node_id:u.node.id,actual_sequence:d(f).sequence,state:"installed",last_report_at:new Date(n-13e3-f*1e3).toISOString(),updated_at:new Date(n-18e3).toISOString()}}));return{panel:{...xs,public_url:"https://panel.example.com",metrics_enabled:!0,updated_at:new Date(n-63*a).toISOString()},nodes:i,releases:r,signingKey:{algorithm:"Ed25519",sha256:"703105fbac33f7388d7cd83e9cf02ad8130fa77d93b62bc111808d4cd5f3d387"},partialErrors:[]}}async function Fe(t,n,a,o){try{return await t}catch(r){return n.push(`${a}: ${r instanceof Error?r.message:"данные недоступны"}`),o}}async function ra(){if(G)return aa();const t=[],[n,a,o,r]=await Promise.all([K("/api/v1/settings"),K("/api/v1/nodes"),Fe(K("/api/v1/agent-releases"),t,"Релизы",[]),Fe(K("/api/v1/agent-releases/signing-key"),t,"Ключ подписи",null)]),d=a.map(i=>({node:i,operational:null,update:null}));return{panel:ta(n),nodes:d,releases:o,signingKey:r,partialErrors:t}}function gs(t){return{theme:t.theme,accent:t.accent,session_timeout_minutes:t.session_timeout_minutes,max_sessions:t.max_sessions,audit_retention_days:t.audit_retention_days}}function oa(t,n){return JSON.stringify(gs(t))===JSON.stringify(gs(n))}function la(t){const n=[];return rn.test(t.accent)||n.push("Акцент: цвет в формате #RRGGBB."),(!Number.isInteger(t.session_timeout_minutes)||t.session_timeout_minutes<5||t.session_timeout_minutes>1440)&&n.push("Таймаут сессии: от 5 до 1440 минут."),(!Number.isInteger(t.max_sessions)||t.max_sessions<1||t.max_sessions>100)&&n.push("Количество сессий: от 1 до 100."),(!Number.isInteger(t.audit_retention_days)||t.audit_retention_days<7||t.audit_retention_days>3650)&&n.push("Хранение аудита: от 7 до 3650 дней."),n}function ca(t,n,a){return a?n===null?"Состояние неизвестно":Ce(t,a)?t.sequence===n?"Установлено":t.sequence>n?"Доступно":"Для отката":"Другая платформа":"Платформа неизвестна"}function ia(t){return{idle:"Ожидание",pending:"Назначено",downloading:"Загрузка",verified:"Проверено",activating:"Установка",installed:"Установлено",failed:"Ошибка",rolled_back:"Выполнен откат"}[t??""]??t??"Нет отчёта"}function ja(){const t=Qn(),n=Yn(),[a,o]=l.useState(null),[r,d]=l.useState(!0),[i,u]=l.useState(null),[f,x]=l.useState(""),[m,b]=l.useState(0),[_,w]=l.useState(!1),[$,N]=l.useState(""),[j,S]=l.useState(""),[k,v]=l.useState(null),[h,W]=l.useState(null),[z,B]=l.useState(""),[ke,Q]=l.useState(!1),[Y,F]=l.useState(""),[U,O]=l.useState("linux"),[H,ne]=l.useState("amd64"),[I,te]=l.useState(null),[X,C]=l.useState(""),[E,P]=l.useState(null),[xe,de]=l.useState(""),[ue,ae]=l.useState(!1),[g,D]=l.useState(xs),[re,Ns]=l.useState(xs),[oe,Cs]=l.useState(!1),[ks,he]=l.useState(""),[$s,Es]=l.useState(!1),[$e,_n]=l.useState(!1),Ve=l.useRef(null),[wn,Rs]=l.useState(0),[Is,Sn]=l.useState("below"),Ee=l.useRef(null),Ps=l.useRef(null),Nn=l.useCallback(s=>{Ee.current?.disconnect(),Ps.current=s,s&&(Rs(s.clientWidth),Ee.current=new ResizeObserver(([c])=>Rs(Math.round(c.contentRect.width))),Ee.current.observe(s))},[]),ve=ea(wn),Ge=sa(ve,Is);l.useLayoutEffect(()=>{const s=Ps.current;if(!s||ve!==2)return;const c=Ln=>Ln.reduce((Bn,Fn)=>Bn+(s.querySelector(`[data-card="${Fn}"]`)?.offsetHeight??0),0),p=parseFloat(getComputedStyle(s).rowGap)||0,R=c(["agent","versions"])+p,T=c(["appearance","security","addresses"])+2*p,be=Math.abs(R-T)<160?"below":R()=>Ee.current?.disconnect(),[]);const Cn=G?"?demo=1":t.search,Re=async()=>{d(!0),u(null),v(null);try{const s=await ra();o(s),D(s.panel),Ns(s.panel),_e(s.panel,!0),he(""),x(c=>c&&s.nodes.some(({node:p})=>p.id===c)?c:s.nodes[0]?.node.id??""),b(c=>c+1)}catch(s){u(s)}finally{d(!1)}};l.useEffect(()=>{Re()},[]),l.useEffect(()=>{if(G||!f){w(!1),N("");return}const s=new AbortController,c=[];return w(!0),N(""),Promise.all([Fe(K(`/api/v1/nodes/${f}/operational`,{signal:s.signal}),c,"Телеметрия",null),Fe(K(`/api/v1/nodes/${f}/agent-update`,{signal:s.signal}),c,"Updater",null)]).then(([p,R])=>{s.signal.aborted||(o(T=>T&&{...T,nodes:T.nodes.map(be=>be.node.id===f?{...be,operational:p,update:R}:be)}),N(c.join(" · ")))}).finally(()=>{s.signal.aborted||w(!1)}),()=>s.abort()},[f,m]);const y=a?.nodes.find(({node:s})=>s.id===f)??a?.nodes[0],J=l.useMemo(()=>[...a?.releases??[]].sort((s,c)=>c.sequence-s.sequence),[a?.releases]),kn=l.useMemo(()=>Zt(J),[J]),le=y?.update?y.update.actual_sequence:null,M=Ks(y?.operational?.latest_heartbeat?.metrics),Ke=J.filter(s=>Ce(s,M)),ge=le===null?void 0:Ke.find(s=>s.sequence===le),V=le===null?void 0:Ke.find(s=>s.sequence>le),As=le===null?[]:Ke.filter(s=>s.sequence!!(c?.latest_heartbeat?.received_at??s.last_seen_at)&&(s.status==="online"||s.status==="degraded")).length??0,Ie=a?.nodes.length??0,Pe=la(g),ye=!oa(g,re),Xe=(s,c)=>{const p=s==="accent"?je(String(c)):null,R=s==="accent"&&p?p:c;D(T=>({...T,[s]:R})),s==="accent"&&at(String(R)),s==="theme"&&rt(R),v(null),he("")},En=s=>{const c=ot[s]??g.accent;D(p=>({...p,theme:s,accent:c})),_e({theme:s,accent:c}),v(null),he("")},Je=s=>{const c=je(s)??s,p=yn(g);D(R=>({...R,theme:p,accent:c})),je(c)&&_e({theme:p,accent:c}),v(null),he("")},Rn=()=>{D(re),_e(re,!0),he("")},Ms=async()=>{if(!(Pe.length||oe)){Cs(!0),he(""),v(null);try{const s=G?{...g,updated_at:new Date().toISOString()}:await K("/api/v1/settings",{method:"PUT",body:JSON.stringify(gs(g))});D(s),Ns(s),o(c=>c&&{...c,panel:s}),_e(s,!0),v({tone:"ok",text:G?"Demo-настройки сохранены в текущем интерфейсе. Live Panel не изменён.":"Настройки панели сохранены."})}catch(s){he(s instanceof ss&&s.status===409?"Конфликт: настройки уже изменены в другой сессии. Обновите состояние перед повторным сохранением.":s instanceof Error?s.message:"Настройки не сохранены.")}finally{Cs(!1)}}},Qe=s=>{s.key==="Enter"&&(s.preventDefault(),ye&&Ms())},Ts=s=>o(c=>c&&{...c,nodes:c.nodes.map(p=>p.node.id===s.node_id?{...p,update:s}:p)}),In=async()=>{if(!(!y||!y.update||!V||!M||!Ce(V,M))){S("update"),v(null);try{const s=G?{...y.update,desired_release:V,state:"assigned",updated_at:new Date().toISOString()}:await K(`/api/v1/nodes/${y.node.id}/agent-update`,{method:"PUT",body:JSON.stringify({release_id:V.id,expected_actual_sequence:y.update.actual_sequence,expected_desired_sequence:y.update.desired_release?.sequence??0})});Ts(s),v({tone:"ok",text:`${V.version} назначен ноде ${y.node.name}. Updater проверит подпись и выполнит авт rollback при ошибке.`})}catch(s){v({tone:"error",text:s instanceof Error?s.message:"Обновление не назначено"})}finally{S("")}}},Pn=async()=>{if(!h)return;const s=a?.nodes.find(({node:p})=>p.id===h.nodeID),c=Ks(s?.operational?.latest_heartbeat?.metrics);if(!c||!Ce(h.release,c)||c.os!==h.platform.os||c.arch!==h.platform.arch){B("Платформа ноды неизвестна или изменилась. Обновите состояние и выберите совместимый релиз заново.");return}S("rollback"),v(null),B("");try{const p=a?.nodes.find(({node:T})=>T.id===h.nodeID)?.update,R=G?{...p,desired_release:h.release,state:"assigned",updated_at:new Date().toISOString()}:await K(`/api/v1/nodes/${h.nodeID}/agent-update/rollback`,{method:"POST",body:JSON.stringify({target_release_id:h.release.id,expected_actual_sequence:h.expectedActualSequence,expected_desired_sequence:h.expectedDesiredSequence})});Ts(R),v({tone:"ok",text:`Безопасный откат ${h.nodeName} на ${h.release.version} назначен.`}),W(null)}catch(p){B(p instanceof Error?p.message:"Откат не назначен")}finally{S("")}},An=s=>{!y||!y.update||!M||!Ce(s,M)||s.sequence>=y.update.actual_sequence||(B(""),W({nodeID:y.node.id,nodeName:y.node.name,release:s,expectedActualSequence:y.update.actual_sequence,expectedDesiredSequence:y.update.desired_release?.sequence??0,platform:M}))},Ye=()=>{Ve.current?.(),Q(!1),F(""),O("linux"),ne("amd64"),te(null),C("")},Mn=s=>{if(s&&s.size>an){Ve.current?.(),te(null),C(`Файл больше 64 MiB: ${ze(s.size)}.`);return}te(s),C("")},Tn=async()=>{if(!(!I||!Y.trim())){if(I.size>an){C(`Файл больше 64 MiB: ${ze(I.size)}.`);return}S("upload"),v(null),C("");try{const s=G?{id:it(),version:Y.trim(),os:U,arch:H,sha256:"demo-artifact-sha256",size_bytes:I.size,sequence:(J[0]?.sequence??0)+1,signature:"demo-signed",created_at:new Date().toISOString()}:await K(`/api/v1/agent-releases?version=${encodeURIComponent(Y.trim())}&os=${encodeURIComponent(U)}&arch=${encodeURIComponent(H)}`,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:I});o(c=>c&&{...c,releases:[s,...c.releases]}),n.removeQueries({queryKey:Hs}),v({tone:"ok",text:`Релиз ${s.version} загружен, SHA-256 проверен и подписан Ed25519.`}),Ye()}catch(s){C(s instanceof Error?s.message:"Релиз не загружен")}finally{S("")}}},zn=async()=>{if(!(!E||ue)){S("delete-release"),de(""),v(null);try{G||await K(`/api/v1/agent-releases/${encodeURIComponent(E.id)}`,{method:"DELETE"}),o(s=>s&&{...s,releases:s.releases.filter(c=>c.id!==E.id)}),n.removeQueries({queryKey:Hs}),v({tone:"ok",text:`Релиз ${E.version} · ${E.os}/${E.arch} удалён.`}),P(null)}catch(s){const c=s instanceof ss&&s.status===409&&s.code==="release_in_use";ae(c),de(s instanceof ss&&s.status===409?"Релиз установлен или назначен хотя бы одной ноде. Сначала переведите эти ноды на другую версию.":s instanceof Error?s.message:"Релиз не удалён.")}finally{S("")}}};if(r)return e.jsx("main",{className:"nf-page nf-settings-page",children:e.jsxs("div",{className:"nf-settings-loading",children:[e.jsx(ct,{visible:!0}),e.jsx("span",{children:"Загружаем параметры панели и подписанные релизы…"})]})});if(i&&Zn(i))return e.jsx(et,{onSuccess:Re});if(i||!a)return e.jsx("main",{className:"nf-page",children:e.jsx(ns,{title:"Настройки не загрузились",description:i instanceof Error?i.message:"Panel API недоступен",tone:"error",action:e.jsx(A,{onClick:Re,children:"Повторить"})})});const zs=5,Ds=$e?J:J.slice(0,zs),Os=!$e&&ge&&!Ds.includes(ge)?ge:null,qs=!M||!y?.update||_||!!j,Ae=!!a.panel.metrics_enabled,Ls=a.panel.metrics_allow_cidrs??0,Ze=`${a.panel.public_url||"http://panel:8080"}/metrics`,Dn=s=>s==="Установлено"?"accent":s==="Доступно"?"ok":s==="Для отката"||s==="Готов к установке"?"muted":"warn",Bs=s=>{const c=a.nodes.length?ca(s,le,M):"Готов к установке",p=kn.get(s.id),R=c==="Установлено",T=y?.update?.desired_release?.id===s.id&&!R;return e.jsxs("div",{className:`nf-release-row${R?" is-installed":""}${p?" is-twin":""}`,role:"row",children:[e.jsx("div",{className:"nf-release-row__version",role:"cell",children:e.jsx("strong",{children:s.version})}),e.jsx("div",{className:"nf-release-row__seq",role:"cell",children:e.jsxs("code",{children:["#",s.sequence]})}),e.jsxs("div",{className:"nf-release-row__platform",role:"cell",children:[s.os,"/",s.arch,e.jsx("small",{children:ze(s.size_bytes)})]}),e.jsx("div",{className:"nf-release-row__date",role:"cell",children:e.jsx(De,{label:tn(s.created_at),withArrow:!0,children:e.jsx("span",{children:Yt(s.created_at)})})}),e.jsx("div",{className:"nf-release-row__sha",role:"cell",children:e.jsx(De,{label:s.sha256,withArrow:!0,multiline:!0,maw:320,children:e.jsx("code",{children:s.sha256.slice(0,10)})})}),e.jsxs("div",{className:"nf-release-row__status",role:"cell",children:[e.jsx(qe,{tone:T?"info":Dn(c),children:T?"Назначено":c}),p&&e.jsx("span",{className:"nf-release-row__twin",title:p.kind==="same"?`SHA-256 совпадает с #${p.sequence}`:`Версия ${s.version} перевыпущена в #${p.sequence}`,children:p.kind==="same"?`тот же бинарник, что #${p.sequence}`:`пересобрана в #${p.sequence}`})]}),e.jsx("div",{className:"nf-release-row__delete",role:"cell",children:e.jsx(De,{label:R?"Установленный релиз удалить нельзя":`Удалить ${s.version} · #${s.sequence}`,withArrow:!0,children:e.jsx(Us,{variant:"subtle",color:"red",size:32,"aria-label":`Удалить релиз ${s.version} #${s.sequence} для ${s.os}/${s.arch}`,onClick:()=>{de(""),ae(!1),P(s)},disabled:!!j||R,children:e.jsx(Js,{size:16})})})})]},s.id)},On=!M||!y?.update?e.jsx(Z,{size:15}):e.jsx(Ot,{size:15}),qn=_?"Проверяем…":M?y?.update?"Актуальная версия":"Нет отчёта updater":"Платформа неизвестна",es=y?.update?.state,Fs={agent:e.jsx(fe,{id:"node-agent",className:"nf-settings-card nf-agent-settings","data-card":"agent",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(nn,{size:18}),"Node Agent"]}),description:e.jsxs("span",{className:"nf-agent-trust",children:[e.jsx(Gs,{size:14}),"Подписанные релизы · ",a.signingKey?.algorithm||"Ed25519"," + SHA-256"]}),actions:e.jsxs(e.Fragment,{children:[a.nodes.length>0&&e.jsx("span",{className:"nf-agent-primary",children:V&&M&&y?.update?e.jsxs(A,{leftSection:e.jsx(nn,{size:16}),onClick:In,disabled:qs,loading:j==="update",title:`Обновить до ${V.version}`,children:["Обновить до ",V.version]}):e.jsxs("span",{className:"nf-agent-uptodate",children:[On,qn]})}),a.nodes.length>0&&e.jsxs(Se,{position:"bottom-end",withinPortal:!0,shadow:"md",width:300,children:[e.jsx(Se.Target,{children:e.jsx(A,{variant:"default",leftSection:e.jsx(ls,{size:16}),rightSection:e.jsx(we,{size:14}),disabled:qs||As.length===0,children:"Откатить"})}),e.jsxs(Se.Dropdown,{className:"nf-rollback-menu",children:[e.jsxs(Se.Label,{children:["Откатить ",y?.node.name," до версии"]}),As.map(s=>{const c=ge&&s.sha256===ge.sha256;return e.jsxs(Se.Item,{leftSection:e.jsx(ls,{size:15}),rightSection:e.jsxs("code",{children:["#",s.sequence]}),onClick:()=>An(s),children:[s.version,c&&e.jsx("small",{children:" · тот же бинарник"})]},s.id)})]})]}),e.jsx(A,{variant:"default",leftSection:e.jsx(os,{size:16}),onClick:()=>Q(!0),children:"Загрузить релиз"})]}),children:a.nodes.length?e.jsxs("div",{className:"nf-agent-node",children:[e.jsxs("dl",{className:"nf-agent-facts",children:[e.jsxs("div",{className:"nf-agent-facts__node",children:[e.jsx("dt",{children:e.jsx("label",{htmlFor:"nf-agent-node-select",children:"Нода"})}),e.jsx("dd",{children:e.jsx(Te,{id:"nf-agent-node-select",className:"nf-agent-node-select","aria-label":"Нода для обновления",value:y?.node.id,onChange:s=>x(s??""),allowDeselect:!1,data:a.nodes.map(({node:s})=>({value:s.id,label:`${s.name} · ${s.address}`})),disabled:!!j,leftSection:e.jsx(pt,{size:15})})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Установлено"}),e.jsxs("dd",{children:[e.jsx("strong",{children:_?"Загрузка…":$n}),y?.update&&e.jsxs("code",{children:["#",y.update.actual_sequence]})]})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Отчёт updater"}),e.jsx("dd",{children:y?.update?.last_report_at?e.jsxs(e.Fragment,{children:[e.jsx("span",{children:ht(y.update.last_report_at)}),es!=="installed"&&e.jsx(qe,{tone:es==="failed"?"danger":"muted",children:ia(es)})]}):e.jsx("span",{className:"is-muted",children:_?"Получаем состояние":"Ещё не получен"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Доступно"}),e.jsx("dd",{children:V?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:V.version}),e.jsxs("code",{children:["#",V.sequence]})]}):e.jsx("span",{className:"is-muted",children:!M||le===null?"—":"Новее нет"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Платформа"}),e.jsx("dd",{children:e.jsx("span",{children:Ws(M)})})]})]}),$&&e.jsx(ee,{color:"yellow",icon:e.jsx(Z,{size:17}),role:"alert",children:$}),!_&&!M&&e.jsx(ee,{color:"yellow",icon:e.jsx(Z,{size:17}),role:"status",title:"Назначение релиза заблокировано",children:"Дождитесь сигнала с полями os и arch. NodeFlow не будет предполагать платформу ноды."}),!_&&M&&!y?.update&&e.jsx(ee,{color:"yellow",icon:e.jsx(Z,{size:17}),role:"status",title:"Состояние updater неизвестно",children:"Назначение и откат заблокированы, пока Panel не получит фактический sequence ноды."}),y?.update?.last_error&&e.jsx(ee,{color:"red",icon:e.jsx(Z,{size:17}),children:y.update.last_error}),e.jsx("p",{className:"nf-agent-note",children:"HAProxy не перезапускается. Если новый Agent не пройдёт проверку запуска, updater атомарно вернёт предыдущий бинарник."})]}):e.jsx(ns,{title:"Нод пока нет",description:"Релизы можно подготовить заранее; назначение обновлений станет доступно после установки ноды.",action:e.jsx(A,{component:nt,to:`/nodes${Cn}`,children:"Добавить ноду"})})},"agent"),versions:e.jsx(fe,{id:"nf-agent-history",className:"nf-settings-card nf-release-history","data-card":"versions",title:e.jsxs("span",{className:"nf-settings-card-title",children:["Версии Agent ",e.jsx("span",{className:"nf-cfg-count",children:J.length})]}),description:"Новая нода получает новейший релиз для своей платформы. Sequence уникален и растёт с каждой загрузкой.",children:J.length?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"nf-release-table",role:"table","aria-label":"Подписанные версии Agent",children:[e.jsxs("div",{className:"nf-release-row is-head",role:"row",children:[e.jsx("span",{role:"columnheader",className:"nf-release-row__version",children:"Версия"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__seq",children:"Seq"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__platform",children:"Платформа"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__date",children:"Загружен"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__sha",children:"SHA-256"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__status",children:"Статус"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__delete",children:e.jsx("span",{className:"nf-visually-hidden",children:"Удалить"})})]}),Ds.map(Bs),Os&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"nf-release-gap",role:"row",children:e.jsx("span",{role:"cell",children:"…"})}),Bs(Os)]})]}),J.length>zs&&e.jsxs("button",{type:"button",className:"nf-release-more",onClick:()=>_n(s=>!s),"aria-expanded":$e,children:[e.jsx(we,{size:15,"aria-hidden":!0}),$e?"Свернуть":`Показать все (${J.length})`]})]}):e.jsx(ns,{title:"Релизов пока нет",description:"Без совместимого релиза установка ноды будет заблокирована. Загрузите бинарник Linux для нужной архитектуры.",action:e.jsx(A,{leftSection:e.jsx(os,{size:16}),onClick:()=>Q(!0),children:"Загрузить релиз"})})},"versions"),appearance:e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact","data-card":"appearance",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Ht,{size:18}),"Внешний вид"]}),description:"Применяется сразу, сохраняется кнопкой «Сохранить»",children:e.jsx("div",{className:"nf-cfg-body",children:e.jsxs(is,{children:[e.jsx(Ne,{id:"panel-theme",label:"Тема",children:e.jsx(Te,{id:"panel-theme",className:"nf-cfg-select",value:g.theme,onChange:s=>En(s??"rose"),allowDeselect:!1,disabled:oe,data:[{value:"rose",label:"Rose"},{value:"green",label:"Green"},{value:"cyan",label:"Arctic Cyan"},{value:"amber",label:"Warm Amber"}]})}),e.jsx(Ne,{id:"panel-accent",label:"Цветовой акцент",children:e.jsxs(ts,{opened:$s,onChange:Es,position:"bottom-start",width:280,shadow:"md",withinPortal:!0,children:[e.jsx(ts.Target,{children:e.jsxs("button",{id:"panel-accent",className:"nf-accent-trigger",type:"button",onClick:()=>Es(s=>!s),disabled:oe,"aria-label":`Выбрать цветовой акцент, сейчас ${g.accent}`,"aria-expanded":$s,children:[e.jsx("i",{style:{background:je(g.accent)??fs}}),e.jsx("span",{children:g.accent||"#RRGGBB"}),e.jsx(we,{size:14,"aria-hidden":!0})]})}),e.jsxs(ts.Dropdown,{className:"nf-accent-popover",children:[e.jsx(Ss,{format:"hex",value:je(g.accent)??fs,onChange:s=>Je(s.toUpperCase()),fullWidth:!0}),e.jsx("div",{className:"nf-accent-presets","aria-label":"Готовые акценты",children:na.map(s=>e.jsx("button",{type:"button",style:{background:s},onClick:()=>Je(s),"aria-label":`Акцент ${s}`},s))}),e.jsx(Vs,{label:"HEX",value:g.accent,onChange:s=>Je(s.currentTarget.value.toUpperCase()),error:g.accent&&!rn.test(g.accent)?"Формат #RRGGBB":void 0,placeholder:"#C27087",maxLength:7})]})]})})]})})},"appearance"),security:e.jsxs("div",{className:"nf-settings-pair","data-card":"security",children:[e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact nf-settings-card--sessions",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Kt,{size:18}),"Сессии и безопасность"]}),children:e.jsx("div",{className:"nf-cfg-body",children:e.jsxs(is,{children:[e.jsx(Ne,{id:"panel-session-timeout",label:"Таймаут неактивности",hint:"5–1440 минут",children:e.jsx(ds,{id:"panel-session-timeout",unit:"мин",value:g.session_timeout_minutes,onChange:s=>Xe("session_timeout_minutes",Number(s)),min:5,max:1440,disabled:oe,"aria-describedby":"panel-session-timeout-hint",onKeyDown:Qe})}),e.jsx(Ne,{id:"panel-max-sessions",label:"Макс. активных сессий",hint:"на панель · 1–100",children:e.jsx(ds,{id:"panel-max-sessions",unit:"шт",value:g.max_sessions,onChange:s=>Xe("max_sessions",Number(s)),min:1,max:100,disabled:oe,"aria-describedby":"panel-max-sessions-hint",onKeyDown:Qe})})]})})}),e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact nf-settings-card--logs",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Ft,{size:18}),"Журналы"]}),children:e.jsx("div",{className:"nf-cfg-body",children:e.jsx(is,{children:e.jsx(Ne,{id:"panel-audit-retention",label:"Хранить события аудита",hint:"7–3650 дней",children:e.jsx(ds,{id:"panel-audit-retention",unit:"дней",value:g.audit_retention_days,onChange:s=>Xe("audit_retention_days",Number(s)),min:7,max:3650,disabled:oe,"aria-describedby":"panel-audit-retention-hint",onKeyDown:Qe})})})})})]},"security"),addresses:e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact","data-card":"addresses",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Xt,{size:18}),"Адреса и канал нод"]}),actions:e.jsxs("span",{className:"nf-cfg-title-note",children:[e.jsx(st,{size:13}),"только чтение"]}),children:e.jsxs("dl",{className:"nf-cfg-kv",title:"Берутся из runtime-конфигурации сервера и не меняются из браузера",children:[e.jsxs("div",{className:"is-wide",children:[e.jsx("dt",{children:"URL панели"}),e.jsx("dd",{children:e.jsx(us,{children:g.public_url||"—"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Web/API-порт"}),e.jsx("dd",{children:e.jsx(us,{children:g.web_port})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Порт канала Agent"}),e.jsx("dd",{children:e.jsx(us,{children:g.agent_port})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"mTLS-канал нод"}),e.jsx("dd",{children:e.jsxs(qe,{tone:We===0?"muted":Wee.jsx(De,{label:s?"Скопировано":"Копировать",withArrow:!0,children:e.jsx(Us,{size:28,variant:"subtle",onClick:c,"aria-label":"Копировать URL",children:s?e.jsx(as,{size:14}):e.jsx(Lt,{size:14})})})})]}),e.jsx("pre",{className:"nf-metrics-snippet",children:`- job_name: nodeflow +import{r as l,q as bs,s as se,t as Ue,j as e,y as pe,v as js,C as Un,a3 as Hn,a4 as q,w as Vn,p as Gn,V as Kn,O as hs,a5 as Wn,o as Xn,E as Me,a6 as Jn,c as ie,u as Qn,k as Yn,a7 as fs,g as K,i as Zn,e as et,B as A,M as Z,a8 as st,a9 as je,aa as rn,f as ee,L as nt,I as tt,ab as _e,ac as at,ad as rt,ae as ot,A as Us,b as ss,m as Hs,_ as lt}from"./index-fgrXogF6.js";import{L as ct,r as it}from"./uuid-CMwH_1Ko.js";import{u as on,n as dt,o as ut,S as ns,c as fe,d as Te,P as ts,T as Vs,t as ht,a as ze}from"./format-DGDz36zr.js";import{e as Be,N as ft,a as Gs,I as we,M as Se,P as mt,c as as,b as rs,T as De}from"./PageHeader-Fvu-o_Iq.js";import{h as Ks,r as Ce,I as os,p as Ws,a as ls}from"./platform-DnnQQ6bP.js";import{a as pt,I as xt}from"./IconServer-DmZ16e5j.js";import{G as Xs,I as gt}from"./IconKey-DrhZ0AMo.js";import{I as Js}from"./IconTrash-Bdw5EaPs.js";import"./chart-react-C4b8adjg.js";function bt(t={timeout:2e3}){const[n,a]=l.useState(null),[o,r]=l.useState(!1),[d,i]=l.useState(null),u=m=>{window.clearTimeout(d),i(window.setTimeout(()=>r(!1),t.timeout)),r(m)};return{copy:m=>{"clipboard"in navigator?navigator.clipboard.writeText(m).then(()=>u(!0)).catch(b=>a(b)):a(new Error("useClipboard: navigator.clipboard is not supported"))},reset:()=>{r(!1),a(null),window.clearTimeout(d)},error:n,copied:o}}function ln(t){return{x:Be(t.x,0,1),y:Be(t.y,0,1)}}function cn(t,n,a="ltr"){const o=l.useRef(!1),r=l.useRef(!1),d=l.useRef(0),[i,u]=l.useState(!1),f=l.useRef(null);return l.useEffect(()=>{o.current=!0},[]),{ref:l.useCallback(m=>{if(f.current&&(f.current(),f.current=null),!m)return;const b=({x:h,y:W})=>{cancelAnimationFrame(d.current),d.current=requestAnimationFrame(()=>{if(o.current&&m){m.style.userSelect="none";const z=m.getBoundingClientRect();if(z.width&&z.height){const B=Be((h-z.left)/z.width,0,1);t({x:a==="ltr"?B:1-B,y:Be((W-z.top)/z.height,0,1)})}}})},_=()=>{document.addEventListener("mousemove",S),document.addEventListener("mouseup",N),document.addEventListener("touchmove",v,{passive:!1}),document.addEventListener("touchend",N)},w=()=>{document.removeEventListener("mousemove",S),document.removeEventListener("mouseup",N),document.removeEventListener("touchmove",v),document.removeEventListener("touchend",N)},$=()=>{!r.current&&o.current&&(r.current=!0,typeof n?.onScrubStart=="function"&&n.onScrubStart(),u(!0),_())},N=()=>{r.current&&o.current&&(r.current=!1,u(!1),w(),setTimeout(()=>{typeof n?.onScrubEnd=="function"&&n.onScrubEnd()},0))},j=h=>{$(),h.preventDefault(),S(h)},S=h=>b({x:h.clientX,y:h.clientY}),k=h=>{h.cancelable&&h.preventDefault(),$(),v(h)},v=h=>{h.cancelable&&h.preventDefault(),b({x:h.changedTouches[0].clientX,y:h.changedTouches[0].clientY})};m.addEventListener("mousedown",j),m.addEventListener("touchstart",k,{passive:!1}),f.current=()=>{m.removeEventListener("mousedown",j),m.removeEventListener("touchstart",k)}},[a,t]),active:i}}var dn={root:"m_b183c0a2"};const jt=js((t,{color:n})=>({root:{"--code-bg":n?Un(n,t):void 0}})),me=bs((t,n)=>{const a=se("Code",null,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,color:x,block:m,variant:b,mod:_,attributes:w,...$}=a,N=Ue({name:"Code",props:a,classes:dn,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:w,vars:f,varsResolver:jt});return e.jsx(pe,{component:m?"pre":"code",variant:b,ref:n,mod:[{block:m},_],...N("root"),...$,dir:"ltr"})});me.classes=dn;me.displayName="@mantine/core/Code";var un={root:"m_de3d2490",colorOverlay:"m_862f3d1b",shadowOverlay:"m_98ae7f22",alphaOverlay:"m_95709ac0",childrenOverlay:"m_93e74e3"};const Qs={withShadow:!0},vt=js((t,{radius:n,size:a})=>({root:{"--cs-radius":n===void 0?void 0:Vn(n),"--cs-size":q(a)}})),He=Hn((t,n)=>{const a=se("ColorSwatch",Qs,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,color:x,size:m,radius:b,withShadow:_,children:w,variant:$,attributes:N,...j}=se("ColorSwatch",Qs,a),S=Ue({name:"ColorSwatch",props:a,classes:un,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:N,vars:f,varsResolver:vt});return e.jsxs(pe,{ref:n,variant:$,size:m,...S("root",{focusable:!0}),...j,children:[e.jsx("span",{...S("alphaOverlay")}),_&&e.jsx("span",{...S("shadowOverlay")}),e.jsx("span",{...S("colorOverlay",{style:{backgroundColor:x}})}),e.jsx("span",{...S("childrenOverlay"),children:w})]})});He.classes=un;He.displayName="@mantine/core/ColorSwatch";const[yt,vs]=Gn(null);var ys={wrapper:"m_fee9c77",preview:"m_9dddfbac",body:"m_bffecc3e",sliders:"m_3283bb96",thumb:"m_40d572ba",swatch:"m_d8ee6fd8",swatches:"m_5711e686",saturation:"m_202a296e",saturationOverlay:"m_11b3db02",slider:"m_d856d47d",sliderOverlay:"m_8f327113"};const _s=l.forwardRef(({position:t,...n},a)=>e.jsx(pe,{ref:a,__vars:{"--thumb-y-offset":`${t.y*100}%`,"--thumb-x-offset":`${t.x*100}%`},...n}));_s.displayName="@mantine/core/ColorPickerThumb";const ws=bs((t,n)=>{const a=se("ColorSlider",null,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,onChange:x,onChangeEnd:m,maxValue:b,round:_,size:w="md",focusable:$=!0,value:N,overlays:j,thumbColor:S="transparent",onScrubStart:k,onScrubEnd:v,__staticSelector:h="ColorPicker",attributes:W,...z}=a,B=Ue({name:h,classes:ys,props:a,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:W}),Q=vs()?.getStyles||B,Y=Kn(),[F,U]=l.useState({y:0,x:N/b}),O=l.useRef(F),H=C=>_?Math.round(C*b):C*b,{ref:ne}=cn(({x:C,y:E})=>{O.current={x:C,y:E},x?.(H(C))},{onScrubEnd:()=>{const{x:C}=O.current;m?.(H(C)),v?.()},onScrubStart:k});hs(()=>{U({y:0,x:N/b})},[N]);const I=(C,E)=>{C.preventDefault();const P=ln(E);x?.(H(P.x)),m?.(H(P.x))},te=C=>{switch(C.key){case"ArrowRight":{I(C,{x:F.x+.05,y:F.y});break}case"ArrowLeft":{I(C,{x:F.x-.05,y:F.y});break}}},X=j.map((C,E)=>l.createElement("div",{...Q("sliderOverlay"),style:C,key:E}));return e.jsxs(pe,{...z,ref:on(ne,n),...Q("slider"),role:"slider","aria-valuenow":N,"aria-valuemax":b,"aria-valuemin":0,tabIndex:$?0:-1,onKeyDown:te,"data-focus-ring":Y.focusRing,__vars:{"--cp-thumb-size":`var(--cp-thumb-size-${w})`},children:[X,e.jsx(_s,{position:F,...Q("thumb",{style:{top:q(1),background:S}})})]})});ws.displayName="@mantine/core/ColorSlider";function L(t,n=0,a=10**n){return Math.round(a*t)/a}function _t({h:t,s:n,l:a,a:o}){const r=n*((a<50?a:100-a)/100);return{h:t,s:r>0?2*r/(a+r)*100:0,v:a+r,a:o}}const wt={grad:360/400,turn:360,rad:360/(Math.PI*2)};function St(t,n="deg"){return Number(t)*(wt[n]||1)}const Nt=/hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;function Ys(t){const n=Nt.exec(t);return n?_t({h:St(n[1],n[2]),s:Number(n[3]),l:Number(n[4]),a:n[5]===void 0?1:Number(n[5])/(n[6]?100:1)}):{h:0,s:0,v:0,a:1}}function ms({r:t,g:n,b:a,a:o}){const r=Math.max(t,n,a),d=r-Math.min(t,n,a),i=d?r===t?(n-a)/d:r===n?2+(a-t)/d:4+(t-n)/d:0;return{h:L(60*(i<0?i+6:i),3),s:L(r?d/r*100:0,3),v:L(r/255*100,3),a:o}}function ps(t){const n=t[0]==="#"?t.slice(1):t;return n.length===3?ms({r:parseInt(n[0]+n[0],16),g:parseInt(n[1]+n[1],16),b:parseInt(n[2]+n[2],16),a:1}):ms({r:parseInt(n.slice(0,2),16),g:parseInt(n.slice(2,4),16),b:parseInt(n.slice(4,6),16),a:1})}function Ct(t){const n=t[0]==="#"?t.slice(1):t,a=i=>L(parseInt(i,16)/255,3);if(n.length===4){const i=n.slice(0,3),u=a(n[3]+n[3]);return{...ps(i),a:u}}const o=n.slice(0,6),r=a(n.slice(6,8));return{...ps(o),a:r}}const kt=/rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;function Zs(t){const n=kt.exec(t);return n?ms({r:Number(n[1])/(n[2]?100/255:1),g:Number(n[3])/(n[4]?100/255:1),b:Number(n[5])/(n[6]?100/255:1),a:n[7]===void 0?1:Number(n[7])/(n[8]?100:1)}):{h:0,s:0,v:0,a:1}}const hn={hex:/^#?([0-9A-F]{3}){1,2}$/i,hexa:/^#?([0-9A-F]{4}){1,2}$/i,rgb:/^rgb\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i,rgba:/^rgba\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i,hsl:/hsl\(\s*(\d+)\s*,\s*(\d+(?:\.\d+)?%)\s*,\s*(\d+(?:\.\d+)?%)\)/i,hsla:/^hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*(\d*(?:\.\d+)?)\)$/i},$t={hex:ps,hexa:Ct,rgb:Zs,rgba:Zs,hsl:Ys,hsla:Ys};function Et(t){for(const[,n]of Object.entries(hn))if(n.test(t))return!0;return!1}function Oe(t){if(typeof t!="string")return{h:0,s:0,v:0,a:1};if(t==="transparent")return{h:0,s:0,v:0,a:0};const n=t.trim();for(const[a,o]of Object.entries(hn))if(o.test(n))return $t[a](n);return{h:0,s:0,v:0,a:1}}const fn=l.forwardRef((t,n)=>{const{value:a,onChange:o,onChangeEnd:r,color:d,...i}=se("AlphaSlider",null,t);return e.jsx(ws,{...i,ref:n,value:a,onChange:u=>o?.(L(u,2)),onChangeEnd:u=>r?.(L(u,2)),maxValue:1,round:!1,"data-alpha":!0,overlays:[{backgroundImage:"linear-gradient(45deg, var(--slider-checkers) 25%, transparent 25%), linear-gradient(-45deg, var(--slider-checkers) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--slider-checkers) 75%), linear-gradient(-45deg, var(--mantine-color-body) 75%, var(--slider-checkers) 75%)",backgroundSize:`${q(8)} ${q(8)}`,backgroundPosition:`0 0, 0 ${q(4)}, ${q(4)} ${q(-4)}, ${q(-4)} 0`},{backgroundImage:`linear-gradient(90deg, transparent, ${d})`},{boxShadow:`rgba(0, 0, 0, .1) 0 0 0 ${q(1)} inset, rgb(0, 0, 0, .15) 0 0 ${q(4)} inset`}]})});fn.displayName="@mantine/core/AlphaSlider";function mn({h:t,s:n,v:a,a:o}){const r=t/360*6,d=n/100,i=a/100,u=Math.floor(r),f=i*(1-d),x=i*(1-(r-u)*d),m=i*(1-(1-r+u)*d),b=u%6;return{r:L([i,x,f,f,m,i][b]*255),g:L([m,i,i,x,f,f][b]*255),b:L([f,f,m,i,i,x][b]*255),a:L(o,2)}}function en(t,n){const{r:a,g:o,b:r,a:d}=mn(t);return n?`rgba(${a}, ${o}, ${r}, ${L(d,2)})`:`rgb(${a}, ${o}, ${r})`}function sn({h:t,s:n,v:a,a:o},r){const d=(200-n)*a/100,i={h:Math.round(t),s:Math.round(d>0&&d<200?n*a/100/(d<=100?d:200-d)*100:0),l:Math.round(d/2)};return r?`hsla(${i.h}, ${i.s}%, ${i.l}%, ${L(o,2)})`:`hsl(${i.h}, ${i.s}%, ${i.l}%)`}function Le(t){const n=t.toString(16);return n.length<2?`0${n}`:n}function pn(t){const{r:n,g:a,b:o}=mn(t);return`#${Le(n)}${Le(a)}${Le(o)}`}function Rt(t){const n=Math.round(t.a*255);return`${pn(t)}${Le(n)}`}const cs={hex:pn,hexa:t=>Rt(t),rgb:t=>en(t,!1),rgba:t=>en(t,!0),hsl:t=>sn(t,!1),hsla:t=>sn(t,!0)};function ce(t,n){return n?t in cs?cs[t](n):cs.hex(n):"#000000"}const xn=l.forwardRef((t,n)=>{const{value:a,onChange:o,onChangeEnd:r,color:d,...i}=se("HueSlider",{},t);return e.jsx(ws,{...i,ref:n,value:a,onChange:o,onChangeEnd:r,maxValue:360,thumbColor:`hsl(${a}, 100%, 50%)`,round:!0,"data-hue":!0,overlays:[{backgroundImage:"linear-gradient(to right,hsl(0,100%,50%),hsl(60,100%,50%),hsl(120,100%,50%),hsl(170,100%,50%),hsl(240,100%,50%),hsl(300,100%,50%),hsl(360,100%,50%))"},{boxShadow:`rgba(0, 0, 0, .1) 0 0 0 ${q(1)} inset, rgb(0, 0, 0, .15) 0 0 ${q(4)} inset`}]})});xn.displayName="@mantine/core/HueSlider";function gn({className:t,onChange:n,onChangeEnd:a,value:o,saturationLabel:r,focusable:d=!0,size:i,color:u,onScrubStart:f,onScrubEnd:x,...m}){const{getStyles:b}=vs(),[_,w]=l.useState({x:o.s/100,y:1-o.v/100}),$=l.useRef(_),{ref:N}=cn(({x:k,y:v})=>{$.current={x:k,y:v},n({s:Math.round(k*100),v:Math.round((1-v)*100)})},{onScrubEnd:()=>{const{x:k,y:v}=$.current;a({s:Math.round(k*100),v:Math.round((1-v)*100)}),x?.()},onScrubStart:f});l.useEffect(()=>{w({x:o.s/100,y:1-o.v/100})},[o.s,o.v]);const j=(k,v)=>{k.preventDefault();const h=ln(v);n({s:Math.round(h.x*100),v:Math.round((1-h.y)*100)}),a({s:Math.round(h.x*100),v:Math.round((1-h.y)*100)})},S=k=>{switch(k.key){case"ArrowUp":{j(k,{y:_.y-.05,x:_.x});break}case"ArrowDown":{j(k,{y:_.y+.05,x:_.x});break}case"ArrowRight":{j(k,{x:_.x+.05,y:_.y});break}case"ArrowLeft":{j(k,{x:_.x-.05,y:_.y});break}}};return e.jsxs(pe,{...b("saturation"),ref:N,...m,role:"slider","aria-label":r,"aria-valuenow":_.x,"aria-valuetext":ce("rgba",o),tabIndex:d?0:-1,onKeyDown:S,children:[e.jsx("div",{...b("saturationOverlay",{style:{backgroundColor:`hsl(${o.h}, 100%, 50%)`}})}),e.jsx("div",{...b("saturationOverlay",{style:{backgroundImage:"linear-gradient(90deg, #fff, transparent)"}})}),e.jsx("div",{...b("saturationOverlay",{style:{backgroundImage:"linear-gradient(0deg, #000, transparent)"}})}),e.jsx(_s,{position:_,...b("thumb",{style:{backgroundColor:u}})})]})}gn.displayName="@mantine/core/Saturation";const bn=l.forwardRef(({className:t,datatype:n,setValue:a,onChangeEnd:o,size:r,focusable:d,data:i,swatchesPerRow:u,value:f,...x},m)=>{const b=vs(),_=i.map((w,$)=>l.createElement(He,{...b.getStyles("swatch"),unstyled:b.unstyled,component:"button",type:"button",color:w,key:$,radius:"sm",onClick:()=>{a(w),o?.(w)},"aria-label":w,tabIndex:d?0:-1,"data-swatch":!0},f===w&&e.jsx(dt,{size:"35%",color:Wn(w)<.5?"white":"black"})));return e.jsx(pe,{...b.getStyles("swatches"),ref:m,...x,children:_})});bn.displayName="@mantine/core/Swatches";const It={swatchesPerRow:7,withPicker:!0,focusable:!0,size:"md",__staticSelector:"ColorPicker"},Pt=js((t,{size:n,swatchesPerRow:a})=>({wrapper:{"--cp-preview-size":Me(n,"cp-preview-size"),"--cp-width":Me(n,"cp-width"),"--cp-body-spacing":Jn(n),"--cp-swatch-size":`${100/a}%`,"--cp-thumb-size":Me(n,"cp-thumb-size"),"--cp-saturation-height":Me(n,"cp-saturation-height")}})),Ss=bs((t,n)=>{const a=se("ColorPicker",It,t),{classNames:o,className:r,style:d,styles:i,unstyled:u,vars:f,format:x="hex",value:m,defaultValue:b,onChange:_,onChangeEnd:w,withPicker:$,size:N,saturationLabel:j,hueLabel:S,alphaLabel:k,focusable:v,swatches:h,swatchesPerRow:W,fullWidth:z,onColorSwatchClick:B,__staticSelector:ke,mod:Q,attributes:Y,...F}=a,U=Ue({name:ke,props:a,classes:ys,className:r,style:d,classNames:o,styles:i,unstyled:u,attributes:Y,rootSelector:"wrapper",vars:f,varsResolver:Pt}),O=l.useRef(x||"hex"),H=l.useRef(""),ne=l.useRef(-1),I=l.useRef(!1),te=x==="hexa"||x==="rgba"||x==="hsla",[X,C,E]=Xn({value:m,defaultValue:b,finalValue:"#FFFFFF",onChange:_}),[P,xe]=l.useState(Oe(X)),de=()=>{window.clearTimeout(ne.current),I.current=!0},ue=()=>{window.clearTimeout(ne.current),ne.current=window.setTimeout(()=>{I.current=!1},200)},ae=g=>{xe(D=>{const re={...D,...g};return H.current=ce(O.current,re),re}),C(H.current)};return hs(()=>{typeof m=="string"&&Et(m)&&!I.current&&xe(Oe(m))},[m]),hs(()=>{O.current=x||"hex",C(ce(O.current,P))},[x]),e.jsx(yt,{value:{getStyles:U,unstyled:u},children:e.jsxs(pe,{ref:n,...U("wrapper"),size:N,mod:[{"full-width":z},Q],...F,children:[$&&e.jsxs(e.Fragment,{children:[e.jsx(gn,{value:P,onChange:ae,onChangeEnd:({s:g,v:D})=>w?.(ce(O.current,{...P,s:g,v:D})),color:X,size:N,focusable:v,saturationLabel:j,onScrubStart:de,onScrubEnd:ue}),e.jsxs("div",{...U("body"),children:[e.jsxs("div",{...U("sliders"),children:[e.jsx(xn,{value:P.h,onChange:g=>ae({h:g}),onChangeEnd:g=>w?.(ce(O.current,{...P,h:g})),size:N,focusable:v,"aria-label":S,onScrubStart:de,onScrubEnd:ue}),te&&e.jsx(fn,{value:P.a,onChange:g=>ae({a:g}),onChangeEnd:g=>{w?.(ce(O.current,{...P,a:g}))},size:N,color:ce("hex",P),focusable:v,"aria-label":k,onScrubStart:de,onScrubEnd:ue})]}),te&&e.jsx(He,{color:X,radius:"sm",size:"var(--cp-preview-size)",...U("preview")})]})]}),Array.isArray(h)&&e.jsx(bn,{data:h,swatchesPerRow:W,focusable:v,setValue:C,value:X,onChangeEnd:g=>{const D=ce(x,Oe(g));B?.(D),w?.(D),E||xe(Oe(g))}})]})})});Ss.classes=ys;Ss.displayName="@mantine/core/ColorPicker";const At={timeout:1e3};function jn(t){const{children:n,timeout:a,value:o,...r}=se("CopyButton",At,t),d=bt({timeout:a}),i=()=>d.copy(o);return e.jsx(e.Fragment,{children:n({copy:i,copied:d.copied,...r})})}jn.displayName="@mantine/core/CopyButton";const Mt={multiple:!1},vn=l.forwardRef((t,n)=>{const{onChange:a,children:o,multiple:r,accept:d,name:i,form:u,resetRef:f,disabled:x,capture:m,inputProps:b,..._}=se("FileButton",Mt,t),w=l.useRef(null),$=()=>{!x&&w.current?.click()},N=S=>{if(S.currentTarget.files===null)return a(r?[]:null);a(r?Array.from(S.currentTarget.files):S.currentTarget.files[0]||null)};return ut(f,()=>{w.current&&(w.current.value="")}),e.jsxs(e.Fragment,{children:[e.jsx("input",{style:{display:"none"},type:"file",accept:d,multiple:r,onChange:N,ref:on(n,w),name:i,form:u,capture:m,...b}),o({onClick:$,..._})]})});vn.displayName="@mantine/core/FileButton";const Tt=[["path",{d:"M3 7a2 2 0 1 0 4 0a2 2 0 1 0 -4 0",key:"svg-0"}],["path",{d:"M14 15a2 2 0 1 0 4 0a2 2 0 1 0 -4 0",key:"svg-1"}],["path",{d:"M15 6a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-2"}],["path",{d:"M3 18a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-3"}],["path",{d:"M9 17l5 -1.5",key:"svg-4"}],["path",{d:"M6.5 8.5l7.81 5.37",key:"svg-5"}],["path",{d:"M7 7l8 -1",key:"svg-6"}]],zt=ie("outline","chart-dots-3","ChartDots3",Tt);const Dt=[["path",{d:"M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0",key:"svg-0"}],["path",{d:"M9 12l2 2l4 -4",key:"svg-1"}]],Ot=ie("outline","circle-check","CircleCheck",Dt);const qt=[["path",{d:"M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666",key:"svg-0"}],["path",{d:"M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1",key:"svg-1"}]],Lt=ie("outline","copy","Copy",qt);const Bt=[["path",{d:"M12 8l0 4l2 2",key:"svg-0"}],["path",{d:"M3.05 11a9 9 0 1 1 .5 4m-.5 5v-5h5",key:"svg-1"}]],Ft=ie("outline","history","History",Bt);const Ut=[["path",{d:"M12 21a9 9 0 0 1 0 -18c4.97 0 9 3.582 9 8c0 1.06 -.474 2.078 -1.318 2.828c-.844 .75 -1.989 1.172 -3.182 1.172h-2.5a2 2 0 0 0 -1 3.75a1.3 1.3 0 0 1 -1 2.25",key:"svg-0"}],["path",{d:"M7.5 10.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-1"}],["path",{d:"M11.5 7.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-2"}],["path",{d:"M15.5 10.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-3"}]],Ht=ie("outline","palette","Palette",Ut);const Vt=[["path",{d:"M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3",key:"svg-0"}],["path",{d:"M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3",key:"svg-1"}],["path",{d:"M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-2"}]],nn=ie("outline","rocket","Rocket",Vt);const Gt=[["path",{d:"M12 3a12 12 0 0 0 8.5 3a12 12 0 0 1 -8.5 15a12 12 0 0 1 -8.5 -15a12 12 0 0 0 8.5 -3",key:"svg-0"}],["path",{d:"M11 11a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",key:"svg-1"}],["path",{d:"M12 12l0 2.5",key:"svg-2"}]],Kt=ie("outline","shield-lock","ShieldLock",Gt);const Wt=[["path",{d:"M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0",key:"svg-0"}],["path",{d:"M3.6 9h16.8",key:"svg-1"}],["path",{d:"M3.6 15h16.8",key:"svg-2"}],["path",{d:"M11.5 3a17 17 0 0 0 0 18",key:"svg-3"}],["path",{d:"M12.5 3a17 17 0 0 1 0 18",key:"svg-4"}]],Xt=ie("outline","world","World",Wt);function Ne({id:t,label:n,hint:a,children:o,group:r=!1}){return e.jsxs("div",{className:"nf-cfg-field",children:[e.jsxs("div",{className:"nf-cfg-field__label",children:[r?e.jsx("span",{id:`${t}-label`,children:n}):e.jsx("label",{htmlFor:t,id:`${t}-label`,children:n}),a&&e.jsx("small",{id:`${t}-hint`,children:a})]}),o]})}function is({children:t}){return e.jsx("div",{className:"nf-cfg-fields",children:t})}function ds({unit:t,...n}){return e.jsx(ft,{...n,className:`nf-cfg-number ${n.className??""}`.trim(),hideControls:!0,allowDecimal:!1,allowNegative:!1,rightSection:e.jsx("span",{className:"nf-cfg-number__unit",children:t}),rightSectionPointerEvents:"none",rightSectionWidth:t.length>3?64:48})}function qe({tone:t="muted",children:n,title:a}){return e.jsx("span",{className:`nf-cfg-pill is-${t}`,title:a,children:n})}function us({children:t,mono:n=!0}){return e.jsx("span",{className:`nf-cfg-value${n?" is-mono":""}`,children:t})}const Jt=new Intl.DateTimeFormat("ru-RU",{day:"numeric",month:"short",year:"numeric"}),Qt=new Intl.DateTimeFormat("ru-RU",{day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"});function Yt(t){const n=new Date(t);return Number.isNaN(n.getTime())?"—":Jt.format(n)}function tn(t){const n=new Date(t);return Number.isNaN(n.getTime())?"—":Qt.format(n)}function Zt(t){const n=new Map,a=[...t].sort((r,d)=>d.sequence-r.sequence),o=r=>`${r.os.trim().toLowerCase()}/${r.arch.trim().toLowerCase()}`;return a.forEach((r,d)=>{const i=a.slice(0,d).filter(x=>o(x)===o(r)).reverse(),u=i.find(x=>x.sha256===r.sha256);if(u){n.set(r.id,{kind:"same",sequence:u.sequence});return}const f=i.find(x=>x.version===r.version);f&&n.set(r.id,{kind:"rebuilt",sequence:f.sequence})}),n}function ea(t){return t>=1960?3:t>=1e3?2:1}function sa(t,n){const a=["appearance","security","addresses"];return t===3?{columns:[["agent","versions"],a,["metrics"]],below:[]}:t===2?n==="below"?{columns:[["agent","versions"],a],below:["metrics"]}:{columns:n==="left"?[["agent","versions","metrics"],a]:[["agent","versions"],[...a,"metrics"]],below:[]}:{columns:[["agent","versions","appearance","addresses","security","metrics"]],below:[]}}const an=64*1024*1024,xs={public_url:"https://panel.example.com",web_port:8080,agent_port:4200,theme:"rose",accent:fs,session_timeout_minutes:30,max_sessions:5,audit_retention_days:90},na=["#22C55E","#C27087","#45C7D8","#E7B84B"];function yn(t){return["green","rose","cyan","amber"].includes(t.theme)?t.theme:je(t.accent)==="#22C55E"?"green":"rose"}function ta(t){return{...t,theme:yn(t)}}const G=new URLSearchParams(window.location.search).get("demo")==="1"||!1;async function aa(){const{demoNodeBundles:t}=await lt(async()=>{const{demoNodeBundles:u}=await import("./demo-k0hjezoN.js");return{demoNodeBundles:u}},[]),n=Date.now(),a=864e5,r=[[22,"2.0.0",8470528,.1,"9c3e71a4f0b25d68e1c7a93f4b0d2e86c5f17a39b2e4d60c8f1a7b35e92d04c6"],[21,"1.1.2",8462336,.2,"25f449ad85c1be0d9a7f1c3e0b54a2d7e61f9c08a3b7d42e95f06c1d8a2b3e47"],[20,"1.1.2",8462336,.25,"25f449ad85c1be0d9a7f1c3e0b54a2d7e61f9c08a3b7d42e95f06c1d8a2b3e47"],[19,"1.1.1",8451840,.4,"47c24b0b96e3a1f7d05c2b8e9f4a6d13c7b25e80f9a1d4c6b3e72a05f8d91c2b"],[18,"1.1.0",8441344,1.2,"a68a075355d2e8b1c47f09a3e6b5d21c8f7a4e90b3c6d15f2a8e7b40c9d31f6a"],[17,"1.1.0",8441344,1.3,"6e8654c4c4f1a0b9d73e25c8a6f4b1e09d7c3a52f8e6b14d0c9a7e35b2f81d4c"],[16,"1.0.5",7749632,56,"a8d400cff41e7b2c9d05a6f3e8b1c47d2a9f60e3b5c8d71f4a2e9b06c3d85f1a"],[15,"1.0.4",7749632,63,"84e063ebb7a2f5c1d98e40b6a3f7c2e15d9b08a4f6e3c71b2d5a8e94f0c6b3d2"],[14,"1.0.2",7749632,64,"be71d6c2219f3a8e5b0c7d4f1a6e2b98c3d05f7a4e1b6c92d8f3a50e7b4c1d6f"],[13,"0.5.0",7738880,67,"e5a975f060b8c3d1e7f4a2b95c0d6e83f1a7b4c29d5e0f6a3b8c71d4e2f95a0b"],[12,"0.4.9-dev",7738880,68,"a76ab9c9a9d2e5f1b8c4a07e3d6f92b5c1e8a4d73f0b6c29e5a1d8f4b7c03e6d"],[11,"0.4.8-dev",7738880,68.2,"fd19989d4e7a3c1b6f02d8e5a9c4b71f3e6d0a28b5c9f14e7d3a6b80c2f5e19a"]].map(([u,f,x,m,b])=>({id:`00000000-0000-4000-8000-${String(u).padStart(12,"0")}`,version:f,os:"linux",arch:"amd64",sha256:b,size_bytes:x,sequence:u,signature:"verified",created_at:new Date(n-m*a).toISOString()})),d=u=>r.find(f=>f.sequence===(u===0?22:16)),i=t.map((u,f)=>({node:u.node,operational:u.operational&&u.operational.latest_heartbeat?{...u.operational,latest_heartbeat:{...u.operational.latest_heartbeat,agent_version:d(f).version}}:u.operational,update:{node_id:u.node.id,actual_sequence:d(f).sequence,state:"installed",last_report_at:new Date(n-13e3-f*1e3).toISOString(),updated_at:new Date(n-18e3).toISOString()}}));return{panel:{...xs,public_url:"https://panel.example.com",metrics_enabled:!0,updated_at:new Date(n-63*a).toISOString()},nodes:i,releases:r,signingKey:{algorithm:"Ed25519",sha256:"703105fbac33f7388d7cd83e9cf02ad8130fa77d93b62bc111808d4cd5f3d387"},partialErrors:[]}}async function Fe(t,n,a,o){try{return await t}catch(r){return n.push(`${a}: ${r instanceof Error?r.message:"данные недоступны"}`),o}}async function ra(){if(G)return aa();const t=[],[n,a,o,r]=await Promise.all([K("/api/v1/settings"),K("/api/v1/nodes"),Fe(K("/api/v1/agent-releases"),t,"Релизы",[]),Fe(K("/api/v1/agent-releases/signing-key"),t,"Ключ подписи",null)]),d=a.map(i=>({node:i,operational:null,update:null}));return{panel:ta(n),nodes:d,releases:o,signingKey:r,partialErrors:t}}function gs(t){return{theme:t.theme,accent:t.accent,session_timeout_minutes:t.session_timeout_minutes,max_sessions:t.max_sessions,audit_retention_days:t.audit_retention_days}}function oa(t,n){return JSON.stringify(gs(t))===JSON.stringify(gs(n))}function la(t){const n=[];return rn.test(t.accent)||n.push("Акцент: цвет в формате #RRGGBB."),(!Number.isInteger(t.session_timeout_minutes)||t.session_timeout_minutes<5||t.session_timeout_minutes>1440)&&n.push("Таймаут сессии: от 5 до 1440 минут."),(!Number.isInteger(t.max_sessions)||t.max_sessions<1||t.max_sessions>100)&&n.push("Количество сессий: от 1 до 100."),(!Number.isInteger(t.audit_retention_days)||t.audit_retention_days<7||t.audit_retention_days>3650)&&n.push("Хранение аудита: от 7 до 3650 дней."),n}function ca(t,n,a){return a?n===null?"Состояние неизвестно":Ce(t,a)?t.sequence===n?"Установлено":t.sequence>n?"Доступно":"Для отката":"Другая платформа":"Платформа неизвестна"}function ia(t){return{idle:"Ожидание",pending:"Назначено",downloading:"Загрузка",verified:"Проверено",activating:"Установка",installed:"Установлено",failed:"Ошибка",rolled_back:"Выполнен откат"}[t??""]??t??"Нет отчёта"}function ja(){const t=Qn(),n=Yn(),[a,o]=l.useState(null),[r,d]=l.useState(!0),[i,u]=l.useState(null),[f,x]=l.useState(""),[m,b]=l.useState(0),[_,w]=l.useState(!1),[$,N]=l.useState(""),[j,S]=l.useState(""),[k,v]=l.useState(null),[h,W]=l.useState(null),[z,B]=l.useState(""),[ke,Q]=l.useState(!1),[Y,F]=l.useState(""),[U,O]=l.useState("linux"),[H,ne]=l.useState("amd64"),[I,te]=l.useState(null),[X,C]=l.useState(""),[E,P]=l.useState(null),[xe,de]=l.useState(""),[ue,ae]=l.useState(!1),[g,D]=l.useState(xs),[re,Ns]=l.useState(xs),[oe,Cs]=l.useState(!1),[ks,he]=l.useState(""),[$s,Es]=l.useState(!1),[$e,_n]=l.useState(!1),Ve=l.useRef(null),[wn,Rs]=l.useState(0),[Is,Sn]=l.useState("below"),Ee=l.useRef(null),Ps=l.useRef(null),Nn=l.useCallback(s=>{Ee.current?.disconnect(),Ps.current=s,s&&(Rs(s.clientWidth),Ee.current=new ResizeObserver(([c])=>Rs(Math.round(c.contentRect.width))),Ee.current.observe(s))},[]),ve=ea(wn),Ge=sa(ve,Is);l.useLayoutEffect(()=>{const s=Ps.current;if(!s||ve!==2)return;const c=Ln=>Ln.reduce((Bn,Fn)=>Bn+(s.querySelector(`[data-card="${Fn}"]`)?.offsetHeight??0),0),p=parseFloat(getComputedStyle(s).rowGap)||0,R=c(["agent","versions"])+p,T=c(["appearance","security","addresses"])+2*p,be=Math.abs(R-T)<160?"below":R()=>Ee.current?.disconnect(),[]);const Cn=G?"?demo=1":t.search,Re=async()=>{d(!0),u(null),v(null);try{const s=await ra();o(s),D(s.panel),Ns(s.panel),_e(s.panel,!0),he(""),x(c=>c&&s.nodes.some(({node:p})=>p.id===c)?c:s.nodes[0]?.node.id??""),b(c=>c+1)}catch(s){u(s)}finally{d(!1)}};l.useEffect(()=>{Re()},[]),l.useEffect(()=>{if(G||!f){w(!1),N("");return}const s=new AbortController,c=[];return w(!0),N(""),Promise.all([Fe(K(`/api/v1/nodes/${f}/operational`,{signal:s.signal}),c,"Телеметрия",null),Fe(K(`/api/v1/nodes/${f}/agent-update`,{signal:s.signal}),c,"Updater",null)]).then(([p,R])=>{s.signal.aborted||(o(T=>T&&{...T,nodes:T.nodes.map(be=>be.node.id===f?{...be,operational:p,update:R}:be)}),N(c.join(" · ")))}).finally(()=>{s.signal.aborted||w(!1)}),()=>s.abort()},[f,m]);const y=a?.nodes.find(({node:s})=>s.id===f)??a?.nodes[0],J=l.useMemo(()=>[...a?.releases??[]].sort((s,c)=>c.sequence-s.sequence),[a?.releases]),kn=l.useMemo(()=>Zt(J),[J]),le=y?.update?y.update.actual_sequence:null,M=Ks(y?.operational?.latest_heartbeat?.metrics),Ke=J.filter(s=>Ce(s,M)),ge=le===null?void 0:Ke.find(s=>s.sequence===le),V=le===null?void 0:Ke.find(s=>s.sequence>le),As=le===null?[]:Ke.filter(s=>s.sequence!!(c?.latest_heartbeat?.received_at??s.last_seen_at)&&(s.status==="online"||s.status==="degraded")).length??0,Ie=a?.nodes.length??0,Pe=la(g),ye=!oa(g,re),Xe=(s,c)=>{const p=s==="accent"?je(String(c)):null,R=s==="accent"&&p?p:c;D(T=>({...T,[s]:R})),s==="accent"&&at(String(R)),s==="theme"&&rt(R),v(null),he("")},En=s=>{const c=ot[s]??g.accent;D(p=>({...p,theme:s,accent:c})),_e({theme:s,accent:c}),v(null),he("")},Je=s=>{const c=je(s)??s,p=yn(g);D(R=>({...R,theme:p,accent:c})),je(c)&&_e({theme:p,accent:c}),v(null),he("")},Rn=()=>{D(re),_e(re,!0),he("")},Ms=async()=>{if(!(Pe.length||oe)){Cs(!0),he(""),v(null);try{const s=G?{...g,updated_at:new Date().toISOString()}:await K("/api/v1/settings",{method:"PUT",body:JSON.stringify(gs(g))});D(s),Ns(s),o(c=>c&&{...c,panel:s}),_e(s,!0),v({tone:"ok",text:G?"Demo-настройки сохранены в текущем интерфейсе. Live Panel не изменён.":"Настройки панели сохранены."})}catch(s){he(s instanceof ss&&s.status===409?"Конфликт: настройки уже изменены в другой сессии. Обновите состояние перед повторным сохранением.":s instanceof Error?s.message:"Настройки не сохранены.")}finally{Cs(!1)}}},Qe=s=>{s.key==="Enter"&&(s.preventDefault(),ye&&Ms())},Ts=s=>o(c=>c&&{...c,nodes:c.nodes.map(p=>p.node.id===s.node_id?{...p,update:s}:p)}),In=async()=>{if(!(!y||!y.update||!V||!M||!Ce(V,M))){S("update"),v(null);try{const s=G?{...y.update,desired_release:V,state:"assigned",updated_at:new Date().toISOString()}:await K(`/api/v1/nodes/${y.node.id}/agent-update`,{method:"PUT",body:JSON.stringify({release_id:V.id,expected_actual_sequence:y.update.actual_sequence,expected_desired_sequence:y.update.desired_release?.sequence??0})});Ts(s),v({tone:"ok",text:`${V.version} назначен ноде ${y.node.name}. Updater проверит подпись и выполнит авт rollback при ошибке.`})}catch(s){v({tone:"error",text:s instanceof Error?s.message:"Обновление не назначено"})}finally{S("")}}},Pn=async()=>{if(!h)return;const s=a?.nodes.find(({node:p})=>p.id===h.nodeID),c=Ks(s?.operational?.latest_heartbeat?.metrics);if(!c||!Ce(h.release,c)||c.os!==h.platform.os||c.arch!==h.platform.arch){B("Платформа ноды неизвестна или изменилась. Обновите состояние и выберите совместимый релиз заново.");return}S("rollback"),v(null),B("");try{const p=a?.nodes.find(({node:T})=>T.id===h.nodeID)?.update,R=G?{...p,desired_release:h.release,state:"assigned",updated_at:new Date().toISOString()}:await K(`/api/v1/nodes/${h.nodeID}/agent-update/rollback`,{method:"POST",body:JSON.stringify({target_release_id:h.release.id,expected_actual_sequence:h.expectedActualSequence,expected_desired_sequence:h.expectedDesiredSequence})});Ts(R),v({tone:"ok",text:`Безопасный откат ${h.nodeName} на ${h.release.version} назначен.`}),W(null)}catch(p){B(p instanceof Error?p.message:"Откат не назначен")}finally{S("")}},An=s=>{!y||!y.update||!M||!Ce(s,M)||s.sequence>=y.update.actual_sequence||(B(""),W({nodeID:y.node.id,nodeName:y.node.name,release:s,expectedActualSequence:y.update.actual_sequence,expectedDesiredSequence:y.update.desired_release?.sequence??0,platform:M}))},Ye=()=>{Ve.current?.(),Q(!1),F(""),O("linux"),ne("amd64"),te(null),C("")},Mn=s=>{if(s&&s.size>an){Ve.current?.(),te(null),C(`Файл больше 64 MiB: ${ze(s.size)}.`);return}te(s),C("")},Tn=async()=>{if(!(!I||!Y.trim())){if(I.size>an){C(`Файл больше 64 MiB: ${ze(I.size)}.`);return}S("upload"),v(null),C("");try{const s=G?{id:it(),version:Y.trim(),os:U,arch:H,sha256:"demo-artifact-sha256",size_bytes:I.size,sequence:(J[0]?.sequence??0)+1,signature:"demo-signed",created_at:new Date().toISOString()}:await K(`/api/v1/agent-releases?version=${encodeURIComponent(Y.trim())}&os=${encodeURIComponent(U)}&arch=${encodeURIComponent(H)}`,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:I});o(c=>c&&{...c,releases:[s,...c.releases]}),n.removeQueries({queryKey:Hs}),v({tone:"ok",text:`Релиз ${s.version} загружен, SHA-256 проверен и подписан Ed25519.`}),Ye()}catch(s){C(s instanceof Error?s.message:"Релиз не загружен")}finally{S("")}}},zn=async()=>{if(!(!E||ue)){S("delete-release"),de(""),v(null);try{G||await K(`/api/v1/agent-releases/${encodeURIComponent(E.id)}`,{method:"DELETE"}),o(s=>s&&{...s,releases:s.releases.filter(c=>c.id!==E.id)}),n.removeQueries({queryKey:Hs}),v({tone:"ok",text:`Релиз ${E.version} · ${E.os}/${E.arch} удалён.`}),P(null)}catch(s){const c=s instanceof ss&&s.status===409&&s.code==="release_in_use";ae(c),de(s instanceof ss&&s.status===409?"Релиз установлен или назначен хотя бы одной ноде. Сначала переведите эти ноды на другую версию.":s instanceof Error?s.message:"Релиз не удалён.")}finally{S("")}}};if(r)return e.jsx("main",{className:"nf-page nf-settings-page",children:e.jsxs("div",{className:"nf-settings-loading",children:[e.jsx(ct,{visible:!0}),e.jsx("span",{children:"Загружаем параметры панели и подписанные релизы…"})]})});if(i&&Zn(i))return e.jsx(et,{onSuccess:Re});if(i||!a)return e.jsx("main",{className:"nf-page",children:e.jsx(ns,{title:"Настройки не загрузились",description:i instanceof Error?i.message:"Panel API недоступен",tone:"error",action:e.jsx(A,{onClick:Re,children:"Повторить"})})});const zs=5,Ds=$e?J:J.slice(0,zs),Os=!$e&&ge&&!Ds.includes(ge)?ge:null,qs=!M||!y?.update||_||!!j,Ae=!!a.panel.metrics_enabled,Ls=a.panel.metrics_allow_cidrs??0,Ze=`${a.panel.public_url||"http://panel:8080"}/metrics`,Dn=s=>s==="Установлено"?"accent":s==="Доступно"?"ok":s==="Для отката"||s==="Готов к установке"?"muted":"warn",Bs=s=>{const c=a.nodes.length?ca(s,le,M):"Готов к установке",p=kn.get(s.id),R=c==="Установлено",T=y?.update?.desired_release?.id===s.id&&!R;return e.jsxs("div",{className:`nf-release-row${R?" is-installed":""}${p?" is-twin":""}`,role:"row",children:[e.jsx("div",{className:"nf-release-row__version",role:"cell",children:e.jsx("strong",{children:s.version})}),e.jsx("div",{className:"nf-release-row__seq",role:"cell",children:e.jsxs("code",{children:["#",s.sequence]})}),e.jsxs("div",{className:"nf-release-row__platform",role:"cell",children:[s.os,"/",s.arch,e.jsx("small",{children:ze(s.size_bytes)})]}),e.jsx("div",{className:"nf-release-row__date",role:"cell",children:e.jsx(De,{label:tn(s.created_at),withArrow:!0,children:e.jsx("span",{children:Yt(s.created_at)})})}),e.jsx("div",{className:"nf-release-row__sha",role:"cell",children:e.jsx(De,{label:s.sha256,withArrow:!0,multiline:!0,maw:320,children:e.jsx("code",{children:s.sha256.slice(0,10)})})}),e.jsxs("div",{className:"nf-release-row__status",role:"cell",children:[e.jsx(qe,{tone:T?"info":Dn(c),children:T?"Назначено":c}),p&&e.jsx("span",{className:"nf-release-row__twin",title:p.kind==="same"?`SHA-256 совпадает с #${p.sequence}`:`Версия ${s.version} перевыпущена в #${p.sequence}`,children:p.kind==="same"?`тот же бинарник, что #${p.sequence}`:`пересобрана в #${p.sequence}`})]}),e.jsx("div",{className:"nf-release-row__delete",role:"cell",children:e.jsx(De,{label:R?"Установленный релиз удалить нельзя":`Удалить ${s.version} · #${s.sequence}`,withArrow:!0,children:e.jsx(Us,{variant:"subtle",color:"red",size:32,"aria-label":`Удалить релиз ${s.version} #${s.sequence} для ${s.os}/${s.arch}`,onClick:()=>{de(""),ae(!1),P(s)},disabled:!!j||R,children:e.jsx(Js,{size:16})})})})]},s.id)},On=!M||!y?.update?e.jsx(Z,{size:15}):e.jsx(Ot,{size:15}),qn=_?"Проверяем…":M?y?.update?"Актуальная версия":"Нет отчёта updater":"Платформа неизвестна",es=y?.update?.state,Fs={agent:e.jsx(fe,{id:"node-agent",className:"nf-settings-card nf-agent-settings","data-card":"agent",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(nn,{size:18}),"Node Agent"]}),description:e.jsxs("span",{className:"nf-agent-trust",children:[e.jsx(Gs,{size:14}),"Подписанные релизы · ",a.signingKey?.algorithm||"Ed25519"," + SHA-256"]}),actions:e.jsxs(e.Fragment,{children:[a.nodes.length>0&&e.jsx("span",{className:"nf-agent-primary",children:V&&M&&y?.update?e.jsxs(A,{leftSection:e.jsx(nn,{size:16}),onClick:In,disabled:qs,loading:j==="update",title:`Обновить до ${V.version}`,children:["Обновить до ",V.version]}):e.jsxs("span",{className:"nf-agent-uptodate",children:[On,qn]})}),a.nodes.length>0&&e.jsxs(Se,{position:"bottom-end",withinPortal:!0,shadow:"md",width:300,children:[e.jsx(Se.Target,{children:e.jsx(A,{variant:"default",leftSection:e.jsx(ls,{size:16}),rightSection:e.jsx(we,{size:14}),disabled:qs||As.length===0,children:"Откатить"})}),e.jsxs(Se.Dropdown,{className:"nf-rollback-menu",children:[e.jsxs(Se.Label,{children:["Откатить ",y?.node.name," до версии"]}),As.map(s=>{const c=ge&&s.sha256===ge.sha256;return e.jsxs(Se.Item,{leftSection:e.jsx(ls,{size:15}),rightSection:e.jsxs("code",{children:["#",s.sequence]}),onClick:()=>An(s),children:[s.version,c&&e.jsx("small",{children:" · тот же бинарник"})]},s.id)})]})]}),e.jsx(A,{variant:"default",leftSection:e.jsx(os,{size:16}),onClick:()=>Q(!0),children:"Загрузить релиз"})]}),children:a.nodes.length?e.jsxs("div",{className:"nf-agent-node",children:[e.jsxs("dl",{className:"nf-agent-facts",children:[e.jsxs("div",{className:"nf-agent-facts__node",children:[e.jsx("dt",{children:e.jsx("label",{htmlFor:"nf-agent-node-select",children:"Нода"})}),e.jsx("dd",{children:e.jsx(Te,{id:"nf-agent-node-select",className:"nf-agent-node-select","aria-label":"Нода для обновления",value:y?.node.id,onChange:s=>x(s??""),allowDeselect:!1,data:a.nodes.map(({node:s})=>({value:s.id,label:`${s.name} · ${s.address}`})),disabled:!!j,leftSection:e.jsx(pt,{size:15})})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Установлено"}),e.jsxs("dd",{children:[e.jsx("strong",{children:_?"Загрузка…":$n}),y?.update&&e.jsxs("code",{children:["#",y.update.actual_sequence]})]})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Отчёт updater"}),e.jsx("dd",{children:y?.update?.last_report_at?e.jsxs(e.Fragment,{children:[e.jsx("span",{children:ht(y.update.last_report_at)}),es!=="installed"&&e.jsx(qe,{tone:es==="failed"?"danger":"muted",children:ia(es)})]}):e.jsx("span",{className:"is-muted",children:_?"Получаем состояние":"Ещё не получен"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Доступно"}),e.jsx("dd",{children:V?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:V.version}),e.jsxs("code",{children:["#",V.sequence]})]}):e.jsx("span",{className:"is-muted",children:!M||le===null?"—":"Новее нет"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Платформа"}),e.jsx("dd",{children:e.jsx("span",{children:Ws(M)})})]})]}),$&&e.jsx(ee,{color:"yellow",icon:e.jsx(Z,{size:17}),role:"alert",children:$}),!_&&!M&&e.jsx(ee,{color:"yellow",icon:e.jsx(Z,{size:17}),role:"status",title:"Назначение релиза заблокировано",children:"Дождитесь сигнала с полями os и arch. NodeFlow не будет предполагать платформу ноды."}),!_&&M&&!y?.update&&e.jsx(ee,{color:"yellow",icon:e.jsx(Z,{size:17}),role:"status",title:"Состояние updater неизвестно",children:"Назначение и откат заблокированы, пока Panel не получит фактический sequence ноды."}),y?.update?.last_error&&e.jsx(ee,{color:"red",icon:e.jsx(Z,{size:17}),children:y.update.last_error}),e.jsx("p",{className:"nf-agent-note",children:"HAProxy не перезапускается. Если новый Agent не пройдёт проверку запуска, updater атомарно вернёт предыдущий бинарник."})]}):e.jsx(ns,{title:"Нод пока нет",description:"Релизы можно подготовить заранее; назначение обновлений станет доступно после установки ноды.",action:e.jsx(A,{component:nt,to:`/nodes${Cn}`,children:"Добавить ноду"})})},"agent"),versions:e.jsx(fe,{id:"nf-agent-history",className:"nf-settings-card nf-release-history","data-card":"versions",title:e.jsxs("span",{className:"nf-settings-card-title",children:["Версии Agent ",e.jsx("span",{className:"nf-cfg-count",children:J.length})]}),description:"Новая нода получает новейший релиз для своей платформы. Sequence уникален и растёт с каждой загрузкой.",children:J.length?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"nf-release-table",role:"table","aria-label":"Подписанные версии Agent",children:[e.jsxs("div",{className:"nf-release-row is-head",role:"row",children:[e.jsx("span",{role:"columnheader",className:"nf-release-row__version",children:"Версия"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__seq",children:"Seq"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__platform",children:"Платформа"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__date",children:"Загружен"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__sha",children:"SHA-256"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__status",children:"Статус"}),e.jsx("span",{role:"columnheader",className:"nf-release-row__delete",children:e.jsx("span",{className:"nf-visually-hidden",children:"Удалить"})})]}),Ds.map(Bs),Os&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"nf-release-gap",role:"row",children:e.jsx("span",{role:"cell",children:"…"})}),Bs(Os)]})]}),J.length>zs&&e.jsxs("button",{type:"button",className:"nf-release-more",onClick:()=>_n(s=>!s),"aria-expanded":$e,children:[e.jsx(we,{size:15,"aria-hidden":!0}),$e?"Свернуть":`Показать все (${J.length})`]})]}):e.jsx(ns,{title:"Релизов пока нет",description:"Без совместимого релиза установка ноды будет заблокирована. Загрузите бинарник Linux для нужной архитектуры.",action:e.jsx(A,{leftSection:e.jsx(os,{size:16}),onClick:()=>Q(!0),children:"Загрузить релиз"})})},"versions"),appearance:e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact","data-card":"appearance",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Ht,{size:18}),"Внешний вид"]}),description:"Применяется сразу, сохраняется кнопкой «Сохранить»",children:e.jsx("div",{className:"nf-cfg-body",children:e.jsxs(is,{children:[e.jsx(Ne,{id:"panel-theme",label:"Тема",children:e.jsx(Te,{id:"panel-theme",className:"nf-cfg-select",value:g.theme,onChange:s=>En(s??"rose"),allowDeselect:!1,disabled:oe,data:[{value:"rose",label:"Rose"},{value:"green",label:"Green"},{value:"cyan",label:"Arctic Cyan"},{value:"amber",label:"Warm Amber"}]})}),e.jsx(Ne,{id:"panel-accent",label:"Цветовой акцент",children:e.jsxs(ts,{opened:$s,onChange:Es,position:"bottom-start",width:280,shadow:"md",withinPortal:!0,children:[e.jsx(ts.Target,{children:e.jsxs("button",{id:"panel-accent",className:"nf-accent-trigger",type:"button",onClick:()=>Es(s=>!s),disabled:oe,"aria-label":`Выбрать цветовой акцент, сейчас ${g.accent}`,"aria-expanded":$s,children:[e.jsx("i",{style:{background:je(g.accent)??fs}}),e.jsx("span",{children:g.accent||"#RRGGBB"}),e.jsx(we,{size:14,"aria-hidden":!0})]})}),e.jsxs(ts.Dropdown,{className:"nf-accent-popover",children:[e.jsx(Ss,{format:"hex",value:je(g.accent)??fs,onChange:s=>Je(s.toUpperCase()),fullWidth:!0}),e.jsx("div",{className:"nf-accent-presets","aria-label":"Готовые акценты",children:na.map(s=>e.jsx("button",{type:"button",style:{background:s},onClick:()=>Je(s),"aria-label":`Акцент ${s}`},s))}),e.jsx(Vs,{label:"HEX",value:g.accent,onChange:s=>Je(s.currentTarget.value.toUpperCase()),error:g.accent&&!rn.test(g.accent)?"Формат #RRGGBB":void 0,placeholder:"#C27087",maxLength:7})]})]})})]})})},"appearance"),security:e.jsxs("div",{className:"nf-settings-pair","data-card":"security",children:[e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact nf-settings-card--sessions",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Kt,{size:18}),"Сессии и безопасность"]}),children:e.jsx("div",{className:"nf-cfg-body",children:e.jsxs(is,{children:[e.jsx(Ne,{id:"panel-session-timeout",label:"Таймаут неактивности",hint:"5–1440 минут",children:e.jsx(ds,{id:"panel-session-timeout",unit:"мин",value:g.session_timeout_minutes,onChange:s=>Xe("session_timeout_minutes",Number(s)),min:5,max:1440,disabled:oe,"aria-describedby":"panel-session-timeout-hint",onKeyDown:Qe})}),e.jsx(Ne,{id:"panel-max-sessions",label:"Макс. активных сессий",hint:"на панель · 1–100",children:e.jsx(ds,{id:"panel-max-sessions",unit:"шт",value:g.max_sessions,onChange:s=>Xe("max_sessions",Number(s)),min:1,max:100,disabled:oe,"aria-describedby":"panel-max-sessions-hint",onKeyDown:Qe})})]})})}),e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact nf-settings-card--logs",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Ft,{size:18}),"Журналы"]}),children:e.jsx("div",{className:"nf-cfg-body",children:e.jsx(is,{children:e.jsx(Ne,{id:"panel-audit-retention",label:"Хранить события аудита",hint:"7–3650 дней",children:e.jsx(ds,{id:"panel-audit-retention",unit:"дней",value:g.audit_retention_days,onChange:s=>Xe("audit_retention_days",Number(s)),min:7,max:3650,disabled:oe,"aria-describedby":"panel-audit-retention-hint",onKeyDown:Qe})})})})})]},"security"),addresses:e.jsx(fe,{className:"nf-settings-card nf-settings-card--compact","data-card":"addresses",title:e.jsxs("span",{className:"nf-settings-card-title",children:[e.jsx(Xt,{size:18}),"Адреса и канал нод"]}),actions:e.jsxs("span",{className:"nf-cfg-title-note",children:[e.jsx(st,{size:13}),"только чтение"]}),children:e.jsxs("dl",{className:"nf-cfg-kv",title:"Берутся из runtime-конфигурации сервера и не меняются из браузера",children:[e.jsxs("div",{className:"is-wide",children:[e.jsx("dt",{children:"URL панели"}),e.jsx("dd",{children:e.jsx(us,{children:g.public_url||"—"})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Web/API-порт"}),e.jsx("dd",{children:e.jsx(us,{children:g.web_port})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Порт канала Agent"}),e.jsx("dd",{children:e.jsx(us,{children:g.agent_port})})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"mTLS-канал нод"}),e.jsx("dd",{children:e.jsxs(qe,{tone:We===0?"muted":Wee.jsx(De,{label:s?"Скопировано":"Копировать",withArrow:!0,children:e.jsx(Us,{size:28,variant:"subtle",onClick:c,"aria-label":"Копировать URL",children:s?e.jsx(as,{size:14}):e.jsx(Lt,{size:14})})})})]}),e.jsx("pre",{className:"nf-metrics-snippet",children:`- job_name: nodeflow metrics_path: /metrics authorization: credentials: diff --git a/internal/panel/web_dist/assets/TrafficChart-BU3flakD.js b/internal/panel/web_dist/assets/TrafficChart-84ShhOyf.js similarity index 98% rename from internal/panel/web_dist/assets/TrafficChart-BU3flakD.js rename to internal/panel/web_dist/assets/TrafficChart-84ShhOyf.js index 89ddfb4..0c40ad6 100644 --- a/internal/panel/web_dist/assets/TrafficChart-BU3flakD.js +++ b/internal/panel/web_dist/assets/TrafficChart-84ShhOyf.js @@ -1 +1 @@ -import{q as te,s as se,t as ie,j as c,y as ae,v as re,w as ne,a4 as D,ao as oe,ap as B,aq as x,ar as U,as as j,at as P,au as L,av as z,aw as le,ax as k,ay as ce,az as he,aA as G,aB as K,r as p,aC as J,k as ue,c as Y,W as de,aD as fe,aE as pe}from"./index-Dy6W__Vz.js";import{R as me}from"./chart-react-C4b8adjg.js";import{e as be,u as ve,i as ye,a as xe,b as ge,c as Re,d as Se}from"./chart-engine-Dbh3Q7E_.js";import{f as I}from"./format-D6_ab21F.js";import{S as we}from"./IconArrowUp-Cj3lrfzR.js";var Z={root:"m_18320242","skeleton-fade":"m_299c329c"};const Oe={visible:!0,animate:!0},Ee=re((e,{width:t,height:s,radius:i,circle:r})=>({root:{"--skeleton-height":D(s),"--skeleton-width":r?D(s):D(t),"--skeleton-radius":r?"1000px":i===void 0?void 0:ne(i)}})),q=te((e,t)=>{const s=se("Skeleton",Oe,e),{classNames:i,className:r,style:u,styles:o,unstyled:y,vars:g,width:O,height:n,circle:v,visible:l,radius:h,animate:d,mod:m,attributes:E,...N}=s,w=ie({name:"Skeleton",classes:Z,props:s,className:r,style:u,classNames:i,styles:o,unstyled:y,attributes:E,vars:g,varsResolver:Ee});return c.jsx(ae,{ref:t,...w("root"),mod:[{visible:l,animate:d},m],...N})});q.classes=Z;q.displayName="@mantine/core/Skeleton";var Te=class extends oe{constructor(e,t){super(),this.options=t,this.#s=e,this.#a=null,this.#i=B(),this.bindMethods(),this.setOptions(t)}#s;#e=void 0;#p=void 0;#t=void 0;#n;#h;#i;#a;#m;#u;#d;#o;#l;#r;#f=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(this.#e.addObserver(this),V(this.#e,this.options)?this.#c():this.updateResult(),this.#x())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return A(this.#e,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return A(this.#e,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#g(),this.#R(),this.#e.removeObserver(this)}setOptions(e){const t=this.options,s=this.#e;if(this.options=this.#s.defaultQueryOptions(e),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof x(this.options.enabled,this.#e)!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");this.#S(),this.#e.setOptions(this.options),t._defaulted&&!U(this.options,t)&&this.#s.getQueryCache().notify({type:"observerOptionsUpdated",query:this.#e,observer:this});const i=this.hasListeners();i&&X(this.#e,s,this.options,t)&&this.#c(),this.updateResult(),i&&(this.#e!==s||x(this.options.enabled,this.#e)!==x(t.enabled,this.#e)||j(this.options.staleTime,this.#e)!==j(t.staleTime,this.#e))&&this.#b();const r=this.#v();i&&(this.#e!==s||x(this.options.enabled,this.#e)!==x(t.enabled,this.#e)||r!==this.#r)&&this.#y(r)}getOptimisticResult(e){const t=this.#s.getQueryCache().build(this.#s,e),s=this.createResult(t,e);return Ne(this,s)&&(this.#t=s,this.#h=this.options,this.#n=this.#e.state),s}getCurrentResult(){return this.#t}trackResult(e,t){return new Proxy(e,{get:(s,i)=>(this.trackProp(i),t?.(i),i==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&this.#i.status==="pending"&&this.#i.reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(s,i))})}trackProp(e){this.#f.add(e)}getCurrentQuery(){return this.#e}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){const t=this.#s.defaultQueryOptions(e),s=this.#s.getQueryCache().build(this.#s,t);return s.fetch().then(()=>this.createResult(s,t))}fetch(e){return this.#c({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#t))}#c(e){this.#S();let t=this.#e.fetch(this.options,e);return e?.throwOnError||(t=t.catch(P)),t}#b(){this.#g();const e=j(this.options.staleTime,this.#e);if(L.isServer()||this.#t.isStale||!z(e))return;const s=le(this.#t.dataUpdatedAt,e)+1;this.#o=k.setTimeout(()=>{this.#t.isStale||this.updateResult()},s)}#v(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(this.#e):this.options.refetchInterval)??!1}#y(e){this.#R(),this.#r=e,!(L.isServer()||x(this.options.enabled,this.#e)===!1||!z(this.#r)||this.#r===0)&&(this.#l=k.setInterval(()=>{(this.options.refetchIntervalInBackground||ce.isFocused())&&this.#c()},this.#r))}#x(){this.#b(),this.#y(this.#v())}#g(){this.#o!==void 0&&(k.clearTimeout(this.#o),this.#o=void 0)}#R(){this.#l!==void 0&&(k.clearInterval(this.#l),this.#l=void 0)}createResult(e,t){const s=this.#e,i=this.options,r=this.#t,u=this.#n,o=this.#h,g=e!==s?e.state:this.#p,{state:O}=e;let n={...O},v=!1,l;if(t._optimisticResults){const f=this.hasListeners(),T=!f&&V(e,t),a=f&&X(e,s,t,i);(T||a)&&(n={...n,...he(O.data,e.options)}),t._optimisticResults==="isRestoring"&&(n.fetchStatus="idle")}let{error:h,errorUpdatedAt:d,status:m}=n;l=n.data;let E=!1;if(t.placeholderData!==void 0&&l===void 0&&m==="pending"){let f;r?.isPlaceholderData&&t.placeholderData===o?.placeholderData?(f=r.data,E=!0):f=typeof t.placeholderData=="function"?t.placeholderData(this.#d?.state.data,this.#d):t.placeholderData,f!==void 0&&(m="success",l=G(r?.data,f,t),v=!0)}if(t.select&&l!==void 0&&!E)if(r&&l===u?.data&&t.select===this.#m)l=this.#u;else try{this.#m=t.select,l=t.select(l),l=G(r?.data,l,t),this.#u=l,this.#a=null}catch(f){this.#a=f}this.#a&&(h=this.#a,l=this.#u,d=Date.now(),m="error");const N=n.fetchStatus==="fetching",w=m==="pending",M=m==="error",_=w&&N,F=l!==void 0,R={status:m,fetchStatus:n.fetchStatus,isPending:w,isSuccess:m==="success",isError:M,isInitialLoading:_,isLoading:_,data:l,dataUpdatedAt:n.dataUpdatedAt,error:h,errorUpdatedAt:d,failureCount:n.fetchFailureCount,failureReason:n.fetchFailureReason,errorUpdateCount:n.errorUpdateCount,isFetched:e.isFetched(),isFetchedAfterMount:n.dataUpdateCount>g.dataUpdateCount||n.errorUpdateCount>g.errorUpdateCount,isFetching:N,isRefetching:N&&!w,isLoadingError:M&&!F,isPaused:n.fetchStatus==="paused",isPlaceholderData:v,isRefetchError:M&&F,isStale:$(e,t),refetch:this.refetch,promise:this.#i,isEnabled:x(t.enabled,e)!==!1};if(this.options.experimental_prefetchInRender){const f=R.data!==void 0,T=R.status==="error"&&!f,a=S=>{T?S.reject(R.error):f&&S.resolve(R.data)},b=()=>{const S=this.#i=R.promise=B();a(S)},C=this.#i;switch(C.status){case"pending":e.queryHash===s.queryHash&&a(C);break;case"fulfilled":(T||R.data!==C.value)&&b();break;case"rejected":(!T||R.error!==C.reason)&&b();break}}return R}updateResult(){const e=this.#t,t=this.createResult(this.#e,this.options);if(this.#n=this.#e.state,this.#h=this.options,this.#n.data!==void 0&&(this.#d=this.#e),U(t,e))return;this.#t=t;const s=()=>{if(!e)return!0;const{notifyOnChangeProps:i}=this.options,r=typeof i=="function"?i():i;if(r==="all"||!r&&!this.#f.size)return!0;const u=new Set(r??this.#f);return this.options.throwOnError&&u.add("error"),Object.keys(this.#t).some(o=>{const y=o;return this.#t[y]!==e[y]&&u.has(y)})};this.#w({listeners:s()})}#S(){const e=this.#s.getQueryCache().build(this.#s,this.options);if(e===this.#e)return;const t=this.#e;this.#e=e,this.#p=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#x()}#w(e){K.batch(()=>{e.listeners&&this.listeners.forEach(t=>{t(this.#t)}),this.#s.getQueryCache().notify({query:this.#e,type:"observerResultsUpdated"})})}};function Ce(e,t){return x(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&x(t.retryOnMount,e)===!1)}function V(e,t){return Ce(e,t)||e.state.data!==void 0&&A(e,t,t.refetchOnMount)}function A(e,t,s){if(x(t.enabled,e)!==!1&&j(t.staleTime,e)!=="static"){const i=typeof s=="function"?s(e):s;return i==="always"||i!==!1&&$(e,t)}return!1}function X(e,t,s,i){return(e!==t||x(i.enabled,e)===!1)&&(!s.suspense||e.state.status!=="error")&&$(e,s)}function $(e,t){return x(t.enabled,e)!==!1&&e.isStaleByTime(j(t.staleTime,e))}function Ne(e,t){return!U(e.getCurrentResult(),t)}var ee=p.createContext(!1),Ie=()=>p.useContext(ee);ee.Provider;function Me(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var _e=p.createContext(Me()),Fe=()=>p.useContext(_e),je=(e,t,s)=>{const i=s?.state.error&&typeof e.throwOnError=="function"?J(e.throwOnError,[s.state.error,s]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||i)&&(t.isReset()||(e.retryOnMount=!1))},ke=e=>{p.useEffect(()=>{e.clearReset()},[e])},Qe=({result:e,errorResetBoundary:t,throwOnError:s,query:i,suspense:r})=>e.isError&&!t.isReset()&&!e.isFetching&&i&&(r&&e.data===void 0||J(s,[e.error,i])),De=e=>{if(e.suspense){const s=r=>r==="static"?r:Math.max(r??1e3,1e3),i=e.staleTime;e.staleTime=typeof i=="function"?(...r)=>s(i(...r)):s(i),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},Ue=(e,t)=>e.isLoading&&e.isFetching&&!t,Pe=(e,t)=>e?.suspense&&t.isPending,H=(e,t,s)=>t.fetchOptimistic(e).catch(()=>{s.clearReset()});function Le(e,t,s){const i=Ie(),r=Fe(),u=ue(),o=u.defaultQueryOptions(e);u.getDefaultOptions().queries?._experimental_beforeQuery?.(o);const y=u.getQueryCache().get(o.queryHash),g=e.subscribed!==!1;o._optimisticResults=i?"isRestoring":g?"optimistic":void 0,De(o),je(o,r,y),ke(r);const O=!u.getQueryCache().get(o.queryHash),[n]=p.useState(()=>new t(u,o)),v=n.getOptimisticResult(o),l=!i&&g;if(p.useSyncExternalStore(p.useCallback(h=>{const d=l?n.subscribe(K.batchCalls(h)):P;return n.updateResult(),d},[n,l]),()=>n.getCurrentResult(),()=>n.getCurrentResult()),p.useEffect(()=>{n.setOptions(o)},[o,n]),Pe(o,v))throw H(o,n,r);if(Qe({result:v,errorResetBoundary:r,throwOnError:o.throwOnError,query:y,suspense:o.suspense}))throw v.error;return u.getDefaultOptions().queries?._experimental_afterQuery?.(o,v),o.experimental_prefetchInRender&&!L.isServer()&&Ue(v,i)&&(O?H(o,n,r):y?.promise)?.catch(P).finally(()=>{n.updateResult()}),o.notifyOnChangeProps?v:n.trackResult(v)}function We(e,t){return Le(e,Te)}const Ae=[["path",{d:"M3 19a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-0"}],["path",{d:"M19 7a2 2 0 1 0 0 -4a2 2 0 0 0 0 4",key:"svg-1"}],["path",{d:"M11 19h5.5a3.5 3.5 0 0 0 0 -7h-8a3.5 3.5 0 0 1 0 -7h4.5",key:"svg-2"}]],Ke=Y("outline","route","Route",Ae);const $e=[["path",{d:"M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0",key:"svg-0"}],["path",{d:"M21 21l-6 -6",key:"svg-1"}]],Je=Y("outline","search","Search",$e),W=[{label:"1м",value:"1m"},{label:"5м",value:"5m"},{label:"1ч",value:"1h"},{label:"24ч",value:"24h"},{label:"7д",value:"7d"},{label:"30д",value:"30d"}];function Be(e,t){const s=new Date(e);return Number.isNaN(s.getTime())?"":t==="1m"?new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(s):t==="5m"||t==="1h"||t==="24h"?new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit"}).format(s):new Intl.DateTimeFormat("ru-RU",{day:"2-digit",month:"2-digit"}).format(s)}ve([ye,xe,ge,Re,Se]);function Ye({samples:e,range:t,onRangeChange:s,currentRx:i,currentTx:r,status:u,emptyTitle:o="История трафика собирается",emptyDescription:y="Первая точка появится после сигнала Node Agent.",emptyFooterLabel:g="Ожидаем первую точку"}){const O=de(),n=fe("(max-width: 479px)")??!1,[v,l]=p.useState(0);p.useEffect(()=>{const a=()=>l(b=>b+1);return window.addEventListener("nodeflow:appearance",a),()=>window.removeEventListener("nodeflow:appearance",a)},[]);const h=p.useMemo(()=>pe(),[v]),d=[...e].reverse().find(a=>Number.isFinite(a.rx_bps)||Number.isFinite(a.tx_bps)),m=p.useMemo(()=>e.reduce((a,b)=>(Number.isFinite(b.rx_bps)?a.rxObserved+=1:a.rxGaps+=1,Number.isFinite(b.tx_bps)?a.txObserved+=1:a.txGaps+=1,a),{rxObserved:0,rxGaps:0,txObserved:0,txGaps:0}),[e]),E=p.useMemo(()=>{const a=e.map(S=>new Date(S.timestamp).getTime()).filter(Number.isFinite);if(!a.length)return;const b=Math.min(...a),C=Math.max(...a);return[b,C>b?C:b+1e3]},[e]),N=p.useMemo(()=>({animation:!O,animationDuration:220,animationDurationUpdate:180,animationEasing:"cubicOut",animationEasingUpdate:"cubicOut",aria:{enabled:!0,decal:{show:!1}},grid:{top:18,right:n?6:10,bottom:34,left:n?50:72},textStyle:{fontFamily:"Inter, system-ui, sans-serif"},tooltip:{trigger:"axis",confine:!0,className:"nf-chart-tooltip",axisPointer:{type:"line",lineStyle:{color:h.pointer,width:1}},formatter:a=>{const b=Array.isArray(a)?a:[];return`${b[0]?.axisValueLabel??""}${b.map(S=>`${S.marker??""}${S.seriesName} ${I(S.value?.[1])}`).join("")}`}},xAxis:{type:"time",boundaryGap:!1,min:E?.[0],max:E?.[1],splitNumber:n?3:6,axisLine:{lineStyle:{color:h.axisLine}},axisTick:{show:!1},axisLabel:{color:h.axisText,fontSize:n?10:11,hideOverlap:!0,margin:14,formatter:a=>Be(a,t)},splitLine:{show:!1}},yAxis:{type:"value",min:0,axisLine:{show:!1},axisTick:{show:!1},axisLabel:{color:h.axisText,fontSize:n?10:11,formatter:a=>a>0&&a<1?"":I(a)},splitLine:{lineStyle:{color:h.splitLine,type:"dashed"}}},series:[{name:"RX",type:"line",data:e.map(a=>[a.timestamp,Number.isFinite(a.rx_bps)?a.rx_bps:null]),connectNulls:!1,showSymbol:!1,smooth:.14,lineStyle:{width:1.7,color:h.primary},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:h.primaryAreaTop},{offset:1,color:h.primaryAreaBottom}]}}},{name:"TX",type:"line",data:e.map(a=>[a.timestamp,Number.isFinite(a.tx_bps)?a.tx_bps:null]),connectNulls:!1,showSymbol:!1,smooth:.14,lineStyle:{width:1.5,color:h.secondary},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:h.secondaryAreaTop},{offset:1,color:h.secondaryAreaBottom}]}}}]}),[e,t,O,n,E,h]),w=d?.timestamp?new Date(d.timestamp):null,M=w&&!Number.isNaN(w.getTime())?`Обновлено: ${new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(w)}`:g,_=i!==void 0||r!==void 0,F=i===void 0?d?.rx_bps:i,Q=r===void 0?d?.tx_bps:r,R=_?"Сейчас":"Последняя точка",f=`Трафик за период ${W.find(a=>a.value===t)?.label??t}. ${R} RX ${I(F)}, TX ${I(Q)}.`,T=u??{tone:d?"stale":"offline",label:d?"Исторические данные":"Нет свежих данных"};return c.jsxs("div",{className:"nf-traffic-chart",children:[c.jsxs("div",{className:"nf-chart-head",children:[c.jsxs("div",{className:"nf-chart-legend","aria-label":_?"Текущая скорость":"Последняя точка истории",children:[c.jsxs("span",{children:[c.jsx("i",{className:"is-rx"})," RX ",c.jsx("b",{children:I(F)})]}),c.jsxs("span",{children:[c.jsx("i",{className:"is-tx"})," TX ",c.jsx("b",{children:I(Q)})]})]}),c.jsx(we,{className:"nf-range-control",value:t,onChange:a=>s(a),data:W,size:"sm","aria-label":"Период графика"})]}),d?c.jsxs("div",{role:"img","aria-label":f,"data-rx-observed-points":m.rxObserved,"data-rx-gap-points":m.rxGaps,"data-tx-observed-points":m.txObserved,"data-tx-gap-points":m.txGaps,children:[c.jsx(me,{echarts:be,option:N,notMerge:!0,lazyUpdate:!0,className:"nf-chart-canvas"}),c.jsx("p",{className:"nf-visually-hidden",children:f})]}):c.jsxs("div",{className:"nf-chart-empty",children:[c.jsx("strong",{children:o}),c.jsx("span",{children:y})]}),c.jsxs("footer",{className:"nf-chart-footer",children:[c.jsxs("span",{className:`is-${T.tone}`,children:[c.jsx("i",{}),T.label]}),c.jsx("time",{dateTime:d?.timestamp,children:M})]})]})}export{Ke as I,q as S,Ye as T,Je as a,We as u}; +import{q as te,s as se,t as ie,j as c,y as ae,v as re,w as ne,a4 as D,ao as oe,ap as B,aq as x,ar as U,as as j,at as P,au as L,av as z,aw as le,ax as k,ay as ce,az as he,aA as G,aB as K,r as p,aC as J,k as ue,c as Y,W as de,aD as fe,aE as pe}from"./index-fgrXogF6.js";import{R as me}from"./chart-react-C4b8adjg.js";import{e as be,u as ve,i as ye,a as xe,b as ge,c as Re,d as Se}from"./chart-engine-Dbh3Q7E_.js";import{f as I}from"./format-DGDz36zr.js";import{S as we}from"./IconArrowUp-DwKi77Ll.js";var Z={root:"m_18320242","skeleton-fade":"m_299c329c"};const Oe={visible:!0,animate:!0},Ee=re((e,{width:t,height:s,radius:i,circle:r})=>({root:{"--skeleton-height":D(s),"--skeleton-width":r?D(s):D(t),"--skeleton-radius":r?"1000px":i===void 0?void 0:ne(i)}})),q=te((e,t)=>{const s=se("Skeleton",Oe,e),{classNames:i,className:r,style:u,styles:o,unstyled:y,vars:g,width:O,height:n,circle:v,visible:l,radius:h,animate:d,mod:m,attributes:E,...N}=s,w=ie({name:"Skeleton",classes:Z,props:s,className:r,style:u,classNames:i,styles:o,unstyled:y,attributes:E,vars:g,varsResolver:Ee});return c.jsx(ae,{ref:t,...w("root"),mod:[{visible:l,animate:d},m],...N})});q.classes=Z;q.displayName="@mantine/core/Skeleton";var Te=class extends oe{constructor(e,t){super(),this.options=t,this.#s=e,this.#a=null,this.#i=B(),this.bindMethods(),this.setOptions(t)}#s;#e=void 0;#p=void 0;#t=void 0;#n;#h;#i;#a;#m;#u;#d;#o;#l;#r;#f=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(this.#e.addObserver(this),V(this.#e,this.options)?this.#c():this.updateResult(),this.#x())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return A(this.#e,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return A(this.#e,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#g(),this.#R(),this.#e.removeObserver(this)}setOptions(e){const t=this.options,s=this.#e;if(this.options=this.#s.defaultQueryOptions(e),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof x(this.options.enabled,this.#e)!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");this.#S(),this.#e.setOptions(this.options),t._defaulted&&!U(this.options,t)&&this.#s.getQueryCache().notify({type:"observerOptionsUpdated",query:this.#e,observer:this});const i=this.hasListeners();i&&X(this.#e,s,this.options,t)&&this.#c(),this.updateResult(),i&&(this.#e!==s||x(this.options.enabled,this.#e)!==x(t.enabled,this.#e)||j(this.options.staleTime,this.#e)!==j(t.staleTime,this.#e))&&this.#b();const r=this.#v();i&&(this.#e!==s||x(this.options.enabled,this.#e)!==x(t.enabled,this.#e)||r!==this.#r)&&this.#y(r)}getOptimisticResult(e){const t=this.#s.getQueryCache().build(this.#s,e),s=this.createResult(t,e);return Ne(this,s)&&(this.#t=s,this.#h=this.options,this.#n=this.#e.state),s}getCurrentResult(){return this.#t}trackResult(e,t){return new Proxy(e,{get:(s,i)=>(this.trackProp(i),t?.(i),i==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&this.#i.status==="pending"&&this.#i.reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(s,i))})}trackProp(e){this.#f.add(e)}getCurrentQuery(){return this.#e}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){const t=this.#s.defaultQueryOptions(e),s=this.#s.getQueryCache().build(this.#s,t);return s.fetch().then(()=>this.createResult(s,t))}fetch(e){return this.#c({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#t))}#c(e){this.#S();let t=this.#e.fetch(this.options,e);return e?.throwOnError||(t=t.catch(P)),t}#b(){this.#g();const e=j(this.options.staleTime,this.#e);if(L.isServer()||this.#t.isStale||!z(e))return;const s=le(this.#t.dataUpdatedAt,e)+1;this.#o=k.setTimeout(()=>{this.#t.isStale||this.updateResult()},s)}#v(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(this.#e):this.options.refetchInterval)??!1}#y(e){this.#R(),this.#r=e,!(L.isServer()||x(this.options.enabled,this.#e)===!1||!z(this.#r)||this.#r===0)&&(this.#l=k.setInterval(()=>{(this.options.refetchIntervalInBackground||ce.isFocused())&&this.#c()},this.#r))}#x(){this.#b(),this.#y(this.#v())}#g(){this.#o!==void 0&&(k.clearTimeout(this.#o),this.#o=void 0)}#R(){this.#l!==void 0&&(k.clearInterval(this.#l),this.#l=void 0)}createResult(e,t){const s=this.#e,i=this.options,r=this.#t,u=this.#n,o=this.#h,g=e!==s?e.state:this.#p,{state:O}=e;let n={...O},v=!1,l;if(t._optimisticResults){const f=this.hasListeners(),T=!f&&V(e,t),a=f&&X(e,s,t,i);(T||a)&&(n={...n,...he(O.data,e.options)}),t._optimisticResults==="isRestoring"&&(n.fetchStatus="idle")}let{error:h,errorUpdatedAt:d,status:m}=n;l=n.data;let E=!1;if(t.placeholderData!==void 0&&l===void 0&&m==="pending"){let f;r?.isPlaceholderData&&t.placeholderData===o?.placeholderData?(f=r.data,E=!0):f=typeof t.placeholderData=="function"?t.placeholderData(this.#d?.state.data,this.#d):t.placeholderData,f!==void 0&&(m="success",l=G(r?.data,f,t),v=!0)}if(t.select&&l!==void 0&&!E)if(r&&l===u?.data&&t.select===this.#m)l=this.#u;else try{this.#m=t.select,l=t.select(l),l=G(r?.data,l,t),this.#u=l,this.#a=null}catch(f){this.#a=f}this.#a&&(h=this.#a,l=this.#u,d=Date.now(),m="error");const N=n.fetchStatus==="fetching",w=m==="pending",M=m==="error",_=w&&N,F=l!==void 0,R={status:m,fetchStatus:n.fetchStatus,isPending:w,isSuccess:m==="success",isError:M,isInitialLoading:_,isLoading:_,data:l,dataUpdatedAt:n.dataUpdatedAt,error:h,errorUpdatedAt:d,failureCount:n.fetchFailureCount,failureReason:n.fetchFailureReason,errorUpdateCount:n.errorUpdateCount,isFetched:e.isFetched(),isFetchedAfterMount:n.dataUpdateCount>g.dataUpdateCount||n.errorUpdateCount>g.errorUpdateCount,isFetching:N,isRefetching:N&&!w,isLoadingError:M&&!F,isPaused:n.fetchStatus==="paused",isPlaceholderData:v,isRefetchError:M&&F,isStale:$(e,t),refetch:this.refetch,promise:this.#i,isEnabled:x(t.enabled,e)!==!1};if(this.options.experimental_prefetchInRender){const f=R.data!==void 0,T=R.status==="error"&&!f,a=S=>{T?S.reject(R.error):f&&S.resolve(R.data)},b=()=>{const S=this.#i=R.promise=B();a(S)},C=this.#i;switch(C.status){case"pending":e.queryHash===s.queryHash&&a(C);break;case"fulfilled":(T||R.data!==C.value)&&b();break;case"rejected":(!T||R.error!==C.reason)&&b();break}}return R}updateResult(){const e=this.#t,t=this.createResult(this.#e,this.options);if(this.#n=this.#e.state,this.#h=this.options,this.#n.data!==void 0&&(this.#d=this.#e),U(t,e))return;this.#t=t;const s=()=>{if(!e)return!0;const{notifyOnChangeProps:i}=this.options,r=typeof i=="function"?i():i;if(r==="all"||!r&&!this.#f.size)return!0;const u=new Set(r??this.#f);return this.options.throwOnError&&u.add("error"),Object.keys(this.#t).some(o=>{const y=o;return this.#t[y]!==e[y]&&u.has(y)})};this.#w({listeners:s()})}#S(){const e=this.#s.getQueryCache().build(this.#s,this.options);if(e===this.#e)return;const t=this.#e;this.#e=e,this.#p=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#x()}#w(e){K.batch(()=>{e.listeners&&this.listeners.forEach(t=>{t(this.#t)}),this.#s.getQueryCache().notify({query:this.#e,type:"observerResultsUpdated"})})}};function Ce(e,t){return x(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&x(t.retryOnMount,e)===!1)}function V(e,t){return Ce(e,t)||e.state.data!==void 0&&A(e,t,t.refetchOnMount)}function A(e,t,s){if(x(t.enabled,e)!==!1&&j(t.staleTime,e)!=="static"){const i=typeof s=="function"?s(e):s;return i==="always"||i!==!1&&$(e,t)}return!1}function X(e,t,s,i){return(e!==t||x(i.enabled,e)===!1)&&(!s.suspense||e.state.status!=="error")&&$(e,s)}function $(e,t){return x(t.enabled,e)!==!1&&e.isStaleByTime(j(t.staleTime,e))}function Ne(e,t){return!U(e.getCurrentResult(),t)}var ee=p.createContext(!1),Ie=()=>p.useContext(ee);ee.Provider;function Me(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var _e=p.createContext(Me()),Fe=()=>p.useContext(_e),je=(e,t,s)=>{const i=s?.state.error&&typeof e.throwOnError=="function"?J(e.throwOnError,[s.state.error,s]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||i)&&(t.isReset()||(e.retryOnMount=!1))},ke=e=>{p.useEffect(()=>{e.clearReset()},[e])},Qe=({result:e,errorResetBoundary:t,throwOnError:s,query:i,suspense:r})=>e.isError&&!t.isReset()&&!e.isFetching&&i&&(r&&e.data===void 0||J(s,[e.error,i])),De=e=>{if(e.suspense){const s=r=>r==="static"?r:Math.max(r??1e3,1e3),i=e.staleTime;e.staleTime=typeof i=="function"?(...r)=>s(i(...r)):s(i),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},Ue=(e,t)=>e.isLoading&&e.isFetching&&!t,Pe=(e,t)=>e?.suspense&&t.isPending,H=(e,t,s)=>t.fetchOptimistic(e).catch(()=>{s.clearReset()});function Le(e,t,s){const i=Ie(),r=Fe(),u=ue(),o=u.defaultQueryOptions(e);u.getDefaultOptions().queries?._experimental_beforeQuery?.(o);const y=u.getQueryCache().get(o.queryHash),g=e.subscribed!==!1;o._optimisticResults=i?"isRestoring":g?"optimistic":void 0,De(o),je(o,r,y),ke(r);const O=!u.getQueryCache().get(o.queryHash),[n]=p.useState(()=>new t(u,o)),v=n.getOptimisticResult(o),l=!i&&g;if(p.useSyncExternalStore(p.useCallback(h=>{const d=l?n.subscribe(K.batchCalls(h)):P;return n.updateResult(),d},[n,l]),()=>n.getCurrentResult(),()=>n.getCurrentResult()),p.useEffect(()=>{n.setOptions(o)},[o,n]),Pe(o,v))throw H(o,n,r);if(Qe({result:v,errorResetBoundary:r,throwOnError:o.throwOnError,query:y,suspense:o.suspense}))throw v.error;return u.getDefaultOptions().queries?._experimental_afterQuery?.(o,v),o.experimental_prefetchInRender&&!L.isServer()&&Ue(v,i)&&(O?H(o,n,r):y?.promise)?.catch(P).finally(()=>{n.updateResult()}),o.notifyOnChangeProps?v:n.trackResult(v)}function We(e,t){return Le(e,Te)}const Ae=[["path",{d:"M3 19a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-0"}],["path",{d:"M19 7a2 2 0 1 0 0 -4a2 2 0 0 0 0 4",key:"svg-1"}],["path",{d:"M11 19h5.5a3.5 3.5 0 0 0 0 -7h-8a3.5 3.5 0 0 1 0 -7h4.5",key:"svg-2"}]],Ke=Y("outline","route","Route",Ae);const $e=[["path",{d:"M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0",key:"svg-0"}],["path",{d:"M21 21l-6 -6",key:"svg-1"}]],Je=Y("outline","search","Search",$e),W=[{label:"1м",value:"1m"},{label:"5м",value:"5m"},{label:"1ч",value:"1h"},{label:"24ч",value:"24h"},{label:"7д",value:"7d"},{label:"30д",value:"30d"}];function Be(e,t){const s=new Date(e);return Number.isNaN(s.getTime())?"":t==="1m"?new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(s):t==="5m"||t==="1h"||t==="24h"?new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit"}).format(s):new Intl.DateTimeFormat("ru-RU",{day:"2-digit",month:"2-digit"}).format(s)}ve([ye,xe,ge,Re,Se]);function Ye({samples:e,range:t,onRangeChange:s,currentRx:i,currentTx:r,status:u,emptyTitle:o="История трафика собирается",emptyDescription:y="Первая точка появится после сигнала Node Agent.",emptyFooterLabel:g="Ожидаем первую точку"}){const O=de(),n=fe("(max-width: 479px)")??!1,[v,l]=p.useState(0);p.useEffect(()=>{const a=()=>l(b=>b+1);return window.addEventListener("nodeflow:appearance",a),()=>window.removeEventListener("nodeflow:appearance",a)},[]);const h=p.useMemo(()=>pe(),[v]),d=[...e].reverse().find(a=>Number.isFinite(a.rx_bps)||Number.isFinite(a.tx_bps)),m=p.useMemo(()=>e.reduce((a,b)=>(Number.isFinite(b.rx_bps)?a.rxObserved+=1:a.rxGaps+=1,Number.isFinite(b.tx_bps)?a.txObserved+=1:a.txGaps+=1,a),{rxObserved:0,rxGaps:0,txObserved:0,txGaps:0}),[e]),E=p.useMemo(()=>{const a=e.map(S=>new Date(S.timestamp).getTime()).filter(Number.isFinite);if(!a.length)return;const b=Math.min(...a),C=Math.max(...a);return[b,C>b?C:b+1e3]},[e]),N=p.useMemo(()=>({animation:!O,animationDuration:220,animationDurationUpdate:180,animationEasing:"cubicOut",animationEasingUpdate:"cubicOut",aria:{enabled:!0,decal:{show:!1}},grid:{top:18,right:n?6:10,bottom:34,left:n?50:72},textStyle:{fontFamily:"Inter, system-ui, sans-serif"},tooltip:{trigger:"axis",confine:!0,className:"nf-chart-tooltip",axisPointer:{type:"line",lineStyle:{color:h.pointer,width:1}},formatter:a=>{const b=Array.isArray(a)?a:[];return`${b[0]?.axisValueLabel??""}${b.map(S=>`${S.marker??""}${S.seriesName} ${I(S.value?.[1])}`).join("")}`}},xAxis:{type:"time",boundaryGap:!1,min:E?.[0],max:E?.[1],splitNumber:n?3:6,axisLine:{lineStyle:{color:h.axisLine}},axisTick:{show:!1},axisLabel:{color:h.axisText,fontSize:n?10:11,hideOverlap:!0,margin:14,formatter:a=>Be(a,t)},splitLine:{show:!1}},yAxis:{type:"value",min:0,axisLine:{show:!1},axisTick:{show:!1},axisLabel:{color:h.axisText,fontSize:n?10:11,formatter:a=>a>0&&a<1?"":I(a)},splitLine:{lineStyle:{color:h.splitLine,type:"dashed"}}},series:[{name:"RX",type:"line",data:e.map(a=>[a.timestamp,Number.isFinite(a.rx_bps)?a.rx_bps:null]),connectNulls:!1,showSymbol:!1,smooth:.14,lineStyle:{width:1.7,color:h.primary},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:h.primaryAreaTop},{offset:1,color:h.primaryAreaBottom}]}}},{name:"TX",type:"line",data:e.map(a=>[a.timestamp,Number.isFinite(a.tx_bps)?a.tx_bps:null]),connectNulls:!1,showSymbol:!1,smooth:.14,lineStyle:{width:1.5,color:h.secondary},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:h.secondaryAreaTop},{offset:1,color:h.secondaryAreaBottom}]}}}]}),[e,t,O,n,E,h]),w=d?.timestamp?new Date(d.timestamp):null,M=w&&!Number.isNaN(w.getTime())?`Обновлено: ${new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(w)}`:g,_=i!==void 0||r!==void 0,F=i===void 0?d?.rx_bps:i,Q=r===void 0?d?.tx_bps:r,R=_?"Сейчас":"Последняя точка",f=`Трафик за период ${W.find(a=>a.value===t)?.label??t}. ${R} RX ${I(F)}, TX ${I(Q)}.`,T=u??{tone:d?"stale":"offline",label:d?"Исторические данные":"Нет свежих данных"};return c.jsxs("div",{className:"nf-traffic-chart",children:[c.jsxs("div",{className:"nf-chart-head",children:[c.jsxs("div",{className:"nf-chart-legend","aria-label":_?"Текущая скорость":"Последняя точка истории",children:[c.jsxs("span",{children:[c.jsx("i",{className:"is-rx"})," RX ",c.jsx("b",{children:I(F)})]}),c.jsxs("span",{children:[c.jsx("i",{className:"is-tx"})," TX ",c.jsx("b",{children:I(Q)})]})]}),c.jsx(we,{className:"nf-range-control",value:t,onChange:a=>s(a),data:W,size:"sm","aria-label":"Период графика"})]}),d?c.jsxs("div",{role:"img","aria-label":f,"data-rx-observed-points":m.rxObserved,"data-rx-gap-points":m.rxGaps,"data-tx-observed-points":m.txObserved,"data-tx-gap-points":m.txGaps,children:[c.jsx(me,{echarts:be,option:N,notMerge:!0,lazyUpdate:!0,className:"nf-chart-canvas"}),c.jsx("p",{className:"nf-visually-hidden",children:f})]}):c.jsxs("div",{className:"nf-chart-empty",children:[c.jsx("strong",{children:o}),c.jsx("span",{children:y})]}),c.jsxs("footer",{className:"nf-chart-footer",children:[c.jsxs("span",{className:`is-${T.tone}`,children:[c.jsx("i",{}),T.label]}),c.jsx("time",{dateTime:d?.timestamp,children:M})]})]})}export{Ke as I,q as S,Ye as T,Je as a,We as u}; diff --git a/internal/panel/web_dist/assets/TrafficPage-BPEXjV3K.js b/internal/panel/web_dist/assets/TrafficPage-BghnUjc1.js similarity index 97% rename from internal/panel/web_dist/assets/TrafficPage-BPEXjV3K.js rename to internal/panel/web_dist/assets/TrafficPage-BghnUjc1.js index 206eebf..619018c 100644 --- a/internal/panel/web_dist/assets/TrafficPage-BPEXjV3K.js +++ b/internal/panel/web_dist/assets/TrafficPage-BghnUjc1.js @@ -1 +1 @@ -import{c as te,u as ne,a as ae,d as re,j as e,L as D,B as je,h as pe,r as y,an as be,i as ge,e as Ne,A as ye}from"./index-Dy6W__Vz.js";import{b as U,f as v,a as R,t as ve,d as $e,S as X,R as Se,c as z,T as ke}from"./format-D6_ab21F.js";import{T as Ce,I as Te,a as Re,S as B}from"./TrafficChart-BU3flakD.js";import{i as le}from"./interaction-BrakVCuN.js";import{I as O,a as H}from"./IconArrowUp-Cj3lrfzR.js";import{u as Me,a as we,i as Ie}from"./useTrafficOverview-7XLu6zlh.js";import{a as Z,I as Pe}from"./IconServer-BpOSndTX.js";import"./chart-react-C4b8adjg.js";import"./chart-engine-Dbh3Q7E_.js";import"./chart-renderer-CWmX7Ukt.js";const Le=[["path",{d:"M3 12h4.5l1.5 -6l4 12l2 -9l1.5 3h4.5",key:"svg-0"}]],Fe=te("outline","activity-heartbeat","ActivityHeartbeat",Le);const Ae=[["path",{d:"M7 12l5 5l-1.5 1.5a3.536 3.536 0 1 1 -5 -5l1.5 -1.5",key:"svg-0"}],["path",{d:"M17 12l-5 -5l1.5 -1.5a3.536 3.536 0 1 1 5 5l-1.5 1.5",key:"svg-1"}],["path",{d:"M3 21l2.5 -2.5",key:"svg-2"}],["path",{d:"M18.5 5.5l2.5 -2.5",key:"svg-3"}],["path",{d:"M10 11l-2 2",key:"svg-4"}],["path",{d:"M13 14l-2 2",key:"svg-5"}]],Ee=te("outline","plug-connected","PlugConnected",Ae);function k(a){const r=String(a.node.status??"").toLowerCase();return r==="online"?"online":r==="degraded"?"degraded":"offline"}const Xe={online:"Работает",degraded:"Деградирует",offline:"Недоступна"};function ze(a){const r=Number(a.node.metadata?.traffic_limit_bytes);return Number.isFinite(r)&&r>0?r:0}function Be({nodes:a,selectedNodeId:r,totalRate:m,totalMonthBytes:_,onSelect:i}){const d=ne(),u=ae(),p=re(d.search);return e.jsx("div",{className:"nf-traffic-nodes-table",children:e.jsxs("table",{children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Статус"}),e.jsx("th",{children:"Нода"}),e.jsx("th",{children:"Маршруты"}),e.jsx("th",{children:"Соединения"}),e.jsx("th",{children:"RX / TX"}),e.jsx("th",{children:"Трафик за месяц"}),e.jsx("th",{children:"Последняя точка"}),e.jsx("th",{children:e.jsx("span",{className:"nf-visually-hidden",children:"Выбрать источник графика"})})]})}),e.jsx("tbody",{children:a.map(s=>{const g=k(s),x=s.rate_sampled_at?s.rx_bits_per_second:null,l=s.rate_sampled_at?s.tx_bits_per_second:null,j=Number.isFinite(x)&&Number.isFinite(l)?Number(x)+Number(l):null,h=j!==null&&m!==null&&m>0?j/m*100:null,n=ze(s),$=_>0?s.traffic_used_bytes/_*100:0,S=n>0?s.traffic_used_bytes/n*100:0,C=Math.max(0,Math.min(100,n>0?S:$)),T=s.latest_heartbeat?.metrics.haproxy_runtime?.connections_current,o=g!=="offline"&&Number.isFinite(T)?Number(T):null,N=r===s.node.id;return e.jsxs("tr",{className:`is-${g}${N?" is-selected":""}`,tabIndex:0,"aria-label":`Открыть ноду ${s.node.name}`,onClick:f=>{le(f.target,f.currentTarget)||u(`/nodes/${s.node.id}${p}`)},onKeyDown:f=>{f.key==="Enter"&&f.target===f.currentTarget&&u(`/nodes/${s.node.id}${p}`)},children:[e.jsx("td",{"data-label":"Статус",children:e.jsxs("span",{className:"nf-traffic-node-state",children:[e.jsx("i",{}),Xe[g]]})}),e.jsx("td",{"data-label":"Нода",children:e.jsxs(D,{className:"nf-traffic-node-name",to:`/nodes/${s.node.id}${p}`,children:[e.jsx("strong",{children:s.node.name}),e.jsx("span",{children:s.node.address})]})}),e.jsxs("td",{"data-label":"Маршруты",children:[e.jsx("strong",{children:s.routes_enabled}),e.jsxs("span",{className:"nf-traffic-cell-muted",children:[" из ",s.routes_total]})]}),e.jsx("td",{"data-label":"Соединения",children:e.jsx("strong",{children:U(o)})}),e.jsx("td",{"data-label":"RX / TX",children:e.jsxs("div",{className:"nf-traffic-node-rate",children:[e.jsxs("span",{children:[e.jsx(O,{size:13}),v(x)]}),e.jsxs("span",{children:[e.jsx(H,{size:13}),v(l)]})]})}),e.jsx("td",{"data-label":"Трафик за месяц",children:e.jsxs("div",{className:"nf-traffic-node-volume",children:[e.jsx("strong",{children:s.traffic_observed?`${R(s.traffic_used_bytes)}${n>0?` / ${R(n)}`:""}`:"—"}),s.traffic_observed&&e.jsx("i",{"aria-hidden":"true",children:e.jsx("em",{style:{transform:`scaleX(${C/100})`}})}),e.jsx("span",{children:s.traffic_observed?n>0?`${Math.round(S)}% квоты`:`${Math.round($)}% общего объёма`:"Нет данных за месяц"})]})}),e.jsx("td",{"data-label":"Последняя точка",children:s.rate_sampled_at?e.jsx("time",{dateTime:s.rate_sampled_at,children:ve(s.rate_sampled_at)}):"Нет точки"}),e.jsx("td",{children:e.jsx(je,{variant:N?"light":"subtle",color:"nodeflow",size:"compact-sm",leftSection:e.jsx(pe,{size:15}),onClick:()=>i(N?void 0:s.node.id),"aria-pressed":N,"aria-label":N?`Вернуть общий график вместо ${s.node.name}`:h===null?`Показать трафик ноды ${s.node.name}, текущая скорость недоступна`:`Показать трафик ноды ${s.node.name}, сейчас ${Math.round(h)}% общей скорости`,children:N?"Общий":"На график"})})]},s.node.id)})})]})})}function ee(a){return a.fallback?"Любой TCP":a.snis.length?`SNI ${a.snis.join(", ")}`:"IP назначения"}const De={"1m":"1 мин","5m":"5 мин","1h":"1 ч","24h":"24 ч","7d":"7 д","30d":"30 д"};function Ue({routes:a,scopeLabel:r,range:m}){const _=ne(),i=ae(),d=re(_.search),[u,p]=y.useState(!1);return e.jsxs("section",{className:"nf-traffic-routes","aria-labelledby":"traffic-routes-title",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("h2",{id:"traffic-routes-title",children:"Топ маршрутов"}),e.jsxs("p",{children:["Средняя RX + TX · ",r," · ",De[m]]})]}),e.jsx("span",{children:a.length||"—"})]}),e.jsxs("div",{className:"nf-traffic-routes__head","aria-hidden":"true",children:[e.jsx("span",{children:"#"}),e.jsx("span",{children:"Маршрут"}),e.jsx("span",{children:"Нода"}),e.jsx("span",{children:"Скорость"}),e.jsx("span",{children:"Доля"})]}),a.length?e.jsxs("ol",{children:[a.map((s,g)=>e.jsxs("li",{className:g>=3&&!u?"is-mobile-collapsed":"",tabIndex:0,"aria-label":`Редактировать маршрут ${s.name}`,onClick:x=>{le(x.target,x.currentTarget)||i(`/nodes/${s.node_id}/routes/${s.route_id}/edit${d}`)},onKeyDown:x=>{x.key==="Enter"&&x.target===x.currentTarget&&i(`/nodes/${s.node_id}/routes/${s.route_id}/edit${d}`)},children:[e.jsx("span",{className:"nf-traffic-routes__index",children:g+1}),e.jsxs("div",{className:"nf-traffic-routes__identity",children:[e.jsx(D,{to:`/nodes/${s.node_id}/routes/${s.route_id}/edit${d}`,title:s.name,children:s.name}),e.jsxs("small",{title:`${s.node_name} · ${ee(s)} · ${s.listener_ip||"*"}:${s.listener_port}`,children:[s.node_name," · ",ee(s)," · ",s.listener_ip||"*",":",s.listener_port]}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("em",{style:{transform:`scaleX(${Math.max(3,Math.min(100,s.share_percent))/100})`}})})]}),e.jsx(D,{className:"nf-traffic-routes__node",to:`/nodes/${s.node_id}${d}`,children:s.node_name}),e.jsxs("div",{className:"nf-traffic-routes__rate",title:`Текущий месяц RX + TX: ${R(s.used_bytes)}`,children:[e.jsx("strong",{children:v(s.bits_per_second)}),e.jsxs("small",{children:[e.jsxs("span",{children:[e.jsx(O,{size:11}),v(s.rx_bits_per_second)]}),e.jsxs("span",{children:[e.jsx(H,{size:11}),v(s.tx_bits_per_second)]})]})]}),e.jsxs("b",{children:[Math.round(s.share_percent),"%"]})]},s.route_id)),a.length>3&&e.jsx("li",{className:"nf-traffic-routes__mobile-more",children:e.jsx("button",{type:"button",onClick:()=>p(s=>!s),children:u?"Свернуть список":`Ещё ${a.length-3} маршрута`})})]}):e.jsxs("div",{className:"nf-traffic-routes__empty",role:"status",children:[e.jsx("strong",{children:"Нет маршрутных точек"}),e.jsx("span",{children:"Скорость появится после следующего сигнала HAProxy."})]})]})}const Oe=new Set(["1m","5m","1h","24h","7d","30d"]);function He(a){const r=a.latest_heartbeat?.metrics.haproxy_runtime,m=Object.values(r?.servers??{}).flatMap(i=>Object.values(i).filter(d=>d.address===void 0||!!d.address).map(d=>d.status));return(m.length?m:Object.values(r?.backends??{}).map(i=>i.status)).reduce((i,d)=>{const u=String(d??"").toUpperCase();return u==="UP"||u==="OPEN"?i.healthy+=1:u==="DOWN"||u==="CLOSED"||u==="MAINT"?i.unavailable+=1:i.degraded+=1,i},{healthy:0,degraded:0,unavailable:0})}function se(a){const r=Number(a?.node.metadata?.traffic_limit_bytes);return Number.isFinite(r)&&r>0?r:0}function qe(){return e.jsxs("div",{className:"nf-traffic-page__skeleton","aria-label":"Загрузка статистики трафика",children:[e.jsx(B,{height:392}),e.jsx(B,{height:88}),e.jsx(B,{height:300})]})}function ts(){const[a,r]=be(),m=a.get("range"),_=m&&Oe.has(m)?m:"24h",i=a.get("node")||void 0,[d,u]=y.useState(""),[p,s]=y.useState("all"),[g,x]=y.useState(!1),l=Me(_,i),j=l.data,h=j?.nodes??[],n=h.find(t=>t.node.id===i),$=!!(i&&we(l.error));y.useEffect(()=>{$&&(x(!0),r(t=>{const c=new URLSearchParams(t);return c.delete("node"),c.has("range")||c.set("range",_),c},{replace:!0}))},[$,_,r]);const S=(t,c)=>{const b=new URLSearchParams(a);c?b.set(t,c):b.delete(t),b.has("range")||b.set("range",_),r(b,{replace:!0})},C=y.useMemo(()=>h.reduce((t,c)=>(t[k(c)]+=1,t),{online:0,degraded:0,offline:0}),[h]),T=y.useMemo(()=>{const t=d.trim().toLowerCase();return h.filter(c=>{const b=p==="all"||k(c)===p,_e=!t||`${c.node.name} ${c.node.address}`.toLowerCase().includes(t);return b&&_e})},[h,d,p]),o=j?.totals,f=(n?He(n):null)??{healthy:o?.backends_healthy??0,degraded:o?.backends_degraded??0,unavailable:o?.backends_unavailable??0},q=f.healthy+f.degraded+f.unavailable,Q=q?Math.round(f.healthy/q*100):null,I=!!n?.rate_sampled_at,P=o?.current_rate_complete===!0&&Number.isFinite(o.rx_bits_per_second)&&Number.isFinite(o.tx_bits_per_second),L=n?I&&Number.isFinite(n.rx_bits_per_second)?Number(n.rx_bits_per_second):null:P?Number(o?.rx_bits_per_second):null,F=n?I&&Number.isFinite(n.tx_bits_per_second)?Number(n.tx_bits_per_second):null:P?Number(o?.tx_bits_per_second):null,K=L!==null&&F!==null,W=K?"из HAProxy counters":n&&!I?"нет текущей точки":"неполные данные",ie=n?.traffic_used_bytes??o?.traffic_month_bytes??0,A=h.map(se),V=n?se(n):A.length&&A.every(t=>t>0)?A.reduce((t,c)=>t+c,0):0,G=n?.latest_heartbeat?.metrics.haproxy_runtime?.connections_current,ce=h.length>0&&h.every(t=>k(t)!=="offline"&&Number.isFinite(t.latest_heartbeat?.metrics.haproxy_runtime?.connections_current)),oe=n?k(n)!=="offline"&&Number.isFinite(G)?Number(G):null:ce?h.reduce((t,c)=>t+Number(c.latest_heartbeat?.metrics.haproxy_runtime?.connections_current),0):null,de=n?.routes_total??o?.routes_total??0,M=n?.node.name??"Все ноды",he=P?Number(o?.rx_bits_per_second)+Number(o?.tx_bits_per_second):null,w=[...j?.traffic_history.samples??[]].reverse().find(t=>t.rx_bps!==null||t.tx_bps!==null),J=w?.timestamp?Date.parse(w.timestamp):Number.NaN,fe=Math.max(45e3,(j?.traffic_history.bucket_seconds??15)*2500),ue=!!(w&&(!Number.isFinite(J)||Date.now()-J>fe)),E=!!(j&&l.isError),Y=l.dataUpdatedAt?new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(l.dataUpdatedAt):"—",xe=(()=>{if(E||ue)return{tone:"stale",label:"Данные устарели"};if(!w)return{tone:"offline",label:"Нет свежих данных"};if(!K)return{tone:"degraded",label:n?"Нет полной текущей точки":"Текущие данные неполные"};if(n){const t=k(n);return t==="offline"?{tone:"offline",label:"Нода недоступна"}:t==="degraded"?{tone:"degraded",label:"Нода деградирует"}:{tone:"online",label:"Онлайн"}}return(o?.nodes_online??0)===0?{tone:"offline",label:"Ноды недоступны"}:(o?.nodes_degraded??0)>0||(o?.nodes_offline??0)>0?{tone:"degraded",label:"Частично доступно"}:{tone:"online",label:"Онлайн"}})(),me=E?`Нет связи · последние данные ${Y}`:l.isFetching?"Обновление…":`Обновлено ${Y}`;return l.isError&&ge(l.error)?e.jsx(Ne,{onSuccess:()=>l.refetch()}):e.jsxs("main",{className:"nf-page nf-traffic-page",children:[e.jsxs("header",{className:"nf-page-header nf-traffic-page__header",children:[e.jsxs("div",{children:[e.jsx("h1",{children:"Трафик"}),Ie()&&e.jsx("span",{className:"nf-demo-badge",children:"Демо-данные"})]}),e.jsxs("div",{className:"nf-page-tools nf-traffic-page__tools",children:[e.jsx($e,{className:"nf-traffic-page__scope",value:i??"all",onChange:t=>S("node",t==="all"?void 0:t??void 0),data:[{value:"all",label:"Все ноды"},...h.map(t=>({value:t.node.id,label:t.node.name}))],allowDeselect:!1,searchable:!0,"aria-label":"Источник статистики трафика",leftSection:e.jsx(Z,{size:16}),disabled:!h.length}),e.jsx(ye,{variant:"default",size:"lg",onClick:()=>l.refetch(),loading:l.isFetching,"aria-label":"Обновить статистику трафика",children:e.jsx(Pe,{size:18})})]})]}),g&&e.jsxs("div",{className:"nf-traffic-page__recovery",role:"status",children:["Выбранная нода больше недоступна. Показан общий трафик всех нод.",e.jsx("button",{type:"button",onClick:()=>x(!1),"aria-label":"Скрыть уведомление",children:"Скрыть"})]}),l.isPending||$?e.jsx(qe,{}):l.isError&&!j?e.jsx(X,{title:"Не удалось загрузить трафик",description:l.error instanceof Error?l.error.message:"Panel API недоступен",tone:"error",action:e.jsx(Se,{onClick:()=>l.refetch()})}):!j||!h.length?e.jsx(X,{title:"Нет данных о трафике",description:"Сначала добавьте ноду и дождитесь первого сигнала Node Agent."}):e.jsxs(e.Fragment,{children:[e.jsxs(z,{className:"nf-traffic-page__workspace",children:[e.jsxs("section",{className:"nf-traffic-page__chart","aria-labelledby":"traffic-chart-title",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("h2",{id:"traffic-chart-title",children:"Трафик HAProxy"}),e.jsxs("p",{children:[M," · RX и TX"]})]}),e.jsxs("span",{className:`nf-traffic-page__live is-${E?"stale":"fresh"}`,role:"status","aria-live":"polite",children:[e.jsx("i",{}),me]})]}),e.jsx(Ce,{samples:j.traffic_history.samples,range:_,onRangeChange:t=>S("range",t),currentRx:L,currentTx:F,status:xe})]}),e.jsx(Ue,{routes:j.top_routes,scopeLabel:M,range:_})]}),e.jsxs(z,{className:"nf-traffic-page__summary","aria-label":`Сводка: ${M}`,children:[e.jsxs("div",{className:"nf-traffic-summary-cell is-scope",children:[e.jsx(Z,{}),e.jsx("span",{children:"Источник"}),e.jsx("strong",{children:M}),e.jsx("small",{children:n?n.node.address:`${h.length} нод`})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(O,{}),e.jsx("span",{children:"RX сейчас"}),e.jsx("strong",{children:v(L)}),e.jsx("small",{children:W})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(H,{}),e.jsx("span",{children:"TX сейчас"}),e.jsx("strong",{children:v(F)}),e.jsx("small",{children:W})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(Te,{}),e.jsx("span",{children:"Трафик за месяц"}),e.jsx("strong",{children:R(ie)}),e.jsx("small",{children:V>0?`лимит ${R(V)}`:n?"без лимита":"без общего лимита"})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(Ee,{}),e.jsx("span",{children:"Соединения"}),e.jsx("strong",{children:U(oe)}),e.jsxs("small",{children:[U(de)," маршрутов"]})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(Fe,{}),e.jsx("span",{children:"Backend health"}),e.jsx("strong",{children:Q===null?"—":`${Q}%`}),e.jsxs("small",{children:[f.healthy," работают · ",f.degraded+f.unavailable," требуют внимания"]})]})]}),e.jsxs(z,{className:"nf-traffic-page__nodes",title:"Трафик по нодам",description:"Сравнение текущей скорости и месячного объёма",children:[e.jsxs("div",{className:"nf-traffic-page__node-toolbar",children:[e.jsx("div",{className:"nf-traffic-page__status-tabs",role:"group","aria-label":"Фильтр состояния нод",children:[["all","Все",h.length],["online","Работают",C.online],["degraded","Деградируют",C.degraded],["offline","Недоступны",C.offline]].map(([t,c,b])=>e.jsxs("button",{type:"button",className:p===t?"is-active":"",onClick:()=>s(t),"aria-pressed":p===t,children:[c,e.jsx("span",{children:b})]},t))}),e.jsx(ke,{value:d,onChange:t=>u(t.currentTarget.value),placeholder:"Имя или IP ноды...",leftSection:e.jsx(Re,{size:16}),"aria-label":"Поиск ноды в статистике"})]}),T.length?e.jsx(Be,{nodes:T,selectedNodeId:i,totalRate:he,totalMonthBytes:o?.traffic_month_bytes??0,onSelect:t=>S("node",t)}):e.jsx(X,{title:"Ноды не найдены",description:"Измените строку поиска или фильтр состояния."})]})]})]})}export{ts as TrafficPage}; +import{c as te,u as ne,a as ae,d as re,j as e,L as D,B as je,h as pe,r as y,an as be,i as ge,e as Ne,A as ye}from"./index-fgrXogF6.js";import{b as U,f as v,a as R,t as ve,d as $e,S as X,R as Se,c as z,T as ke}from"./format-DGDz36zr.js";import{T as Ce,I as Te,a as Re,S as B}from"./TrafficChart-84ShhOyf.js";import{i as le}from"./interaction-BrakVCuN.js";import{I as O,a as H}from"./IconArrowUp-DwKi77Ll.js";import{u as Me,a as we,i as Ie}from"./useTrafficOverview-CPWkIFeU.js";import{a as Z,I as Pe}from"./IconServer-DmZ16e5j.js";import"./chart-react-C4b8adjg.js";import"./chart-engine-Dbh3Q7E_.js";import"./chart-renderer-CWmX7Ukt.js";const Le=[["path",{d:"M3 12h4.5l1.5 -6l4 12l2 -9l1.5 3h4.5",key:"svg-0"}]],Fe=te("outline","activity-heartbeat","ActivityHeartbeat",Le);const Ae=[["path",{d:"M7 12l5 5l-1.5 1.5a3.536 3.536 0 1 1 -5 -5l1.5 -1.5",key:"svg-0"}],["path",{d:"M17 12l-5 -5l1.5 -1.5a3.536 3.536 0 1 1 5 5l-1.5 1.5",key:"svg-1"}],["path",{d:"M3 21l2.5 -2.5",key:"svg-2"}],["path",{d:"M18.5 5.5l2.5 -2.5",key:"svg-3"}],["path",{d:"M10 11l-2 2",key:"svg-4"}],["path",{d:"M13 14l-2 2",key:"svg-5"}]],Ee=te("outline","plug-connected","PlugConnected",Ae);function k(a){const r=String(a.node.status??"").toLowerCase();return r==="online"?"online":r==="degraded"?"degraded":"offline"}const Xe={online:"Работает",degraded:"Деградирует",offline:"Недоступна"};function ze(a){const r=Number(a.node.metadata?.traffic_limit_bytes);return Number.isFinite(r)&&r>0?r:0}function Be({nodes:a,selectedNodeId:r,totalRate:m,totalMonthBytes:_,onSelect:i}){const d=ne(),u=ae(),p=re(d.search);return e.jsx("div",{className:"nf-traffic-nodes-table",children:e.jsxs("table",{children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Статус"}),e.jsx("th",{children:"Нода"}),e.jsx("th",{children:"Маршруты"}),e.jsx("th",{children:"Соединения"}),e.jsx("th",{children:"RX / TX"}),e.jsx("th",{children:"Трафик за месяц"}),e.jsx("th",{children:"Последняя точка"}),e.jsx("th",{children:e.jsx("span",{className:"nf-visually-hidden",children:"Выбрать источник графика"})})]})}),e.jsx("tbody",{children:a.map(s=>{const g=k(s),x=s.rate_sampled_at?s.rx_bits_per_second:null,l=s.rate_sampled_at?s.tx_bits_per_second:null,j=Number.isFinite(x)&&Number.isFinite(l)?Number(x)+Number(l):null,h=j!==null&&m!==null&&m>0?j/m*100:null,n=ze(s),$=_>0?s.traffic_used_bytes/_*100:0,S=n>0?s.traffic_used_bytes/n*100:0,C=Math.max(0,Math.min(100,n>0?S:$)),T=s.latest_heartbeat?.metrics.haproxy_runtime?.connections_current,o=g!=="offline"&&Number.isFinite(T)?Number(T):null,N=r===s.node.id;return e.jsxs("tr",{className:`is-${g}${N?" is-selected":""}`,tabIndex:0,"aria-label":`Открыть ноду ${s.node.name}`,onClick:f=>{le(f.target,f.currentTarget)||u(`/nodes/${s.node.id}${p}`)},onKeyDown:f=>{f.key==="Enter"&&f.target===f.currentTarget&&u(`/nodes/${s.node.id}${p}`)},children:[e.jsx("td",{"data-label":"Статус",children:e.jsxs("span",{className:"nf-traffic-node-state",children:[e.jsx("i",{}),Xe[g]]})}),e.jsx("td",{"data-label":"Нода",children:e.jsxs(D,{className:"nf-traffic-node-name",to:`/nodes/${s.node.id}${p}`,children:[e.jsx("strong",{children:s.node.name}),e.jsx("span",{children:s.node.address})]})}),e.jsxs("td",{"data-label":"Маршруты",children:[e.jsx("strong",{children:s.routes_enabled}),e.jsxs("span",{className:"nf-traffic-cell-muted",children:[" из ",s.routes_total]})]}),e.jsx("td",{"data-label":"Соединения",children:e.jsx("strong",{children:U(o)})}),e.jsx("td",{"data-label":"RX / TX",children:e.jsxs("div",{className:"nf-traffic-node-rate",children:[e.jsxs("span",{children:[e.jsx(O,{size:13}),v(x)]}),e.jsxs("span",{children:[e.jsx(H,{size:13}),v(l)]})]})}),e.jsx("td",{"data-label":"Трафик за месяц",children:e.jsxs("div",{className:"nf-traffic-node-volume",children:[e.jsx("strong",{children:s.traffic_observed?`${R(s.traffic_used_bytes)}${n>0?` / ${R(n)}`:""}`:"—"}),s.traffic_observed&&e.jsx("i",{"aria-hidden":"true",children:e.jsx("em",{style:{transform:`scaleX(${C/100})`}})}),e.jsx("span",{children:s.traffic_observed?n>0?`${Math.round(S)}% квоты`:`${Math.round($)}% общего объёма`:"Нет данных за месяц"})]})}),e.jsx("td",{"data-label":"Последняя точка",children:s.rate_sampled_at?e.jsx("time",{dateTime:s.rate_sampled_at,children:ve(s.rate_sampled_at)}):"Нет точки"}),e.jsx("td",{children:e.jsx(je,{variant:N?"light":"subtle",color:"nodeflow",size:"compact-sm",leftSection:e.jsx(pe,{size:15}),onClick:()=>i(N?void 0:s.node.id),"aria-pressed":N,"aria-label":N?`Вернуть общий график вместо ${s.node.name}`:h===null?`Показать трафик ноды ${s.node.name}, текущая скорость недоступна`:`Показать трафик ноды ${s.node.name}, сейчас ${Math.round(h)}% общей скорости`,children:N?"Общий":"На график"})})]},s.node.id)})})]})})}function ee(a){return a.fallback?"Любой TCP":a.snis.length?`SNI ${a.snis.join(", ")}`:"IP назначения"}const De={"1m":"1 мин","5m":"5 мин","1h":"1 ч","24h":"24 ч","7d":"7 д","30d":"30 д"};function Ue({routes:a,scopeLabel:r,range:m}){const _=ne(),i=ae(),d=re(_.search),[u,p]=y.useState(!1);return e.jsxs("section",{className:"nf-traffic-routes","aria-labelledby":"traffic-routes-title",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("h2",{id:"traffic-routes-title",children:"Топ маршрутов"}),e.jsxs("p",{children:["Средняя RX + TX · ",r," · ",De[m]]})]}),e.jsx("span",{children:a.length||"—"})]}),e.jsxs("div",{className:"nf-traffic-routes__head","aria-hidden":"true",children:[e.jsx("span",{children:"#"}),e.jsx("span",{children:"Маршрут"}),e.jsx("span",{children:"Нода"}),e.jsx("span",{children:"Скорость"}),e.jsx("span",{children:"Доля"})]}),a.length?e.jsxs("ol",{children:[a.map((s,g)=>e.jsxs("li",{className:g>=3&&!u?"is-mobile-collapsed":"",tabIndex:0,"aria-label":`Редактировать маршрут ${s.name}`,onClick:x=>{le(x.target,x.currentTarget)||i(`/nodes/${s.node_id}/routes/${s.route_id}/edit${d}`)},onKeyDown:x=>{x.key==="Enter"&&x.target===x.currentTarget&&i(`/nodes/${s.node_id}/routes/${s.route_id}/edit${d}`)},children:[e.jsx("span",{className:"nf-traffic-routes__index",children:g+1}),e.jsxs("div",{className:"nf-traffic-routes__identity",children:[e.jsx(D,{to:`/nodes/${s.node_id}/routes/${s.route_id}/edit${d}`,title:s.name,children:s.name}),e.jsxs("small",{title:`${s.node_name} · ${ee(s)} · ${s.listener_ip||"*"}:${s.listener_port}`,children:[s.node_name," · ",ee(s)," · ",s.listener_ip||"*",":",s.listener_port]}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("em",{style:{transform:`scaleX(${Math.max(3,Math.min(100,s.share_percent))/100})`}})})]}),e.jsx(D,{className:"nf-traffic-routes__node",to:`/nodes/${s.node_id}${d}`,children:s.node_name}),e.jsxs("div",{className:"nf-traffic-routes__rate",title:`Текущий месяц RX + TX: ${R(s.used_bytes)}`,children:[e.jsx("strong",{children:v(s.bits_per_second)}),e.jsxs("small",{children:[e.jsxs("span",{children:[e.jsx(O,{size:11}),v(s.rx_bits_per_second)]}),e.jsxs("span",{children:[e.jsx(H,{size:11}),v(s.tx_bits_per_second)]})]})]}),e.jsxs("b",{children:[Math.round(s.share_percent),"%"]})]},s.route_id)),a.length>3&&e.jsx("li",{className:"nf-traffic-routes__mobile-more",children:e.jsx("button",{type:"button",onClick:()=>p(s=>!s),children:u?"Свернуть список":`Ещё ${a.length-3} маршрута`})})]}):e.jsxs("div",{className:"nf-traffic-routes__empty",role:"status",children:[e.jsx("strong",{children:"Нет маршрутных точек"}),e.jsx("span",{children:"Скорость появится после следующего сигнала HAProxy."})]})]})}const Oe=new Set(["1m","5m","1h","24h","7d","30d"]);function He(a){const r=a.latest_heartbeat?.metrics.haproxy_runtime,m=Object.values(r?.servers??{}).flatMap(i=>Object.values(i).filter(d=>d.address===void 0||!!d.address).map(d=>d.status));return(m.length?m:Object.values(r?.backends??{}).map(i=>i.status)).reduce((i,d)=>{const u=String(d??"").toUpperCase();return u==="UP"||u==="OPEN"?i.healthy+=1:u==="DOWN"||u==="CLOSED"||u==="MAINT"?i.unavailable+=1:i.degraded+=1,i},{healthy:0,degraded:0,unavailable:0})}function se(a){const r=Number(a?.node.metadata?.traffic_limit_bytes);return Number.isFinite(r)&&r>0?r:0}function qe(){return e.jsxs("div",{className:"nf-traffic-page__skeleton","aria-label":"Загрузка статистики трафика",children:[e.jsx(B,{height:392}),e.jsx(B,{height:88}),e.jsx(B,{height:300})]})}function ts(){const[a,r]=be(),m=a.get("range"),_=m&&Oe.has(m)?m:"24h",i=a.get("node")||void 0,[d,u]=y.useState(""),[p,s]=y.useState("all"),[g,x]=y.useState(!1),l=Me(_,i),j=l.data,h=j?.nodes??[],n=h.find(t=>t.node.id===i),$=!!(i&&we(l.error));y.useEffect(()=>{$&&(x(!0),r(t=>{const c=new URLSearchParams(t);return c.delete("node"),c.has("range")||c.set("range",_),c},{replace:!0}))},[$,_,r]);const S=(t,c)=>{const b=new URLSearchParams(a);c?b.set(t,c):b.delete(t),b.has("range")||b.set("range",_),r(b,{replace:!0})},C=y.useMemo(()=>h.reduce((t,c)=>(t[k(c)]+=1,t),{online:0,degraded:0,offline:0}),[h]),T=y.useMemo(()=>{const t=d.trim().toLowerCase();return h.filter(c=>{const b=p==="all"||k(c)===p,_e=!t||`${c.node.name} ${c.node.address}`.toLowerCase().includes(t);return b&&_e})},[h,d,p]),o=j?.totals,f=(n?He(n):null)??{healthy:o?.backends_healthy??0,degraded:o?.backends_degraded??0,unavailable:o?.backends_unavailable??0},q=f.healthy+f.degraded+f.unavailable,Q=q?Math.round(f.healthy/q*100):null,I=!!n?.rate_sampled_at,P=o?.current_rate_complete===!0&&Number.isFinite(o.rx_bits_per_second)&&Number.isFinite(o.tx_bits_per_second),L=n?I&&Number.isFinite(n.rx_bits_per_second)?Number(n.rx_bits_per_second):null:P?Number(o?.rx_bits_per_second):null,F=n?I&&Number.isFinite(n.tx_bits_per_second)?Number(n.tx_bits_per_second):null:P?Number(o?.tx_bits_per_second):null,K=L!==null&&F!==null,W=K?"из HAProxy counters":n&&!I?"нет текущей точки":"неполные данные",ie=n?.traffic_used_bytes??o?.traffic_month_bytes??0,A=h.map(se),V=n?se(n):A.length&&A.every(t=>t>0)?A.reduce((t,c)=>t+c,0):0,G=n?.latest_heartbeat?.metrics.haproxy_runtime?.connections_current,ce=h.length>0&&h.every(t=>k(t)!=="offline"&&Number.isFinite(t.latest_heartbeat?.metrics.haproxy_runtime?.connections_current)),oe=n?k(n)!=="offline"&&Number.isFinite(G)?Number(G):null:ce?h.reduce((t,c)=>t+Number(c.latest_heartbeat?.metrics.haproxy_runtime?.connections_current),0):null,de=n?.routes_total??o?.routes_total??0,M=n?.node.name??"Все ноды",he=P?Number(o?.rx_bits_per_second)+Number(o?.tx_bits_per_second):null,w=[...j?.traffic_history.samples??[]].reverse().find(t=>t.rx_bps!==null||t.tx_bps!==null),J=w?.timestamp?Date.parse(w.timestamp):Number.NaN,fe=Math.max(45e3,(j?.traffic_history.bucket_seconds??15)*2500),ue=!!(w&&(!Number.isFinite(J)||Date.now()-J>fe)),E=!!(j&&l.isError),Y=l.dataUpdatedAt?new Intl.DateTimeFormat("ru-RU",{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(l.dataUpdatedAt):"—",xe=(()=>{if(E||ue)return{tone:"stale",label:"Данные устарели"};if(!w)return{tone:"offline",label:"Нет свежих данных"};if(!K)return{tone:"degraded",label:n?"Нет полной текущей точки":"Текущие данные неполные"};if(n){const t=k(n);return t==="offline"?{tone:"offline",label:"Нода недоступна"}:t==="degraded"?{tone:"degraded",label:"Нода деградирует"}:{tone:"online",label:"Онлайн"}}return(o?.nodes_online??0)===0?{tone:"offline",label:"Ноды недоступны"}:(o?.nodes_degraded??0)>0||(o?.nodes_offline??0)>0?{tone:"degraded",label:"Частично доступно"}:{tone:"online",label:"Онлайн"}})(),me=E?`Нет связи · последние данные ${Y}`:l.isFetching?"Обновление…":`Обновлено ${Y}`;return l.isError&&ge(l.error)?e.jsx(Ne,{onSuccess:()=>l.refetch()}):e.jsxs("main",{className:"nf-page nf-traffic-page",children:[e.jsxs("header",{className:"nf-page-header nf-traffic-page__header",children:[e.jsxs("div",{children:[e.jsx("h1",{children:"Трафик"}),Ie()&&e.jsx("span",{className:"nf-demo-badge",children:"Демо-данные"})]}),e.jsxs("div",{className:"nf-page-tools nf-traffic-page__tools",children:[e.jsx($e,{className:"nf-traffic-page__scope",value:i??"all",onChange:t=>S("node",t==="all"?void 0:t??void 0),data:[{value:"all",label:"Все ноды"},...h.map(t=>({value:t.node.id,label:t.node.name}))],allowDeselect:!1,searchable:!0,"aria-label":"Источник статистики трафика",leftSection:e.jsx(Z,{size:16}),disabled:!h.length}),e.jsx(ye,{variant:"default",size:"lg",onClick:()=>l.refetch(),loading:l.isFetching,"aria-label":"Обновить статистику трафика",children:e.jsx(Pe,{size:18})})]})]}),g&&e.jsxs("div",{className:"nf-traffic-page__recovery",role:"status",children:["Выбранная нода больше недоступна. Показан общий трафик всех нод.",e.jsx("button",{type:"button",onClick:()=>x(!1),"aria-label":"Скрыть уведомление",children:"Скрыть"})]}),l.isPending||$?e.jsx(qe,{}):l.isError&&!j?e.jsx(X,{title:"Не удалось загрузить трафик",description:l.error instanceof Error?l.error.message:"Panel API недоступен",tone:"error",action:e.jsx(Se,{onClick:()=>l.refetch()})}):!j||!h.length?e.jsx(X,{title:"Нет данных о трафике",description:"Сначала добавьте ноду и дождитесь первого сигнала Node Agent."}):e.jsxs(e.Fragment,{children:[e.jsxs(z,{className:"nf-traffic-page__workspace",children:[e.jsxs("section",{className:"nf-traffic-page__chart","aria-labelledby":"traffic-chart-title",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("h2",{id:"traffic-chart-title",children:"Трафик HAProxy"}),e.jsxs("p",{children:[M," · RX и TX"]})]}),e.jsxs("span",{className:`nf-traffic-page__live is-${E?"stale":"fresh"}`,role:"status","aria-live":"polite",children:[e.jsx("i",{}),me]})]}),e.jsx(Ce,{samples:j.traffic_history.samples,range:_,onRangeChange:t=>S("range",t),currentRx:L,currentTx:F,status:xe})]}),e.jsx(Ue,{routes:j.top_routes,scopeLabel:M,range:_})]}),e.jsxs(z,{className:"nf-traffic-page__summary","aria-label":`Сводка: ${M}`,children:[e.jsxs("div",{className:"nf-traffic-summary-cell is-scope",children:[e.jsx(Z,{}),e.jsx("span",{children:"Источник"}),e.jsx("strong",{children:M}),e.jsx("small",{children:n?n.node.address:`${h.length} нод`})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(O,{}),e.jsx("span",{children:"RX сейчас"}),e.jsx("strong",{children:v(L)}),e.jsx("small",{children:W})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(H,{}),e.jsx("span",{children:"TX сейчас"}),e.jsx("strong",{children:v(F)}),e.jsx("small",{children:W})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(Te,{}),e.jsx("span",{children:"Трафик за месяц"}),e.jsx("strong",{children:R(ie)}),e.jsx("small",{children:V>0?`лимит ${R(V)}`:n?"без лимита":"без общего лимита"})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(Ee,{}),e.jsx("span",{children:"Соединения"}),e.jsx("strong",{children:U(oe)}),e.jsxs("small",{children:[U(de)," маршрутов"]})]}),e.jsxs("div",{className:"nf-traffic-summary-cell",children:[e.jsx(Fe,{}),e.jsx("span",{children:"Backend health"}),e.jsx("strong",{children:Q===null?"—":`${Q}%`}),e.jsxs("small",{children:[f.healthy," работают · ",f.degraded+f.unavailable," требуют внимания"]})]})]}),e.jsxs(z,{className:"nf-traffic-page__nodes",title:"Трафик по нодам",description:"Сравнение текущей скорости и месячного объёма",children:[e.jsxs("div",{className:"nf-traffic-page__node-toolbar",children:[e.jsx("div",{className:"nf-traffic-page__status-tabs",role:"group","aria-label":"Фильтр состояния нод",children:[["all","Все",h.length],["online","Работают",C.online],["degraded","Деградируют",C.degraded],["offline","Недоступны",C.offline]].map(([t,c,b])=>e.jsxs("button",{type:"button",className:p===t?"is-active":"",onClick:()=>s(t),"aria-pressed":p===t,children:[c,e.jsx("span",{children:b})]},t))}),e.jsx(ke,{value:d,onChange:t=>u(t.currentTarget.value),placeholder:"Имя или IP ноды...",leftSection:e.jsx(Re,{size:16}),"aria-label":"Поиск ноды в статистике"})]}),T.length?e.jsx(Be,{nodes:T,selectedNodeId:i,totalRate:he,totalMonthBytes:o?.traffic_month_bytes??0,onSelect:t=>S("node",t)}):e.jsx(X,{title:"Ноды не найдены",description:"Измените строку поиска или фильтр состояния."})]})]})]})}export{ts as TrafficPage}; diff --git a/internal/panel/web_dist/assets/demo-42aef_vS.js b/internal/panel/web_dist/assets/demo-k0hjezoN.js similarity index 50% rename from internal/panel/web_dist/assets/demo-42aef_vS.js rename to internal/panel/web_dist/assets/demo-k0hjezoN.js index 9f96c14..a5006b9 100644 --- a/internal/panel/web_dist/assets/demo-42aef_vS.js +++ b/internal/panel/web_dist/assets/demo-k0hjezoN.js @@ -1 +1 @@ -const b=Date.now(),w=new Date().toISOString().slice(0,7),B=[["dev-node-01","203.0.113.11",128,3842,23,41,412e6,256e6,12.4*1099511627776,20*1099511627776],["edge-msk-01","203.0.113.21",96,2911,31,48,298e6,184e6,10.7*1099511627776,20*1099511627776],["edge-spb-02","203.0.113.22",84,2374,27,44,236e6,152e6,9.3*1099511627776,20*1099511627776],["relay-de-01","198.51.100.31",64,2189,19,39,152e6,98e6,7.6*1099511627776,15*1099511627776],["relay-nl-01","198.51.100.32",58,1642,17,36,98e6,64e6,4.9*1099511627776,10*1099511627776],["backup-ru-01","192.0.2.41",42,1150,15,33,44e6,26e6,3.5*1099511627776,10*1099511627776]];function g(t){return`00000000-0000-4000-8000-${String(t).padStart(12,"0")}`}function O(t,e,n){return{range:"24h",bucket_seconds:1800,samples:Array.from({length:49},(s,o)=>{const r=o/48,h=r<.5?r*1.5:.75-(r-.5)*.5,d=Math.sin(o*.9+t)*.08+Math.sin(o*.23)*.12;return{timestamp:new Date(b-(48-o)*30*60*1e3).toISOString(),rx_bps:Math.max(0,e*(.48+h+d)),tx_bps:Math.max(0,n*(.4+h*.36+d*.35))}})}}function D(t,e,n=443){const a=["api.internal","cdn.video","storage-backup","update.service","metrics.internal"],s=a[t%a.length],o=t%a.length===2;return{id:g(1e3+e*200+t),node_id:g(e+1),name:s,version:1,listener_ip:"*",listener_port:n,match_mode:o?"any_tcp":"sni",snis:o?[]:[`${s}.example.com`],fallback:o,hostname:o?"":`${s}.example.com`,target_type:"tcp",dns_pool:!1,target_host:`10.20.${e}.${8+t}`,target_port:n,unix_socket_path:"",health_check:!0,proxy_protocol:t%3===0?"v2":"none",quota_bytes:null,quota_action:"observe",quota_period:"calendar_month",client_upload_mbps:null,client_download_mbps:null,enabled:!0,deployed:!0,deployment_state:"active",...R(t,e,s,n)}}function i(t,e,n,a,s,o={}){return{id:`${t.slice(0,-2)}${String(e).padStart(2,"0")}`,route_id:t,position:e,name:n,target_type:"tcp",host:a,port:s,unix_socket_path:"",backup:o.backup??!1,dns_pool:o.dnsPool??!1,preferred_ip:"",weight:o.weight??0,cost:o.cost??0,ip_weights:o.ipWeights??[]}}function R(t,e,n,a){const s=g(1e3+e*200+t);return t===0?{balance_mode:"pool",balance_algorithm:"roundrobin",sticky_enabled:!1,sticky_mode:"none",sticky_ttl:"",servers:[i(s,1,"main",`10.20.${e}.10`,a,{weight:150}),i(s,2,"aux",`10.20.${e}.11`,a,{weight:50})]}:t===1?{balance_mode:"pool",balance_algorithm:"random",balance_random_draws:2,sticky_enabled:!0,sticky_mode:"source_table",sticky_ttl:"15m",sticky_table_entries:"10k",servers:[i(s,1,"fra",`10.20.${e}.51`,a),i(s,2,"ams",`10.20.${e}.52`,a),i(s,3,"waw",`10.20.${e}.53`,a)]}:t===2?{balance_mode:"pool",balance_algorithm:"leastping",leastping_tolerance:.2,balance_tolerance:.2,leastping_tolerance_ms:50,sticky_enabled:!1,sticky_mode:"none",sticky_ttl:"",health_check:!0,servers:[i(s,1,"fast",`10.20.${e}.71`,a,{cost:1}),i(s,2,"slow",`10.20.${e}.72`,a,{cost:1.8}),i(s,3,"edge",`edge-pool.${n}.example.com`,a,{dnsPool:!0,ipWeights:[{ip:"203.0.113.40",weight:0,cost:2.5},{ip:"203.0.113.41",weight:60,cost:.8}]})]}:t===3?{balance_mode:"pool",sticky_enabled:!0,sticky_mode:"source",sticky_hash:"",servers:[i(s,1,"edge",`edge-pool.${n}.example.com`,a,{dnsPool:!0,ipWeights:[{ip:"203.0.113.40",weight:200},{ip:"203.0.113.41",weight:50}]}),i(s,2,"origin",`10.20.${e}.40`,a)]}:{balance_mode:"pool",balance_algorithm:"leastconn",balance_tolerance:.2,leastping_tolerance:.2,sticky_enabled:!1,sticky_mode:"none",sticky_ttl:"",slowstart:"60s",health_check:!0,servers:[i(s,1,"main-a",`10.20.${e}.61`,a),i(s,2,"main-b",`10.20.${e}.62`,a,{cost:2})]}}function I(t,e){const[n,a,s,o,r,h,d,k,_,S]=t,l={id:g(e+1),name:n,address:a,status:"online",metadata:{traffic_limit_bytes:S},last_seen_at:new Date(b-8e3-e*1100).toISOString(),created_at:new Date(b-14*864e5).toISOString(),updated_at:new Date(b-8e3).toISOString()},$=Object.fromEntries(Array.from({length:Math.min(s,5)},(f,c)=>[`nf_be_${String(e)}_${c}`,{status:"UP",sessions_current:Math.round(o/Math.min(s,5)),sessions_total:o*120,session_rate:Math.max(1,Math.round(o/380))}])),p={node:l,haproxy_control:{node_id:l.id,supported:!0,desired_enabled:!0,generation:1,restart_generation:1,actual_enabled:!0,active_state:"active",report_generation:1,reported_at:l.last_seen_at,updated_at:l.updated_at},routes_total:s,routes_enabled:s,traffic_month:w,traffic_bytes_in:Math.round(_*.64),traffic_bytes_out:Math.round(_*.36),traffic_used_bytes:Math.round(_),traffic_observed:!0,latest_heartbeat:{agent_version:e===0?"2.0.0":"1.0.5",status:"online",received_at:l.last_seen_at,routes_ok:!0,metrics:{os:"linux",arch:"amd64",cpu_count:e<3?8:4,cpu_percent:r,load:[r/28,r/31,r/34],memory_total_bytes:8*1073741824,memory_available_bytes:8*1073741824*(1-h/100),network_bytes_per_second:{eth0_rx:d/8,eth0_tx:k/8},haproxy_version:"3.4.2-1ppa1~noble",haproxy_stats_available:!0,haproxy_runtime:{connections_current:o,connections_total:o*220,connection_rate:Math.max(1,Math.round(o/340)),backends:$}}}},m=Array.from({length:Math.min(s,5)},(f,c)=>D(c,e,c===2?10065:443)),M=m.map((f,c)=>({route_id:f.id,backend_key:`nf_be_${String(e)}_${c}`,bytes_in:Math.round(_*(.3-c*.035)/m.length),bytes_out:Math.round(_*(.18-c*.018)/m.length),used_bytes:Math.round(_*(.48-c*.053)/m.length),quota_used_bytes:0,limit_bytes:null,reached:!1,observed:!0,applied:!0})),T={node_id:l.id,month:w,bytes_in:p.traffic_bytes_in,bytes_out:p.traffic_bytes_out,used_bytes:p.traffic_used_bytes,enforcement:!1,routes:M};return{node:l,operational:p,routes:m,traffic:T,history:O(e,d,k)}}const C=B.map(I),u=new Map,y="nodeflow.demo.routes.v1";function v(){if(!u.size)try{const t=globalThis.sessionStorage?.getItem(y);if(!t)return;const e=JSON.parse(t);Object.entries(e).forEach(([n,a])=>{u.set(n,new Map(a.map(s=>[s.id,s])))})}catch{globalThis.sessionStorage?.removeItem(y)}}function N(){try{globalThis.sessionStorage?.setItem(y,JSON.stringify(Object.fromEntries([...u].map(([t,e])=>[t,[...e.values()]]))))}catch{}}function A(t){return v(),[...u.get(t)?.values()??[]].map(e=>structuredClone(e))}function W(t,e){const n=A(t),a=new Map(n.map(r=>[r.id,r])),s=e.map(r=>a.get(r.id)??r),o=new Set(e.map(r=>r.id));return[...s,...n.filter(r=>!o.has(r.id))]}function q(t,e){v();const n=u.get(t)??new Map;n.set(e.id,structuredClone({...e,node_id:t})),u.set(t,n),N()}async function P(t){await new Promise(o=>globalThis.setTimeout(o,380));const e=t.trim().toLowerCase().replace(/\.$/,""),n=new Date().toISOString();if(!e||e.endsWith(".invalid")||e.startsWith("nx."))return{host:e,addresses:[],resolved_at:n,error:"NXDOMAIN: домен не найден"};let a=0;for(const o of e)a=(a*31+o.charCodeAt(0))%200;const s=20+a%180;return{host:e,addresses:[`203.0.113.${s}`,`203.0.113.${s+1}`,`198.51.100.${s}`,`2001:db8:${s.toString(16)}::10`],resolved_at:n}}export{C as demoNodeBundles,P as demoResolveDNS,A as demoRoutesForNode,W as mergeDemoRoutes,q as upsertDemoRoute}; +const b=Date.now(),w=new Date().toISOString().slice(0,7),B=[["dev-node-01","203.0.113.11",128,3842,23,41,412e6,256e6,12.4*1099511627776,20*1099511627776],["edge-msk-01","203.0.113.21",96,2911,31,48,298e6,184e6,10.7*1099511627776,20*1099511627776],["edge-spb-02","203.0.113.22",84,2374,27,44,236e6,152e6,9.3*1099511627776,20*1099511627776],["relay-de-01","198.51.100.31",64,2189,19,39,152e6,98e6,7.6*1099511627776,15*1099511627776],["relay-nl-01","198.51.100.32",58,1642,17,36,98e6,64e6,4.9*1099511627776,10*1099511627776],["backup-ru-01","192.0.2.41",42,1150,15,33,44e6,26e6,3.5*1099511627776,10*1099511627776]];function g(t){return`00000000-0000-4000-8000-${String(t).padStart(12,"0")}`}function O(t,e,n){return{range:"24h",bucket_seconds:1800,samples:Array.from({length:49},(s,o)=>{const r=o/48,h=r<.5?r*1.5:.75-(r-.5)*.5,d=Math.sin(o*.9+t)*.08+Math.sin(o*.23)*.12;return{timestamp:new Date(b-(48-o)*30*60*1e3).toISOString(),rx_bps:Math.max(0,e*(.48+h+d)),tx_bps:Math.max(0,n*(.4+h*.36+d*.35))}})}}function D(t,e,n=443){const a=["api.internal","cdn.video","storage-backup","update.service","metrics.internal"],s=a[t%a.length],o=t%a.length===2;return{id:g(1e3+e*200+t),node_id:g(e+1),name:s,version:1,listener_ip:"*",listener_port:n,match_mode:o?"any_tcp":"sni",snis:o?[]:[`${s}.example.com`],fallback:o,hostname:o?"":`${s}.example.com`,target_type:"tcp",dns_pool:!1,target_host:`10.20.${e}.${8+t}`,target_port:n,unix_socket_path:"",health_check:!0,proxy_protocol:t%3===0?"v2":"none",quota_bytes:null,quota_action:"observe",quota_period:"calendar_month",client_upload_mbps:null,client_download_mbps:null,enabled:!0,deployed:!0,deployment_state:"active",...R(t,e,s,n)}}function i(t,e,n,a,s,o={}){return{id:`${t.slice(0,-2)}${String(e).padStart(2,"0")}`,route_id:t,position:e,name:n,target_type:"tcp",host:a,port:s,unix_socket_path:"",backup:o.backup??!1,dns_pool:o.dnsPool??!1,preferred_ip:"",weight:o.weight??0,cost:o.cost??0,ip_weights:o.ipWeights??[]}}function R(t,e,n,a){const s=g(1e3+e*200+t);return t===0?{balance_mode:"pool",balance_algorithm:"roundrobin",sticky_enabled:!1,sticky_mode:"none",sticky_ttl:"",servers:[i(s,1,"main",`10.20.${e}.10`,a,{weight:150}),i(s,2,"aux",`10.20.${e}.11`,a,{weight:50})]}:t===1?{balance_mode:"pool",balance_algorithm:"random",balance_random_draws:2,sticky_enabled:!0,sticky_mode:"source_table",sticky_ttl:"15m",sticky_table_entries:"10k",servers:[i(s,1,"fra",`10.20.${e}.51`,a),i(s,2,"ams",`10.20.${e}.52`,a),i(s,3,"waw",`10.20.${e}.53`,a)]}:t===2?{balance_mode:"pool",balance_algorithm:"leastping",leastping_tolerance:.2,balance_tolerance:.2,leastping_tolerance_ms:50,sticky_enabled:!1,sticky_mode:"none",sticky_ttl:"",health_check:!0,servers:[i(s,1,"fast",`10.20.${e}.71`,a,{cost:1}),i(s,2,"slow",`10.20.${e}.72`,a,{cost:1.8}),i(s,3,"edge",`edge-pool.${n}.example.com`,a,{dnsPool:!0,ipWeights:[{ip:"203.0.113.40",weight:0,cost:2.5},{ip:"203.0.113.41",weight:60,cost:.8}]})]}:t===3?{balance_mode:"pool",sticky_enabled:!0,sticky_mode:"source",sticky_hash:"",servers:[i(s,1,"edge",`edge-pool.${n}.example.com`,a,{dnsPool:!0,ipWeights:[{ip:"203.0.113.40",weight:200},{ip:"203.0.113.41",weight:50}]}),i(s,2,"origin",`10.20.${e}.40`,a)]}:{balance_mode:"pool",balance_algorithm:"leastconn",balance_tolerance:.2,leastping_tolerance:.2,sticky_enabled:!1,sticky_mode:"none",sticky_ttl:"",slowstart:"60s",health_check:!0,servers:[i(s,1,"main-a",`10.20.${e}.61`,a,{weight:2}),i(s,2,"main-b",`10.20.${e}.62`,a)]}}function I(t,e){const[n,a,s,o,r,h,d,k,_,S]=t,l={id:g(e+1),name:n,address:a,status:"online",metadata:{traffic_limit_bytes:S},last_seen_at:new Date(b-8e3-e*1100).toISOString(),created_at:new Date(b-14*864e5).toISOString(),updated_at:new Date(b-8e3).toISOString()},$=Object.fromEntries(Array.from({length:Math.min(s,5)},(f,c)=>[`nf_be_${String(e)}_${c}`,{status:"UP",sessions_current:Math.round(o/Math.min(s,5)),sessions_total:o*120,session_rate:Math.max(1,Math.round(o/380))}])),p={node:l,haproxy_control:{node_id:l.id,supported:!0,desired_enabled:!0,generation:1,restart_generation:1,actual_enabled:!0,active_state:"active",report_generation:1,reported_at:l.last_seen_at,updated_at:l.updated_at},routes_total:s,routes_enabled:s,traffic_month:w,traffic_bytes_in:Math.round(_*.64),traffic_bytes_out:Math.round(_*.36),traffic_used_bytes:Math.round(_),traffic_observed:!0,latest_heartbeat:{agent_version:e===0?"2.0.0":"1.0.5",status:"online",received_at:l.last_seen_at,routes_ok:!0,metrics:{os:"linux",arch:"amd64",cpu_count:e<3?8:4,cpu_percent:r,load:[r/28,r/31,r/34],memory_total_bytes:8*1073741824,memory_available_bytes:8*1073741824*(1-h/100),network_bytes_per_second:{eth0_rx:d/8,eth0_tx:k/8},haproxy_version:"3.4.2-1ppa1~noble",haproxy_stats_available:!0,haproxy_runtime:{connections_current:o,connections_total:o*220,connection_rate:Math.max(1,Math.round(o/340)),backends:$}}}},m=Array.from({length:Math.min(s,5)},(f,c)=>D(c,e,c===2?10065:443)),M=m.map((f,c)=>({route_id:f.id,backend_key:`nf_be_${String(e)}_${c}`,bytes_in:Math.round(_*(.3-c*.035)/m.length),bytes_out:Math.round(_*(.18-c*.018)/m.length),used_bytes:Math.round(_*(.48-c*.053)/m.length),quota_used_bytes:0,limit_bytes:null,reached:!1,observed:!0,applied:!0})),T={node_id:l.id,month:w,bytes_in:p.traffic_bytes_in,bytes_out:p.traffic_bytes_out,used_bytes:p.traffic_used_bytes,enforcement:!1,routes:M};return{node:l,operational:p,routes:m,traffic:T,history:O(e,d,k)}}const C=B.map(I),u=new Map,y="nodeflow.demo.routes.v1";function v(){if(!u.size)try{const t=globalThis.sessionStorage?.getItem(y);if(!t)return;const e=JSON.parse(t);Object.entries(e).forEach(([n,a])=>{u.set(n,new Map(a.map(s=>[s.id,s])))})}catch{globalThis.sessionStorage?.removeItem(y)}}function N(){try{globalThis.sessionStorage?.setItem(y,JSON.stringify(Object.fromEntries([...u].map(([t,e])=>[t,[...e.values()]]))))}catch{}}function A(t){return v(),[...u.get(t)?.values()??[]].map(e=>structuredClone(e))}function W(t,e){const n=A(t),a=new Map(n.map(r=>[r.id,r])),s=e.map(r=>a.get(r.id)??r),o=new Set(e.map(r=>r.id));return[...s,...n.filter(r=>!o.has(r.id))]}function q(t,e){v();const n=u.get(t)??new Map;n.set(e.id,structuredClone({...e,node_id:t})),u.set(t,n),N()}async function P(t){await new Promise(o=>globalThis.setTimeout(o,380));const e=t.trim().toLowerCase().replace(/\.$/,""),n=new Date().toISOString();if(!e||e.endsWith(".invalid")||e.startsWith("nx."))return{host:e,addresses:[],resolved_at:n,error:"NXDOMAIN: домен не найден"};let a=0;for(const o of e)a=(a*31+o.charCodeAt(0))%200;const s=20+a%180;return{host:e,addresses:[`203.0.113.${s}`,`203.0.113.${s+1}`,`198.51.100.${s}`,`2001:db8:${s.toString(16)}::10`],resolved_at:n}}export{C as demoNodeBundles,P as demoResolveDNS,A as demoRoutesForNode,W as mergeDemoRoutes,q as upsertDemoRoute}; diff --git a/internal/panel/web_dist/assets/demo-node-detail-DkbalCRs.js b/internal/panel/web_dist/assets/demo-node-detail-DYja70C8.js similarity index 96% rename from internal/panel/web_dist/assets/demo-node-detail-DkbalCRs.js rename to internal/panel/web_dist/assets/demo-node-detail-DYja70C8.js index 7249989..9cdef55 100644 --- a/internal/panel/web_dist/assets/demo-node-detail-DkbalCRs.js +++ b/internal/panel/web_dist/assets/demo-node-detail-DYja70C8.js @@ -1 +1 @@ -import{demoNodeBundles as m,mergeDemoRoutes as h}from"./demo-42aef_vS.js";function f(s,l,e){const c={"1m":6e4,"5m":3e5,"1h":36e5,"24h":864e5,"7d":6048e5,"30d":2592e6},i=s==="1m"?13:s==="5m"?21:49,o=c[s],_=o/(i-1),p=Date.now(),a=Array.from({length:i},(t,r)=>{const d=r/(i-1),u=Math.sin(r*.86)*.08+Math.sin(r*.23+.7)*.11,n=Math.exp(-Math.pow((d-.52)/.2,2))*.56;return{timestamp:new Date(p-o+r*_).toISOString(),rx_bps:Math.max(0,l*(.65+n+u)),tx_bps:Math.max(0,e*(.58+n*.28+u*.42)),cpu_percent:19+n*10+u*8,memory_percent:38+n*4+u*2}});return{range:s,bucket_seconds:Math.max(1,Math.round(_/1e3)),samples:a}}function w(s,l){const e=structuredClone(m.find(({node:a})=>a.id===s)??m[0]),c=new Date(Date.now()-8e3).toISOString();e.node.id=s,e.node.status="online",e.node.last_seen_at=c;const i=e.history?.samples.at(-1);if(e.history=f(l,i?.rx_bps??412e6,i?.tx_bps??256e6),e.operational){e.operational.node=e.node,e.operational.credential_prefix="nf_demo",e.operational.credential_last_used_at=new Date(Date.now()-12e3).toISOString(),e.operational.credential_expires_at=new Date(Date.now()+720*864e5).toISOString(),e.operational.latest_heartbeat&&(e.operational.latest_heartbeat.received_at=c);const a=e.operational.latest_heartbeat?.metrics;a&&(a.uptime_seconds=7*86400+4*3600+1260,a.process_count=138,a.process_names=["haproxy","nodeflow-node-agent","sshd","systemd"],Object.values(a.haproxy_runtime?.backends??{}).forEach((t,r)=>{t.connections_current=1284-r*168,t.tcp_sessions_current=1261-r*164,t.rx_bps=Math.max(0,198e6-r*46e6),t.tx_bps=Math.max(0,124e6-r*38e6)}),a.haproxy_runtime&&(a.haproxy_runtime.servers=Object.fromEntries(Object.keys(a.haproxy_runtime.backends??{}).map((t,r)=>{const d=r<2?2+(r===1?1:0):1;return[t,Object.fromEntries(Array.from({length:d},(u,n)=>[`srv_${n+1}`,{status:"UP",check_status:"L7OK",active:!0,sessions_current:Math.max(0,620-r*110-n*34)}]))]}))))}e.routes=e.routes.map((a,t)=>({...a,node_id:s,listener_port:t===2?10065:t===3?8443:t===4?9443:443,enabled:t!==4,deployed:t!==4,deployment_state:t===4?"draft":"active",quota_bytes:t===0?6*1024**4:t===1?3*1024**4:null})),e.routes=h(s,e.routes),e.traffic&&(e.traffic.node_id=s,e.traffic.routes=e.traffic.routes.map((a,t)=>({...a,limit_bytes:e.routes[t]?.quota_bytes??null,quota_used_bytes:e.routes[t]?.quota_bytes?a.used_bytes:a.quota_used_bytes,quota_period:e.routes[t]?.quota_period,quota_action:e.routes[t]?.quota_action,applied:e.routes[t]?.enabled??!1})));const o=Date.now(),_=[["route.enabled","Маршрут api.internal включён"],["agent.update.installed","Node Agent обновлён до 0.4.4-dev"],["firewall.port.opened","Открыт listener 10065/TCP"],["route.updated","Лимит connections изменён"],["route.created","Создан черновик draft.new-service"],["firewall.policy.updated","UFW переведён в автоматический режим"]].map(([a,t],r)=>({id:r+1,actor_type:r===1?"agent":"browser_session",actor_id:r===1?"node-agent":"operator",action:a,resource_type:a.startsWith("route")?"route":a.startsWith("firewall")?"firewall":"agent_release",details:{summary:t},source_ip:"192.0.2.2",created_at:new Date(o-r*21*6e4).toISOString()})),p=[{id:"00000000-0000-4000-8000-000000000005",version:"0.4.5-dev",os:"linux",arch:"amd64",sha256:"5d0d4c6b",size_bytes:7340032,sequence:5,signature:"verified",created_at:new Date(o-36e5).toISOString()},{id:"00000000-0000-4000-8000-000000000004",version:"0.4.4-dev",os:"linux",arch:"amd64",sha256:"8d19bd20",size_bytes:7286784,sequence:4,signature:"verified",created_at:new Date(o-864e5).toISOString()},{id:"00000000-0000-4000-8000-000000000003",version:"0.4.3-dev",os:"linux",arch:"amd64",sha256:"e73e7d79",size_bytes:7233536,sequence:3,signature:"verified",created_at:new Date(o-2*864e5).toISOString()}];return{bundle:e,firewall:{node_id:s,mode:"apply",tcp_ports:[443,8443,10065],plan_complete:!0,updated_at:new Date(o-3e4).toISOString()},update:{node_id:s,actual_sequence:4,state:"installed",last_report_at:new Date(o-18e3).toISOString(),updated_at:new Date(o-18e3).toISOString()},releases:p,audit:_,partialErrors:{}}}export{w as createDemoDetail}; +import{demoNodeBundles as m,mergeDemoRoutes as h}from"./demo-k0hjezoN.js";function f(s,l,e){const c={"1m":6e4,"5m":3e5,"1h":36e5,"24h":864e5,"7d":6048e5,"30d":2592e6},i=s==="1m"?13:s==="5m"?21:49,o=c[s],_=o/(i-1),p=Date.now(),a=Array.from({length:i},(t,r)=>{const d=r/(i-1),u=Math.sin(r*.86)*.08+Math.sin(r*.23+.7)*.11,n=Math.exp(-Math.pow((d-.52)/.2,2))*.56;return{timestamp:new Date(p-o+r*_).toISOString(),rx_bps:Math.max(0,l*(.65+n+u)),tx_bps:Math.max(0,e*(.58+n*.28+u*.42)),cpu_percent:19+n*10+u*8,memory_percent:38+n*4+u*2}});return{range:s,bucket_seconds:Math.max(1,Math.round(_/1e3)),samples:a}}function w(s,l){const e=structuredClone(m.find(({node:a})=>a.id===s)??m[0]),c=new Date(Date.now()-8e3).toISOString();e.node.id=s,e.node.status="online",e.node.last_seen_at=c;const i=e.history?.samples.at(-1);if(e.history=f(l,i?.rx_bps??412e6,i?.tx_bps??256e6),e.operational){e.operational.node=e.node,e.operational.credential_prefix="nf_demo",e.operational.credential_last_used_at=new Date(Date.now()-12e3).toISOString(),e.operational.credential_expires_at=new Date(Date.now()+720*864e5).toISOString(),e.operational.latest_heartbeat&&(e.operational.latest_heartbeat.received_at=c);const a=e.operational.latest_heartbeat?.metrics;a&&(a.uptime_seconds=7*86400+4*3600+1260,a.process_count=138,a.process_names=["haproxy","nodeflow-node-agent","sshd","systemd"],Object.values(a.haproxy_runtime?.backends??{}).forEach((t,r)=>{t.connections_current=1284-r*168,t.tcp_sessions_current=1261-r*164,t.rx_bps=Math.max(0,198e6-r*46e6),t.tx_bps=Math.max(0,124e6-r*38e6)}),a.haproxy_runtime&&(a.haproxy_runtime.servers=Object.fromEntries(Object.keys(a.haproxy_runtime.backends??{}).map((t,r)=>{const d=r<2?2+(r===1?1:0):1;return[t,Object.fromEntries(Array.from({length:d},(u,n)=>[`srv_${n+1}`,{status:"UP",check_status:"L7OK",active:!0,sessions_current:Math.max(0,620-r*110-n*34)}]))]}))))}e.routes=e.routes.map((a,t)=>({...a,node_id:s,listener_port:t===2?10065:t===3?8443:t===4?9443:443,enabled:t!==4,deployed:t!==4,deployment_state:t===4?"draft":"active",quota_bytes:t===0?6*1024**4:t===1?3*1024**4:null})),e.routes=h(s,e.routes),e.traffic&&(e.traffic.node_id=s,e.traffic.routes=e.traffic.routes.map((a,t)=>({...a,limit_bytes:e.routes[t]?.quota_bytes??null,quota_used_bytes:e.routes[t]?.quota_bytes?a.used_bytes:a.quota_used_bytes,quota_period:e.routes[t]?.quota_period,quota_action:e.routes[t]?.quota_action,applied:e.routes[t]?.enabled??!1})));const o=Date.now(),_=[["route.enabled","Маршрут api.internal включён"],["agent.update.installed","Node Agent обновлён до 0.4.4-dev"],["firewall.port.opened","Открыт listener 10065/TCP"],["route.updated","Лимит connections изменён"],["route.created","Создан черновик draft.new-service"],["firewall.policy.updated","UFW переведён в автоматический режим"]].map(([a,t],r)=>({id:r+1,actor_type:r===1?"agent":"browser_session",actor_id:r===1?"node-agent":"operator",action:a,resource_type:a.startsWith("route")?"route":a.startsWith("firewall")?"firewall":"agent_release",details:{summary:t},source_ip:"192.0.2.2",created_at:new Date(o-r*21*6e4).toISOString()})),p=[{id:"00000000-0000-4000-8000-000000000005",version:"0.4.5-dev",os:"linux",arch:"amd64",sha256:"5d0d4c6b",size_bytes:7340032,sequence:5,signature:"verified",created_at:new Date(o-36e5).toISOString()},{id:"00000000-0000-4000-8000-000000000004",version:"0.4.4-dev",os:"linux",arch:"amd64",sha256:"8d19bd20",size_bytes:7286784,sequence:4,signature:"verified",created_at:new Date(o-864e5).toISOString()},{id:"00000000-0000-4000-8000-000000000003",version:"0.4.3-dev",os:"linux",arch:"amd64",sha256:"e73e7d79",size_bytes:7233536,sequence:3,signature:"verified",created_at:new Date(o-2*864e5).toISOString()}];return{bundle:e,firewall:{node_id:s,mode:"apply",tcp_ports:[443,8443,10065],plan_complete:!0,updated_at:new Date(o-3e4).toISOString()},update:{node_id:s,actual_sequence:4,state:"installed",last_report_at:new Date(o-18e3).toISOString(),updated_at:new Date(o-18e3).toISOString()},releases:p,audit:_,partialErrors:{}}}export{w as createDemoDetail}; diff --git a/internal/panel/web_dist/assets/demo-overview-C5p3jFU5.js b/internal/panel/web_dist/assets/demo-overview-DCTL98Sj.js similarity index 95% rename from internal/panel/web_dist/assets/demo-overview-C5p3jFU5.js rename to internal/panel/web_dist/assets/demo-overview-DCTL98Sj.js index f3a7030..279ce35 100644 --- a/internal/panel/web_dist/assets/demo-overview-C5p3jFU5.js +++ b/internal/panel/web_dist/assets/demo-overview-DCTL98Sj.js @@ -1 +1 @@ -import{b as m}from"./index-Dy6W__Vz.js";import{i as b}from"./haproxy-BnB0NJ0D.js";import{demoNodeBundles as h}from"./demo-42aef_vS.js";import"./chart-react-C4b8adjg.js";const p={"1m":1250,"5m":6250,"1h":75e3,"24h":30*6e4,"7d":3.5*60*6e4,"30d":900*6e4};function d(e){const t=e.history?.samples.at(-1);return{rx:Number.isFinite(t?.rx_bps)?Number(t?.rx_bps):null,tx:Number.isFinite(t?.tx_bps)?Number(t?.tx_bps):null}}function x(e,t,i){const s=new Date(t-7e3-i*900).toISOString(),r=d(e),n=structuredClone(e.node);n.last_seen_at=s;const o=e.operational?.latest_heartbeat?structuredClone(e.operational.latest_heartbeat):void 0;return o&&(o.received_at=s),{node:n,latest_heartbeat:o,routes_total:e.operational?.routes_total??e.routes.length,routes_enabled:e.operational?.routes_enabled??e.routes.filter(c=>c.enabled).length,traffic_month:e.traffic?.month??e.operational?.traffic_month??"",traffic_bytes_in:e.traffic?.bytes_in??e.operational?.traffic_bytes_in??0,traffic_bytes_out:e.traffic?.bytes_out??e.operational?.traffic_bytes_out??0,traffic_used_bytes:e.traffic?.used_bytes??e.operational?.traffic_used_bytes??0,traffic_observed:e.operational?.traffic_observed??!!e.traffic,rx_bits_per_second:r.rx,tx_bits_per_second:r.tx,rate_sampled_at:r.rx!==null||r.tx!==null?new Date(t).toISOString():void 0}}function y(e,t,i){const s=Math.max(0,...e.map(n=>n.history?.samples.length??0)),r=p[t];return Array.from({length:s},(n,o)=>{let c=0,a=0;for(const _ of e){const l=_.history?.samples??[],f=l[Math.max(0,l.length-s+o)];c+=Number(f?.rx_bps)||0,a+=Number(f?.tx_bps)||0}return{timestamp:new Date(i-(s-1-o)*r).toISOString(),rx_bps:c,tx_bps:a}})}function g(e){const t=e.flatMap(s=>{const{rx:r,tx:n}=d(s);if(r===null||n===null)return[];const o=new Map((s.traffic?.routes??[]).map(a=>[a.route_id,a])),c=(s.traffic?.routes??[]).reduce((a,_)=>a+Number(_.used_bytes||0),0);return s.routes.map(a=>{const _=o.get(a.id),l=c>0?Number(_?.used_bytes||0)/c:1/Math.max(1,s.routes.length),f=r*l,u=n*l;return{route_id:a.id,node_id:s.node.id,node_name:s.node.name,name:a.name||a.hostname||a.snis[0]||(a.fallback?"Весь TCP-трафик":"Маршрут"),listener_ip:a.listener_ip,listener_port:a.listener_port,snis:a.snis,fallback:a.fallback,bytes_in:_?.bytes_in??0,bytes_out:_?.bytes_out??0,used_bytes:_?.used_bytes??0,rx_bits_per_second:f,tx_bits_per_second:u,bits_per_second:f+u,share_percent:0}})}),i=t.reduce((s,r)=>s+r.bits_per_second,0);return t.map(s=>({...s,share_percent:i>0?s.bits_per_second/i*100:0})).sort((s,r)=>r.bits_per_second-s.bits_per_second).slice(0,5)}function v(e){const t=e.operational?.latest_heartbeat?.metrics.haproxy_runtime,i=Object.values(t?.servers??{}).flatMap(r=>Object.values(r).filter(b).map(n=>n.status));return(i.length?i:Object.values(t?.backends??{}).map(r=>r.status)).reduce((r,n)=>{const o=String(n??"").toUpperCase();return o==="UP"||o==="OPEN"?r.healthy+=1:o==="DOWN"||o==="CLOSED"||o==="MAINT"?r.unavailable+=1:r.degraded+=1,r},{healthy:0,degraded:0,unavailable:0})}function k(e){const t={nodes_total:e.length,nodes_online:0,nodes_degraded:0,nodes_offline:0,routes_total:0,connections_current:0,rx_bits_per_second:null,tx_bits_per_second:null,current_rate_complete:!1,traffic_month_bytes:0,backends_healthy:0,backends_degraded:0,backends_unavailable:0};let i=0,s=0,r=0,n=!0;for(const o of e){const c=String(o.node.status).toLowerCase();c==="online"?t.nodes_online+=1:c==="degraded"?t.nodes_degraded+=1:t.nodes_offline+=1;const a=d(o),_=v(o);t.routes_total+=o.operational?.routes_total??o.routes.length,t.connections_current+=Number(o.operational?.latest_heartbeat?.metrics.haproxy_runtime?.connections_current)||0,c!=="offline"&&(r+=1,a.rx===null||a.tx===null?n=!1:(i+=a.rx,s+=a.tx)),t.traffic_month_bytes+=o.operational?.traffic_used_bytes??o.traffic?.used_bytes??0,t.backends_healthy+=_.healthy,t.backends_degraded+=_.degraded,t.backends_unavailable+=_.unavailable}return t.current_rate_complete=r>0&&n,t.current_rate_complete&&(t.rx_bits_per_second=i,t.tx_bits_per_second=s),t}function w(e,t){const i=Date.now(),s=structuredClone(h);if(t&&!s.some(n=>n.node.id===t))throw new m("Выбранная нода не найдена",404,"not_found");const r=t?s.filter(n=>n.node.id===t):s;return{range:e,selected_node_id:t,nodes:s.map((n,o)=>x(n,i,o)),traffic_history:{range:e,bucket_seconds:Math.max(1,Math.round(p[e]/1e3)),samples:y(r,e,i)},top_routes:g(r),totals:k(s)}}export{w as buildDemoOverview}; +import{b as m}from"./index-fgrXogF6.js";import{i as b}from"./haproxy-BnB0NJ0D.js";import{demoNodeBundles as h}from"./demo-k0hjezoN.js";import"./chart-react-C4b8adjg.js";const p={"1m":1250,"5m":6250,"1h":75e3,"24h":30*6e4,"7d":3.5*60*6e4,"30d":900*6e4};function d(e){const t=e.history?.samples.at(-1);return{rx:Number.isFinite(t?.rx_bps)?Number(t?.rx_bps):null,tx:Number.isFinite(t?.tx_bps)?Number(t?.tx_bps):null}}function x(e,t,i){const s=new Date(t-7e3-i*900).toISOString(),r=d(e),n=structuredClone(e.node);n.last_seen_at=s;const o=e.operational?.latest_heartbeat?structuredClone(e.operational.latest_heartbeat):void 0;return o&&(o.received_at=s),{node:n,latest_heartbeat:o,routes_total:e.operational?.routes_total??e.routes.length,routes_enabled:e.operational?.routes_enabled??e.routes.filter(c=>c.enabled).length,traffic_month:e.traffic?.month??e.operational?.traffic_month??"",traffic_bytes_in:e.traffic?.bytes_in??e.operational?.traffic_bytes_in??0,traffic_bytes_out:e.traffic?.bytes_out??e.operational?.traffic_bytes_out??0,traffic_used_bytes:e.traffic?.used_bytes??e.operational?.traffic_used_bytes??0,traffic_observed:e.operational?.traffic_observed??!!e.traffic,rx_bits_per_second:r.rx,tx_bits_per_second:r.tx,rate_sampled_at:r.rx!==null||r.tx!==null?new Date(t).toISOString():void 0}}function y(e,t,i){const s=Math.max(0,...e.map(n=>n.history?.samples.length??0)),r=p[t];return Array.from({length:s},(n,o)=>{let c=0,a=0;for(const _ of e){const l=_.history?.samples??[],f=l[Math.max(0,l.length-s+o)];c+=Number(f?.rx_bps)||0,a+=Number(f?.tx_bps)||0}return{timestamp:new Date(i-(s-1-o)*r).toISOString(),rx_bps:c,tx_bps:a}})}function g(e){const t=e.flatMap(s=>{const{rx:r,tx:n}=d(s);if(r===null||n===null)return[];const o=new Map((s.traffic?.routes??[]).map(a=>[a.route_id,a])),c=(s.traffic?.routes??[]).reduce((a,_)=>a+Number(_.used_bytes||0),0);return s.routes.map(a=>{const _=o.get(a.id),l=c>0?Number(_?.used_bytes||0)/c:1/Math.max(1,s.routes.length),f=r*l,u=n*l;return{route_id:a.id,node_id:s.node.id,node_name:s.node.name,name:a.name||a.hostname||a.snis[0]||(a.fallback?"Весь TCP-трафик":"Маршрут"),listener_ip:a.listener_ip,listener_port:a.listener_port,snis:a.snis,fallback:a.fallback,bytes_in:_?.bytes_in??0,bytes_out:_?.bytes_out??0,used_bytes:_?.used_bytes??0,rx_bits_per_second:f,tx_bits_per_second:u,bits_per_second:f+u,share_percent:0}})}),i=t.reduce((s,r)=>s+r.bits_per_second,0);return t.map(s=>({...s,share_percent:i>0?s.bits_per_second/i*100:0})).sort((s,r)=>r.bits_per_second-s.bits_per_second).slice(0,5)}function v(e){const t=e.operational?.latest_heartbeat?.metrics.haproxy_runtime,i=Object.values(t?.servers??{}).flatMap(r=>Object.values(r).filter(b).map(n=>n.status));return(i.length?i:Object.values(t?.backends??{}).map(r=>r.status)).reduce((r,n)=>{const o=String(n??"").toUpperCase();return o==="UP"||o==="OPEN"?r.healthy+=1:o==="DOWN"||o==="CLOSED"||o==="MAINT"?r.unavailable+=1:r.degraded+=1,r},{healthy:0,degraded:0,unavailable:0})}function k(e){const t={nodes_total:e.length,nodes_online:0,nodes_degraded:0,nodes_offline:0,routes_total:0,connections_current:0,rx_bits_per_second:null,tx_bits_per_second:null,current_rate_complete:!1,traffic_month_bytes:0,backends_healthy:0,backends_degraded:0,backends_unavailable:0};let i=0,s=0,r=0,n=!0;for(const o of e){const c=String(o.node.status).toLowerCase();c==="online"?t.nodes_online+=1:c==="degraded"?t.nodes_degraded+=1:t.nodes_offline+=1;const a=d(o),_=v(o);t.routes_total+=o.operational?.routes_total??o.routes.length,t.connections_current+=Number(o.operational?.latest_heartbeat?.metrics.haproxy_runtime?.connections_current)||0,c!=="offline"&&(r+=1,a.rx===null||a.tx===null?n=!1:(i+=a.rx,s+=a.tx)),t.traffic_month_bytes+=o.operational?.traffic_used_bytes??o.traffic?.used_bytes??0,t.backends_healthy+=_.healthy,t.backends_degraded+=_.degraded,t.backends_unavailable+=_.unavailable}return t.current_rate_complete=r>0&&n,t.current_rate_complete&&(t.rx_bits_per_second=i,t.tx_bits_per_second=s),t}function w(e,t){const i=Date.now(),s=structuredClone(h);if(t&&!s.some(n=>n.node.id===t))throw new m("Выбранная нода не найдена",404,"not_found");const r=t?s.filter(n=>n.node.id===t):s;return{range:e,selected_node_id:t,nodes:s.map((n,o)=>x(n,i,o)),traffic_history:{range:e,bucket_seconds:Math.max(1,Math.round(p[e]/1e3)),samples:y(r,e,i)},top_routes:g(r),totals:k(s)}}export{w as buildDemoOverview}; diff --git a/internal/panel/web_dist/assets/format-D6_ab21F.js b/internal/panel/web_dist/assets/format-DGDz36zr.js similarity index 99% rename from internal/panel/web_dist/assets/format-D6_ab21F.js rename to internal/panel/web_dist/assets/format-DGDz36zr.js index 7e6484e..202f15b 100644 --- a/internal/panel/web_dist/assets/format-D6_ab21F.js +++ b/internal/panel/web_dist/assets/format-DGDz36zr.js @@ -1 +1 @@ -import{r as u,O as Wt,R as kn,aG as lo,Q as co,j as w,H as wt,aH as en,s as W,y as Q,q as Y,t as We,v as tt,a4 as ze,a3 as xr,ag as ao,w as uo,aI as Cr,aJ as tn,af as fo,ak as po,o as mt,$ as mo,G as yt,ah as Rr,C as Sr,E as Bt,x as ho,K as _n,Z as xt,c as go,B as Er}from"./index-Dy6W__Vz.js";function bo(e){return Array.isArray(e)||e===null?!1:typeof e=="object"?e.type!==u.Fragment:!1}const Pr=()=>{};function Tr(e,t={active:!0}){return typeof e!="function"||!t.active?t.onKeyDown||Pr:n=>{n.key==="Escape"&&(e(n),t.onTrigger?.())}}function Le(e){const t=u.useRef(e);return u.useEffect(()=>{t.current=e}),u.useMemo(()=>((...n)=>t.current?.(...n)),[])}function Ct(e,t){const{delay:n,flushOnUnmount:o,leading:r}=typeof t=="number"?{delay:t,flushOnUnmount:!1,leading:!1}:t,i=Le(e),s=u.useRef(0),l=u.useMemo(()=>{const c=Object.assign((...a)=>{window.clearTimeout(s.current);const f=c._isFirstCall;c._isFirstCall=!1;function p(){window.clearTimeout(s.current),s.current=0,c._isFirstCall=!0}if(r&&f){i(...a);const h=()=>{p()},g=()=>{s.current!==0&&(p(),i(...a))},b=()=>{p()};c.flush=g,c.cancel=b,s.current=window.setTimeout(h,n);return}if(r&&!f){const h=()=>{s.current!==0&&(p(),i(...a))},g=()=>{p()};c.flush=h,c.cancel=g;const b=()=>{p()};s.current=window.setTimeout(b,n);return}const d=()=>{s.current!==0&&(p(),i(...a))},m=()=>{p()};c.flush=d,c.cancel=m,s.current=window.setTimeout(d,n)},{flush:()=>{},cancel:()=>{},_isFirstCall:!0});return c},[i,n,r]);return u.useEffect(()=>()=>{o?l.flush():l.cancel()},[l,o]),l}const Or=["mousedown","touchstart"];function Ar(e,t,n){const o=u.useRef(null),r=t||Or;return u.useEffect(()=>{const i=s=>{const{target:l}=s??{};if(Array.isArray(n)){const c=!document.body.contains(l)&&l?.tagName!=="HTML";n.every(f=>!!f&&!s.composedPath().includes(f))&&!c&&e(s)}else o.current&&!o.current.contains(l)&&e(s)};return r.forEach(s=>document.addEventListener(s,i)),()=>{r.forEach(s=>document.removeEventListener(s,i))}},[o,e,n]),o}function Dr({opened:e,shouldReturnFocus:t=!0}){const n=u.useRef(null),o=()=>{n.current&&"focus"in n.current&&typeof n.current.focus=="function"&&n.current?.focus({preventScroll:!0})};return Wt(()=>{let r=-1;const i=s=>{s.key==="Tab"&&window.clearTimeout(r)};return document.addEventListener("keydown",i),e?n.current=document.activeElement:t&&(r=window.setTimeout(o,10)),()=>{window.clearTimeout(r),document.removeEventListener("keydown",i)}},[e,t]),o}const Nr=/input|select|textarea|button|object/,vo="a, input, select, textarea, button, object, [tabindex]";function Lr(e){return e.style.display==="none"}function Mr(e){if(e.getAttribute("aria-hidden")||e.getAttribute("hidden")||e.getAttribute("type")==="hidden")return!1;let n=e;for(;n&&!(n===document.body||n.nodeType===11);){if(Lr(n))return!1;n=n.parentNode}return!0}function wo(e){let t=e.getAttribute("tabindex");return t===null&&(t=void 0),parseInt(t,10)}function Kt(e){const t=e.nodeName.toLowerCase(),n=!Number.isNaN(wo(e));return(Nr.test(t)&&!e.disabled||e instanceof HTMLAnchorElement&&e.href||n)&&Mr(e)}function yo(e){const t=wo(e);return(Number.isNaN(t)||t>=0)&&Kt(e)}function Ir(e){return Array.from(e.querySelectorAll(vo)).filter(yo)}function kr(e,t){const n=Ir(e);if(!n.length){t.preventDefault();return}const o=n[t.shiftKey?0:n.length-1],r=e.getRootNode();let i=o===r.activeElement||e===r.activeElement;const s=r.activeElement;if(s.tagName==="INPUT"&&s.getAttribute("type")==="radio"&&(i=n.filter(f=>f.getAttribute("type")==="radio"&&f.getAttribute("name")===s.getAttribute("name")).includes(o)),!i)return;t.preventDefault();const c=n[t.shiftKey?n.length-1:0];c&&c.focus()}function _r(e=!0){const t=u.useRef(null),n=r=>{let i=r.querySelector("[data-autofocus]");if(!i){const s=Array.from(r.querySelectorAll(vo));i=s.find(yo)||s.find(Kt)||null,!i&&Kt(r)&&(i=r)}i&&i.focus({preventScroll:!0})},o=u.useCallback(r=>{e&&r!==null&&t.current!==r&&(r?(setTimeout(()=>{r.getRootNode()&&n(r)}),t.current=r):t.current=null)},[e]);return u.useEffect(()=>{if(!e)return;t.current&&setTimeout(()=>n(t.current));const r=i=>{i.key==="Tab"&&t.current&&kr(t.current,i)};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[e]),o}function Xt(e,t){if(typeof e=="function")return e(t);typeof e=="object"&&e!==null&&"current"in e&&(e.current=t)}function Fr(...e){const t=new Map;return n=>{if(e.forEach(o=>{const r=Xt(o,n);r&&t.set(o,r)}),t.size>0)return()=>{e.forEach(o=>{const r=t.get(o);r&&typeof r=="function"?r():Xt(o,null)}),t.clear()}}}function re(...e){return u.useCallback(Fr(...e),e)}function jr(e){const t=u.useRef(void 0);return u.useEffect(()=>{t.current=e},[e]),t.current}function xo(e){const t=kn.version;return typeof kn.version!="string"||t.startsWith("18.")?e?.ref:e?.props?.ref}function ut(e,t=document){const n=t.querySelector(e);if(n)return n;const o=t.querySelectorAll("*");for(let r=0;r{},setDirection:()=>{}});function nn(){return u.useContext($r)}function St(){return typeof window<"u"}function Be(e){return Co(e)?(e.nodeName||"").toLowerCase():"#document"}function q(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function ve(e){var t;return(t=(Co(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function Co(e){return St()?e instanceof Node||e instanceof q(e).Node:!1}function V(e){return St()?e instanceof Element||e instanceof q(e).Element:!1}function fe(e){return St()?e instanceof HTMLElement||e instanceof q(e).HTMLElement:!1}function Yt(e){return!St()||typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof q(e).ShadowRoot}function Et(e){const{overflow:t,overflowX:n,overflowY:o,display:r}=ae(e);return/auto|scroll|overlay|hidden|clip/.test(t+o+n)&&r!=="inline"&&r!=="contents"}function Hr(e){return/^(table|td|th)$/.test(Be(e))}function Pt(e){try{if(e.matches(":popover-open"))return!0}catch{}try{return e.matches(":modal")}catch{return!1}}const zr=/transform|translate|scale|rotate|perspective|filter/,Vr=/paint|layout|strict|content/,Ne=e=>!!e&&e!=="none";let kt;function on(e){const t=V(e)?ae(e):e;return Ne(t.transform)||Ne(t.translate)||Ne(t.scale)||Ne(t.rotate)||Ne(t.perspective)||!Tt()&&(Ne(t.backdropFilter)||Ne(t.filter))||zr.test(t.willChange||"")||Vr.test(t.contain||"")}function Wr(e){let t=Se(e);for(;fe(t)&&!xe(t);){if(on(t))return t;if(Pt(t))return null;t=Se(t)}return null}function Tt(){return kt==null&&(kt=typeof CSS<"u"&&CSS.supports&&CSS.supports("-webkit-backdrop-filter","none")),kt}function xe(e){return/^(html|body|#document)$/.test(Be(e))}function ae(e){return q(e).getComputedStyle(e)}function Ot(e){return V(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function Se(e){if(Be(e)==="html")return e;const t=e.assignedSlot||e.parentNode||Yt(e)&&e.host||ve(e);return Yt(t)?t.host:t}function Ro(e){const t=Se(e);return xe(t)?(e.ownerDocument||e).body:fe(t)&&Et(t)?t:Ro(t)}function Ce(e,t,n){var o;t===void 0&&(t=[]),n===void 0&&(n=!0);const r=Ro(e),i=r===((o=e.ownerDocument)==null?void 0:o.body),s=q(r);if(i){const l=Ut(s);return t.concat(s,s.visualViewport||[],Et(r)?r:[],l&&n?Ce(l):[])}else return t.concat(r,Ce(r,[],n))}function Ut(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}const Br=["top","right","bottom","left"],ue=Math.min,oe=Math.max,ht=Math.round,ct=Math.floor,be=e=>({x:e,y:e}),Kr={left:"right",right:"left",bottom:"top",top:"bottom"};function So(e,t,n){return oe(e,ue(t,n))}function he(e,t){return typeof e=="function"?e(t):e}function ge(e){return e.split("-")[0]}function Ke(e){return e.split("-")[1]}function rn(e){return e==="x"?"y":"x"}function sn(e){return e==="y"?"height":"width"}function ce(e){const t=e[0];return t==="t"||t==="b"?"y":"x"}function ln(e){return rn(ce(e))}function Xr(e,t,n){n===void 0&&(n=!1);const o=Ke(e),r=ln(e),i=sn(r);let s=r==="x"?o===(n?"end":"start")?"right":"left":o==="start"?"bottom":"top";return t.reference[i]>t.floating[i]&&(s=gt(s)),[s,gt(s)]}function Yr(e){const t=gt(e);return[qt(e),t,qt(t)]}function qt(e){return e.includes("start")?e.replace("start","end"):e.replace("end","start")}const Fn=["left","right"],jn=["right","left"],Ur=["top","bottom"],qr=["bottom","top"];function Gr(e,t,n){switch(e){case"top":case"bottom":return n?t?jn:Fn:t?Fn:jn;case"left":case"right":return t?Ur:qr;default:return[]}}function Zr(e,t,n,o){const r=Ke(e);let i=Gr(ge(e),n==="start",o);return r&&(i=i.map(s=>s+"-"+r),t&&(i=i.concat(i.map(qt)))),i}function gt(e){const t=ge(e);return Kr[t]+e.slice(t.length)}function Jr(e){var t,n,o,r;return{top:(t=e.top)!=null?t:0,right:(n=e.right)!=null?n:0,bottom:(o=e.bottom)!=null?o:0,left:(r=e.left)!=null?r:0}}function cn(e){return typeof e!="number"?Jr(e):{top:e,right:e,bottom:e,left:e}}function Re(e){const{x:t,y:n,width:o,height:r}=e;return{width:o,height:r,top:n,left:t,right:t+o,bottom:n+r,x:t,y:n}}function Qr(){const e=navigator.userAgentData;return e!=null&&e.platform?e.platform:navigator.platform}function es(){const e=navigator.userAgentData;return e&&Array.isArray(e.brands)?e.brands.map(t=>{let{brand:n,version:o}=t;return n+"/"+o}).join(" "):navigator.userAgent}function ts(){return/apple/i.test(navigator.vendor)}function ns(){return Qr().toLowerCase().startsWith("mac")&&!navigator.maxTouchPoints}function os(){return es().includes("jsdom/")}const $n="data-floating-ui-focusable",rs="input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";function Hn(e){let t=e.activeElement;for(;((n=t)==null||(n=n.shadowRoot)==null?void 0:n.activeElement)!=null;){var n;t=t.shadowRoot.activeElement}return t}function Qe(e,t){if(!e||!t)return!1;const n=t.getRootNode==null?void 0:t.getRootNode();if(e.contains(t))return!0;if(n&&Yt(n)){let o=t;for(;o;){if(e===o)return!0;o=o.parentNode||o.host}}return!1}function $e(e){return"composedPath"in e?e.composedPath()[0]:e.target}function _t(e,t){if(t==null)return!1;if("composedPath"in e)return e.composedPath().includes(t);const n=e;return n.target!=null&&t.contains(n.target)}function ss(e){return e.matches("html,body")}function Me(e){return e?.ownerDocument||document}function is(e){return fe(e)&&e.matches(rs)}function ls(e){if(!e||os())return!0;try{return e.matches(":focus-visible")}catch{return!0}}function cs(e){return e?e.hasAttribute($n)?e:e.querySelector("["+$n+"]")||e:null}function ft(e,t,n){return n===void 0&&(n=!0),e.filter(r=>{var i;return r.parentId===t&&(!n||((i=r.context)==null?void 0:i.open))}).flatMap(r=>[r,...ft(e,r.id,n)])}function as(e){return"nativeEvent"in e}function Gt(e,t){const n=["mouse","pen"];return n.push("",void 0),n.includes(e)}var us=typeof document<"u",fs=function(){},me=us?u.useLayoutEffect:fs;const ds={...lo};function at(e){const t=u.useRef(e);return me(()=>{t.current=e}),t}const ps=ds.useInsertionEffect,ms=ps||(e=>e());function pe(e){const t=u.useRef(()=>{});return ms(()=>{t.current=e}),u.useCallback(function(){for(var n=arguments.length,o=new Array(n),r=0;r{const{placement:o="bottom",strategy:r="absolute",middleware:i=[],platform:s}=n,l=s.detectOverflow?s:{...s,detectOverflow:hs},c=await(s.isRTL==null?void 0:s.isRTL(t));let a=await s.getElementRects({reference:e,floating:t,strategy:r}),{x:f,y:p}=zn(a,o,c),d=o,m=0;const h={};for(let g=0;g({name:"arrow",options:e,async fn(t){const{x:n,y:o,placement:r,rects:i,platform:s,elements:l,middlewareData:c}=t,{element:a,padding:f=0}=he(e,t)||{};if(a==null)return{};const p=cn(f),d={x:n,y:o},m=ln(r),h=sn(m),g=await s.getDimensions(a),b=m==="y",v=b?"top":"left",C=b?"bottom":"right",S=b?"clientHeight":"clientWidth",x=i.reference[h]+i.reference[m]-d[m]-i.floating[h],T=d[m]-i.reference[m],R=await(s.getOffsetParent==null?void 0:s.getOffsetParent(a));let E=R?R[S]:0;(!E||!await(s.isElement==null?void 0:s.isElement(R)))&&(E=l.floating[S]||i.floating[h]);const O=x/2-T/2,_=E/2-g[h]/2-1,I=ue(p[v],_),H=ue(p[C],_),j=E-g[h]-H,M=E/2-g[h]/2+O,A=So(I,M,j),k=!c.arrow&&Ke(r)!=null&&M!==A&&i.reference[h]/2-(MA<=0)){var H,j;const A=(((H=i.flip)==null?void 0:H.index)||0)+1,k=E[A];if(k&&(!(p==="alignment"?C!==ce(k):!1)||I.every(y=>ce(y.placement)===C?y.overflows[0]>0:!0)))return{data:{index:A,overflows:I},reset:{placement:k}};let D=(j=I.filter(P=>P.overflows[0]<=0).sort((P,y)=>P.overflows[1]-y.overflows[1])[0])==null?void 0:j.placement;if(!D)switch(m){case"bestFit":{var M;const P=(M=I.filter(y=>{if(R){const N=ce(y.placement);return N===C||N==="y"}return!0}).map(y=>[y.placement,y.overflows.filter(N=>N>0).reduce((N,L)=>N+L,0)]).sort((y,N)=>y[1]-N[1])[0])==null?void 0:M[0];P&&(D=P);break}case"initialPlacement":D=l;break}if(r!==D)return{reset:{placement:D}}}return{}}}};function Vn(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function Wn(e){return Br.some(t=>e[t]>=0)}const ys=function(e){return e===void 0&&(e={}),{name:"hide",options:e,async fn(t){const{rects:n,platform:o}=t,{strategy:r="referenceHidden",...i}=he(e,t);switch(r){case"referenceHidden":{const s=await o.detectOverflow(t,{...i,elementContext:"reference"}),l=Vn(s,n.reference);return{data:{referenceHiddenOffsets:l,referenceHidden:Wn(l)}}}case"escaped":{const s=await o.detectOverflow(t,{...i,altBoundary:!0}),l=Vn(s,n.floating);return{data:{escapedOffsets:l,escaped:Wn(l)}}}default:return{}}}}};function Eo(e){const t=ue(...e.map(i=>i.left)),n=ue(...e.map(i=>i.top)),o=oe(...e.map(i=>i.right)),r=oe(...e.map(i=>i.bottom));return{x:t,y:n,width:o-t,height:r-n}}function xs(e){const t=e.slice().sort((r,i)=>r.y-i.y),n=[];let o=null;for(let r=0;ro.height/2?n.push([i]):n[n.length-1].push(i),o=i}return n.map(r=>Re(Eo(r)))}const Cs=function(e){return e===void 0&&(e={}),{name:"inline",options:e,async fn(t){const{placement:n,elements:o,rects:r,platform:i,strategy:s}=t,{padding:l=2,x:c,y:a}=he(e,t),f=Array.from(await(i.getClientRects==null?void 0:i.getClientRects(o.reference))||[]);if(!f.length)return{};const p=xs(f),d=Re(Eo(f)),m=cn(l);function h(){if(p.length===2&&(p[0].left>p[1].right||p[1].left>p[0].right)&&c!=null&&a!=null)return p.find(b=>c>b.left-m.left&&cb.top-m.top&&a=2){if(ce(n)==="y"){const R=p[0],E=p[p.length-1],O=ge(n)==="top",_=R.top,I=E.bottom,H=O?R.left:E.left,j=O?R.right:E.right;return Re({x:H,y:_,width:j-H,height:I-_})}const b=ge(n)==="left",v=oe(...p.map(R=>R.right)),C=ue(...p.map(R=>R.left)),S=p.filter(R=>b?R.left===C:R.right===v),x=S[0].top,T=S[S.length-1].bottom;return Re({x:C,y:x,width:v-C,height:T-x})}return d}const g=await i.getElementRects({reference:{getBoundingClientRect:h},floating:o.floating,strategy:s});return r.reference.x!==g.reference.x||r.reference.y!==g.reference.y||r.reference.width!==g.reference.width||r.reference.height!==g.reference.height?{reset:{rects:g}}:{}}}},Po=new Set(["left","top"]);async function Rs(e,t){const{placement:n,platform:o,elements:r}=e,i=await(o.isRTL==null?void 0:o.isRTL(r.floating)),s=ge(n),l=Ke(n),c=ce(n)==="y",a=Po.has(s)?-1:1,f=i&&c?-1:1,p=he(t,e);let{mainAxis:d,crossAxis:m,alignmentAxis:h}=typeof p=="number"?{mainAxis:p,crossAxis:0,alignmentAxis:null}:{mainAxis:p.mainAxis||0,crossAxis:p.crossAxis||0,alignmentAxis:p.alignmentAxis};return l&&typeof h=="number"&&(m=l==="end"?h*-1:h),c?{x:m*f,y:d*a}:{x:d*a,y:m*f}}const Ss=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var n,o;const{x:r,y:i,placement:s,middlewareData:l}=t,c=await Rs(t,e);return s===((n=l.offset)==null?void 0:n.placement)&&(o=l.arrow)!=null&&o.alignmentOffset?{}:{x:r+c.x,y:i+c.y,data:{...c,placement:s}}}}},Es=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){const{x:n,y:o,placement:r,platform:i}=t,{mainAxis:s=!0,crossAxis:l=!1,limiter:c={fn:C=>{let{x:S,y:x}=C;return{x:S,y:x}}},...a}=he(e,t),f={x:n,y:o},p=await i.detectOverflow(t,a),d=ce(r),m=rn(d);let h=f[m],g=f[d];const b=(C,S)=>So(S+p[C==="y"?"top":"left"],S,S-p[C==="y"?"bottom":"right"]);s&&(h=b(m,h)),l&&(g=b(d,g));const v=c.fn({...t,[m]:h,[d]:g});return{...v,data:{x:v.x-n,y:v.y-o,enabled:{[m]:s,[d]:l}}}}}},Ps=function(e){return e===void 0&&(e={}),{options:e,fn(t){var n,o;const{x:r,y:i,placement:s,rects:l,middlewareData:c}=t,{offset:a=0,mainAxis:f=!0,crossAxis:p=!0}=he(e,t),d={x:r,y:i},m=ce(s),h=rn(m);let g=d[h],b=d[m];const v=he(a,t),C=typeof v=="number"?{mainAxis:v,crossAxis:0}:{mainAxis:(n=v.mainAxis)!=null?n:0,crossAxis:(o=v.crossAxis)!=null?o:0};if(f){const T=h==="y"?"height":"width",R=l.reference[h]-l.floating[T]+C.mainAxis,E=l.reference[h]+l.reference[T]-C.mainAxis;gE&&(g=E)}if(p){var S,x;const T=h==="y"?"width":"height",R=Po.has(ge(s)),E=l.reference[m]-l.floating[T]+(R&&((S=c.offset)==null?void 0:S[m])||0)+(R?0:C.crossAxis),O=l.reference[m]+l.reference[T]+(R?0:((x=c.offset)==null?void 0:x[m])||0)-(R?C.crossAxis:0);bO&&(b=O)}return{[h]:g,[m]:b}}}},Ts=function(e){return e===void 0&&(e={}),{name:"size",options:e,async fn(t){const{placement:n,rects:o,platform:r,elements:i}=t,{apply:s=()=>{},...l}=he(e,t),c=await r.detectOverflow(t,l),a=ge(n),f=Ke(n),p=ce(n)==="y",{width:d,height:m}=o.floating;let h,g;a==="top"||a==="bottom"?(h=a,g=f===(await(r.isRTL==null?void 0:r.isRTL(i.floating))?"start":"end")?"left":"right"):(g=a,h=f==="end"?"top":"bottom");const b=m-c.top-c.bottom,v=d-c.left-c.right,C=ue(m-c[h],b),S=ue(d-c[g],v),x=t.middlewareData.shift,T=!x;let R=C,E=S;x!=null&&x.enabled.x&&(E=v),x!=null&&x.enabled.y&&(R=b),T&&!f&&(p?E=d-2*oe(c.left,c.right):R=m-2*oe(c.top,c.bottom)),await s({...t,availableWidth:E,availableHeight:R});const O=await r.getDimensions(i.floating);return d!==O.width||m!==O.height?{reset:{rects:!0}}:{}}}};function To(e){const t=ae(e);let n=parseFloat(t.width)||0,o=parseFloat(t.height)||0;const r=fe(e),i=r?e.offsetWidth:n,s=r?e.offsetHeight:o,l=ht(n)!==i||ht(o)!==s;return l&&(n=i,o=s),{width:n,height:o,$:l}}function an(e){return V(e)?e:e.contextElement}function He(e){const t=an(e);if(!fe(t))return be(1);const n=t.getBoundingClientRect(),{width:o,height:r,$:i}=To(t);let s=(i?ht(n.width):n.width)/o,l=(i?ht(n.height):n.height)/r;return(!s||!Number.isFinite(s))&&(s=1),(!l||!Number.isFinite(l))&&(l=1),{x:s,y:l}}const Os=be(0);function Oo(e){const t=q(e);return!Tt()||!t.visualViewport?Os:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function As(e,t,n){return t===void 0&&(t=!1),!!n&&t&&n===q(e)}function ke(e,t,n,o){t===void 0&&(t=!1),n===void 0&&(n=!1);const r=e.getBoundingClientRect(),i=an(e);let s=be(1);t&&(o?V(o)&&(s=He(o)):s=He(e));const l=As(i,n,o)?Oo(i):be(0);let c=(r.left+l.x)/s.x,a=(r.top+l.y)/s.y,f=r.width/s.x,p=r.height/s.y;if(i&&o){const d=q(i),m=V(o)?q(o):o;let h=d,g=Ut(h);for(;g&&m!==h;){const b=He(g),v=g.getBoundingClientRect(),C=ae(g),S=v.left+(g.clientLeft+parseFloat(C.paddingLeft))*b.x,x=v.top+(g.clientTop+parseFloat(C.paddingTop))*b.y;c*=b.x,a*=b.y,f*=b.x,p*=b.y,c+=S,a+=x,h=q(g),g=Ut(h)}}return Re({width:f,height:p,x:c,y:a})}function At(e,t){const n=Ot(e).scrollLeft;return t?t.left+n:ke(ve(e)).left+n}function Ao(e,t){const n=e.getBoundingClientRect(),o=n.left+t.scrollLeft-At(e,n),r=n.top+t.scrollTop;return{x:o,y:r}}function Ds(e){let{elements:t,rect:n,offsetParent:o,strategy:r}=e;const i=r==="fixed",s=ve(o),l=t?Pt(t.floating):!1;if(o===s||l&&i)return n;let c={scrollLeft:0,scrollTop:0},a=be(1);const f=be(0),p=fe(o);if((p||!i)&&((Be(o)!=="body"||Et(s))&&(c=Ot(o)),p)){const m=ke(o);a=He(o),f.x=m.x+o.clientLeft,f.y=m.y+o.clientTop}const d=s&&!p&&!i?Ao(s,c):be(0);return{width:n.width*a.x,height:n.height*a.y,x:n.x*a.x-c.scrollLeft*a.x+f.x+d.x,y:n.y*a.y-c.scrollTop*a.y+f.y+d.y}}function Ns(e){return e.getClientRects?Array.from(e.getClientRects()):[]}function Ls(e){const t=Ot(e),n=e.ownerDocument.body,o=oe(e.scrollWidth,e.clientWidth,n.scrollWidth,n.clientWidth),r=oe(e.scrollHeight,e.clientHeight,n.scrollHeight,n.clientHeight);let i=-t.scrollLeft+At(e);const s=-t.scrollTop;return ae(n).direction==="rtl"&&(i+=oe(e.clientWidth,n.clientWidth)-o),{width:o,height:r,x:i,y:s}}const Ms=25;function Is(e,t,n){n===void 0&&(n="viewport");const o=n==="layoutViewport",r=q(e),i=ve(e),s=r.visualViewport;let l=i.clientWidth,c=i.clientHeight,a=0,f=0;if(s){const d=!Tt()||t==="fixed";o?d||(a=-s.offsetLeft,f=-s.offsetTop):(l=s.width,c=s.height,d&&(a=s.offsetLeft,f=s.offsetTop))}if(At(i)<=0){const d=i.ownerDocument,m=d.body,h=getComputedStyle(m),g=d.compatMode==="CSS1Compat"&&parseFloat(h.marginLeft)+parseFloat(h.marginRight)||0,b=Math.abs(i.clientWidth-m.clientWidth-g),v=getComputedStyle(i).scrollbarGutter==="stable both-edges"?b/2:b;v<=Ms&&(l-=v)}return{width:l,height:c,x:a,y:f}}function ks(e,t){const n=ke(e,!0,t==="fixed"),o=n.top+e.clientTop,r=n.left+e.clientLeft,i=He(e),s=e.clientWidth*i.x,l=e.clientHeight*i.y,c=r*i.x,a=o*i.y;return{width:s,height:l,x:c,y:a}}function Bn(e,t,n){let o;if(t==="viewport"||t==="layoutViewport")o=Is(e,n,t);else if(t==="document")o=Ls(ve(e));else if(V(t))o=ks(t,n);else{const r=Oo(e);o={x:t.x-r.x,y:t.y-r.y,width:t.width,height:t.height}}return Re(o)}function _s(e,t){const n=t.get(e);if(n)return n;let o=Ce(e,[],!1).filter(l=>V(l)&&Be(l)!=="body"),r=null;const i=ae(e).position==="fixed";let s=i?Se(e):e;for(;V(s)&&!xe(s);){const l=ae(s),c=on(s),a=r?r.position:i?"fixed":"";!c&&(a==="fixed"||a==="absolute"&&l.position==="static")?o=o.filter(p=>p!==s):r=l,s=Se(s)}return t.set(e,o),o}function Fs(e){let{element:t,boundary:n,rootBoundary:o,strategy:r}=e;const s=[...n==="clippingAncestors"?Pt(t)?[]:_s(t,this._c):[].concat(n),o],l=Bn(t,s[0],r);let c=l.top,a=l.right,f=l.bottom,p=l.left;for(let d=1;d{l(!1,1e-7)},1e3)}E=!1}try{o=new IntersectionObserver(O,{...R,root:i.ownerDocument})}catch{o=new IntersectionObserver(O,R)}o.observe(e)}const c=q(e),a=()=>l(n);return c.addEventListener("resize",a),l(!0),()=>{c.removeEventListener("resize",a),s()}}function Xn(e,t,n,o){o===void 0&&(o={});const{ancestorScroll:r=!0,ancestorResize:i=!0,elementResize:s=typeof ResizeObserver=="function",layoutShift:l=typeof IntersectionObserver=="function",animationFrame:c=!1}=o,a=an(e),f=r||i?[...a?Ce(a):[],...t?Ce(t):[]]:[];f.forEach(v=>{r&&v.addEventListener("scroll",n),i&&v.addEventListener("resize",n)});const p=a&&l?Ws(a,n,i):null;let d=-1,m=null;s&&(m=new ResizeObserver(v=>{let[C]=v;C&&C.target===a&&m&&t&&(m.unobserve(t),cancelAnimationFrame(d),d=requestAnimationFrame(()=>{var S;(S=m)==null||S.observe(t)})),n()}),a&&!c&&m.observe(a),t&&m.observe(t));let h,g=c?ke(e):null;c&&b();function b(){const v=ke(e);g&&!No(g,v)&&n(),g=v,h=requestAnimationFrame(b)}return n(),()=>{var v;f.forEach(C=>{r&&C.removeEventListener("scroll",n),i&&C.removeEventListener("resize",n)}),p?.(),(v=m)==null||v.disconnect(),m=null,c&&cancelAnimationFrame(h)}}const Bs=Ss,Ks=Es,Xs=ws,Ys=Ts,Us=ys,Yn=vs,qs=Cs,Gs=Ps,Zs=(e,t,n)=>{const o=new Map,r=n??{},i={...Vs,...r.platform,_c:o};return bs(e,t,{...r,platform:i})};var Js=typeof document<"u",Qs=function(){},dt=Js?u.useLayoutEffect:Qs;function bt(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e=="function"&&e.toString()===t.toString())return!0;let n,o,r;if(e&&t&&typeof e=="object"){if(Array.isArray(e)){if(n=e.length,n!==t.length)return!1;for(o=n;o--!==0;)if(!bt(e[o],t[o]))return!1;return!0}if(r=Object.keys(e),n=r.length,n!==Object.keys(t).length)return!1;for(o=n;o--!==0;)if(!{}.hasOwnProperty.call(t,r[o]))return!1;for(o=n;o--!==0;){const i=r[o];if(!(i==="_owner"&&e.$$typeof)&&!bt(e[i],t[i]))return!1}return!0}return e!==e&&t!==t}function Lo(e){return typeof window>"u"?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function Un(e,t){const n=Lo(e);return Math.round(t*n)/n}function jt(e){const t=u.useRef(e);return dt(()=>{t.current=e}),t}function ei(e){e===void 0&&(e={});const{placement:t="bottom",strategy:n="absolute",middleware:o=[],platform:r,elements:{reference:i,floating:s}={},transform:l=!0,whileElementsMounted:c,open:a}=e,[f,p]=u.useState({x:0,y:0,strategy:n,placement:t,middlewareData:{},isPositioned:!1}),[d,m]=u.useState(o);bt(d,o)||m(o);const[h,g]=u.useState(null),[b,v]=u.useState(null),C=u.useCallback(y=>{y!==R.current&&(R.current=y,g(y))},[]),S=u.useCallback(y=>{y!==E.current&&(E.current=y,v(y))},[]),x=i||h,T=s||b,R=u.useRef(null),E=u.useRef(null),O=u.useRef(f),_=c!=null,I=jt(c),H=jt(r),j=jt(a),M=u.useCallback(()=>{if(!R.current||!E.current)return;const y={placement:t,strategy:n,middleware:d};H.current&&(y.platform=H.current),Zs(R.current,E.current,y).then(N=>{const L={...N,isPositioned:j.current!==!1};A.current&&!bt(O.current,L)&&(O.current=L,co.flushSync(()=>{p(L)}))})},[d,t,n,H,j]);dt(()=>{a===!1&&O.current.isPositioned&&(O.current.isPositioned=!1,p(y=>({...y,isPositioned:!1})))},[a]);const A=u.useRef(!1);dt(()=>(A.current=!0,()=>{A.current=!1}),[]),dt(()=>{if(x&&(R.current=x),T&&(E.current=T),x&&T){if(I.current)return I.current(x,T,M);M()}},[x,T,M,I,_]);const k=u.useMemo(()=>({reference:R,floating:E,setReference:C,setFloating:S}),[C,S]),D=u.useMemo(()=>({reference:x,floating:T}),[x,T]),P=u.useMemo(()=>{const y={position:n,left:0,top:0};if(!D.floating)return y;const N=Un(D.floating,f.x),L=Un(D.floating,f.y);return l?{...y,transform:"translate("+N+"px, "+L+"px)",...Lo(D.floating)>=1.5&&{willChange:"transform"}}:{position:n,left:N,top:L}},[n,l,D.floating,f.x,f.y]);return u.useMemo(()=>({...f,update:M,refs:k,elements:D,floatingStyles:P}),[f,M,k,D,P])}const ti=e=>{function t(n){return{}.hasOwnProperty.call(n,"current")}return{name:"arrow",options:e,fn(n){const{element:o,padding:r}=typeof e=="function"?e(n):e;return o&&t(o)?o.current!=null?Yn({element:o.current,padding:r}).fn(n):{}:o?Yn({element:o,padding:r}).fn(n):{}}}},ni=(e,t)=>{const n=Bs(e);return{name:n.name,fn:n.fn,options:[e,t]}},oi=(e,t)=>{const n=Ks(e);return{name:n.name,fn:n.fn,options:[e,t]}},qn=(e,t)=>({fn:Gs(e).fn,options:[e,t]}),Gn=(e,t)=>{const n=Xs(e);return{name:n.name,fn:n.fn,options:[e,t]}},ri=(e,t)=>{const n=Ys(e);return{name:n.name,fn:n.fn,options:[e,t]}},si=(e,t)=>{const n=Us(e);return{name:n.name,fn:n.fn,options:[e,t]}},Zn=(e,t)=>{const n=qs(e);return{name:n.name,fn:n.fn,options:[e,t]}},ii=(e,t)=>{const n=ti(e);return{name:n.name,fn:n.fn,options:[e,t]}};function Mo(e){const t=u.useRef(void 0),n=u.useCallback(o=>{const r=e.map(i=>{if(i!=null){if(typeof i=="function"){const s=i,l=s(o);return typeof l=="function"?l:()=>{s(null)}}return i.current=o,()=>{i.current=null}}});return()=>{r.forEach(i=>i?.())}},e);return u.useMemo(()=>e.every(o=>o==null)?null:o=>{t.current&&(t.current(),t.current=void 0),o!=null&&(t.current=n(o))},e)}const li="data-floating-ui-focusable",Jn="active",Qn="selected",ci={...lo};let eo=!1,ai=0;const to=()=>"floating-ui-"+Math.random().toString(36).slice(2,6)+ai++;function ui(){const[e,t]=u.useState(()=>eo?to():void 0);return me(()=>{e==null&&t(to())},[]),u.useEffect(()=>{eo=!0},[]),e}const fi=ci.useId,Io=fi||ui;function di(){const e=new Map;return{emit(t,n){var o;(o=e.get(t))==null||o.forEach(r=>r(n))},on(t,n){e.has(t)||e.set(t,new Set),e.get(t).add(n)},off(t,n){var o;(o=e.get(t))==null||o.delete(n)}}}const pi=u.createContext(null),mi=u.createContext(null),un=()=>{var e;return((e=u.useContext(pi))==null?void 0:e.id)||null},fn=()=>u.useContext(mi);function dn(e){return"data-floating-ui-"+e}function ne(e){e.current!==-1&&(clearTimeout(e.current),e.current=-1)}const no=dn("safe-polygon");function pt(e,t,n){if(n&&!Gt(n))return 0;if(typeof e=="number")return e;if(typeof e=="function"){const o=e();return typeof o=="number"?o:o?.[t]}return e?.[t]}function $t(e){return typeof e=="function"?e():e}function ml(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,dataRef:r,events:i,elements:s}=e,{enabled:l=!0,delay:c=0,handleClose:a=null,mouseOnly:f=!1,restMs:p=0,move:d=!0}=t,m=fn(),h=un(),g=at(a),b=at(c),v=at(n),C=at(p),S=u.useRef(),x=u.useRef(-1),T=u.useRef(),R=u.useRef(-1),E=u.useRef(!0),O=u.useRef(!1),_=u.useRef(()=>{}),I=u.useRef(!1),H=pe(()=>{var P;const y=(P=r.current.openEvent)==null?void 0:P.type;return y?.includes("mouse")&&y!=="mousedown"});u.useEffect(()=>{if(!l)return;function P(y){let{open:N}=y;N||(ne(x),ne(R),E.current=!0,I.current=!1)}return i.on("openchange",P),()=>{i.off("openchange",P)}},[l,i]),u.useEffect(()=>{if(!l||!g.current||!n)return;function P(N){H()&&o(!1,N,"hover")}const y=Me(s.floating).documentElement;return y.addEventListener("mouseleave",P),()=>{y.removeEventListener("mouseleave",P)}},[s.floating,n,o,l,g,H]);const j=u.useCallback(function(P,y,N){y===void 0&&(y=!0),N===void 0&&(N="hover");const L=pt(b.current,"close",S.current);L&&!T.current?(ne(x),x.current=window.setTimeout(()=>o(!1,P,N),L)):y&&(ne(x),o(!1,P,N))},[b,o]),M=pe(()=>{_.current(),T.current=void 0}),A=pe(()=>{if(O.current){const P=Me(s.floating).body;P.style.pointerEvents="",P.removeAttribute(no),O.current=!1}}),k=pe(()=>r.current.openEvent?["click","mousedown"].includes(r.current.openEvent.type):!1);u.useEffect(()=>{if(!l)return;function P($){if(ne(x),E.current=!1,f&&!Gt(S.current)||$t(C.current)>0&&!pt(b.current,"open"))return;const K=pt(b.current,"open",S.current);K?x.current=window.setTimeout(()=>{v.current||o(!0,$,"hover")},K):n||o(!0,$,"hover")}function y($){if(k()){A();return}_.current();const K=Me(s.floating);if(ne(R),I.current=!1,g.current&&r.current.floatingContext){n||ne(x),T.current=g.current({...r.current.floatingContext,tree:m,x:$.clientX,y:$.clientY,onClose(){A(),M(),k()||j($,!0,"safe-polygon")}});const X=T.current;K.addEventListener("mousemove",X),_.current=()=>{K.removeEventListener("mousemove",X)};return}(S.current!=="touch"||!Qe(s.floating,$.relatedTarget))&&j($)}function N($){k()||r.current.floatingContext&&(g.current==null||g.current({...r.current.floatingContext,tree:m,x:$.clientX,y:$.clientY,onClose(){A(),M(),k()||j($)}})($))}function L(){ne(x)}function B($){k()||j($,!1)}if(V(s.domReference)){const $=s.domReference,K=s.floating;return n&&$.addEventListener("mouseleave",N),d&&$.addEventListener("mousemove",P,{once:!0}),$.addEventListener("mouseenter",P),$.addEventListener("mouseleave",y),K&&(K.addEventListener("mouseleave",N),K.addEventListener("mouseenter",L),K.addEventListener("mouseleave",B)),()=>{n&&$.removeEventListener("mouseleave",N),d&&$.removeEventListener("mousemove",P),$.removeEventListener("mouseenter",P),$.removeEventListener("mouseleave",y),K&&(K.removeEventListener("mouseleave",N),K.removeEventListener("mouseenter",L),K.removeEventListener("mouseleave",B))}}},[s,l,e,f,d,j,M,A,o,n,v,m,b,g,r,k,C]),me(()=>{var P;if(l&&n&&(P=g.current)!=null&&(P=P.__options)!=null&&P.blockPointerEvents&&H()){O.current=!0;const N=s.floating;if(V(s.domReference)&&N){var y;const L=Me(s.floating).body;L.setAttribute(no,"");const B=s.domReference,$=m==null||(y=m.nodesRef.current.find(K=>K.id===h))==null||(y=y.context)==null?void 0:y.elements.floating;return $&&($.style.pointerEvents=""),L.style.pointerEvents="none",B.style.pointerEvents="auto",N.style.pointerEvents="auto",()=>{L.style.pointerEvents="",B.style.pointerEvents="",N.style.pointerEvents=""}}}},[l,n,h,s,m,g,H]),me(()=>{n||(S.current=void 0,I.current=!1,M(),A())},[n,M,A]),u.useEffect(()=>()=>{M(),ne(x),ne(R),A()},[l,s.domReference,M,A]);const D=u.useMemo(()=>{function P(y){S.current=y.pointerType}return{onPointerDown:P,onPointerEnter:P,onMouseMove(y){const{nativeEvent:N}=y;function L(){!E.current&&!v.current&&o(!0,N,"hover")}f&&!Gt(S.current)||n||$t(C.current)===0||I.current&&y.movementX**2+y.movementY**2<2||(ne(R),S.current==="touch"?L():(I.current=!0,R.current=window.setTimeout(L,$t(C.current))))}}},[f,o,n,v,C]);return u.useMemo(()=>l?{reference:D}:{},[l,D])}const Zt=()=>{},ko=u.createContext({delay:0,initialDelay:0,timeoutMs:0,currentId:null,setCurrentId:Zt,setState:Zt,isInstantPhase:!1}),hi=()=>u.useContext(ko);function hl(e){const{children:t,delay:n,timeoutMs:o=0}=e,[r,i]=u.useReducer((c,a)=>({...c,...a}),{delay:n,timeoutMs:o,initialDelay:n,currentId:null,isInstantPhase:!1}),s=u.useRef(null),l=u.useCallback(c=>{i({currentId:c})},[]);return me(()=>{r.currentId?s.current===null?s.current=r.currentId:r.isInstantPhase||i({isInstantPhase:!0}):(r.isInstantPhase&&i({isInstantPhase:!1}),s.current=null)},[r.currentId,r.isInstantPhase]),w.jsx(ko.Provider,{value:u.useMemo(()=>({...r,setState:i,setCurrentId:l}),[r,l]),children:t})}function gl(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,floatingId:r}=e,{id:i,enabled:s=!0}=t,l=i??r,c=hi(),{currentId:a,setCurrentId:f,initialDelay:p,setState:d,timeoutMs:m}=c;return me(()=>{s&&a&&(d({delay:{open:1,close:pt(p,"close")}}),a!==l&&o(!1))},[s,l,o,d,a,p]),me(()=>{function h(){o(!1),d({delay:p,currentId:null})}if(s&&a&&!n&&a===l){if(m){const g=window.setTimeout(h,m);return()=>{clearTimeout(g)}}h()}},[s,n,d,a,l,o,p,m]),me(()=>{s&&(f===Zt||!n||f(l))},[s,n,f,l]),c}const gi={pointerdown:"onPointerDown",mousedown:"onMouseDown",click:"onClick"},bi={pointerdown:"onPointerDownCapture",mousedown:"onMouseDownCapture",click:"onClickCapture"},oo=e=>{var t,n;return{escapeKey:typeof e=="boolean"?e:(t=e?.escapeKey)!=null?t:!1,outsidePress:typeof e=="boolean"?e:(n=e?.outsidePress)!=null?n:!0}};function bl(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,elements:r,dataRef:i}=e,{enabled:s=!0,escapeKey:l=!0,outsidePress:c=!0,outsidePressEvent:a="pointerdown",referencePress:f=!1,referencePressEvent:p="pointerdown",ancestorScroll:d=!1,bubbles:m,capture:h}=t,g=fn(),b=pe(typeof c=="function"?c:()=>!1),v=typeof c=="function"?b:c,C=u.useRef(!1),{escapeKey:S,outsidePress:x}=oo(m),{escapeKey:T,outsidePress:R}=oo(h),E=u.useRef(!1),O=pe(A=>{var k;if(!n||!s||!l||A.key!=="Escape"||E.current)return;const D=(k=i.current.floatingContext)==null?void 0:k.nodeId,P=g?ft(g.nodesRef.current,D):[];if(!S&&(A.stopPropagation(),P.length>0)){let y=!0;if(P.forEach(N=>{var L;if((L=N.context)!=null&&L.open&&!N.context.dataRef.current.__escapeKeyBubbles){y=!1;return}}),!y)return}o(!1,as(A)?A.nativeEvent:A,"escape-key")}),_=pe(A=>{var k;const D=()=>{var P;O(A),(P=$e(A))==null||P.removeEventListener("keydown",D)};(k=$e(A))==null||k.addEventListener("keydown",D)}),I=pe(A=>{var k;const D=i.current.insideReactTree;i.current.insideReactTree=!1;const P=C.current;if(C.current=!1,a==="click"&&P||D||typeof v=="function"&&!v(A))return;const y=$e(A),N="["+dn("inert")+"]",L=Me(r.floating).querySelectorAll(N);let B=V(y)?y:null;for(;B&&!xe(B);){const X=Se(B);if(xe(X)||!V(X))break;B=X}if(L.length&&V(y)&&!ss(y)&&!Qe(y,r.floating)&&Array.from(L).every(X=>!Qe(B,X)))return;if(fe(y)&&M){const X=xe(y),ee=ae(y),de=/auto|scroll/,Xe=X||de.test(ee.overflowX),Te=X||de.test(ee.overflowY),Ye=Xe&&y.clientWidth>0&&y.scrollWidth>y.clientWidth,Ue=Te&&y.clientHeight>0&&y.scrollHeight>y.clientHeight,Oe=ee.direction==="rtl",qe=Ue&&(Oe?A.offsetX<=y.offsetWidth-y.clientWidth:A.offsetX>y.clientWidth),_e=Ye&&A.offsetY>y.clientHeight;if(qe||_e)return}const $=(k=i.current.floatingContext)==null?void 0:k.nodeId,K=g&&ft(g.nodesRef.current,$).some(X=>{var ee;return _t(A,(ee=X.context)==null?void 0:ee.elements.floating)});if(_t(A,r.floating)||_t(A,r.domReference)||K)return;const Pe=g?ft(g.nodesRef.current,$):[];if(Pe.length>0){let X=!0;if(Pe.forEach(ee=>{var de;if((de=ee.context)!=null&&de.open&&!ee.context.dataRef.current.__outsidePressBubbles){X=!1;return}}),!X)return}o(!1,A,"outside-press")}),H=pe(A=>{var k;const D=()=>{var P;I(A),(P=$e(A))==null||P.removeEventListener(a,D)};(k=$e(A))==null||k.addEventListener(a,D)});u.useEffect(()=>{if(!n||!s)return;i.current.__escapeKeyBubbles=S,i.current.__outsidePressBubbles=x;let A=-1;function k(L){o(!1,L,"ancestor-scroll")}function D(){window.clearTimeout(A),E.current=!0}function P(){A=window.setTimeout(()=>{E.current=!1},Tt()?5:0)}const y=Me(r.floating);l&&(y.addEventListener("keydown",T?_:O,T),y.addEventListener("compositionstart",D),y.addEventListener("compositionend",P)),v&&y.addEventListener(a,R?H:I,R);let N=[];return d&&(V(r.domReference)&&(N=Ce(r.domReference)),V(r.floating)&&(N=N.concat(Ce(r.floating))),!V(r.reference)&&r.reference&&r.reference.contextElement&&(N=N.concat(Ce(r.reference.contextElement)))),N=N.filter(L=>{var B;return L!==((B=y.defaultView)==null?void 0:B.visualViewport)}),N.forEach(L=>{L.addEventListener("scroll",k)}),()=>{l&&(y.removeEventListener("keydown",T?_:O,T),y.removeEventListener("compositionstart",D),y.removeEventListener("compositionend",P)),v&&y.removeEventListener(a,R?H:I,R),N.forEach(L=>{L.removeEventListener("scroll",k)}),window.clearTimeout(A)}},[i,r,l,v,a,n,o,d,s,S,x,O,T,_,I,R,H]),u.useEffect(()=>{i.current.insideReactTree=!1},[i,v,a]);const j=u.useMemo(()=>({onKeyDown:O,...f&&{[gi[p]]:A=>{o(!1,A.nativeEvent,"reference-press")},...p!=="click"&&{onClick(A){o(!1,A.nativeEvent,"reference-press")}}}}),[O,o,f,p]),M=u.useMemo(()=>{function A(k){k.button===0&&(C.current=!0)}return{onKeyDown:O,onMouseDown:A,onMouseUp:A,[bi[a]]:()=>{i.current.insideReactTree=!0}}},[O,a,i]);return u.useMemo(()=>s?{reference:j,floating:M}:{},[s,j,M])}function vi(e){const{open:t=!1,onOpenChange:n,elements:o}=e,r=Io(),i=u.useRef({}),[s]=u.useState(()=>di()),l=un()!=null,[c,a]=u.useState(o.reference),f=pe((m,h,g)=>{i.current.openEvent=m?h:void 0,s.emit("openchange",{open:m,event:h,reason:g,nested:l}),n?.(m,h,g)}),p=u.useMemo(()=>({setPositionReference:a}),[]),d=u.useMemo(()=>({reference:c||o.reference||null,floating:o.floating||null,domReference:o.reference}),[c,o.reference,o.floating]);return u.useMemo(()=>({dataRef:i,open:t,onOpenChange:f,elements:d,events:s,floatingId:r,refs:p}),[t,f,d,s,r,p])}function wi(e){var t,n;let{elements:o,...r}=e===void 0?{}:e;const{nodeId:i}=r,s=vi({...r,elements:{reference:(t=o?.reference)!=null?t:null,floating:(n=o?.floating)!=null?n:null}}),l=r.rootContext||s,c=l.elements,[a,f]=u.useState(null),[p,d]=u.useState(null),h=c?.domReference||a,g=u.useRef(null),b=fn();me(()=>{h&&(g.current=h)},[h]);const v=ei({...r,elements:{...c,...p&&{reference:p}}}),C=u.useCallback(E=>{const O=V(E)?{getBoundingClientRect:()=>E.getBoundingClientRect(),getClientRects:()=>E.getClientRects(),contextElement:E}:E;d(O),v.refs.setReference(O)},[v.refs]),S=u.useCallback(E=>{(V(E)||E===null)&&(g.current=E,f(E)),(V(v.refs.reference.current)||v.refs.reference.current===null||E!==null&&!V(E))&&v.refs.setReference(E)},[v.refs]),x=u.useMemo(()=>({...v.refs,setReference:S,setPositionReference:C,domReference:g}),[v.refs,S,C]),T=u.useMemo(()=>({...v.elements,domReference:h}),[v.elements,h]),R=u.useMemo(()=>({...v,...l,refs:x,elements:T,nodeId:i}),[v,x,T,i,l]);return me(()=>{l.dataRef.current.floatingContext=R;const E=b?.nodesRef.current.find(O=>O.id===i);E&&(E.context=R)}),u.useMemo(()=>({...v,context:R,refs:x,elements:T}),[v,x,T,R])}function Ht(){return ns()&&ts()}function vl(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,events:r,dataRef:i,elements:s}=e,{enabled:l=!0,visibleOnly:c=!0}=t,a=u.useRef(!1),f=u.useRef(-1),p=u.useRef(!0);u.useEffect(()=>{if(!l)return;const m=q(s.domReference);function h(){!n&&fe(s.domReference)&&s.domReference===Hn(Me(s.domReference))&&(a.current=!0)}function g(){p.current=!0}function b(){p.current=!1}return m.addEventListener("blur",h),Ht()&&(m.addEventListener("keydown",g,!0),m.addEventListener("pointerdown",b,!0)),()=>{m.removeEventListener("blur",h),Ht()&&(m.removeEventListener("keydown",g,!0),m.removeEventListener("pointerdown",b,!0))}},[s.domReference,n,l]),u.useEffect(()=>{if(!l)return;function m(h){let{reason:g}=h;(g==="reference-press"||g==="escape-key")&&(a.current=!0)}return r.on("openchange",m),()=>{r.off("openchange",m)}},[r,l]),u.useEffect(()=>()=>{ne(f)},[]);const d=u.useMemo(()=>({onMouseLeave(){a.current=!1},onFocus(m){if(a.current)return;const h=$e(m.nativeEvent);if(c&&V(h)){if(Ht()&&!m.relatedTarget){if(!p.current&&!is(h))return}else if(!ls(h))return}o(!0,m.nativeEvent,"focus")},onBlur(m){a.current=!1;const h=m.relatedTarget,g=m.nativeEvent,b=V(h)&&h.hasAttribute(dn("focus-guard"))&&h.getAttribute("data-type")==="outside";f.current=window.setTimeout(()=>{var v;const C=Hn(s.domReference?s.domReference.ownerDocument:document);!h&&C===s.domReference||Qe((v=i.current.floatingContext)==null?void 0:v.refs.floating.current,C)||Qe(s.domReference,C)||b||o(!1,g,"focus")})}}),[i,s.domReference,o,c]);return u.useMemo(()=>l?{reference:d}:{},[l,d])}function zt(e,t,n){const o=new Map,r=n==="item";let i=e;if(r&&e){const{[Jn]:s,[Qn]:l,...c}=e;i=c}return{...n==="floating"&&{tabIndex:-1,[li]:""},...i,...t.map(s=>{const l=s?s[n]:null;return typeof l=="function"?e?l(e):null:l}).concat(e).reduce((s,l)=>(l&&Object.entries(l).forEach(c=>{let[a,f]=c;if(!(r&&[Jn,Qn].includes(a)))if(a.indexOf("on")===0){if(o.has(a)||o.set(a,[]),typeof f=="function"){var p;(p=o.get(a))==null||p.push(f),s[a]=function(){for(var d,m=arguments.length,h=new Array(m),g=0;gb(...h)).find(b=>b!==void 0)}}}else s[a]=f}),s),{})}}function wl(e){e===void 0&&(e=[]);const t=e.map(l=>l?.reference),n=e.map(l=>l?.floating),o=e.map(l=>l?.item),r=u.useCallback(l=>zt(l,e,"reference"),t),i=u.useCallback(l=>zt(l,e,"floating"),n),s=u.useCallback(l=>zt(l,e,"item"),o);return u.useMemo(()=>({getReferenceProps:r,getFloatingProps:i,getItemProps:s}),[r,i,s])}const yi=new Map([["select","listbox"],["combobox","listbox"],["label",!1]]);function yl(e,t){var n,o;t===void 0&&(t={});const{open:r,elements:i,floatingId:s}=e,{enabled:l=!0,role:c="dialog"}=t,a=Io(),f=((n=i.domReference)==null?void 0:n.id)||a,p=u.useMemo(()=>{var C;return((C=cs(i.floating))==null?void 0:C.id)||s},[i.floating,s]),d=(o=yi.get(c))!=null?o:c,h=un()!=null,g=u.useMemo(()=>d==="tooltip"||c==="label"?{["aria-"+(c==="label"?"labelledby":"describedby")]:r?p:void 0}:{"aria-expanded":r?"true":"false","aria-haspopup":d==="alertdialog"?"dialog":d,"aria-controls":r?p:void 0,...d==="listbox"&&{role:"combobox"},...d==="menu"&&{id:f},...d==="menu"&&h&&{role:"menuitem"},...c==="select"&&{"aria-autocomplete":"none"},...c==="combobox"&&{"aria-autocomplete":"list"}},[d,p,h,r,f,c]),b=u.useMemo(()=>{const C={id:p,...d&&{role:d}};return d==="tooltip"||c==="label"?C:{...C,...d==="menu"&&{"aria-labelledby":f}}},[d,p,f,c]),v=u.useCallback(C=>{let{active:S,selected:x}=C;const T={role:"option",...S&&{id:p+"-fui-option"}};switch(c){case"select":case"combobox":return{...T,"aria-selected":x}}return{}},[p,c]);return u.useMemo(()=>l?{reference:g,floating:b,item:v}:{},[l,g,b,v])}var pn={root:"m_d57069b5",content:"m_b1336c6",viewport:"m_c0783ff9",viewportInner:"m_f8f631dd",scrollbar:"m_c44ba933",thumb:"m_d8b5e363",corner:"m_21657268"};const[xi,se]=wt("ScrollArea.Root component was not found in tree");function Ve(e,t){const n=Le(t);en(()=>{let o=0;if(e){const r=new ResizeObserver(()=>{cancelAnimationFrame(o),o=window.requestAnimationFrame(n)});return r.observe(e),()=>{window.cancelAnimationFrame(o),r.unobserve(e)}}},[e,n])}const Ci=u.forwardRef((e,t)=>{const{style:n,...o}=e,r=se(),[i,s]=u.useState(0),[l,c]=u.useState(0),a=!!(i&&l);return Ve(r.scrollbarX,()=>{const f=r.scrollbarX?.offsetHeight||0;r.onCornerHeightChange(f),c(f)}),Ve(r.scrollbarY,()=>{const f=r.scrollbarY?.offsetWidth||0;r.onCornerWidthChange(f),s(f)}),a?w.jsx("div",{...o,ref:t,style:{...n,width:i,height:l}}):null}),Ri=u.forwardRef((e,t)=>{const n=se(),o=!!(n.scrollbarX&&n.scrollbarY);return n.type!=="scroll"&&o?w.jsx(Ci,{...e,ref:t}):null}),Si={scrollHideDelay:1e3,type:"hover"},_o=u.forwardRef((e,t)=>{const{type:n,scrollHideDelay:o,scrollbars:r,getStyles:i,...s}=W("ScrollAreaRoot",Si,e),[l,c]=u.useState(null),[a,f]=u.useState(null),[p,d]=u.useState(null),[m,h]=u.useState(null),[g,b]=u.useState(null),[v,C]=u.useState(0),[S,x]=u.useState(0),[T,R]=u.useState(!1),[E,O]=u.useState(!1),_=re(t,I=>c(I));return w.jsx(xi,{value:{type:n,scrollHideDelay:o,scrollArea:l,viewport:a,onViewportChange:f,content:p,onContentChange:d,scrollbarX:m,onScrollbarXChange:h,scrollbarXEnabled:T,onScrollbarXEnabledChange:R,scrollbarY:g,onScrollbarYChange:b,scrollbarYEnabled:E,onScrollbarYEnabledChange:O,onCornerWidthChange:C,onCornerHeightChange:x,getStyles:i},children:w.jsx(Q,{...s,ref:_,__vars:{"--sa-corner-width":r!=="xy"?"0px":`${v}px`,"--sa-corner-height":r!=="xy"?"0px":`${S}px`}})})});_o.displayName="@mantine/core/ScrollAreaRoot";function Fo(e,t){const n=e/t;return Number.isNaN(n)?0:n}function Dt(e){const t=Fo(e.viewport,e.content),n=e.scrollbar.paddingStart+e.scrollbar.paddingEnd,o=(e.scrollbar.size-n)*t;return Math.max(o,18)}function jo(e,t){return n=>{if(e[0]===e[1]||t[0]===t[1])return t[0];const o=(t[1]-t[0])/(e[1]-e[0]);return t[0]+o*(n-e[0])}}function Ei(e,[t,n]){return Math.min(n,Math.max(t,e))}function ro(e,t,n="ltr"){const o=Dt(t),r=t.scrollbar.paddingStart+t.scrollbar.paddingEnd,i=t.scrollbar.size-r,s=t.content-t.viewport,l=i-o,c=n==="ltr"?[0,s]:[s*-1,0],a=Ei(e,c);return jo([0,s],[0,l])(a)}function Pi(e,t,n,o="ltr"){const r=Dt(n),i=r/2,s=t||i,l=r-s,c=n.scrollbar.paddingStart+s,a=n.scrollbar.size-n.scrollbar.paddingEnd-l,f=n.content-n.viewport,p=o==="ltr"?[0,f]:[f*-1,0];return jo([c,a],p)(e)}function $o(e,t){return e>0&&e{e?.(o),(n===!1||!o.defaultPrevented)&&t?.(o)}}const[Ti,Ho]=wt("ScrollAreaScrollbar was not found in tree"),zo=u.forwardRef((e,t)=>{const{sizes:n,hasThumb:o,onThumbChange:r,onThumbPointerUp:i,onThumbPointerDown:s,onThumbPositionChange:l,onDragScroll:c,onWheelScroll:a,onResize:f,...p}=e,d=se(),[m,h]=u.useState(null),g=re(t,O=>h(O)),b=u.useRef(null),v=u.useRef(""),{viewport:C}=d,S=n.content-n.viewport,x=Le(a),T=Le(l),R=Ct(f,10),E=O=>{if(b.current){const _=O.clientX-b.current.left,I=O.clientY-b.current.top;c({x:_,y:I})}};return u.useEffect(()=>{const O=_=>{const I=_.target;m?.contains(I)&&x(_,S)};return document.addEventListener("wheel",O,{passive:!1}),()=>document.removeEventListener("wheel",O,{passive:!1})},[C,m,S,x]),u.useEffect(T,[n,T]),Ve(m,R),Ve(d.content,R),w.jsx(Ti,{value:{scrollbar:m,hasThumb:o,onThumbChange:Le(r),onThumbPointerUp:Le(i),onThumbPositionChange:T,onThumbPointerDown:Le(s)},children:w.jsx("div",{...p,ref:g,"data-mantine-scrollbar":!0,style:{position:"absolute",...p.style},onPointerDown:Ie(e.onPointerDown,O=>{O.preventDefault(),O.button===0&&(O.target.setPointerCapture(O.pointerId),b.current=m.getBoundingClientRect(),v.current=document.body.style.webkitUserSelect,document.body.style.webkitUserSelect="none",E(O))}),onPointerMove:Ie(e.onPointerMove,E),onPointerUp:Ie(e.onPointerUp,O=>{const _=O.target;_.hasPointerCapture(O.pointerId)&&(O.preventDefault(),_.releasePointerCapture(O.pointerId))}),onLostPointerCapture:()=>{document.body.style.webkitUserSelect=v.current,b.current=null}})})}),Vo=u.forwardRef((e,t)=>{const{sizes:n,onSizesChange:o,style:r,...i}=e,s=se(),[l,c]=u.useState(),a=u.useRef(null),f=re(t,a,s.onScrollbarXChange);return u.useEffect(()=>{a.current&&c(getComputedStyle(a.current))},[a]),w.jsx(zo,{"data-orientation":"horizontal",...i,ref:f,sizes:n,style:{...r,"--sa-thumb-width":`${Dt(n)}px`},onThumbPointerDown:p=>e.onThumbPointerDown(p.x),onDragScroll:p=>e.onDragScroll(p.x),onWheelScroll:(p,d)=>{if(s.viewport){const m=s.viewport.scrollLeft+p.deltaX;e.onWheelScroll(m),$o(m,d)&&p.preventDefault()}},onResize:()=>{a.current&&s.viewport&&l&&o({content:s.viewport.scrollWidth,viewport:s.viewport.offsetWidth,scrollbar:{size:a.current.clientWidth,paddingStart:vt(l.paddingLeft),paddingEnd:vt(l.paddingRight)}})}})});Vo.displayName="@mantine/core/ScrollAreaScrollbarX";const Wo=u.forwardRef((e,t)=>{const{sizes:n,onSizesChange:o,style:r,...i}=e,s=se(),[l,c]=u.useState(),a=u.useRef(null),f=re(t,a,s.onScrollbarYChange);return u.useEffect(()=>{a.current&&c(window.getComputedStyle(a.current))},[]),w.jsx(zo,{...i,"data-orientation":"vertical",ref:f,sizes:n,style:{"--sa-thumb-height":`${Dt(n)}px`,...r},onThumbPointerDown:p=>e.onThumbPointerDown(p.y),onDragScroll:p=>e.onDragScroll(p.y),onWheelScroll:(p,d)=>{if(s.viewport){const m=s.viewport.scrollTop+p.deltaY;e.onWheelScroll(m),$o(m,d)&&p.preventDefault()}},onResize:()=>{a.current&&s.viewport&&l&&o({content:s.viewport.scrollHeight,viewport:s.viewport.offsetHeight,scrollbar:{size:a.current.clientHeight,paddingStart:vt(l.paddingTop),paddingEnd:vt(l.paddingBottom)}})}})});Wo.displayName="@mantine/core/ScrollAreaScrollbarY";const Nt=u.forwardRef((e,t)=>{const{orientation:n="vertical",...o}=e,{dir:r}=nn(),i=se(),s=u.useRef(null),l=u.useRef(0),[c,a]=u.useState({content:0,viewport:0,scrollbar:{size:0,paddingStart:0,paddingEnd:0}}),f=Fo(c.viewport,c.content),p={...o,sizes:c,onSizesChange:a,hasThumb:f>0&&f<1,onThumbChange:m=>{s.current=m},onThumbPointerUp:()=>{l.current=0},onThumbPointerDown:m=>{l.current=m}},d=(m,h)=>Pi(m,l.current,c,h);return n==="horizontal"?w.jsx(Vo,{...p,ref:t,onThumbPositionChange:()=>{if(i.viewport&&s.current){const m=i.viewport.scrollLeft,h=ro(m,c,r);s.current.style.transform=`translate3d(${h}px, 0, 0)`}},onWheelScroll:m=>{i.viewport&&(i.viewport.scrollLeft=m)},onDragScroll:m=>{i.viewport&&(i.viewport.scrollLeft=d(m,r))}}):n==="vertical"?w.jsx(Wo,{...p,ref:t,onThumbPositionChange:()=>{if(i.viewport&&s.current){const m=i.viewport.scrollTop,h=ro(m,c);c.scrollbar.size===0?s.current.style.setProperty("--thumb-opacity","0"):s.current.style.setProperty("--thumb-opacity","1"),s.current.style.transform=`translate3d(0, ${h}px, 0)`}},onWheelScroll:m=>{i.viewport&&(i.viewport.scrollTop=m)},onDragScroll:m=>{i.viewport&&(i.viewport.scrollTop=d(m))}}):null});Nt.displayName="@mantine/core/ScrollAreaScrollbarVisible";const mn=u.forwardRef((e,t)=>{const n=se(),{forceMount:o,...r}=e,[i,s]=u.useState(!1),l=e.orientation==="horizontal",c=Ct(()=>{if(n.viewport){const a=n.viewport.offsetWidth{const{forceMount:n,...o}=e,r=se(),[i,s]=u.useState(!1);return u.useEffect(()=>{const{scrollArea:l}=r;let c=0;if(l){const a=()=>{window.clearTimeout(c),s(!0)},f=()=>{c=window.setTimeout(()=>s(!1),r.scrollHideDelay)};return l.addEventListener("pointerenter",a),l.addEventListener("pointerleave",f),()=>{window.clearTimeout(c),l.removeEventListener("pointerenter",a),l.removeEventListener("pointerleave",f)}}},[r.scrollArea,r.scrollHideDelay]),n||i?w.jsx(mn,{"data-state":i?"visible":"hidden",...o,ref:t}):null});Bo.displayName="@mantine/core/ScrollAreaScrollbarHover";const Oi=u.forwardRef((e,t)=>{const{forceMount:n,...o}=e,r=se(),i=e.orientation==="horizontal",[s,l]=u.useState("hidden"),c=Ct(()=>l("idle"),100);return u.useEffect(()=>{if(s==="idle"){const a=window.setTimeout(()=>l("hidden"),r.scrollHideDelay);return()=>window.clearTimeout(a)}},[s,r.scrollHideDelay]),u.useEffect(()=>{const{viewport:a}=r,f=i?"scrollLeft":"scrollTop";if(a){let p=a[f];const d=()=>{const m=a[f];p!==m&&(l("scrolling"),c()),p=m};return a.addEventListener("scroll",d),()=>a.removeEventListener("scroll",d)}},[r.viewport,i,c]),n||s!=="hidden"?w.jsx(Nt,{"data-state":s==="hidden"?"hidden":"visible",...o,ref:t,onPointerEnter:Ie(e.onPointerEnter,()=>l("interacting")),onPointerLeave:Ie(e.onPointerLeave,()=>l("idle"))}):null}),Jt=u.forwardRef((e,t)=>{const{forceMount:n,...o}=e,r=se(),{onScrollbarXEnabledChange:i,onScrollbarYEnabledChange:s}=r,l=e.orientation==="horizontal";return u.useEffect(()=>(l?i(!0):s(!0),()=>{l?i(!1):s(!1)}),[l,i,s]),r.type==="hover"?w.jsx(Bo,{...o,ref:t,forceMount:n}):r.type==="scroll"?w.jsx(Oi,{...o,ref:t,forceMount:n}):r.type==="auto"?w.jsx(mn,{...o,ref:t,forceMount:n}):r.type==="always"?w.jsx(Nt,{...o,ref:t}):null});Jt.displayName="@mantine/core/ScrollAreaScrollbar";function Ai(e,t=()=>{}){let n={left:e.scrollLeft,top:e.scrollTop},o=0;return(function r(){const i={left:e.scrollLeft,top:e.scrollTop},s=n.left!==i.left,l=n.top!==i.top;(s||l)&&t(),n=i,o=window.requestAnimationFrame(r)})(),()=>window.cancelAnimationFrame(o)}const Ko=u.forwardRef((e,t)=>{const{style:n,...o}=e,r=se(),i=Ho(),{onThumbPositionChange:s}=i,l=re(t,f=>i.onThumbChange(f)),c=u.useRef(void 0),a=Ct(()=>{c.current&&(c.current(),c.current=void 0)},100);return u.useEffect(()=>{const{viewport:f}=r;if(f){const p=()=>{if(a(),!c.current){const d=Ai(f,s);c.current=d,s()}};return s(),f.addEventListener("scroll",p),()=>f.removeEventListener("scroll",p)}},[r.viewport,a,s]),w.jsx("div",{"data-state":i.hasThumb?"visible":"hidden",...o,ref:l,style:{width:"var(--sa-thumb-width)",height:"var(--sa-thumb-height)",...n},onPointerDownCapture:Ie(e.onPointerDownCapture,f=>{const d=f.target.getBoundingClientRect(),m=f.clientX-d.left,h=f.clientY-d.top;i.onThumbPointerDown({x:m,y:h})}),onPointerUp:Ie(e.onPointerUp,i.onThumbPointerUp)})});Ko.displayName="@mantine/core/ScrollAreaThumb";const Qt=u.forwardRef((e,t)=>{const{forceMount:n,...o}=e,r=Ho();return n||r.hasThumb?w.jsx(Ko,{ref:t,...o}):null});Qt.displayName="@mantine/core/ScrollAreaThumb";const Xo=u.forwardRef(({children:e,style:t,onWheel:n,...o},r)=>{const i=se(),s=re(r,i.onViewportChange),l=c=>{if(n?.(c),i.scrollbarXEnabled&&i.viewport&&c.shiftKey){const{scrollTop:a,scrollHeight:f,clientHeight:p,scrollWidth:d,clientWidth:m}=i.viewport,h=a<1,g=a>=f-p-1;d>m&&(h||g)&&c.stopPropagation()}};return w.jsx(Q,{...o,ref:s,onWheel:l,style:{overflowX:i.scrollbarXEnabled?"scroll":"hidden",overflowY:i.scrollbarYEnabled?"scroll":"hidden",...t},children:w.jsx("div",{...i.getStyles("content"),ref:i.onContentChange,children:e})})});Xo.displayName="@mantine/core/ScrollAreaViewport";const Yo={scrollHideDelay:1e3,type:"hover",scrollbars:"xy"},Di=tt((e,{scrollbarSize:t,overscrollBehavior:n,scrollbars:o})=>{let r=n;return n&&o&&(o==="x"?r=`${n} auto`:o==="y"&&(r=`auto ${n}`)),{root:{"--scrollarea-scrollbar-size":ze(t),"--scrollarea-over-scroll-behavior":r}}}),nt=Y((e,t)=>{const n=W("ScrollArea",Yo,e),{classNames:o,className:r,style:i,styles:s,unstyled:l,scrollbarSize:c,vars:a,type:f,scrollHideDelay:p,viewportProps:d,viewportRef:m,onScrollPositionChange:h,children:g,offsetScrollbars:b,scrollbars:v,onBottomReached:C,onTopReached:S,overscrollBehavior:x,attributes:T,...R}=n,[E,O]=u.useState(!1),[_,I]=u.useState(!1),[H,j]=u.useState(!1),M=We({name:"ScrollArea",props:n,classes:pn,className:r,style:i,classNames:o,styles:s,unstyled:l,attributes:T,vars:a,varsResolver:Di}),A=u.useRef(null),k=Mo([m,A]);return u.useEffect(()=>{if(!A.current||b!=="present")return;const D=A.current,P=new ResizeObserver(()=>{const{scrollHeight:y,clientHeight:N,scrollWidth:L,clientWidth:B}=D;I(y>N),j(L>B)});return P.observe(D),()=>P.disconnect()},[A,b]),w.jsxs(_o,{getStyles:M,type:f==="never"?"always":f,scrollHideDelay:p,ref:t,scrollbars:v,...M("root"),...R,children:[w.jsx(Xo,{...d,...M("viewport",{style:d?.style}),ref:k,"data-offset-scrollbars":b===!0?"xy":b||void 0,"data-scrollbars":v||void 0,"data-horizontal-hidden":b==="present"&&!H?"true":void 0,"data-vertical-hidden":b==="present"&&!_?"true":void 0,onScroll:D=>{d?.onScroll?.(D),h?.({x:D.currentTarget.scrollLeft,y:D.currentTarget.scrollTop});const{scrollTop:P,scrollHeight:y,clientHeight:N}=D.currentTarget;P-(y-N)>=-.8&&C?.(),P===0&&S?.()},children:g}),(v==="xy"||v==="x")&&w.jsx(Jt,{...M("scrollbar"),orientation:"horizontal","data-hidden":f==="never"||b==="present"&&!H?!0:void 0,forceMount:!0,onMouseEnter:()=>O(!0),onMouseLeave:()=>O(!1),children:w.jsx(Qt,{...M("thumb")})}),(v==="xy"||v==="y")&&w.jsx(Jt,{...M("scrollbar"),orientation:"vertical","data-hidden":f==="never"||b==="present"&&!_?!0:void 0,forceMount:!0,onMouseEnter:()=>O(!0),onMouseLeave:()=>O(!1),children:w.jsx(Qt,{...M("thumb")})}),w.jsx(Ri,{...M("corner"),"data-hovered":E||void 0,"data-hidden":f==="never"||void 0})]})});nt.displayName="@mantine/core/ScrollArea";const hn=Y((e,t)=>{const{children:n,classNames:o,styles:r,scrollbarSize:i,scrollHideDelay:s,type:l,dir:c,offsetScrollbars:a,overscrollBehavior:f,viewportRef:p,onScrollPositionChange:d,unstyled:m,variant:h,viewportProps:g,scrollbars:b,style:v,vars:C,onBottomReached:S,onTopReached:x,onOverflowChange:T,...R}=W("ScrollAreaAutosize",Yo,e),E=u.useRef(null),O=Mo([p,E]),[_,I]=u.useState(!1),H=u.useRef(!1);return u.useEffect(()=>{if(!T)return;const j=E.current;if(!j)return;const M=()=>{const k=j.scrollHeight>j.clientHeight;k!==_&&(H.current?T?.(k):(H.current=!0,k&&T?.(!0)),I(k))};M();const A=new ResizeObserver(M);return A.observe(j),()=>A.disconnect()},[T,_]),w.jsx(Q,{...R,ref:t,style:[{display:"flex",overflow:"hidden"},v],children:w.jsx(Q,{style:{display:"flex",flexDirection:"column",flex:1,overflow:"hidden",...b==="y"&&{minWidth:0},...b==="x"&&{minHeight:0},...b==="xy"&&{minWidth:0,minHeight:0},...b===!1&&{minWidth:0,minHeight:0}},children:w.jsx(nt,{classNames:o,styles:r,scrollHideDelay:s,scrollbarSize:i,type:l,dir:c,offsetScrollbars:a,overscrollBehavior:f,viewportRef:O,onScrollPositionChange:d,unstyled:m,variant:h,viewportProps:g,vars:C,scrollbars:b,onBottomReached:S,onTopReached:x,"data-autosize":"true",children:n})})})});nt.classes=pn;hn.displayName="@mantine/core/ScrollAreaAutosize";hn.classes=pn;nt.Autosize=hn;var Uo={root:"m_515a97f8"};const gn=Y((e,t)=>{const n=W("VisuallyHidden",null,e),{classNames:o,className:r,style:i,styles:s,unstyled:l,vars:c,attributes:a,...f}=n,p=We({name:"VisuallyHidden",classes:Uo,props:n,className:r,style:i,classNames:o,styles:s,unstyled:l,attributes:a});return w.jsx(Q,{component:"span",ref:t,...p("root"),...f})});gn.classes=Uo;gn.displayName="@mantine/core/VisuallyHidden";function so(e,t,n,o){return e==="center"||o==="center"?{top:t}:e==="end"?{bottom:n}:e==="start"?{top:n}:{}}function io(e,t,n,o,r){return e==="center"||o==="center"?{left:t}:e==="end"?{[r==="ltr"?"right":"left"]:n}:e==="start"?{[r==="ltr"?"left":"right"]:n}:{}}const Ni={bottom:"borderTopLeftRadius",left:"borderTopRightRadius",right:"borderBottomLeftRadius",top:"borderBottomRightRadius"};function Li({position:e,arrowSize:t,arrowOffset:n,arrowRadius:o,arrowPosition:r,arrowX:i,arrowY:s,dir:l}){const[c,a="center"]=e.split("-"),f={width:t,height:t,transform:"rotate(45deg)",position:"absolute",[Ni[c]]:o},p=-t/2;return c==="left"?{...f,...so(a,s,n,r),right:p,borderLeftColor:"transparent",borderBottomColor:"transparent",clipPath:"polygon(100% 0, 0 0, 100% 100%)"}:c==="right"?{...f,...so(a,s,n,r),left:p,borderRightColor:"transparent",borderTopColor:"transparent",clipPath:"polygon(0 100%, 0 0, 100% 100%)"}:c==="top"?{...f,...io(a,i,n,r,l),bottom:p,borderTopColor:"transparent",borderLeftColor:"transparent",clipPath:"polygon(0 100%, 100% 100%, 100% 0)"}:c==="bottom"?{...f,...io(a,i,n,r,l),top:p,borderBottomColor:"transparent",borderRightColor:"transparent",clipPath:"polygon(0 100%, 0 0, 100% 0)"}:{}}const qo=u.forwardRef(({position:e,arrowSize:t,arrowOffset:n,arrowRadius:o,arrowPosition:r,visible:i,arrowX:s,arrowY:l,style:c,...a},f)=>{const{dir:p}=nn();return i?w.jsx("div",{...a,ref:f,style:{...c,...Li({position:e,arrowSize:t,arrowOffset:n,arrowRadius:o,arrowPosition:r,dir:p,arrowX:s,arrowY:l})}}):null});qo.displayName="@mantine/core/FloatingArrow";function Mi(e,t){if(e==="rtl"&&(t.includes("right")||t.includes("left"))){const[n,o]=t.split("-"),r=n==="right"?"left":"right";return o===void 0?r:`${r}-${o}`}return t}var Go={root:"m_9814e45f"};const Ii={zIndex:ao("modal")},ki=tt((e,{gradient:t,color:n,backgroundOpacity:o,blur:r,radius:i,zIndex:s})=>({root:{"--overlay-bg":t||(n!==void 0||o!==void 0)&&Cr(n||"#000",o??.6)||void 0,"--overlay-filter":r?`blur(${ze(r)})`:void 0,"--overlay-radius":i===void 0?void 0:uo(i),"--overlay-z-index":s?.toString()}})),bn=xr((e,t)=>{const n=W("Overlay",Ii,e),{classNames:o,className:r,style:i,styles:s,unstyled:l,vars:c,fixed:a,center:f,children:p,radius:d,zIndex:m,gradient:h,blur:g,color:b,backgroundOpacity:v,mod:C,attributes:S,...x}=n,T=We({name:"Overlay",props:n,classes:Go,className:r,style:i,classNames:o,styles:s,unstyled:l,attributes:S,vars:c,varsResolver:ki});return w.jsx(Q,{ref:t,...T("root"),mod:[{center:f,fixed:a},C],...x,children:p})});bn.classes=Go;bn.displayName="@mantine/core/Overlay";function Vt(e){const t=document.createElement("div");return t.setAttribute("data-portal","true"),typeof e.className=="string"&&t.classList.add(...e.className.split(" ").filter(Boolean)),typeof e.style=="object"&&Object.assign(t.style,e.style),typeof e.id=="string"&&t.setAttribute("id",e.id),t}function _i({target:e,reuseTargetNode:t,...n}){if(e)return typeof e=="string"?document.querySelector(e)||Vt(n):e;if(t){const o=document.querySelector("[data-mantine-shared-portal-node]");if(o)return o;const r=Vt(n);return r.setAttribute("data-mantine-shared-portal-node","true"),document.body.appendChild(r),r}return Vt(n)}const Fi={reuseTargetNode:!0},Zo=Y((e,t)=>{const{children:n,target:o,reuseTargetNode:r,...i}=W("Portal",Fi,e),[s,l]=u.useState(!1),c=u.useRef(null);return en(()=>(l(!0),c.current=_i({target:o,reuseTargetNode:r,...i}),Xt(t,c.current),!o&&!r&&c.current&&document.body.appendChild(c.current),()=>{!o&&!r&&c.current&&document.body.removeChild(c.current)}),[o]),!s||!c.current?null:co.createPortal(w.jsx(w.Fragment,{children:n}),c.current)});Zo.displayName="@mantine/core/Portal";const vn=Y(({withinPortal:e=!0,children:t,...n},o)=>tn()==="test"||!e?w.jsx(w.Fragment,{children:t}):w.jsx(Zo,{ref:o,...n,children:t}));vn.displayName="@mantine/core/OptionalPortal";const[ji,Jo]=wt("Popover component was not found in the tree");var Qo={dropdown:"m_38a85659",arrow:"m_a31dc6c1",overlay:"m_3d7bc908"};function wn({children:e,active:t=!0,refProp:n="ref",innerRef:o}){const r=_r(t),i=re(r,o),s=Rt(e);return s?u.cloneElement(s,{[n]:i}):e}function er(e){return w.jsx(gn,{tabIndex:-1,"data-autofocus":!0,...e})}wn.displayName="@mantine/core/FocusTrap";er.displayName="@mantine/core/FocusTrapInitialFocus";wn.InitialFocus=er;const yn=Y((e,t)=>{const n=W("PopoverDropdown",null,e),{className:o,style:r,vars:i,children:s,onKeyDownCapture:l,variant:c,classNames:a,styles:f,...p}=n,d=Jo(),m=Dr({opened:d.opened,shouldReturnFocus:d.returnFocus}),h=d.withRoles?{"aria-labelledby":d.getTargetId(),id:d.getDropdownId(),role:"dialog",tabIndex:-1}:{},g=re(t,d.floating);return d.disabled?null:w.jsx(vn,{...d.portalProps,withinPortal:d.withinPortal,children:w.jsx(fo,{mounted:d.opened,...d.transitionProps,transition:d.transitionProps?.transition||"fade",duration:d.transitionProps?.duration??150,keepMounted:d.keepMounted,exitDuration:typeof d.transitionProps?.exitDuration=="number"?d.transitionProps.exitDuration:d.transitionProps?.duration,children:b=>w.jsx(wn,{active:d.trapFocus&&d.opened,innerRef:g,children:w.jsxs(Q,{...h,...p,variant:c,onKeyDownCapture:Tr(()=>{d.onClose?.(),d.onDismiss?.()},{active:d.closeOnEscape,onTrigger:m,onKeyDown:l}),"data-position":d.placement,"data-fixed":d.floatingStrategy==="fixed"||void 0,...d.getStyles("dropdown",{className:o,props:n,classNames:a,styles:f,style:[{...b,zIndex:d.zIndex,top:d.y??0,left:d.x??0,width:d.width==="target"?void 0:ze(d.width),...d.referenceHidden?{display:"none"}:null},d.resolvedStyles.dropdown,f?.dropdown,r]}),children:[s,w.jsx(qo,{ref:d.arrowRef,arrowX:d.arrowX,arrowY:d.arrowY,visible:d.withArrow,position:d.placement,arrowSize:d.arrowSize,arrowRadius:d.arrowRadius,arrowOffset:d.arrowOffset,arrowPosition:d.arrowPosition,...d.getStyles("arrow",{props:n,classNames:a,styles:f})})]})})})})});yn.classes=Qo;yn.displayName="@mantine/core/PopoverDropdown";const $i={refProp:"ref",popupType:"dialog"},tr=Y((e,t)=>{const{children:n,refProp:o,popupType:r,...i}=W("PopoverTarget",$i,e),s=Rt(n);if(!s)throw new Error("Popover.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const l=i,c=Jo(),a=re(c.reference,xo(s),t),f=c.withRoles?{"aria-haspopup":r,"aria-expanded":c.opened,"aria-controls":c.opened?c.getDropdownId():void 0,id:c.getTargetId()}:{},p=s.props;return u.cloneElement(s,{...l,...f,...c.targetProps,className:po(c.targetProps.className,l.className,p.className),[o]:a,...c.controlled?null:{onClick:()=>{c.onToggle(),p.onClick?.()}}})});tr.displayName="@mantine/core/PopoverTarget";function Hi(e){if(e===void 0)return{shift:!0,flip:!0};const t={...e};return e.shift===void 0&&(t.shift=!0),e.flip===void 0&&(t.flip=!0),t}function zi(e,t,n){const o=Hi(e.middlewares),r=[ni(e.offset),si()];return e.dropdownVisible&&n!=="test"&&e.preventPositionChangeWhenVisible&&(o.flip=!1),o.flip&&r.push(typeof o.flip=="boolean"?Gn():Gn(o.flip)),o.shift&&r.push(oi(typeof o.shift=="boolean"?{limiter:qn(),padding:5}:{limiter:qn(),padding:5,...o.shift})),o.inline&&r.push(typeof o.inline=="boolean"?Zn():Zn(o.inline)),r.push(ii({element:e.arrowRef,padding:e.arrowOffset})),(o.size||e.width==="target")&&r.push(ri({...typeof o.size=="boolean"?{}:o.size,apply({rects:i,availableWidth:s,availableHeight:l,...c}){const f=t().refs.floating.current?.style??{};o.size&&(typeof o.size=="object"&&o.size.apply?o.size.apply({rects:i,availableWidth:s,availableHeight:l,...c}):Object.assign(f,{maxWidth:`${s}px`,maxHeight:`${l}px`})),e.width==="target"&&Object.assign(f,{width:`${i.reference.width}px`})}})),r}function Vi(e){const t=tn(),[n,o]=mt({value:e.opened,defaultValue:e.defaultOpened,finalValue:!1,onChange:e.onChange}),r=u.useRef(n),i=()=>{n&&!e.disabled&&o(!1)},s=()=>{e.disabled||o(!n)},l=wi({strategy:e.strategy,placement:e.preventPositionChangeWhenVisible?e.positionRef.current:e.position,middleware:zi(e,()=>l,t),whileElementsMounted:e.keepMounted?void 0:Xn});return u.useEffect(()=>{if(!(!l.refs.reference.current||!l.refs.floating.current)&&n)return Xn(l.refs.reference.current,l.refs.floating.current,l.update)},[n,l.update]),Wt(()=>{e.onPositionChange?.(l.placement),e.positionRef.current=l.placement},[l.placement,e.preventPositionChangeWhenVisible]),Wt(()=>{n!==r.current&&(n?e.onOpen?.():e.onClose?.()),r.current=n},[n,e.onClose,e.onOpen]),en(()=>{let c=-1;return n&&(c=window.setTimeout(()=>e.setDropdownVisible(!0),4)),()=>{window.clearTimeout(c)}},[n,e.position]),{floating:l,controlled:typeof e.opened=="boolean",opened:n,onClose:i,onToggle:s}}const Wi={position:"bottom",offset:8,positionDependencies:[],transitionProps:{transition:"fade",duration:150},middlewares:{flip:!0,shift:!0,inline:!1},arrowSize:7,arrowOffset:5,arrowRadius:0,arrowPosition:"side",closeOnClickOutside:!0,withinPortal:!0,closeOnEscape:!0,trapFocus:!1,withRoles:!0,returnFocus:!1,withOverlay:!1,hideDetached:!0,clickOutsideEvents:["mousedown","touchstart"],zIndex:ao("popover"),__staticSelector:"Popover",width:"max-content"},Bi=tt((e,{radius:t,shadow:n})=>({dropdown:{"--popover-radius":t===void 0?void 0:uo(t),"--popover-shadow":Rr(n)}}));function Ee(e){const t=W("Popover",Wi,e),{children:n,position:o,offset:r,onPositionChange:i,positionDependencies:s,opened:l,transitionProps:c,onExitTransitionEnd:a,onEnterTransitionEnd:f,width:p,middlewares:d,withArrow:m,arrowSize:h,arrowOffset:g,arrowRadius:b,arrowPosition:v,unstyled:C,classNames:S,styles:x,closeOnClickOutside:T,withinPortal:R,portalProps:E,closeOnEscape:O,clickOutsideEvents:_,trapFocus:I,onClose:H,onDismiss:j,onOpen:M,onChange:A,zIndex:k,radius:D,shadow:P,id:y,defaultOpened:N,__staticSelector:L,withRoles:B,disabled:$,returnFocus:K,variant:Pe,keepMounted:X,vars:ee,floatingStrategy:de,withOverlay:Xe,overlayProps:Te,hideDetached:Ye,attributes:Ue,preventPositionChangeWhenVisible:Oe,...qe}=t,_e=We({name:L,props:t,classes:Qo,classNames:S,styles:x,unstyled:C,attributes:Ue,rootSelector:"dropdown",vars:ee,varsResolver:Bi}),{resolvedStyles:Nn}=mo({classNames:S,styles:x,props:t}),[Ln,Lt]=u.useState(l??N??!1),ot=u.useRef(o),Ge=u.useRef(null),[Mt,rt]=u.useState(null),[Fe,Ze]=u.useState(null),{dir:je}=nn(),U=tn(),Je=yt(y),F=Vi({middlewares:d,width:p,position:Mi(je,o),offset:typeof r=="number"?r+(m?h/2:0):r,arrowRef:Ge,arrowOffset:g,onPositionChange:i,positionDependencies:s,opened:l,defaultOpened:N,onChange:A,onOpen:M,onClose:H,onDismiss:j,strategy:de,dropdownVisible:Ln,setDropdownVisible:Lt,positionRef:ot,disabled:$,preventPositionChangeWhenVisible:Oe,keepMounted:X});Ar(()=>{T&&(F.onClose(),j?.())},_,[Mt,Fe]);const st=u.useCallback(te=>{rt(te),F.floating.refs.setReference(te)},[F.floating.refs.setReference]),it=u.useCallback(te=>{Ze(te),F.floating.refs.setFloating(te)},[F.floating.refs.setFloating]),le=u.useCallback(()=>{c?.onExited?.(),a?.(),Lt(!1),Oe||(ot.current=o)},[c?.onExited,a,Oe,o]),lt=u.useCallback(()=>{c?.onEntered?.(),f?.()},[c?.onEntered,f]);return w.jsxs(ji,{value:{returnFocus:K,disabled:$,controlled:F.controlled,reference:st,floating:it,x:F.floating.x,y:F.floating.y,arrowX:F.floating?.middlewareData?.arrow?.x,arrowY:F.floating?.middlewareData?.arrow?.y,opened:F.opened,arrowRef:Ge,transitionProps:{...c,onExited:le,onEntered:lt},width:p,withArrow:m,arrowSize:h,arrowOffset:g,arrowRadius:b,arrowPosition:v,placement:F.floating.placement,trapFocus:I,withinPortal:R,portalProps:E,zIndex:k,radius:D,shadow:P,closeOnEscape:O,onDismiss:j,onClose:F.onClose,onToggle:F.onToggle,getTargetId:()=>`${Je}-target`,getDropdownId:()=>`${Je}-dropdown`,withRoles:B,targetProps:qe,__staticSelector:L,classNames:S,styles:x,unstyled:C,variant:Pe,keepMounted:X,getStyles:_e,resolvedStyles:Nn,floatingStrategy:de,referenceHidden:Ye&&U!=="test"?F.floating.middlewareData.hide?.referenceHidden:!1},children:[n,Xe&&w.jsx(fo,{transition:"fade",mounted:F.opened,duration:c?.duration||250,exitDuration:c?.exitDuration||250,children:te=>w.jsx(vn,{withinPortal:R,children:w.jsx(bn,{...Te,..._e("overlay",{className:Te?.className,style:[te,Te?.style]})})})})]})}Ee.Target=tr;Ee.Dropdown=yn;Ee.displayName="@mantine/core/Popover";Ee.extend=e=>e;function nr(e){return typeof e=="string"?{value:e,label:e}:"value"in e&&!("label"in e)?{value:e.value,label:e.value,disabled:e.disabled}:typeof e=="number"?{value:e.toString(),label:e.toString()}:"group"in e?{group:e.group,items:e.items.map(t=>nr(t))}:e}function Ki(e){return e?e.map(t=>nr(t)):[]}function or(e){return e.reduce((t,n)=>"group"in n?{...t,...or(n.items)}:(t[n.value]=n,t),{})}var G={dropdown:"m_88b62a41",search:"m_985517d8",options:"m_b2821a6e",option:"m_92253aa5",empty:"m_2530cd1d",header:"m_858f94bd",footer:"m_82b967cb",group:"m_254f3e4f",groupLabel:"m_2bb2e9e5",chevron:"m_2943220b",optionsDropdownOption:"m_390b5f4",optionsDropdownCheckIcon:"m_8ee53fc2",optionsDropdownCheckPlaceholder:"m_a530ee0a"};const Xi={error:null},Yi=tt((e,{size:t,color:n})=>({chevron:{"--combobox-chevron-size":Bt(t,"combobox-chevron-size"),"--combobox-chevron-color":n?Sr(n,e):void 0}})),xn=Y((e,t)=>{const n=W("ComboboxChevron",Xi,e),{size:o,error:r,style:i,className:s,classNames:l,styles:c,unstyled:a,vars:f,mod:p,...d}=n,m=We({name:"ComboboxChevron",classes:G,props:n,style:i,className:s,classNames:l,styles:c,unstyled:a,vars:f,varsResolver:Yi,rootSelector:"chevron"});return w.jsx(Q,{component:"svg",...d,...m("chevron"),size:o,viewBox:"0 0 15 15",fill:"none",xmlns:"http://www.w3.org/2000/svg",mod:["combobox-chevron",{error:r},p],ref:t,children:w.jsx("path",{d:"M4.93179 5.43179C4.75605 5.60753 4.75605 5.89245 4.93179 6.06819C5.10753 6.24392 5.39245 6.24392 5.56819 6.06819L7.49999 4.13638L9.43179 6.06819C9.60753 6.24392 9.89245 6.24392 10.0682 6.06819C10.2439 5.89245 10.2439 5.60753 10.0682 5.43179L7.81819 3.18179C7.73379 3.0974 7.61933 3.04999 7.49999 3.04999C7.38064 3.04999 7.26618 3.0974 7.18179 3.18179L4.93179 5.43179ZM10.0682 9.56819C10.2439 9.39245 10.2439 9.10753 10.0682 8.93179C9.89245 8.75606 9.60753 8.75606 9.43179 8.93179L7.49999 10.8636L5.56819 8.93179C5.39245 8.75606 5.10753 8.75606 4.93179 8.93179C4.75605 9.10753 4.75605 9.39245 4.93179 9.56819L7.18179 11.8182C7.35753 11.9939 7.64245 11.9939 7.81819 11.8182L10.0682 9.56819Z",fill:"currentColor",fillRule:"evenodd",clipRule:"evenodd"})})});xn.classes=G;xn.displayName="@mantine/core/ComboboxChevron";const[Ui,ie]=wt("Combobox component was not found in tree"),rr=u.forwardRef(({size:e,onMouseDown:t,onClick:n,onClear:o,...r},i)=>w.jsx(ho.ClearButton,{ref:i,tabIndex:-1,"aria-hidden":!0,...r,onMouseDown:s=>{s.preventDefault(),t?.(s)},onClick:s=>{o(),n?.(s)}}));rr.displayName="@mantine/core/ComboboxClearButton";const Cn=Y((e,t)=>{const{classNames:n,styles:o,className:r,style:i,hidden:s,...l}=W("ComboboxDropdown",null,e),c=ie();return w.jsx(Ee.Dropdown,{...l,ref:t,role:"presentation","data-hidden":s||void 0,...c.getStyles("dropdown",{className:r,style:i,classNames:n,styles:o})})});Cn.classes=G;Cn.displayName="@mantine/core/ComboboxDropdown";const qi={refProp:"ref"},sr=Y((e,t)=>{const{children:n,refProp:o}=W("ComboboxDropdownTarget",qi,e);if(ie(),!bo(n))throw new Error("Combobox.DropdownTarget component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");return w.jsx(Ee.Target,{ref:t,refProp:o,children:n})});sr.displayName="@mantine/core/ComboboxDropdownTarget";const Rn=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,...l}=W("ComboboxEmpty",null,e),c=ie();return w.jsx(Q,{ref:t,...c.getStyles("empty",{className:o,classNames:n,styles:i,style:r}),...l})});Rn.classes=G;Rn.displayName="@mantine/core/ComboboxEmpty";function Sn({onKeyDown:e,withKeyboardNavigation:t,withAriaAttributes:n,withExpandedAttribute:o,targetType:r,autoComplete:i}){const s=ie(),[l,c]=u.useState(null),a=p=>{if(e?.(p),!s.readOnly&&t){if(p.nativeEvent.isComposing)return;if(p.nativeEvent.code==="ArrowDown"&&(p.preventDefault(),s.store.dropdownOpened?c(s.store.selectNextOption()):(s.store.openDropdown("keyboard"),c(s.store.selectActiveOption()),s.store.updateSelectedOptionIndex("selected",{scrollIntoView:!0}))),p.nativeEvent.code==="ArrowUp"&&(p.preventDefault(),s.store.dropdownOpened?c(s.store.selectPreviousOption()):(s.store.openDropdown("keyboard"),c(s.store.selectActiveOption()),s.store.updateSelectedOptionIndex("selected",{scrollIntoView:!0}))),p.nativeEvent.code==="Enter"||p.nativeEvent.code==="NumpadEnter"){if(p.nativeEvent.keyCode===229)return;const d=s.store.getSelectedOptionIndex();s.store.dropdownOpened&&d!==-1?(p.preventDefault(),s.store.clickSelectedOption()):r==="button"&&(p.preventDefault(),s.store.openDropdown("keyboard"))}p.key==="Escape"&&s.store.closeDropdown("keyboard"),p.nativeEvent.code==="Space"&&r==="button"&&(p.preventDefault(),s.store.toggleDropdown("keyboard"))}};return{...n?{"aria-haspopup":"listbox","aria-expanded":o?!!(s.store.listId&&s.store.dropdownOpened):void 0,"aria-controls":s.store.dropdownOpened&&s.store.listId?s.store.listId:void 0,"aria-activedescendant":s.store.dropdownOpened&&l||void 0,autoComplete:i,"data-expanded":s.store.dropdownOpened||void 0,"data-mantine-stop-propagation":s.store.dropdownOpened||void 0}:{},onKeyDown:a}}const Gi={refProp:"ref",targetType:"input",withKeyboardNavigation:!0,withAriaAttributes:!0,withExpandedAttribute:!1,autoComplete:"off"},ir=Y((e,t)=>{const{children:n,refProp:o,withKeyboardNavigation:r,withAriaAttributes:i,withExpandedAttribute:s,targetType:l,autoComplete:c,...a}=W("ComboboxEventsTarget",Gi,e),f=Rt(n);if(!f)throw new Error("Combobox.EventsTarget component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const p=ie(),d=Sn({targetType:l,withAriaAttributes:i,withKeyboardNavigation:r,withExpandedAttribute:s,onKeyDown:f.props.onKeyDown,autoComplete:c});return u.cloneElement(f,{...d,...a,[o]:re(t,p.store.targetRef,xo(f))})});ir.displayName="@mantine/core/ComboboxEventsTarget";const En=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,...l}=W("ComboboxFooter",null,e),c=ie();return w.jsx(Q,{ref:t,...c.getStyles("footer",{className:o,classNames:n,style:r,styles:i}),...l,onMouseDown:a=>{a.preventDefault()}})});En.classes=G;En.displayName="@mantine/core/ComboboxFooter";const Pn=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,children:l,label:c,id:a,...f}=W("ComboboxGroup",null,e),p=ie(),d=yt(a);return w.jsxs(Q,{ref:t,role:"group","aria-labelledby":c?d:void 0,...p.getStyles("group",{className:o,classNames:n,style:r,styles:i}),...f,children:[c&&w.jsx("div",{id:d,...p.getStyles("groupLabel",{classNames:n,styles:i}),children:c}),l]})});Pn.classes=G;Pn.displayName="@mantine/core/ComboboxGroup";const Tn=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,...l}=W("ComboboxHeader",null,e),c=ie();return w.jsx(Q,{ref:t,...c.getStyles("header",{className:o,classNames:n,style:r,styles:i}),...l,onMouseDown:a=>{a.preventDefault()}})});Tn.classes=G;Tn.displayName="@mantine/core/ComboboxHeader";function lr({value:e,valuesDivider:t=",",...n}){return w.jsx("input",{type:"hidden",value:Array.isArray(e)?e.join(t):e||"",...n})}lr.displayName="@mantine/core/ComboboxHiddenInput";const On=Y((e,t)=>{const n=W("ComboboxOption",null,e),{classNames:o,className:r,style:i,styles:s,vars:l,onClick:c,id:a,active:f,onMouseDown:p,onMouseOver:d,disabled:m,selected:h,mod:g,...b}=n,v=ie(),C=u.useId(),S=a||C;return w.jsx(Q,{...v.getStyles("option",{className:r,classNames:o,styles:s,style:i}),...b,ref:t,id:S,mod:["combobox-option",{"combobox-active":f,"combobox-disabled":m,"combobox-selected":h},g],role:"option",onClick:x=>{m?x.preventDefault():(v.onOptionSubmit?.(n.value,n),c?.(x))},onMouseDown:x=>{x.preventDefault(),p?.(x)},onMouseOver:x=>{v.resetSelectionOnOptionHover&&v.store.resetSelectedOption(),d?.(x)}})});On.classes=G;On.displayName="@mantine/core/ComboboxOption";const An=Y((e,t)=>{const n=W("ComboboxOptions",null,e),{classNames:o,className:r,style:i,styles:s,id:l,onMouseDown:c,labelledBy:a,...f}=n,p=ie(),d=yt(l);return u.useEffect(()=>{p.store.setListId(d)},[d]),w.jsx(Q,{ref:t,...p.getStyles("options",{className:r,style:i,classNames:o,styles:s}),...f,id:d,role:"listbox","aria-labelledby":a,onMouseDown:m=>{m.preventDefault(),c?.(m)}})});An.classes=G;An.displayName="@mantine/core/ComboboxOptions";const Zi={withAriaAttributes:!0,withKeyboardNavigation:!0},Dn=Y((e,t)=>{const n=W("ComboboxSearch",Zi,e),{classNames:o,styles:r,unstyled:i,vars:s,withAriaAttributes:l,onKeyDown:c,withKeyboardNavigation:a,size:f,...p}=n,d=ie(),m=d.getStyles("search"),h=Sn({targetType:"input",withAriaAttributes:l,withKeyboardNavigation:a,withExpandedAttribute:!1,onKeyDown:c,autoComplete:"off"});return w.jsx(ho,{ref:re(t,d.store.searchRef),classNames:[{input:m.className},o],styles:[{input:m.style},r],size:f||d.size,...h,...p,__staticSelector:"Combobox"})});Dn.classes=G;Dn.displayName="@mantine/core/ComboboxSearch";const Ji={refProp:"ref",targetType:"input",withKeyboardNavigation:!0,withAriaAttributes:!0,withExpandedAttribute:!1,autoComplete:"off"},cr=Y((e,t)=>{const{children:n,refProp:o,withKeyboardNavigation:r,withAriaAttributes:i,withExpandedAttribute:s,targetType:l,autoComplete:c,...a}=W("ComboboxTarget",Ji,e),f=Rt(n);if(!f)throw new Error("Combobox.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const p=ie(),d=Sn({targetType:l,withAriaAttributes:i,withKeyboardNavigation:r,withExpandedAttribute:s,onKeyDown:f.props.onKeyDown,autoComplete:c}),m=u.cloneElement(f,{...d,...a});return w.jsx(Ee.Target,{ref:re(t,p.store.targetRef),children:m})});cr.displayName="@mantine/core/ComboboxTarget";function Qi(e,t,n){for(let o=e-1;o>=0;o-=1)if(!t[o].hasAttribute("data-combobox-disabled"))return o;if(n){for(let o=t.length-1;o>-1;o-=1)if(!t[o].hasAttribute("data-combobox-disabled"))return o}return e}function el(e,t,n){for(let o=e+1;o{l||(c(!0),r?.(D))},[c,r,l]),v=u.useCallback((D="unknown")=>{l&&(c(!1),o?.(D))},[c,o,l]),C=u.useCallback((D="unknown")=>{l?v(D):b(D)},[v,b,l]),S=u.useCallback(()=>{const D=we(d.current),P=ut(`#${a.current} [data-combobox-selected]`,D);P?.removeAttribute("data-combobox-selected"),P?.removeAttribute("aria-selected")},[]),x=u.useCallback(D=>{const P=we(d.current),y=ut(`#${a.current}`,P),N=y?ye("[data-combobox-option]",y):null;if(!N)return null;const L=D>=N.length?0:D<0?N.length-1:D;return f.current=L,N?.[L]&&!N[L].hasAttribute("data-combobox-disabled")?(S(),N[L].setAttribute("data-combobox-selected","true"),N[L].setAttribute("aria-selected","true"),N[L].scrollIntoView({block:"nearest",behavior:s}),N[L].id):null},[s,S]),T=u.useCallback(()=>{const D=we(d.current),P=ut(`#${a.current} [data-combobox-active]`,D);if(P){const N=ye(`#${a.current} [data-combobox-option]`,D).findIndex(L=>L===P);return x(N)}return x(0)},[x]),R=u.useCallback(()=>{const D=we(d.current),P=ye(`#${a.current} [data-combobox-option]`,D);return x(el(f.current,P,i))},[x,i]),E=u.useCallback(()=>{const D=we(d.current),P=ye(`#${a.current} [data-combobox-option]`,D);return x(Qi(f.current,P,i))},[x,i]),O=u.useCallback(()=>{const D=we(d.current),P=ye(`#${a.current} [data-combobox-option]`,D);return x(tl(P))},[x]),_=u.useCallback((D="selected",P)=>{g.current=window.setTimeout(()=>{const y=we(d.current),N=ye(`#${a.current} [data-combobox-option]`,y),L=N.findIndex(B=>B.hasAttribute(`data-combobox-${D}`));f.current=L,P?.scrollIntoView&&N[L]?.scrollIntoView({block:"nearest",behavior:s})},0)},[]),I=u.useCallback(()=>{f.current=-1,S()},[S]),H=u.useCallback(()=>{const D=we(d.current);ye(`#${a.current} [data-combobox-option]`,D)?.[f.current]?.click()},[]),j=u.useCallback(D=>{a.current=D},[]),M=u.useCallback(()=>{m.current=window.setTimeout(()=>p.current?.focus(),0)},[]),A=u.useCallback(()=>{h.current=window.setTimeout(()=>d.current?.focus(),0)},[]),k=u.useCallback(()=>f.current,[]);return u.useEffect(()=>()=>{window.clearTimeout(m.current),window.clearTimeout(h.current),window.clearTimeout(g.current)},[]),{dropdownOpened:l,openDropdown:b,closeDropdown:v,toggleDropdown:C,selectedOptionIndex:f.current,getSelectedOptionIndex:k,selectOption:x,selectFirstOption:O,selectActiveOption:T,selectNextOption:R,selectPreviousOption:E,resetSelectedOption:I,updateSelectedOptionIndex:_,listId:a.current,setListId:j,clickSelectedOption:H,searchRef:p,focusSearchInput:M,targetRef:d,focusTarget:A}}const nl={keepMounted:!0,withinPortal:!0,resetSelectionOnOptionHover:!1,width:"target",transitionProps:{transition:"fade",duration:0},size:"sm"},ol=tt((e,{size:t,dropdownPadding:n})=>({options:{"--combobox-option-fz":_n(t),"--combobox-option-padding":Bt(t,"combobox-option-padding")},dropdown:{"--combobox-padding":n===void 0?void 0:ze(n),"--combobox-option-fz":_n(t),"--combobox-option-padding":Bt(t,"combobox-option-padding")}}));function z(e){const t=W("Combobox",nl,e),{classNames:n,styles:o,unstyled:r,children:i,store:s,vars:l,onOptionSubmit:c,onClose:a,size:f,dropdownPadding:p,resetSelectionOnOptionHover:d,__staticSelector:m,readOnly:h,attributes:g,...b}=t,v=ar(),C=s||v,S=We({name:m||"Combobox",classes:G,props:t,classNames:n,styles:o,unstyled:r,attributes:g,vars:l,varsResolver:ol}),x=()=>{a?.(),C.closeDropdown()};return w.jsx(Ui,{value:{getStyles:S,store:C,onOptionSubmit:c,size:f,resetSelectionOnOptionHover:d,readOnly:h},children:w.jsx(Ee,{opened:C.dropdownOpened,preventPositionChangeWhenVisible:!1,...b,onChange:T=>!T&&x(),withRoles:!1,unstyled:r,children:i})})}const rl=e=>e;z.extend=rl;z.classes=G;z.displayName="@mantine/core/Combobox";z.Target=cr;z.Dropdown=Cn;z.Options=An;z.Option=On;z.Search=Dn;z.Empty=Rn;z.Chevron=xn;z.Footer=En;z.Header=Tn;z.EventsTarget=ir;z.DropdownTarget=sr;z.Group=Pn;z.ClearButton=rr;z.HiddenInput=lr;function ur({size:e,style:t,...n}){const o=e!==void 0?{width:ze(e),height:ze(e),...t}:t;return w.jsx("svg",{viewBox:"0 0 10 7",fill:"none",xmlns:"http://www.w3.org/2000/svg",style:o,"aria-hidden":!0,...n,children:w.jsx("path",{d:"M4 4.586L1.707 2.293A1 1 0 1 0 .293 3.707l3 3a.997.997 0 0 0 1.414 0l5-5A1 1 0 1 0 8.293.293L4 4.586z",fill:"currentColor",fillRule:"evenodd",clipRule:"evenodd"})})}function xl({indeterminate:e,...t}){return e?w.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 32 6","aria-hidden":!0,...t,children:w.jsx("rect",{width:"32",height:"6",fill:"currentColor",rx:"3"})}):w.jsx(ur,{...t})}function et(e){return"group"in e}function fr({options:e,search:t,limit:n}){const o=t.trim().toLowerCase(),r=[];for(let i=0;i0)return!1;return!0}function dr(e,t=new Set){if(Array.isArray(e))for(const n of e)if(et(n))dr(n.items,t);else{if(typeof n.value>"u")throw new Error("[@mantine/core] Each option must have value property");if(typeof n.value!="string")throw new Error(`[@mantine/core] Option value must be a string, other data formats are not supported, got ${typeof n.value}`);if(t.has(n.value))throw new Error(`[@mantine/core] Duplicate options are not supported. Option with value "${n.value}" was provided more than once`);t.add(n.value)}}function il(e,t){return Array.isArray(e)?e.includes(t):e===t}function pr({data:e,withCheckIcon:t,withAlignedLabels:n,value:o,checkIconPosition:r,unstyled:i,renderOption:s}){if(!et(e)){const c=il(o,e.value),a=t&&(c?w.jsx(ur,{className:G.optionsDropdownCheckIcon}):n?w.jsx("div",{className:G.optionsDropdownCheckPlaceholder}):null),f=w.jsxs(w.Fragment,{children:[r==="left"&&a,w.jsx("span",{children:e.label}),r==="right"&&a]});return w.jsx(z.Option,{value:e.value,disabled:e.disabled,className:po({[G.optionsDropdownOption]:!i}),"data-reverse":r==="right"||void 0,"data-checked":c||void 0,"aria-selected":c,active:c,children:typeof s=="function"?s({option:e,checked:c}):f})}const l=e.items.map(c=>w.jsx(pr,{data:c,value:o,unstyled:i,withCheckIcon:t,withAlignedLabels:n,checkIconPosition:r,renderOption:s},c.value));return w.jsx(z.Group,{label:e.group,children:l})}function ll({data:e,hidden:t,hiddenWhenEmpty:n,filter:o,search:r,limit:i,maxDropdownHeight:s,withScrollArea:l=!0,filterOptions:c=!0,withCheckIcon:a=!1,withAlignedLabels:f=!1,value:p,checkIconPosition:d,nothingFoundMessage:m,unstyled:h,labelId:g,renderOption:b,scrollAreaProps:v,"aria-label":C}){dr(e);const x=typeof r=="string"?(o||fr)({options:e,search:c?r:"",limit:i??1/0}):e,T=sl(x),R=x.map(E=>w.jsx(pr,{data:E,withCheckIcon:a,withAlignedLabels:f,value:p,checkIconPosition:d,unstyled:h,renderOption:b},et(E)?E.group:E.value));return w.jsx(z.Dropdown,{hidden:t||n&&T,"data-composed":!0,children:w.jsxs(z.Options,{labelledBy:g,"aria-label":C,children:[l?w.jsx(nt.Autosize,{mah:s??220,type:"scroll",scrollbarSize:"var(--combobox-padding)",offsetScrollbars:"y",...v,children:R}):R,T&&m&&w.jsx(z.Empty,{children:m})]})})}const cl={withCheckIcon:!0,allowDeselect:!0,checkIconPosition:"left",openOnFocus:!0},mr=Y((e,t)=>{const n=W("Select",cl,e),{classNames:o,styles:r,unstyled:i,vars:s,dropdownOpened:l,defaultDropdownOpened:c,onDropdownClose:a,onDropdownOpen:f,onFocus:p,onBlur:d,onClick:m,onChange:h,data:g,value:b,defaultValue:v,selectFirstOptionOnChange:C,selectFirstOptionOnDropdownOpen:S,onOptionSubmit:x,comboboxProps:T,readOnly:R,disabled:E,filter:O,limit:_,withScrollArea:I,maxDropdownHeight:H,size:j,searchable:M,rightSection:A,checkIconPosition:k,withCheckIcon:D,withAlignedLabels:P,nothingFoundMessage:y,name:N,form:L,searchValue:B,defaultSearchValue:$,onSearchChange:K,allowDeselect:Pe,error:X,rightSectionPointerEvents:ee,id:de,clearable:Xe,clearButtonProps:Te,hiddenInputProps:Ye,renderOption:Ue,onClear:Oe,autoComplete:qe,scrollAreaProps:_e,__defaultRightSection:Nn,__clearSection:Ln,__clearable:Lt,chevronColor:ot,autoSelectOnBlur:Ge,openOnFocus:Mt,attributes:rt,...Fe}=n,Ze=u.useMemo(()=>Ki(g),[g]),je=u.useRef({}),U=u.useMemo(()=>or(Ze),[Ze]),Je=yt(de),[F,st,it]=mt({value:b,defaultValue:v,finalValue:null,onChange:h}),le=typeof F=="string"?F in U?U[F]:je.current[F]:void 0,lt=jr(le),[te,br,vr]=mt({value:B,defaultValue:$,finalValue:le?le.label:"",onChange:K}),Z=ar({opened:l,defaultOpened:c,onDropdownOpen:()=>{f?.(),S?Z.selectFirstOption():Z.updateSelectedOptionIndex("active",{scrollIntoView:!0})},onDropdownClose:()=>{a?.(),setTimeout(Z.resetSelectedOption,0)}}),Ae=J=>{br(J),Z.resetSelectedOption()},{resolvedClassNames:Mn,resolvedStyles:In}=mo({props:n,styles:r,classNames:o});u.useEffect(()=>{C&&Z.selectFirstOption()},[C,te]),u.useEffect(()=>{b===null&&Ae(""),typeof b=="string"&&le&&(lt?.value!==le.value||lt?.label!==le.label)&&Ae(le.label)},[b,le]),u.useEffect(()=>{!it&&!vr&&Ae(typeof F=="string"?F in U?U[F]?.label:je.current[F]?.label||"":"")},[U,F]),u.useEffect(()=>{F&&F in U&&(je.current[F]=U[F])},[U,F]);const wr=w.jsx(z.ClearButton,{...Te,onClear:()=>{st(null,null),Ae(""),Oe?.()}}),yr=Xe&&!!F&&!E&&!R;return w.jsxs(w.Fragment,{children:[w.jsxs(z,{store:Z,__staticSelector:"Select",classNames:Mn,styles:In,unstyled:i,readOnly:R,size:j,attributes:rt,keepMounted:Ge,onOptionSubmit:J=>{x?.(J);const De=Pe&&U[J].value===F?null:U[J],It=De?De.value:null;It!==F&&st(It,De),!it&&Ae(typeof It=="string"&&De?.label||""),Z.closeDropdown()},...T,children:[w.jsx(z.Target,{targetType:M?"input":"button",autoComplete:qe,children:w.jsx(xt,{id:Je,ref:t,__defaultRightSection:w.jsx(z.Chevron,{size:j,error:X,unstyled:i,color:ot}),__clearSection:wr,__clearable:yr,rightSection:A,rightSectionPointerEvents:ee||"none",...Fe,size:j,__staticSelector:"Select",disabled:E,readOnly:R||!M,value:te,onChange:J=>{Ae(J.currentTarget.value),Z.openDropdown(),C&&Z.selectFirstOption()},onFocus:J=>{Mt&&M&&Z.openDropdown(),p?.(J)},onBlur:J=>{Ge&&Z.clickSelectedOption(),M&&Z.closeDropdown();const De=typeof F=="string"&&(F in U?U[F]:je.current[F]);Ae(De&&De.label||""),d?.(J)},onClick:J=>{M?Z.openDropdown():Z.toggleDropdown(),m?.(J)},classNames:Mn,styles:In,unstyled:i,pointer:!M,error:X,attributes:rt})}),w.jsx(ll,{data:Ze,hidden:R||E,filter:O,search:te,limit:_,hiddenWhenEmpty:!y,withScrollArea:I,maxDropdownHeight:H,filterOptions:!!M&&le?.label!==te,value:F,checkIconPosition:k,withCheckIcon:D,withAlignedLabels:P,nothingFoundMessage:y,unstyled:i,labelId:Fe.label?`${Je}-label`:void 0,"aria-label":Fe.label?void 0:Fe["aria-label"],renderOption:Ue,scrollAreaProps:_e})]}),w.jsx(z.HiddenInput,{value:F,name:N,form:L,disabled:E,...Ye})]})});mr.classes={...xt.classes,...z.classes};mr.displayName="@mantine/core/Select";const hr=Y((e,t)=>{const n=W("TextInput",null,e);return w.jsx(xt,{component:"input",ref:t,...n,__staticSelector:"TextInput"})});hr.classes=xt.classes;hr.displayName="@mantine/core/TextInput";const al=[["path",{d:"M12 9v4",key:"svg-0"}],["path",{d:"M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0",key:"svg-1"}],["path",{d:"M12 16h.01",key:"svg-2"}]],ul=go("outline","alert-triangle","AlertTriangle",al);const fl=[["path",{d:"M12.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74",key:"svg-0"}],["path",{d:"M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6",key:"svg-1"}],["path",{d:"M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4",key:"svg-2"}],["path",{d:"M3 3l18 18",key:"svg-3"}]],dl=go("outline","database-off","DatabaseOff",fl);function Cl({title:e,description:t,action:n,tone:o="empty"}){const r=o==="error"?ul:dl;return w.jsxs("div",{className:`nf-state-view nf-state-view--${o}`,role:o==="error"?"alert":"status",children:[w.jsx(r,{size:28,stroke:1.5,"aria-hidden":"true"}),w.jsxs("div",{children:[w.jsx("strong",{children:e}),w.jsx("span",{children:t})]}),n]})}function Rl({onClick:e}){return w.jsx(Er,{variant:"light",color:"nodeflow",onClick:e,children:"Повторить"})}function Sl({title:e,description:t,actions:n,children:o,className:r="",as:i="section",...s}){return w.jsxs(i,{className:`nf-surface ${r}`,...s,children:[(e||t||n)&&w.jsxs("header",{className:"nf-surface__header",children:[w.jsxs("div",{children:[e&&w.jsx("h2",{children:e}),t&&w.jsx("p",{children:t})]}),n&&w.jsx("div",{className:"nf-surface__actions",children:n})]}),o]})}const gr=(e,t=0)=>Number.isFinite(e)?new Intl.NumberFormat("ru-RU",{maximumFractionDigits:t}).format(Number(e)):"—";function El(e){if(!Number.isFinite(e))return"—";const t=["Б","КиБ","МиБ","ГиБ","ТиБ","ПиБ"];let n=Math.max(0,Number(e)),o=0;for(;n>=1024&&o=100?0:n>=10?1:2)} ${t[o]}`}function Pl(e){if(typeof e!="number"||!Number.isFinite(e))return"—";const t=["бит/с","Кбит/с","Мбит/с","Гбит/с","Тбит/с"];let n=Math.max(0,Number(e)),o=0;for(;n>=1e3&&o=100||o===0?0:n>=10?1:2)} ${t[o]}`}function Tl(e){return String(e??"").match(/(?:HAProxy\s+version\s+)?(\d+\.\d+\.\d+)(?:[-+\s]|$)/i)?.[1]??e??"—"}function Ol(e){if(!e)return"никогда";const t=Math.max(0,(Date.now()-Date.parse(e))/1e3);return t<60?`${Math.floor(t)} сек назад`:t<3600?`${Math.floor(t/60)} мин назад`:t<86400?`${Math.floor(t/3600)} ч назад`:`${Math.floor(t/86400)} д назад`}function Al(e){if(!Number.isFinite(e))return"—";let t=Math.max(0,Math.floor(Number(e)));const n=Math.floor(t/86400);t%=86400;const o=Math.floor(t/3600);t%=3600;const r=Math.floor(t/60);return n?`${n} д. ${o} ч. ${r} м.`:o?`${o} ч. ${r} м.`:`${r} мин.`}function Dl(e){return!e||!Number.isFinite(Date.parse(e))?"—":new Intl.DateTimeFormat("ru-RU",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}).format(new Date(e))}export{wi as A,oi as B,xl as C,Ce as D,xo as E,wn as F,hl as G,Xn as H,ul as I,gl as J,wl as K,ml as L,vl as M,yl as N,ll as O,Ee as P,bl as Q,Rl as R,Cl as S,hr as T,ni as U,Gn as V,ii as W,Zn as X,Mi as Y,qo as Z,vt as _,El as a,gr as b,Sl as c,mr as d,Al as e,Pl as f,Dl as g,Ki as h,et as i,or as j,ar as k,z as l,Fr as m,ur as n,Xt as o,bn as p,Dr as q,vn as r,Tl as s,Ol as t,re as u,nn as v,bo as w,Rt as x,nt as y,Pr as z}; +import{r as u,O as Wt,R as kn,aG as lo,Q as co,j as w,H as wt,aH as en,s as W,y as Q,q as Y,t as We,v as tt,a4 as ze,a3 as xr,ag as ao,w as uo,aI as Cr,aJ as tn,af as fo,ak as po,o as mt,$ as mo,G as yt,ah as Rr,C as Sr,E as Bt,x as ho,K as _n,Z as xt,c as go,B as Er}from"./index-fgrXogF6.js";function bo(e){return Array.isArray(e)||e===null?!1:typeof e=="object"?e.type!==u.Fragment:!1}const Pr=()=>{};function Tr(e,t={active:!0}){return typeof e!="function"||!t.active?t.onKeyDown||Pr:n=>{n.key==="Escape"&&(e(n),t.onTrigger?.())}}function Le(e){const t=u.useRef(e);return u.useEffect(()=>{t.current=e}),u.useMemo(()=>((...n)=>t.current?.(...n)),[])}function Ct(e,t){const{delay:n,flushOnUnmount:o,leading:r}=typeof t=="number"?{delay:t,flushOnUnmount:!1,leading:!1}:t,i=Le(e),s=u.useRef(0),l=u.useMemo(()=>{const c=Object.assign((...a)=>{window.clearTimeout(s.current);const f=c._isFirstCall;c._isFirstCall=!1;function p(){window.clearTimeout(s.current),s.current=0,c._isFirstCall=!0}if(r&&f){i(...a);const h=()=>{p()},g=()=>{s.current!==0&&(p(),i(...a))},b=()=>{p()};c.flush=g,c.cancel=b,s.current=window.setTimeout(h,n);return}if(r&&!f){const h=()=>{s.current!==0&&(p(),i(...a))},g=()=>{p()};c.flush=h,c.cancel=g;const b=()=>{p()};s.current=window.setTimeout(b,n);return}const d=()=>{s.current!==0&&(p(),i(...a))},m=()=>{p()};c.flush=d,c.cancel=m,s.current=window.setTimeout(d,n)},{flush:()=>{},cancel:()=>{},_isFirstCall:!0});return c},[i,n,r]);return u.useEffect(()=>()=>{o?l.flush():l.cancel()},[l,o]),l}const Or=["mousedown","touchstart"];function Ar(e,t,n){const o=u.useRef(null),r=t||Or;return u.useEffect(()=>{const i=s=>{const{target:l}=s??{};if(Array.isArray(n)){const c=!document.body.contains(l)&&l?.tagName!=="HTML";n.every(f=>!!f&&!s.composedPath().includes(f))&&!c&&e(s)}else o.current&&!o.current.contains(l)&&e(s)};return r.forEach(s=>document.addEventListener(s,i)),()=>{r.forEach(s=>document.removeEventListener(s,i))}},[o,e,n]),o}function Dr({opened:e,shouldReturnFocus:t=!0}){const n=u.useRef(null),o=()=>{n.current&&"focus"in n.current&&typeof n.current.focus=="function"&&n.current?.focus({preventScroll:!0})};return Wt(()=>{let r=-1;const i=s=>{s.key==="Tab"&&window.clearTimeout(r)};return document.addEventListener("keydown",i),e?n.current=document.activeElement:t&&(r=window.setTimeout(o,10)),()=>{window.clearTimeout(r),document.removeEventListener("keydown",i)}},[e,t]),o}const Nr=/input|select|textarea|button|object/,vo="a, input, select, textarea, button, object, [tabindex]";function Lr(e){return e.style.display==="none"}function Mr(e){if(e.getAttribute("aria-hidden")||e.getAttribute("hidden")||e.getAttribute("type")==="hidden")return!1;let n=e;for(;n&&!(n===document.body||n.nodeType===11);){if(Lr(n))return!1;n=n.parentNode}return!0}function wo(e){let t=e.getAttribute("tabindex");return t===null&&(t=void 0),parseInt(t,10)}function Kt(e){const t=e.nodeName.toLowerCase(),n=!Number.isNaN(wo(e));return(Nr.test(t)&&!e.disabled||e instanceof HTMLAnchorElement&&e.href||n)&&Mr(e)}function yo(e){const t=wo(e);return(Number.isNaN(t)||t>=0)&&Kt(e)}function Ir(e){return Array.from(e.querySelectorAll(vo)).filter(yo)}function kr(e,t){const n=Ir(e);if(!n.length){t.preventDefault();return}const o=n[t.shiftKey?0:n.length-1],r=e.getRootNode();let i=o===r.activeElement||e===r.activeElement;const s=r.activeElement;if(s.tagName==="INPUT"&&s.getAttribute("type")==="radio"&&(i=n.filter(f=>f.getAttribute("type")==="radio"&&f.getAttribute("name")===s.getAttribute("name")).includes(o)),!i)return;t.preventDefault();const c=n[t.shiftKey?n.length-1:0];c&&c.focus()}function _r(e=!0){const t=u.useRef(null),n=r=>{let i=r.querySelector("[data-autofocus]");if(!i){const s=Array.from(r.querySelectorAll(vo));i=s.find(yo)||s.find(Kt)||null,!i&&Kt(r)&&(i=r)}i&&i.focus({preventScroll:!0})},o=u.useCallback(r=>{e&&r!==null&&t.current!==r&&(r?(setTimeout(()=>{r.getRootNode()&&n(r)}),t.current=r):t.current=null)},[e]);return u.useEffect(()=>{if(!e)return;t.current&&setTimeout(()=>n(t.current));const r=i=>{i.key==="Tab"&&t.current&&kr(t.current,i)};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[e]),o}function Xt(e,t){if(typeof e=="function")return e(t);typeof e=="object"&&e!==null&&"current"in e&&(e.current=t)}function Fr(...e){const t=new Map;return n=>{if(e.forEach(o=>{const r=Xt(o,n);r&&t.set(o,r)}),t.size>0)return()=>{e.forEach(o=>{const r=t.get(o);r&&typeof r=="function"?r():Xt(o,null)}),t.clear()}}}function re(...e){return u.useCallback(Fr(...e),e)}function jr(e){const t=u.useRef(void 0);return u.useEffect(()=>{t.current=e},[e]),t.current}function xo(e){const t=kn.version;return typeof kn.version!="string"||t.startsWith("18.")?e?.ref:e?.props?.ref}function ut(e,t=document){const n=t.querySelector(e);if(n)return n;const o=t.querySelectorAll("*");for(let r=0;r{},setDirection:()=>{}});function nn(){return u.useContext($r)}function St(){return typeof window<"u"}function Be(e){return Co(e)?(e.nodeName||"").toLowerCase():"#document"}function q(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function ve(e){var t;return(t=(Co(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function Co(e){return St()?e instanceof Node||e instanceof q(e).Node:!1}function V(e){return St()?e instanceof Element||e instanceof q(e).Element:!1}function fe(e){return St()?e instanceof HTMLElement||e instanceof q(e).HTMLElement:!1}function Yt(e){return!St()||typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof q(e).ShadowRoot}function Et(e){const{overflow:t,overflowX:n,overflowY:o,display:r}=ae(e);return/auto|scroll|overlay|hidden|clip/.test(t+o+n)&&r!=="inline"&&r!=="contents"}function Hr(e){return/^(table|td|th)$/.test(Be(e))}function Pt(e){try{if(e.matches(":popover-open"))return!0}catch{}try{return e.matches(":modal")}catch{return!1}}const zr=/transform|translate|scale|rotate|perspective|filter/,Vr=/paint|layout|strict|content/,Ne=e=>!!e&&e!=="none";let kt;function on(e){const t=V(e)?ae(e):e;return Ne(t.transform)||Ne(t.translate)||Ne(t.scale)||Ne(t.rotate)||Ne(t.perspective)||!Tt()&&(Ne(t.backdropFilter)||Ne(t.filter))||zr.test(t.willChange||"")||Vr.test(t.contain||"")}function Wr(e){let t=Se(e);for(;fe(t)&&!xe(t);){if(on(t))return t;if(Pt(t))return null;t=Se(t)}return null}function Tt(){return kt==null&&(kt=typeof CSS<"u"&&CSS.supports&&CSS.supports("-webkit-backdrop-filter","none")),kt}function xe(e){return/^(html|body|#document)$/.test(Be(e))}function ae(e){return q(e).getComputedStyle(e)}function Ot(e){return V(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function Se(e){if(Be(e)==="html")return e;const t=e.assignedSlot||e.parentNode||Yt(e)&&e.host||ve(e);return Yt(t)?t.host:t}function Ro(e){const t=Se(e);return xe(t)?(e.ownerDocument||e).body:fe(t)&&Et(t)?t:Ro(t)}function Ce(e,t,n){var o;t===void 0&&(t=[]),n===void 0&&(n=!0);const r=Ro(e),i=r===((o=e.ownerDocument)==null?void 0:o.body),s=q(r);if(i){const l=Ut(s);return t.concat(s,s.visualViewport||[],Et(r)?r:[],l&&n?Ce(l):[])}else return t.concat(r,Ce(r,[],n))}function Ut(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}const Br=["top","right","bottom","left"],ue=Math.min,oe=Math.max,ht=Math.round,ct=Math.floor,be=e=>({x:e,y:e}),Kr={left:"right",right:"left",bottom:"top",top:"bottom"};function So(e,t,n){return oe(e,ue(t,n))}function he(e,t){return typeof e=="function"?e(t):e}function ge(e){return e.split("-")[0]}function Ke(e){return e.split("-")[1]}function rn(e){return e==="x"?"y":"x"}function sn(e){return e==="y"?"height":"width"}function ce(e){const t=e[0];return t==="t"||t==="b"?"y":"x"}function ln(e){return rn(ce(e))}function Xr(e,t,n){n===void 0&&(n=!1);const o=Ke(e),r=ln(e),i=sn(r);let s=r==="x"?o===(n?"end":"start")?"right":"left":o==="start"?"bottom":"top";return t.reference[i]>t.floating[i]&&(s=gt(s)),[s,gt(s)]}function Yr(e){const t=gt(e);return[qt(e),t,qt(t)]}function qt(e){return e.includes("start")?e.replace("start","end"):e.replace("end","start")}const Fn=["left","right"],jn=["right","left"],Ur=["top","bottom"],qr=["bottom","top"];function Gr(e,t,n){switch(e){case"top":case"bottom":return n?t?jn:Fn:t?Fn:jn;case"left":case"right":return t?Ur:qr;default:return[]}}function Zr(e,t,n,o){const r=Ke(e);let i=Gr(ge(e),n==="start",o);return r&&(i=i.map(s=>s+"-"+r),t&&(i=i.concat(i.map(qt)))),i}function gt(e){const t=ge(e);return Kr[t]+e.slice(t.length)}function Jr(e){var t,n,o,r;return{top:(t=e.top)!=null?t:0,right:(n=e.right)!=null?n:0,bottom:(o=e.bottom)!=null?o:0,left:(r=e.left)!=null?r:0}}function cn(e){return typeof e!="number"?Jr(e):{top:e,right:e,bottom:e,left:e}}function Re(e){const{x:t,y:n,width:o,height:r}=e;return{width:o,height:r,top:n,left:t,right:t+o,bottom:n+r,x:t,y:n}}function Qr(){const e=navigator.userAgentData;return e!=null&&e.platform?e.platform:navigator.platform}function es(){const e=navigator.userAgentData;return e&&Array.isArray(e.brands)?e.brands.map(t=>{let{brand:n,version:o}=t;return n+"/"+o}).join(" "):navigator.userAgent}function ts(){return/apple/i.test(navigator.vendor)}function ns(){return Qr().toLowerCase().startsWith("mac")&&!navigator.maxTouchPoints}function os(){return es().includes("jsdom/")}const $n="data-floating-ui-focusable",rs="input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";function Hn(e){let t=e.activeElement;for(;((n=t)==null||(n=n.shadowRoot)==null?void 0:n.activeElement)!=null;){var n;t=t.shadowRoot.activeElement}return t}function Qe(e,t){if(!e||!t)return!1;const n=t.getRootNode==null?void 0:t.getRootNode();if(e.contains(t))return!0;if(n&&Yt(n)){let o=t;for(;o;){if(e===o)return!0;o=o.parentNode||o.host}}return!1}function $e(e){return"composedPath"in e?e.composedPath()[0]:e.target}function _t(e,t){if(t==null)return!1;if("composedPath"in e)return e.composedPath().includes(t);const n=e;return n.target!=null&&t.contains(n.target)}function ss(e){return e.matches("html,body")}function Me(e){return e?.ownerDocument||document}function is(e){return fe(e)&&e.matches(rs)}function ls(e){if(!e||os())return!0;try{return e.matches(":focus-visible")}catch{return!0}}function cs(e){return e?e.hasAttribute($n)?e:e.querySelector("["+$n+"]")||e:null}function ft(e,t,n){return n===void 0&&(n=!0),e.filter(r=>{var i;return r.parentId===t&&(!n||((i=r.context)==null?void 0:i.open))}).flatMap(r=>[r,...ft(e,r.id,n)])}function as(e){return"nativeEvent"in e}function Gt(e,t){const n=["mouse","pen"];return n.push("",void 0),n.includes(e)}var us=typeof document<"u",fs=function(){},me=us?u.useLayoutEffect:fs;const ds={...lo};function at(e){const t=u.useRef(e);return me(()=>{t.current=e}),t}const ps=ds.useInsertionEffect,ms=ps||(e=>e());function pe(e){const t=u.useRef(()=>{});return ms(()=>{t.current=e}),u.useCallback(function(){for(var n=arguments.length,o=new Array(n),r=0;r{const{placement:o="bottom",strategy:r="absolute",middleware:i=[],platform:s}=n,l=s.detectOverflow?s:{...s,detectOverflow:hs},c=await(s.isRTL==null?void 0:s.isRTL(t));let a=await s.getElementRects({reference:e,floating:t,strategy:r}),{x:f,y:p}=zn(a,o,c),d=o,m=0;const h={};for(let g=0;g({name:"arrow",options:e,async fn(t){const{x:n,y:o,placement:r,rects:i,platform:s,elements:l,middlewareData:c}=t,{element:a,padding:f=0}=he(e,t)||{};if(a==null)return{};const p=cn(f),d={x:n,y:o},m=ln(r),h=sn(m),g=await s.getDimensions(a),b=m==="y",v=b?"top":"left",C=b?"bottom":"right",S=b?"clientHeight":"clientWidth",x=i.reference[h]+i.reference[m]-d[m]-i.floating[h],T=d[m]-i.reference[m],R=await(s.getOffsetParent==null?void 0:s.getOffsetParent(a));let E=R?R[S]:0;(!E||!await(s.isElement==null?void 0:s.isElement(R)))&&(E=l.floating[S]||i.floating[h]);const O=x/2-T/2,_=E/2-g[h]/2-1,I=ue(p[v],_),H=ue(p[C],_),j=E-g[h]-H,M=E/2-g[h]/2+O,A=So(I,M,j),k=!c.arrow&&Ke(r)!=null&&M!==A&&i.reference[h]/2-(MA<=0)){var H,j;const A=(((H=i.flip)==null?void 0:H.index)||0)+1,k=E[A];if(k&&(!(p==="alignment"?C!==ce(k):!1)||I.every(y=>ce(y.placement)===C?y.overflows[0]>0:!0)))return{data:{index:A,overflows:I},reset:{placement:k}};let D=(j=I.filter(P=>P.overflows[0]<=0).sort((P,y)=>P.overflows[1]-y.overflows[1])[0])==null?void 0:j.placement;if(!D)switch(m){case"bestFit":{var M;const P=(M=I.filter(y=>{if(R){const N=ce(y.placement);return N===C||N==="y"}return!0}).map(y=>[y.placement,y.overflows.filter(N=>N>0).reduce((N,L)=>N+L,0)]).sort((y,N)=>y[1]-N[1])[0])==null?void 0:M[0];P&&(D=P);break}case"initialPlacement":D=l;break}if(r!==D)return{reset:{placement:D}}}return{}}}};function Vn(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function Wn(e){return Br.some(t=>e[t]>=0)}const ys=function(e){return e===void 0&&(e={}),{name:"hide",options:e,async fn(t){const{rects:n,platform:o}=t,{strategy:r="referenceHidden",...i}=he(e,t);switch(r){case"referenceHidden":{const s=await o.detectOverflow(t,{...i,elementContext:"reference"}),l=Vn(s,n.reference);return{data:{referenceHiddenOffsets:l,referenceHidden:Wn(l)}}}case"escaped":{const s=await o.detectOverflow(t,{...i,altBoundary:!0}),l=Vn(s,n.floating);return{data:{escapedOffsets:l,escaped:Wn(l)}}}default:return{}}}}};function Eo(e){const t=ue(...e.map(i=>i.left)),n=ue(...e.map(i=>i.top)),o=oe(...e.map(i=>i.right)),r=oe(...e.map(i=>i.bottom));return{x:t,y:n,width:o-t,height:r-n}}function xs(e){const t=e.slice().sort((r,i)=>r.y-i.y),n=[];let o=null;for(let r=0;ro.height/2?n.push([i]):n[n.length-1].push(i),o=i}return n.map(r=>Re(Eo(r)))}const Cs=function(e){return e===void 0&&(e={}),{name:"inline",options:e,async fn(t){const{placement:n,elements:o,rects:r,platform:i,strategy:s}=t,{padding:l=2,x:c,y:a}=he(e,t),f=Array.from(await(i.getClientRects==null?void 0:i.getClientRects(o.reference))||[]);if(!f.length)return{};const p=xs(f),d=Re(Eo(f)),m=cn(l);function h(){if(p.length===2&&(p[0].left>p[1].right||p[1].left>p[0].right)&&c!=null&&a!=null)return p.find(b=>c>b.left-m.left&&cb.top-m.top&&a=2){if(ce(n)==="y"){const R=p[0],E=p[p.length-1],O=ge(n)==="top",_=R.top,I=E.bottom,H=O?R.left:E.left,j=O?R.right:E.right;return Re({x:H,y:_,width:j-H,height:I-_})}const b=ge(n)==="left",v=oe(...p.map(R=>R.right)),C=ue(...p.map(R=>R.left)),S=p.filter(R=>b?R.left===C:R.right===v),x=S[0].top,T=S[S.length-1].bottom;return Re({x:C,y:x,width:v-C,height:T-x})}return d}const g=await i.getElementRects({reference:{getBoundingClientRect:h},floating:o.floating,strategy:s});return r.reference.x!==g.reference.x||r.reference.y!==g.reference.y||r.reference.width!==g.reference.width||r.reference.height!==g.reference.height?{reset:{rects:g}}:{}}}},Po=new Set(["left","top"]);async function Rs(e,t){const{placement:n,platform:o,elements:r}=e,i=await(o.isRTL==null?void 0:o.isRTL(r.floating)),s=ge(n),l=Ke(n),c=ce(n)==="y",a=Po.has(s)?-1:1,f=i&&c?-1:1,p=he(t,e);let{mainAxis:d,crossAxis:m,alignmentAxis:h}=typeof p=="number"?{mainAxis:p,crossAxis:0,alignmentAxis:null}:{mainAxis:p.mainAxis||0,crossAxis:p.crossAxis||0,alignmentAxis:p.alignmentAxis};return l&&typeof h=="number"&&(m=l==="end"?h*-1:h),c?{x:m*f,y:d*a}:{x:d*a,y:m*f}}const Ss=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var n,o;const{x:r,y:i,placement:s,middlewareData:l}=t,c=await Rs(t,e);return s===((n=l.offset)==null?void 0:n.placement)&&(o=l.arrow)!=null&&o.alignmentOffset?{}:{x:r+c.x,y:i+c.y,data:{...c,placement:s}}}}},Es=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){const{x:n,y:o,placement:r,platform:i}=t,{mainAxis:s=!0,crossAxis:l=!1,limiter:c={fn:C=>{let{x:S,y:x}=C;return{x:S,y:x}}},...a}=he(e,t),f={x:n,y:o},p=await i.detectOverflow(t,a),d=ce(r),m=rn(d);let h=f[m],g=f[d];const b=(C,S)=>So(S+p[C==="y"?"top":"left"],S,S-p[C==="y"?"bottom":"right"]);s&&(h=b(m,h)),l&&(g=b(d,g));const v=c.fn({...t,[m]:h,[d]:g});return{...v,data:{x:v.x-n,y:v.y-o,enabled:{[m]:s,[d]:l}}}}}},Ps=function(e){return e===void 0&&(e={}),{options:e,fn(t){var n,o;const{x:r,y:i,placement:s,rects:l,middlewareData:c}=t,{offset:a=0,mainAxis:f=!0,crossAxis:p=!0}=he(e,t),d={x:r,y:i},m=ce(s),h=rn(m);let g=d[h],b=d[m];const v=he(a,t),C=typeof v=="number"?{mainAxis:v,crossAxis:0}:{mainAxis:(n=v.mainAxis)!=null?n:0,crossAxis:(o=v.crossAxis)!=null?o:0};if(f){const T=h==="y"?"height":"width",R=l.reference[h]-l.floating[T]+C.mainAxis,E=l.reference[h]+l.reference[T]-C.mainAxis;gE&&(g=E)}if(p){var S,x;const T=h==="y"?"width":"height",R=Po.has(ge(s)),E=l.reference[m]-l.floating[T]+(R&&((S=c.offset)==null?void 0:S[m])||0)+(R?0:C.crossAxis),O=l.reference[m]+l.reference[T]+(R?0:((x=c.offset)==null?void 0:x[m])||0)-(R?C.crossAxis:0);bO&&(b=O)}return{[h]:g,[m]:b}}}},Ts=function(e){return e===void 0&&(e={}),{name:"size",options:e,async fn(t){const{placement:n,rects:o,platform:r,elements:i}=t,{apply:s=()=>{},...l}=he(e,t),c=await r.detectOverflow(t,l),a=ge(n),f=Ke(n),p=ce(n)==="y",{width:d,height:m}=o.floating;let h,g;a==="top"||a==="bottom"?(h=a,g=f===(await(r.isRTL==null?void 0:r.isRTL(i.floating))?"start":"end")?"left":"right"):(g=a,h=f==="end"?"top":"bottom");const b=m-c.top-c.bottom,v=d-c.left-c.right,C=ue(m-c[h],b),S=ue(d-c[g],v),x=t.middlewareData.shift,T=!x;let R=C,E=S;x!=null&&x.enabled.x&&(E=v),x!=null&&x.enabled.y&&(R=b),T&&!f&&(p?E=d-2*oe(c.left,c.right):R=m-2*oe(c.top,c.bottom)),await s({...t,availableWidth:E,availableHeight:R});const O=await r.getDimensions(i.floating);return d!==O.width||m!==O.height?{reset:{rects:!0}}:{}}}};function To(e){const t=ae(e);let n=parseFloat(t.width)||0,o=parseFloat(t.height)||0;const r=fe(e),i=r?e.offsetWidth:n,s=r?e.offsetHeight:o,l=ht(n)!==i||ht(o)!==s;return l&&(n=i,o=s),{width:n,height:o,$:l}}function an(e){return V(e)?e:e.contextElement}function He(e){const t=an(e);if(!fe(t))return be(1);const n=t.getBoundingClientRect(),{width:o,height:r,$:i}=To(t);let s=(i?ht(n.width):n.width)/o,l=(i?ht(n.height):n.height)/r;return(!s||!Number.isFinite(s))&&(s=1),(!l||!Number.isFinite(l))&&(l=1),{x:s,y:l}}const Os=be(0);function Oo(e){const t=q(e);return!Tt()||!t.visualViewport?Os:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function As(e,t,n){return t===void 0&&(t=!1),!!n&&t&&n===q(e)}function ke(e,t,n,o){t===void 0&&(t=!1),n===void 0&&(n=!1);const r=e.getBoundingClientRect(),i=an(e);let s=be(1);t&&(o?V(o)&&(s=He(o)):s=He(e));const l=As(i,n,o)?Oo(i):be(0);let c=(r.left+l.x)/s.x,a=(r.top+l.y)/s.y,f=r.width/s.x,p=r.height/s.y;if(i&&o){const d=q(i),m=V(o)?q(o):o;let h=d,g=Ut(h);for(;g&&m!==h;){const b=He(g),v=g.getBoundingClientRect(),C=ae(g),S=v.left+(g.clientLeft+parseFloat(C.paddingLeft))*b.x,x=v.top+(g.clientTop+parseFloat(C.paddingTop))*b.y;c*=b.x,a*=b.y,f*=b.x,p*=b.y,c+=S,a+=x,h=q(g),g=Ut(h)}}return Re({width:f,height:p,x:c,y:a})}function At(e,t){const n=Ot(e).scrollLeft;return t?t.left+n:ke(ve(e)).left+n}function Ao(e,t){const n=e.getBoundingClientRect(),o=n.left+t.scrollLeft-At(e,n),r=n.top+t.scrollTop;return{x:o,y:r}}function Ds(e){let{elements:t,rect:n,offsetParent:o,strategy:r}=e;const i=r==="fixed",s=ve(o),l=t?Pt(t.floating):!1;if(o===s||l&&i)return n;let c={scrollLeft:0,scrollTop:0},a=be(1);const f=be(0),p=fe(o);if((p||!i)&&((Be(o)!=="body"||Et(s))&&(c=Ot(o)),p)){const m=ke(o);a=He(o),f.x=m.x+o.clientLeft,f.y=m.y+o.clientTop}const d=s&&!p&&!i?Ao(s,c):be(0);return{width:n.width*a.x,height:n.height*a.y,x:n.x*a.x-c.scrollLeft*a.x+f.x+d.x,y:n.y*a.y-c.scrollTop*a.y+f.y+d.y}}function Ns(e){return e.getClientRects?Array.from(e.getClientRects()):[]}function Ls(e){const t=Ot(e),n=e.ownerDocument.body,o=oe(e.scrollWidth,e.clientWidth,n.scrollWidth,n.clientWidth),r=oe(e.scrollHeight,e.clientHeight,n.scrollHeight,n.clientHeight);let i=-t.scrollLeft+At(e);const s=-t.scrollTop;return ae(n).direction==="rtl"&&(i+=oe(e.clientWidth,n.clientWidth)-o),{width:o,height:r,x:i,y:s}}const Ms=25;function Is(e,t,n){n===void 0&&(n="viewport");const o=n==="layoutViewport",r=q(e),i=ve(e),s=r.visualViewport;let l=i.clientWidth,c=i.clientHeight,a=0,f=0;if(s){const d=!Tt()||t==="fixed";o?d||(a=-s.offsetLeft,f=-s.offsetTop):(l=s.width,c=s.height,d&&(a=s.offsetLeft,f=s.offsetTop))}if(At(i)<=0){const d=i.ownerDocument,m=d.body,h=getComputedStyle(m),g=d.compatMode==="CSS1Compat"&&parseFloat(h.marginLeft)+parseFloat(h.marginRight)||0,b=Math.abs(i.clientWidth-m.clientWidth-g),v=getComputedStyle(i).scrollbarGutter==="stable both-edges"?b/2:b;v<=Ms&&(l-=v)}return{width:l,height:c,x:a,y:f}}function ks(e,t){const n=ke(e,!0,t==="fixed"),o=n.top+e.clientTop,r=n.left+e.clientLeft,i=He(e),s=e.clientWidth*i.x,l=e.clientHeight*i.y,c=r*i.x,a=o*i.y;return{width:s,height:l,x:c,y:a}}function Bn(e,t,n){let o;if(t==="viewport"||t==="layoutViewport")o=Is(e,n,t);else if(t==="document")o=Ls(ve(e));else if(V(t))o=ks(t,n);else{const r=Oo(e);o={x:t.x-r.x,y:t.y-r.y,width:t.width,height:t.height}}return Re(o)}function _s(e,t){const n=t.get(e);if(n)return n;let o=Ce(e,[],!1).filter(l=>V(l)&&Be(l)!=="body"),r=null;const i=ae(e).position==="fixed";let s=i?Se(e):e;for(;V(s)&&!xe(s);){const l=ae(s),c=on(s),a=r?r.position:i?"fixed":"";!c&&(a==="fixed"||a==="absolute"&&l.position==="static")?o=o.filter(p=>p!==s):r=l,s=Se(s)}return t.set(e,o),o}function Fs(e){let{element:t,boundary:n,rootBoundary:o,strategy:r}=e;const s=[...n==="clippingAncestors"?Pt(t)?[]:_s(t,this._c):[].concat(n),o],l=Bn(t,s[0],r);let c=l.top,a=l.right,f=l.bottom,p=l.left;for(let d=1;d{l(!1,1e-7)},1e3)}E=!1}try{o=new IntersectionObserver(O,{...R,root:i.ownerDocument})}catch{o=new IntersectionObserver(O,R)}o.observe(e)}const c=q(e),a=()=>l(n);return c.addEventListener("resize",a),l(!0),()=>{c.removeEventListener("resize",a),s()}}function Xn(e,t,n,o){o===void 0&&(o={});const{ancestorScroll:r=!0,ancestorResize:i=!0,elementResize:s=typeof ResizeObserver=="function",layoutShift:l=typeof IntersectionObserver=="function",animationFrame:c=!1}=o,a=an(e),f=r||i?[...a?Ce(a):[],...t?Ce(t):[]]:[];f.forEach(v=>{r&&v.addEventListener("scroll",n),i&&v.addEventListener("resize",n)});const p=a&&l?Ws(a,n,i):null;let d=-1,m=null;s&&(m=new ResizeObserver(v=>{let[C]=v;C&&C.target===a&&m&&t&&(m.unobserve(t),cancelAnimationFrame(d),d=requestAnimationFrame(()=>{var S;(S=m)==null||S.observe(t)})),n()}),a&&!c&&m.observe(a),t&&m.observe(t));let h,g=c?ke(e):null;c&&b();function b(){const v=ke(e);g&&!No(g,v)&&n(),g=v,h=requestAnimationFrame(b)}return n(),()=>{var v;f.forEach(C=>{r&&C.removeEventListener("scroll",n),i&&C.removeEventListener("resize",n)}),p?.(),(v=m)==null||v.disconnect(),m=null,c&&cancelAnimationFrame(h)}}const Bs=Ss,Ks=Es,Xs=ws,Ys=Ts,Us=ys,Yn=vs,qs=Cs,Gs=Ps,Zs=(e,t,n)=>{const o=new Map,r=n??{},i={...Vs,...r.platform,_c:o};return bs(e,t,{...r,platform:i})};var Js=typeof document<"u",Qs=function(){},dt=Js?u.useLayoutEffect:Qs;function bt(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e=="function"&&e.toString()===t.toString())return!0;let n,o,r;if(e&&t&&typeof e=="object"){if(Array.isArray(e)){if(n=e.length,n!==t.length)return!1;for(o=n;o--!==0;)if(!bt(e[o],t[o]))return!1;return!0}if(r=Object.keys(e),n=r.length,n!==Object.keys(t).length)return!1;for(o=n;o--!==0;)if(!{}.hasOwnProperty.call(t,r[o]))return!1;for(o=n;o--!==0;){const i=r[o];if(!(i==="_owner"&&e.$$typeof)&&!bt(e[i],t[i]))return!1}return!0}return e!==e&&t!==t}function Lo(e){return typeof window>"u"?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function Un(e,t){const n=Lo(e);return Math.round(t*n)/n}function jt(e){const t=u.useRef(e);return dt(()=>{t.current=e}),t}function ei(e){e===void 0&&(e={});const{placement:t="bottom",strategy:n="absolute",middleware:o=[],platform:r,elements:{reference:i,floating:s}={},transform:l=!0,whileElementsMounted:c,open:a}=e,[f,p]=u.useState({x:0,y:0,strategy:n,placement:t,middlewareData:{},isPositioned:!1}),[d,m]=u.useState(o);bt(d,o)||m(o);const[h,g]=u.useState(null),[b,v]=u.useState(null),C=u.useCallback(y=>{y!==R.current&&(R.current=y,g(y))},[]),S=u.useCallback(y=>{y!==E.current&&(E.current=y,v(y))},[]),x=i||h,T=s||b,R=u.useRef(null),E=u.useRef(null),O=u.useRef(f),_=c!=null,I=jt(c),H=jt(r),j=jt(a),M=u.useCallback(()=>{if(!R.current||!E.current)return;const y={placement:t,strategy:n,middleware:d};H.current&&(y.platform=H.current),Zs(R.current,E.current,y).then(N=>{const L={...N,isPositioned:j.current!==!1};A.current&&!bt(O.current,L)&&(O.current=L,co.flushSync(()=>{p(L)}))})},[d,t,n,H,j]);dt(()=>{a===!1&&O.current.isPositioned&&(O.current.isPositioned=!1,p(y=>({...y,isPositioned:!1})))},[a]);const A=u.useRef(!1);dt(()=>(A.current=!0,()=>{A.current=!1}),[]),dt(()=>{if(x&&(R.current=x),T&&(E.current=T),x&&T){if(I.current)return I.current(x,T,M);M()}},[x,T,M,I,_]);const k=u.useMemo(()=>({reference:R,floating:E,setReference:C,setFloating:S}),[C,S]),D=u.useMemo(()=>({reference:x,floating:T}),[x,T]),P=u.useMemo(()=>{const y={position:n,left:0,top:0};if(!D.floating)return y;const N=Un(D.floating,f.x),L=Un(D.floating,f.y);return l?{...y,transform:"translate("+N+"px, "+L+"px)",...Lo(D.floating)>=1.5&&{willChange:"transform"}}:{position:n,left:N,top:L}},[n,l,D.floating,f.x,f.y]);return u.useMemo(()=>({...f,update:M,refs:k,elements:D,floatingStyles:P}),[f,M,k,D,P])}const ti=e=>{function t(n){return{}.hasOwnProperty.call(n,"current")}return{name:"arrow",options:e,fn(n){const{element:o,padding:r}=typeof e=="function"?e(n):e;return o&&t(o)?o.current!=null?Yn({element:o.current,padding:r}).fn(n):{}:o?Yn({element:o,padding:r}).fn(n):{}}}},ni=(e,t)=>{const n=Bs(e);return{name:n.name,fn:n.fn,options:[e,t]}},oi=(e,t)=>{const n=Ks(e);return{name:n.name,fn:n.fn,options:[e,t]}},qn=(e,t)=>({fn:Gs(e).fn,options:[e,t]}),Gn=(e,t)=>{const n=Xs(e);return{name:n.name,fn:n.fn,options:[e,t]}},ri=(e,t)=>{const n=Ys(e);return{name:n.name,fn:n.fn,options:[e,t]}},si=(e,t)=>{const n=Us(e);return{name:n.name,fn:n.fn,options:[e,t]}},Zn=(e,t)=>{const n=qs(e);return{name:n.name,fn:n.fn,options:[e,t]}},ii=(e,t)=>{const n=ti(e);return{name:n.name,fn:n.fn,options:[e,t]}};function Mo(e){const t=u.useRef(void 0),n=u.useCallback(o=>{const r=e.map(i=>{if(i!=null){if(typeof i=="function"){const s=i,l=s(o);return typeof l=="function"?l:()=>{s(null)}}return i.current=o,()=>{i.current=null}}});return()=>{r.forEach(i=>i?.())}},e);return u.useMemo(()=>e.every(o=>o==null)?null:o=>{t.current&&(t.current(),t.current=void 0),o!=null&&(t.current=n(o))},e)}const li="data-floating-ui-focusable",Jn="active",Qn="selected",ci={...lo};let eo=!1,ai=0;const to=()=>"floating-ui-"+Math.random().toString(36).slice(2,6)+ai++;function ui(){const[e,t]=u.useState(()=>eo?to():void 0);return me(()=>{e==null&&t(to())},[]),u.useEffect(()=>{eo=!0},[]),e}const fi=ci.useId,Io=fi||ui;function di(){const e=new Map;return{emit(t,n){var o;(o=e.get(t))==null||o.forEach(r=>r(n))},on(t,n){e.has(t)||e.set(t,new Set),e.get(t).add(n)},off(t,n){var o;(o=e.get(t))==null||o.delete(n)}}}const pi=u.createContext(null),mi=u.createContext(null),un=()=>{var e;return((e=u.useContext(pi))==null?void 0:e.id)||null},fn=()=>u.useContext(mi);function dn(e){return"data-floating-ui-"+e}function ne(e){e.current!==-1&&(clearTimeout(e.current),e.current=-1)}const no=dn("safe-polygon");function pt(e,t,n){if(n&&!Gt(n))return 0;if(typeof e=="number")return e;if(typeof e=="function"){const o=e();return typeof o=="number"?o:o?.[t]}return e?.[t]}function $t(e){return typeof e=="function"?e():e}function ml(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,dataRef:r,events:i,elements:s}=e,{enabled:l=!0,delay:c=0,handleClose:a=null,mouseOnly:f=!1,restMs:p=0,move:d=!0}=t,m=fn(),h=un(),g=at(a),b=at(c),v=at(n),C=at(p),S=u.useRef(),x=u.useRef(-1),T=u.useRef(),R=u.useRef(-1),E=u.useRef(!0),O=u.useRef(!1),_=u.useRef(()=>{}),I=u.useRef(!1),H=pe(()=>{var P;const y=(P=r.current.openEvent)==null?void 0:P.type;return y?.includes("mouse")&&y!=="mousedown"});u.useEffect(()=>{if(!l)return;function P(y){let{open:N}=y;N||(ne(x),ne(R),E.current=!0,I.current=!1)}return i.on("openchange",P),()=>{i.off("openchange",P)}},[l,i]),u.useEffect(()=>{if(!l||!g.current||!n)return;function P(N){H()&&o(!1,N,"hover")}const y=Me(s.floating).documentElement;return y.addEventListener("mouseleave",P),()=>{y.removeEventListener("mouseleave",P)}},[s.floating,n,o,l,g,H]);const j=u.useCallback(function(P,y,N){y===void 0&&(y=!0),N===void 0&&(N="hover");const L=pt(b.current,"close",S.current);L&&!T.current?(ne(x),x.current=window.setTimeout(()=>o(!1,P,N),L)):y&&(ne(x),o(!1,P,N))},[b,o]),M=pe(()=>{_.current(),T.current=void 0}),A=pe(()=>{if(O.current){const P=Me(s.floating).body;P.style.pointerEvents="",P.removeAttribute(no),O.current=!1}}),k=pe(()=>r.current.openEvent?["click","mousedown"].includes(r.current.openEvent.type):!1);u.useEffect(()=>{if(!l)return;function P($){if(ne(x),E.current=!1,f&&!Gt(S.current)||$t(C.current)>0&&!pt(b.current,"open"))return;const K=pt(b.current,"open",S.current);K?x.current=window.setTimeout(()=>{v.current||o(!0,$,"hover")},K):n||o(!0,$,"hover")}function y($){if(k()){A();return}_.current();const K=Me(s.floating);if(ne(R),I.current=!1,g.current&&r.current.floatingContext){n||ne(x),T.current=g.current({...r.current.floatingContext,tree:m,x:$.clientX,y:$.clientY,onClose(){A(),M(),k()||j($,!0,"safe-polygon")}});const X=T.current;K.addEventListener("mousemove",X),_.current=()=>{K.removeEventListener("mousemove",X)};return}(S.current!=="touch"||!Qe(s.floating,$.relatedTarget))&&j($)}function N($){k()||r.current.floatingContext&&(g.current==null||g.current({...r.current.floatingContext,tree:m,x:$.clientX,y:$.clientY,onClose(){A(),M(),k()||j($)}})($))}function L(){ne(x)}function B($){k()||j($,!1)}if(V(s.domReference)){const $=s.domReference,K=s.floating;return n&&$.addEventListener("mouseleave",N),d&&$.addEventListener("mousemove",P,{once:!0}),$.addEventListener("mouseenter",P),$.addEventListener("mouseleave",y),K&&(K.addEventListener("mouseleave",N),K.addEventListener("mouseenter",L),K.addEventListener("mouseleave",B)),()=>{n&&$.removeEventListener("mouseleave",N),d&&$.removeEventListener("mousemove",P),$.removeEventListener("mouseenter",P),$.removeEventListener("mouseleave",y),K&&(K.removeEventListener("mouseleave",N),K.removeEventListener("mouseenter",L),K.removeEventListener("mouseleave",B))}}},[s,l,e,f,d,j,M,A,o,n,v,m,b,g,r,k,C]),me(()=>{var P;if(l&&n&&(P=g.current)!=null&&(P=P.__options)!=null&&P.blockPointerEvents&&H()){O.current=!0;const N=s.floating;if(V(s.domReference)&&N){var y;const L=Me(s.floating).body;L.setAttribute(no,"");const B=s.domReference,$=m==null||(y=m.nodesRef.current.find(K=>K.id===h))==null||(y=y.context)==null?void 0:y.elements.floating;return $&&($.style.pointerEvents=""),L.style.pointerEvents="none",B.style.pointerEvents="auto",N.style.pointerEvents="auto",()=>{L.style.pointerEvents="",B.style.pointerEvents="",N.style.pointerEvents=""}}}},[l,n,h,s,m,g,H]),me(()=>{n||(S.current=void 0,I.current=!1,M(),A())},[n,M,A]),u.useEffect(()=>()=>{M(),ne(x),ne(R),A()},[l,s.domReference,M,A]);const D=u.useMemo(()=>{function P(y){S.current=y.pointerType}return{onPointerDown:P,onPointerEnter:P,onMouseMove(y){const{nativeEvent:N}=y;function L(){!E.current&&!v.current&&o(!0,N,"hover")}f&&!Gt(S.current)||n||$t(C.current)===0||I.current&&y.movementX**2+y.movementY**2<2||(ne(R),S.current==="touch"?L():(I.current=!0,R.current=window.setTimeout(L,$t(C.current))))}}},[f,o,n,v,C]);return u.useMemo(()=>l?{reference:D}:{},[l,D])}const Zt=()=>{},ko=u.createContext({delay:0,initialDelay:0,timeoutMs:0,currentId:null,setCurrentId:Zt,setState:Zt,isInstantPhase:!1}),hi=()=>u.useContext(ko);function hl(e){const{children:t,delay:n,timeoutMs:o=0}=e,[r,i]=u.useReducer((c,a)=>({...c,...a}),{delay:n,timeoutMs:o,initialDelay:n,currentId:null,isInstantPhase:!1}),s=u.useRef(null),l=u.useCallback(c=>{i({currentId:c})},[]);return me(()=>{r.currentId?s.current===null?s.current=r.currentId:r.isInstantPhase||i({isInstantPhase:!0}):(r.isInstantPhase&&i({isInstantPhase:!1}),s.current=null)},[r.currentId,r.isInstantPhase]),w.jsx(ko.Provider,{value:u.useMemo(()=>({...r,setState:i,setCurrentId:l}),[r,l]),children:t})}function gl(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,floatingId:r}=e,{id:i,enabled:s=!0}=t,l=i??r,c=hi(),{currentId:a,setCurrentId:f,initialDelay:p,setState:d,timeoutMs:m}=c;return me(()=>{s&&a&&(d({delay:{open:1,close:pt(p,"close")}}),a!==l&&o(!1))},[s,l,o,d,a,p]),me(()=>{function h(){o(!1),d({delay:p,currentId:null})}if(s&&a&&!n&&a===l){if(m){const g=window.setTimeout(h,m);return()=>{clearTimeout(g)}}h()}},[s,n,d,a,l,o,p,m]),me(()=>{s&&(f===Zt||!n||f(l))},[s,n,f,l]),c}const gi={pointerdown:"onPointerDown",mousedown:"onMouseDown",click:"onClick"},bi={pointerdown:"onPointerDownCapture",mousedown:"onMouseDownCapture",click:"onClickCapture"},oo=e=>{var t,n;return{escapeKey:typeof e=="boolean"?e:(t=e?.escapeKey)!=null?t:!1,outsidePress:typeof e=="boolean"?e:(n=e?.outsidePress)!=null?n:!0}};function bl(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,elements:r,dataRef:i}=e,{enabled:s=!0,escapeKey:l=!0,outsidePress:c=!0,outsidePressEvent:a="pointerdown",referencePress:f=!1,referencePressEvent:p="pointerdown",ancestorScroll:d=!1,bubbles:m,capture:h}=t,g=fn(),b=pe(typeof c=="function"?c:()=>!1),v=typeof c=="function"?b:c,C=u.useRef(!1),{escapeKey:S,outsidePress:x}=oo(m),{escapeKey:T,outsidePress:R}=oo(h),E=u.useRef(!1),O=pe(A=>{var k;if(!n||!s||!l||A.key!=="Escape"||E.current)return;const D=(k=i.current.floatingContext)==null?void 0:k.nodeId,P=g?ft(g.nodesRef.current,D):[];if(!S&&(A.stopPropagation(),P.length>0)){let y=!0;if(P.forEach(N=>{var L;if((L=N.context)!=null&&L.open&&!N.context.dataRef.current.__escapeKeyBubbles){y=!1;return}}),!y)return}o(!1,as(A)?A.nativeEvent:A,"escape-key")}),_=pe(A=>{var k;const D=()=>{var P;O(A),(P=$e(A))==null||P.removeEventListener("keydown",D)};(k=$e(A))==null||k.addEventListener("keydown",D)}),I=pe(A=>{var k;const D=i.current.insideReactTree;i.current.insideReactTree=!1;const P=C.current;if(C.current=!1,a==="click"&&P||D||typeof v=="function"&&!v(A))return;const y=$e(A),N="["+dn("inert")+"]",L=Me(r.floating).querySelectorAll(N);let B=V(y)?y:null;for(;B&&!xe(B);){const X=Se(B);if(xe(X)||!V(X))break;B=X}if(L.length&&V(y)&&!ss(y)&&!Qe(y,r.floating)&&Array.from(L).every(X=>!Qe(B,X)))return;if(fe(y)&&M){const X=xe(y),ee=ae(y),de=/auto|scroll/,Xe=X||de.test(ee.overflowX),Te=X||de.test(ee.overflowY),Ye=Xe&&y.clientWidth>0&&y.scrollWidth>y.clientWidth,Ue=Te&&y.clientHeight>0&&y.scrollHeight>y.clientHeight,Oe=ee.direction==="rtl",qe=Ue&&(Oe?A.offsetX<=y.offsetWidth-y.clientWidth:A.offsetX>y.clientWidth),_e=Ye&&A.offsetY>y.clientHeight;if(qe||_e)return}const $=(k=i.current.floatingContext)==null?void 0:k.nodeId,K=g&&ft(g.nodesRef.current,$).some(X=>{var ee;return _t(A,(ee=X.context)==null?void 0:ee.elements.floating)});if(_t(A,r.floating)||_t(A,r.domReference)||K)return;const Pe=g?ft(g.nodesRef.current,$):[];if(Pe.length>0){let X=!0;if(Pe.forEach(ee=>{var de;if((de=ee.context)!=null&&de.open&&!ee.context.dataRef.current.__outsidePressBubbles){X=!1;return}}),!X)return}o(!1,A,"outside-press")}),H=pe(A=>{var k;const D=()=>{var P;I(A),(P=$e(A))==null||P.removeEventListener(a,D)};(k=$e(A))==null||k.addEventListener(a,D)});u.useEffect(()=>{if(!n||!s)return;i.current.__escapeKeyBubbles=S,i.current.__outsidePressBubbles=x;let A=-1;function k(L){o(!1,L,"ancestor-scroll")}function D(){window.clearTimeout(A),E.current=!0}function P(){A=window.setTimeout(()=>{E.current=!1},Tt()?5:0)}const y=Me(r.floating);l&&(y.addEventListener("keydown",T?_:O,T),y.addEventListener("compositionstart",D),y.addEventListener("compositionend",P)),v&&y.addEventListener(a,R?H:I,R);let N=[];return d&&(V(r.domReference)&&(N=Ce(r.domReference)),V(r.floating)&&(N=N.concat(Ce(r.floating))),!V(r.reference)&&r.reference&&r.reference.contextElement&&(N=N.concat(Ce(r.reference.contextElement)))),N=N.filter(L=>{var B;return L!==((B=y.defaultView)==null?void 0:B.visualViewport)}),N.forEach(L=>{L.addEventListener("scroll",k)}),()=>{l&&(y.removeEventListener("keydown",T?_:O,T),y.removeEventListener("compositionstart",D),y.removeEventListener("compositionend",P)),v&&y.removeEventListener(a,R?H:I,R),N.forEach(L=>{L.removeEventListener("scroll",k)}),window.clearTimeout(A)}},[i,r,l,v,a,n,o,d,s,S,x,O,T,_,I,R,H]),u.useEffect(()=>{i.current.insideReactTree=!1},[i,v,a]);const j=u.useMemo(()=>({onKeyDown:O,...f&&{[gi[p]]:A=>{o(!1,A.nativeEvent,"reference-press")},...p!=="click"&&{onClick(A){o(!1,A.nativeEvent,"reference-press")}}}}),[O,o,f,p]),M=u.useMemo(()=>{function A(k){k.button===0&&(C.current=!0)}return{onKeyDown:O,onMouseDown:A,onMouseUp:A,[bi[a]]:()=>{i.current.insideReactTree=!0}}},[O,a,i]);return u.useMemo(()=>s?{reference:j,floating:M}:{},[s,j,M])}function vi(e){const{open:t=!1,onOpenChange:n,elements:o}=e,r=Io(),i=u.useRef({}),[s]=u.useState(()=>di()),l=un()!=null,[c,a]=u.useState(o.reference),f=pe((m,h,g)=>{i.current.openEvent=m?h:void 0,s.emit("openchange",{open:m,event:h,reason:g,nested:l}),n?.(m,h,g)}),p=u.useMemo(()=>({setPositionReference:a}),[]),d=u.useMemo(()=>({reference:c||o.reference||null,floating:o.floating||null,domReference:o.reference}),[c,o.reference,o.floating]);return u.useMemo(()=>({dataRef:i,open:t,onOpenChange:f,elements:d,events:s,floatingId:r,refs:p}),[t,f,d,s,r,p])}function wi(e){var t,n;let{elements:o,...r}=e===void 0?{}:e;const{nodeId:i}=r,s=vi({...r,elements:{reference:(t=o?.reference)!=null?t:null,floating:(n=o?.floating)!=null?n:null}}),l=r.rootContext||s,c=l.elements,[a,f]=u.useState(null),[p,d]=u.useState(null),h=c?.domReference||a,g=u.useRef(null),b=fn();me(()=>{h&&(g.current=h)},[h]);const v=ei({...r,elements:{...c,...p&&{reference:p}}}),C=u.useCallback(E=>{const O=V(E)?{getBoundingClientRect:()=>E.getBoundingClientRect(),getClientRects:()=>E.getClientRects(),contextElement:E}:E;d(O),v.refs.setReference(O)},[v.refs]),S=u.useCallback(E=>{(V(E)||E===null)&&(g.current=E,f(E)),(V(v.refs.reference.current)||v.refs.reference.current===null||E!==null&&!V(E))&&v.refs.setReference(E)},[v.refs]),x=u.useMemo(()=>({...v.refs,setReference:S,setPositionReference:C,domReference:g}),[v.refs,S,C]),T=u.useMemo(()=>({...v.elements,domReference:h}),[v.elements,h]),R=u.useMemo(()=>({...v,...l,refs:x,elements:T,nodeId:i}),[v,x,T,i,l]);return me(()=>{l.dataRef.current.floatingContext=R;const E=b?.nodesRef.current.find(O=>O.id===i);E&&(E.context=R)}),u.useMemo(()=>({...v,context:R,refs:x,elements:T}),[v,x,T,R])}function Ht(){return ns()&&ts()}function vl(e,t){t===void 0&&(t={});const{open:n,onOpenChange:o,events:r,dataRef:i,elements:s}=e,{enabled:l=!0,visibleOnly:c=!0}=t,a=u.useRef(!1),f=u.useRef(-1),p=u.useRef(!0);u.useEffect(()=>{if(!l)return;const m=q(s.domReference);function h(){!n&&fe(s.domReference)&&s.domReference===Hn(Me(s.domReference))&&(a.current=!0)}function g(){p.current=!0}function b(){p.current=!1}return m.addEventListener("blur",h),Ht()&&(m.addEventListener("keydown",g,!0),m.addEventListener("pointerdown",b,!0)),()=>{m.removeEventListener("blur",h),Ht()&&(m.removeEventListener("keydown",g,!0),m.removeEventListener("pointerdown",b,!0))}},[s.domReference,n,l]),u.useEffect(()=>{if(!l)return;function m(h){let{reason:g}=h;(g==="reference-press"||g==="escape-key")&&(a.current=!0)}return r.on("openchange",m),()=>{r.off("openchange",m)}},[r,l]),u.useEffect(()=>()=>{ne(f)},[]);const d=u.useMemo(()=>({onMouseLeave(){a.current=!1},onFocus(m){if(a.current)return;const h=$e(m.nativeEvent);if(c&&V(h)){if(Ht()&&!m.relatedTarget){if(!p.current&&!is(h))return}else if(!ls(h))return}o(!0,m.nativeEvent,"focus")},onBlur(m){a.current=!1;const h=m.relatedTarget,g=m.nativeEvent,b=V(h)&&h.hasAttribute(dn("focus-guard"))&&h.getAttribute("data-type")==="outside";f.current=window.setTimeout(()=>{var v;const C=Hn(s.domReference?s.domReference.ownerDocument:document);!h&&C===s.domReference||Qe((v=i.current.floatingContext)==null?void 0:v.refs.floating.current,C)||Qe(s.domReference,C)||b||o(!1,g,"focus")})}}),[i,s.domReference,o,c]);return u.useMemo(()=>l?{reference:d}:{},[l,d])}function zt(e,t,n){const o=new Map,r=n==="item";let i=e;if(r&&e){const{[Jn]:s,[Qn]:l,...c}=e;i=c}return{...n==="floating"&&{tabIndex:-1,[li]:""},...i,...t.map(s=>{const l=s?s[n]:null;return typeof l=="function"?e?l(e):null:l}).concat(e).reduce((s,l)=>(l&&Object.entries(l).forEach(c=>{let[a,f]=c;if(!(r&&[Jn,Qn].includes(a)))if(a.indexOf("on")===0){if(o.has(a)||o.set(a,[]),typeof f=="function"){var p;(p=o.get(a))==null||p.push(f),s[a]=function(){for(var d,m=arguments.length,h=new Array(m),g=0;gb(...h)).find(b=>b!==void 0)}}}else s[a]=f}),s),{})}}function wl(e){e===void 0&&(e=[]);const t=e.map(l=>l?.reference),n=e.map(l=>l?.floating),o=e.map(l=>l?.item),r=u.useCallback(l=>zt(l,e,"reference"),t),i=u.useCallback(l=>zt(l,e,"floating"),n),s=u.useCallback(l=>zt(l,e,"item"),o);return u.useMemo(()=>({getReferenceProps:r,getFloatingProps:i,getItemProps:s}),[r,i,s])}const yi=new Map([["select","listbox"],["combobox","listbox"],["label",!1]]);function yl(e,t){var n,o;t===void 0&&(t={});const{open:r,elements:i,floatingId:s}=e,{enabled:l=!0,role:c="dialog"}=t,a=Io(),f=((n=i.domReference)==null?void 0:n.id)||a,p=u.useMemo(()=>{var C;return((C=cs(i.floating))==null?void 0:C.id)||s},[i.floating,s]),d=(o=yi.get(c))!=null?o:c,h=un()!=null,g=u.useMemo(()=>d==="tooltip"||c==="label"?{["aria-"+(c==="label"?"labelledby":"describedby")]:r?p:void 0}:{"aria-expanded":r?"true":"false","aria-haspopup":d==="alertdialog"?"dialog":d,"aria-controls":r?p:void 0,...d==="listbox"&&{role:"combobox"},...d==="menu"&&{id:f},...d==="menu"&&h&&{role:"menuitem"},...c==="select"&&{"aria-autocomplete":"none"},...c==="combobox"&&{"aria-autocomplete":"list"}},[d,p,h,r,f,c]),b=u.useMemo(()=>{const C={id:p,...d&&{role:d}};return d==="tooltip"||c==="label"?C:{...C,...d==="menu"&&{"aria-labelledby":f}}},[d,p,f,c]),v=u.useCallback(C=>{let{active:S,selected:x}=C;const T={role:"option",...S&&{id:p+"-fui-option"}};switch(c){case"select":case"combobox":return{...T,"aria-selected":x}}return{}},[p,c]);return u.useMemo(()=>l?{reference:g,floating:b,item:v}:{},[l,g,b,v])}var pn={root:"m_d57069b5",content:"m_b1336c6",viewport:"m_c0783ff9",viewportInner:"m_f8f631dd",scrollbar:"m_c44ba933",thumb:"m_d8b5e363",corner:"m_21657268"};const[xi,se]=wt("ScrollArea.Root component was not found in tree");function Ve(e,t){const n=Le(t);en(()=>{let o=0;if(e){const r=new ResizeObserver(()=>{cancelAnimationFrame(o),o=window.requestAnimationFrame(n)});return r.observe(e),()=>{window.cancelAnimationFrame(o),r.unobserve(e)}}},[e,n])}const Ci=u.forwardRef((e,t)=>{const{style:n,...o}=e,r=se(),[i,s]=u.useState(0),[l,c]=u.useState(0),a=!!(i&&l);return Ve(r.scrollbarX,()=>{const f=r.scrollbarX?.offsetHeight||0;r.onCornerHeightChange(f),c(f)}),Ve(r.scrollbarY,()=>{const f=r.scrollbarY?.offsetWidth||0;r.onCornerWidthChange(f),s(f)}),a?w.jsx("div",{...o,ref:t,style:{...n,width:i,height:l}}):null}),Ri=u.forwardRef((e,t)=>{const n=se(),o=!!(n.scrollbarX&&n.scrollbarY);return n.type!=="scroll"&&o?w.jsx(Ci,{...e,ref:t}):null}),Si={scrollHideDelay:1e3,type:"hover"},_o=u.forwardRef((e,t)=>{const{type:n,scrollHideDelay:o,scrollbars:r,getStyles:i,...s}=W("ScrollAreaRoot",Si,e),[l,c]=u.useState(null),[a,f]=u.useState(null),[p,d]=u.useState(null),[m,h]=u.useState(null),[g,b]=u.useState(null),[v,C]=u.useState(0),[S,x]=u.useState(0),[T,R]=u.useState(!1),[E,O]=u.useState(!1),_=re(t,I=>c(I));return w.jsx(xi,{value:{type:n,scrollHideDelay:o,scrollArea:l,viewport:a,onViewportChange:f,content:p,onContentChange:d,scrollbarX:m,onScrollbarXChange:h,scrollbarXEnabled:T,onScrollbarXEnabledChange:R,scrollbarY:g,onScrollbarYChange:b,scrollbarYEnabled:E,onScrollbarYEnabledChange:O,onCornerWidthChange:C,onCornerHeightChange:x,getStyles:i},children:w.jsx(Q,{...s,ref:_,__vars:{"--sa-corner-width":r!=="xy"?"0px":`${v}px`,"--sa-corner-height":r!=="xy"?"0px":`${S}px`}})})});_o.displayName="@mantine/core/ScrollAreaRoot";function Fo(e,t){const n=e/t;return Number.isNaN(n)?0:n}function Dt(e){const t=Fo(e.viewport,e.content),n=e.scrollbar.paddingStart+e.scrollbar.paddingEnd,o=(e.scrollbar.size-n)*t;return Math.max(o,18)}function jo(e,t){return n=>{if(e[0]===e[1]||t[0]===t[1])return t[0];const o=(t[1]-t[0])/(e[1]-e[0]);return t[0]+o*(n-e[0])}}function Ei(e,[t,n]){return Math.min(n,Math.max(t,e))}function ro(e,t,n="ltr"){const o=Dt(t),r=t.scrollbar.paddingStart+t.scrollbar.paddingEnd,i=t.scrollbar.size-r,s=t.content-t.viewport,l=i-o,c=n==="ltr"?[0,s]:[s*-1,0],a=Ei(e,c);return jo([0,s],[0,l])(a)}function Pi(e,t,n,o="ltr"){const r=Dt(n),i=r/2,s=t||i,l=r-s,c=n.scrollbar.paddingStart+s,a=n.scrollbar.size-n.scrollbar.paddingEnd-l,f=n.content-n.viewport,p=o==="ltr"?[0,f]:[f*-1,0];return jo([c,a],p)(e)}function $o(e,t){return e>0&&e{e?.(o),(n===!1||!o.defaultPrevented)&&t?.(o)}}const[Ti,Ho]=wt("ScrollAreaScrollbar was not found in tree"),zo=u.forwardRef((e,t)=>{const{sizes:n,hasThumb:o,onThumbChange:r,onThumbPointerUp:i,onThumbPointerDown:s,onThumbPositionChange:l,onDragScroll:c,onWheelScroll:a,onResize:f,...p}=e,d=se(),[m,h]=u.useState(null),g=re(t,O=>h(O)),b=u.useRef(null),v=u.useRef(""),{viewport:C}=d,S=n.content-n.viewport,x=Le(a),T=Le(l),R=Ct(f,10),E=O=>{if(b.current){const _=O.clientX-b.current.left,I=O.clientY-b.current.top;c({x:_,y:I})}};return u.useEffect(()=>{const O=_=>{const I=_.target;m?.contains(I)&&x(_,S)};return document.addEventListener("wheel",O,{passive:!1}),()=>document.removeEventListener("wheel",O,{passive:!1})},[C,m,S,x]),u.useEffect(T,[n,T]),Ve(m,R),Ve(d.content,R),w.jsx(Ti,{value:{scrollbar:m,hasThumb:o,onThumbChange:Le(r),onThumbPointerUp:Le(i),onThumbPositionChange:T,onThumbPointerDown:Le(s)},children:w.jsx("div",{...p,ref:g,"data-mantine-scrollbar":!0,style:{position:"absolute",...p.style},onPointerDown:Ie(e.onPointerDown,O=>{O.preventDefault(),O.button===0&&(O.target.setPointerCapture(O.pointerId),b.current=m.getBoundingClientRect(),v.current=document.body.style.webkitUserSelect,document.body.style.webkitUserSelect="none",E(O))}),onPointerMove:Ie(e.onPointerMove,E),onPointerUp:Ie(e.onPointerUp,O=>{const _=O.target;_.hasPointerCapture(O.pointerId)&&(O.preventDefault(),_.releasePointerCapture(O.pointerId))}),onLostPointerCapture:()=>{document.body.style.webkitUserSelect=v.current,b.current=null}})})}),Vo=u.forwardRef((e,t)=>{const{sizes:n,onSizesChange:o,style:r,...i}=e,s=se(),[l,c]=u.useState(),a=u.useRef(null),f=re(t,a,s.onScrollbarXChange);return u.useEffect(()=>{a.current&&c(getComputedStyle(a.current))},[a]),w.jsx(zo,{"data-orientation":"horizontal",...i,ref:f,sizes:n,style:{...r,"--sa-thumb-width":`${Dt(n)}px`},onThumbPointerDown:p=>e.onThumbPointerDown(p.x),onDragScroll:p=>e.onDragScroll(p.x),onWheelScroll:(p,d)=>{if(s.viewport){const m=s.viewport.scrollLeft+p.deltaX;e.onWheelScroll(m),$o(m,d)&&p.preventDefault()}},onResize:()=>{a.current&&s.viewport&&l&&o({content:s.viewport.scrollWidth,viewport:s.viewport.offsetWidth,scrollbar:{size:a.current.clientWidth,paddingStart:vt(l.paddingLeft),paddingEnd:vt(l.paddingRight)}})}})});Vo.displayName="@mantine/core/ScrollAreaScrollbarX";const Wo=u.forwardRef((e,t)=>{const{sizes:n,onSizesChange:o,style:r,...i}=e,s=se(),[l,c]=u.useState(),a=u.useRef(null),f=re(t,a,s.onScrollbarYChange);return u.useEffect(()=>{a.current&&c(window.getComputedStyle(a.current))},[]),w.jsx(zo,{...i,"data-orientation":"vertical",ref:f,sizes:n,style:{"--sa-thumb-height":`${Dt(n)}px`,...r},onThumbPointerDown:p=>e.onThumbPointerDown(p.y),onDragScroll:p=>e.onDragScroll(p.y),onWheelScroll:(p,d)=>{if(s.viewport){const m=s.viewport.scrollTop+p.deltaY;e.onWheelScroll(m),$o(m,d)&&p.preventDefault()}},onResize:()=>{a.current&&s.viewport&&l&&o({content:s.viewport.scrollHeight,viewport:s.viewport.offsetHeight,scrollbar:{size:a.current.clientHeight,paddingStart:vt(l.paddingTop),paddingEnd:vt(l.paddingBottom)}})}})});Wo.displayName="@mantine/core/ScrollAreaScrollbarY";const Nt=u.forwardRef((e,t)=>{const{orientation:n="vertical",...o}=e,{dir:r}=nn(),i=se(),s=u.useRef(null),l=u.useRef(0),[c,a]=u.useState({content:0,viewport:0,scrollbar:{size:0,paddingStart:0,paddingEnd:0}}),f=Fo(c.viewport,c.content),p={...o,sizes:c,onSizesChange:a,hasThumb:f>0&&f<1,onThumbChange:m=>{s.current=m},onThumbPointerUp:()=>{l.current=0},onThumbPointerDown:m=>{l.current=m}},d=(m,h)=>Pi(m,l.current,c,h);return n==="horizontal"?w.jsx(Vo,{...p,ref:t,onThumbPositionChange:()=>{if(i.viewport&&s.current){const m=i.viewport.scrollLeft,h=ro(m,c,r);s.current.style.transform=`translate3d(${h}px, 0, 0)`}},onWheelScroll:m=>{i.viewport&&(i.viewport.scrollLeft=m)},onDragScroll:m=>{i.viewport&&(i.viewport.scrollLeft=d(m,r))}}):n==="vertical"?w.jsx(Wo,{...p,ref:t,onThumbPositionChange:()=>{if(i.viewport&&s.current){const m=i.viewport.scrollTop,h=ro(m,c);c.scrollbar.size===0?s.current.style.setProperty("--thumb-opacity","0"):s.current.style.setProperty("--thumb-opacity","1"),s.current.style.transform=`translate3d(0, ${h}px, 0)`}},onWheelScroll:m=>{i.viewport&&(i.viewport.scrollTop=m)},onDragScroll:m=>{i.viewport&&(i.viewport.scrollTop=d(m))}}):null});Nt.displayName="@mantine/core/ScrollAreaScrollbarVisible";const mn=u.forwardRef((e,t)=>{const n=se(),{forceMount:o,...r}=e,[i,s]=u.useState(!1),l=e.orientation==="horizontal",c=Ct(()=>{if(n.viewport){const a=n.viewport.offsetWidth{const{forceMount:n,...o}=e,r=se(),[i,s]=u.useState(!1);return u.useEffect(()=>{const{scrollArea:l}=r;let c=0;if(l){const a=()=>{window.clearTimeout(c),s(!0)},f=()=>{c=window.setTimeout(()=>s(!1),r.scrollHideDelay)};return l.addEventListener("pointerenter",a),l.addEventListener("pointerleave",f),()=>{window.clearTimeout(c),l.removeEventListener("pointerenter",a),l.removeEventListener("pointerleave",f)}}},[r.scrollArea,r.scrollHideDelay]),n||i?w.jsx(mn,{"data-state":i?"visible":"hidden",...o,ref:t}):null});Bo.displayName="@mantine/core/ScrollAreaScrollbarHover";const Oi=u.forwardRef((e,t)=>{const{forceMount:n,...o}=e,r=se(),i=e.orientation==="horizontal",[s,l]=u.useState("hidden"),c=Ct(()=>l("idle"),100);return u.useEffect(()=>{if(s==="idle"){const a=window.setTimeout(()=>l("hidden"),r.scrollHideDelay);return()=>window.clearTimeout(a)}},[s,r.scrollHideDelay]),u.useEffect(()=>{const{viewport:a}=r,f=i?"scrollLeft":"scrollTop";if(a){let p=a[f];const d=()=>{const m=a[f];p!==m&&(l("scrolling"),c()),p=m};return a.addEventListener("scroll",d),()=>a.removeEventListener("scroll",d)}},[r.viewport,i,c]),n||s!=="hidden"?w.jsx(Nt,{"data-state":s==="hidden"?"hidden":"visible",...o,ref:t,onPointerEnter:Ie(e.onPointerEnter,()=>l("interacting")),onPointerLeave:Ie(e.onPointerLeave,()=>l("idle"))}):null}),Jt=u.forwardRef((e,t)=>{const{forceMount:n,...o}=e,r=se(),{onScrollbarXEnabledChange:i,onScrollbarYEnabledChange:s}=r,l=e.orientation==="horizontal";return u.useEffect(()=>(l?i(!0):s(!0),()=>{l?i(!1):s(!1)}),[l,i,s]),r.type==="hover"?w.jsx(Bo,{...o,ref:t,forceMount:n}):r.type==="scroll"?w.jsx(Oi,{...o,ref:t,forceMount:n}):r.type==="auto"?w.jsx(mn,{...o,ref:t,forceMount:n}):r.type==="always"?w.jsx(Nt,{...o,ref:t}):null});Jt.displayName="@mantine/core/ScrollAreaScrollbar";function Ai(e,t=()=>{}){let n={left:e.scrollLeft,top:e.scrollTop},o=0;return(function r(){const i={left:e.scrollLeft,top:e.scrollTop},s=n.left!==i.left,l=n.top!==i.top;(s||l)&&t(),n=i,o=window.requestAnimationFrame(r)})(),()=>window.cancelAnimationFrame(o)}const Ko=u.forwardRef((e,t)=>{const{style:n,...o}=e,r=se(),i=Ho(),{onThumbPositionChange:s}=i,l=re(t,f=>i.onThumbChange(f)),c=u.useRef(void 0),a=Ct(()=>{c.current&&(c.current(),c.current=void 0)},100);return u.useEffect(()=>{const{viewport:f}=r;if(f){const p=()=>{if(a(),!c.current){const d=Ai(f,s);c.current=d,s()}};return s(),f.addEventListener("scroll",p),()=>f.removeEventListener("scroll",p)}},[r.viewport,a,s]),w.jsx("div",{"data-state":i.hasThumb?"visible":"hidden",...o,ref:l,style:{width:"var(--sa-thumb-width)",height:"var(--sa-thumb-height)",...n},onPointerDownCapture:Ie(e.onPointerDownCapture,f=>{const d=f.target.getBoundingClientRect(),m=f.clientX-d.left,h=f.clientY-d.top;i.onThumbPointerDown({x:m,y:h})}),onPointerUp:Ie(e.onPointerUp,i.onThumbPointerUp)})});Ko.displayName="@mantine/core/ScrollAreaThumb";const Qt=u.forwardRef((e,t)=>{const{forceMount:n,...o}=e,r=Ho();return n||r.hasThumb?w.jsx(Ko,{ref:t,...o}):null});Qt.displayName="@mantine/core/ScrollAreaThumb";const Xo=u.forwardRef(({children:e,style:t,onWheel:n,...o},r)=>{const i=se(),s=re(r,i.onViewportChange),l=c=>{if(n?.(c),i.scrollbarXEnabled&&i.viewport&&c.shiftKey){const{scrollTop:a,scrollHeight:f,clientHeight:p,scrollWidth:d,clientWidth:m}=i.viewport,h=a<1,g=a>=f-p-1;d>m&&(h||g)&&c.stopPropagation()}};return w.jsx(Q,{...o,ref:s,onWheel:l,style:{overflowX:i.scrollbarXEnabled?"scroll":"hidden",overflowY:i.scrollbarYEnabled?"scroll":"hidden",...t},children:w.jsx("div",{...i.getStyles("content"),ref:i.onContentChange,children:e})})});Xo.displayName="@mantine/core/ScrollAreaViewport";const Yo={scrollHideDelay:1e3,type:"hover",scrollbars:"xy"},Di=tt((e,{scrollbarSize:t,overscrollBehavior:n,scrollbars:o})=>{let r=n;return n&&o&&(o==="x"?r=`${n} auto`:o==="y"&&(r=`auto ${n}`)),{root:{"--scrollarea-scrollbar-size":ze(t),"--scrollarea-over-scroll-behavior":r}}}),nt=Y((e,t)=>{const n=W("ScrollArea",Yo,e),{classNames:o,className:r,style:i,styles:s,unstyled:l,scrollbarSize:c,vars:a,type:f,scrollHideDelay:p,viewportProps:d,viewportRef:m,onScrollPositionChange:h,children:g,offsetScrollbars:b,scrollbars:v,onBottomReached:C,onTopReached:S,overscrollBehavior:x,attributes:T,...R}=n,[E,O]=u.useState(!1),[_,I]=u.useState(!1),[H,j]=u.useState(!1),M=We({name:"ScrollArea",props:n,classes:pn,className:r,style:i,classNames:o,styles:s,unstyled:l,attributes:T,vars:a,varsResolver:Di}),A=u.useRef(null),k=Mo([m,A]);return u.useEffect(()=>{if(!A.current||b!=="present")return;const D=A.current,P=new ResizeObserver(()=>{const{scrollHeight:y,clientHeight:N,scrollWidth:L,clientWidth:B}=D;I(y>N),j(L>B)});return P.observe(D),()=>P.disconnect()},[A,b]),w.jsxs(_o,{getStyles:M,type:f==="never"?"always":f,scrollHideDelay:p,ref:t,scrollbars:v,...M("root"),...R,children:[w.jsx(Xo,{...d,...M("viewport",{style:d?.style}),ref:k,"data-offset-scrollbars":b===!0?"xy":b||void 0,"data-scrollbars":v||void 0,"data-horizontal-hidden":b==="present"&&!H?"true":void 0,"data-vertical-hidden":b==="present"&&!_?"true":void 0,onScroll:D=>{d?.onScroll?.(D),h?.({x:D.currentTarget.scrollLeft,y:D.currentTarget.scrollTop});const{scrollTop:P,scrollHeight:y,clientHeight:N}=D.currentTarget;P-(y-N)>=-.8&&C?.(),P===0&&S?.()},children:g}),(v==="xy"||v==="x")&&w.jsx(Jt,{...M("scrollbar"),orientation:"horizontal","data-hidden":f==="never"||b==="present"&&!H?!0:void 0,forceMount:!0,onMouseEnter:()=>O(!0),onMouseLeave:()=>O(!1),children:w.jsx(Qt,{...M("thumb")})}),(v==="xy"||v==="y")&&w.jsx(Jt,{...M("scrollbar"),orientation:"vertical","data-hidden":f==="never"||b==="present"&&!_?!0:void 0,forceMount:!0,onMouseEnter:()=>O(!0),onMouseLeave:()=>O(!1),children:w.jsx(Qt,{...M("thumb")})}),w.jsx(Ri,{...M("corner"),"data-hovered":E||void 0,"data-hidden":f==="never"||void 0})]})});nt.displayName="@mantine/core/ScrollArea";const hn=Y((e,t)=>{const{children:n,classNames:o,styles:r,scrollbarSize:i,scrollHideDelay:s,type:l,dir:c,offsetScrollbars:a,overscrollBehavior:f,viewportRef:p,onScrollPositionChange:d,unstyled:m,variant:h,viewportProps:g,scrollbars:b,style:v,vars:C,onBottomReached:S,onTopReached:x,onOverflowChange:T,...R}=W("ScrollAreaAutosize",Yo,e),E=u.useRef(null),O=Mo([p,E]),[_,I]=u.useState(!1),H=u.useRef(!1);return u.useEffect(()=>{if(!T)return;const j=E.current;if(!j)return;const M=()=>{const k=j.scrollHeight>j.clientHeight;k!==_&&(H.current?T?.(k):(H.current=!0,k&&T?.(!0)),I(k))};M();const A=new ResizeObserver(M);return A.observe(j),()=>A.disconnect()},[T,_]),w.jsx(Q,{...R,ref:t,style:[{display:"flex",overflow:"hidden"},v],children:w.jsx(Q,{style:{display:"flex",flexDirection:"column",flex:1,overflow:"hidden",...b==="y"&&{minWidth:0},...b==="x"&&{minHeight:0},...b==="xy"&&{minWidth:0,minHeight:0},...b===!1&&{minWidth:0,minHeight:0}},children:w.jsx(nt,{classNames:o,styles:r,scrollHideDelay:s,scrollbarSize:i,type:l,dir:c,offsetScrollbars:a,overscrollBehavior:f,viewportRef:O,onScrollPositionChange:d,unstyled:m,variant:h,viewportProps:g,vars:C,scrollbars:b,onBottomReached:S,onTopReached:x,"data-autosize":"true",children:n})})})});nt.classes=pn;hn.displayName="@mantine/core/ScrollAreaAutosize";hn.classes=pn;nt.Autosize=hn;var Uo={root:"m_515a97f8"};const gn=Y((e,t)=>{const n=W("VisuallyHidden",null,e),{classNames:o,className:r,style:i,styles:s,unstyled:l,vars:c,attributes:a,...f}=n,p=We({name:"VisuallyHidden",classes:Uo,props:n,className:r,style:i,classNames:o,styles:s,unstyled:l,attributes:a});return w.jsx(Q,{component:"span",ref:t,...p("root"),...f})});gn.classes=Uo;gn.displayName="@mantine/core/VisuallyHidden";function so(e,t,n,o){return e==="center"||o==="center"?{top:t}:e==="end"?{bottom:n}:e==="start"?{top:n}:{}}function io(e,t,n,o,r){return e==="center"||o==="center"?{left:t}:e==="end"?{[r==="ltr"?"right":"left"]:n}:e==="start"?{[r==="ltr"?"left":"right"]:n}:{}}const Ni={bottom:"borderTopLeftRadius",left:"borderTopRightRadius",right:"borderBottomLeftRadius",top:"borderBottomRightRadius"};function Li({position:e,arrowSize:t,arrowOffset:n,arrowRadius:o,arrowPosition:r,arrowX:i,arrowY:s,dir:l}){const[c,a="center"]=e.split("-"),f={width:t,height:t,transform:"rotate(45deg)",position:"absolute",[Ni[c]]:o},p=-t/2;return c==="left"?{...f,...so(a,s,n,r),right:p,borderLeftColor:"transparent",borderBottomColor:"transparent",clipPath:"polygon(100% 0, 0 0, 100% 100%)"}:c==="right"?{...f,...so(a,s,n,r),left:p,borderRightColor:"transparent",borderTopColor:"transparent",clipPath:"polygon(0 100%, 0 0, 100% 100%)"}:c==="top"?{...f,...io(a,i,n,r,l),bottom:p,borderTopColor:"transparent",borderLeftColor:"transparent",clipPath:"polygon(0 100%, 100% 100%, 100% 0)"}:c==="bottom"?{...f,...io(a,i,n,r,l),top:p,borderBottomColor:"transparent",borderRightColor:"transparent",clipPath:"polygon(0 100%, 0 0, 100% 0)"}:{}}const qo=u.forwardRef(({position:e,arrowSize:t,arrowOffset:n,arrowRadius:o,arrowPosition:r,visible:i,arrowX:s,arrowY:l,style:c,...a},f)=>{const{dir:p}=nn();return i?w.jsx("div",{...a,ref:f,style:{...c,...Li({position:e,arrowSize:t,arrowOffset:n,arrowRadius:o,arrowPosition:r,dir:p,arrowX:s,arrowY:l})}}):null});qo.displayName="@mantine/core/FloatingArrow";function Mi(e,t){if(e==="rtl"&&(t.includes("right")||t.includes("left"))){const[n,o]=t.split("-"),r=n==="right"?"left":"right";return o===void 0?r:`${r}-${o}`}return t}var Go={root:"m_9814e45f"};const Ii={zIndex:ao("modal")},ki=tt((e,{gradient:t,color:n,backgroundOpacity:o,blur:r,radius:i,zIndex:s})=>({root:{"--overlay-bg":t||(n!==void 0||o!==void 0)&&Cr(n||"#000",o??.6)||void 0,"--overlay-filter":r?`blur(${ze(r)})`:void 0,"--overlay-radius":i===void 0?void 0:uo(i),"--overlay-z-index":s?.toString()}})),bn=xr((e,t)=>{const n=W("Overlay",Ii,e),{classNames:o,className:r,style:i,styles:s,unstyled:l,vars:c,fixed:a,center:f,children:p,radius:d,zIndex:m,gradient:h,blur:g,color:b,backgroundOpacity:v,mod:C,attributes:S,...x}=n,T=We({name:"Overlay",props:n,classes:Go,className:r,style:i,classNames:o,styles:s,unstyled:l,attributes:S,vars:c,varsResolver:ki});return w.jsx(Q,{ref:t,...T("root"),mod:[{center:f,fixed:a},C],...x,children:p})});bn.classes=Go;bn.displayName="@mantine/core/Overlay";function Vt(e){const t=document.createElement("div");return t.setAttribute("data-portal","true"),typeof e.className=="string"&&t.classList.add(...e.className.split(" ").filter(Boolean)),typeof e.style=="object"&&Object.assign(t.style,e.style),typeof e.id=="string"&&t.setAttribute("id",e.id),t}function _i({target:e,reuseTargetNode:t,...n}){if(e)return typeof e=="string"?document.querySelector(e)||Vt(n):e;if(t){const o=document.querySelector("[data-mantine-shared-portal-node]");if(o)return o;const r=Vt(n);return r.setAttribute("data-mantine-shared-portal-node","true"),document.body.appendChild(r),r}return Vt(n)}const Fi={reuseTargetNode:!0},Zo=Y((e,t)=>{const{children:n,target:o,reuseTargetNode:r,...i}=W("Portal",Fi,e),[s,l]=u.useState(!1),c=u.useRef(null);return en(()=>(l(!0),c.current=_i({target:o,reuseTargetNode:r,...i}),Xt(t,c.current),!o&&!r&&c.current&&document.body.appendChild(c.current),()=>{!o&&!r&&c.current&&document.body.removeChild(c.current)}),[o]),!s||!c.current?null:co.createPortal(w.jsx(w.Fragment,{children:n}),c.current)});Zo.displayName="@mantine/core/Portal";const vn=Y(({withinPortal:e=!0,children:t,...n},o)=>tn()==="test"||!e?w.jsx(w.Fragment,{children:t}):w.jsx(Zo,{ref:o,...n,children:t}));vn.displayName="@mantine/core/OptionalPortal";const[ji,Jo]=wt("Popover component was not found in the tree");var Qo={dropdown:"m_38a85659",arrow:"m_a31dc6c1",overlay:"m_3d7bc908"};function wn({children:e,active:t=!0,refProp:n="ref",innerRef:o}){const r=_r(t),i=re(r,o),s=Rt(e);return s?u.cloneElement(s,{[n]:i}):e}function er(e){return w.jsx(gn,{tabIndex:-1,"data-autofocus":!0,...e})}wn.displayName="@mantine/core/FocusTrap";er.displayName="@mantine/core/FocusTrapInitialFocus";wn.InitialFocus=er;const yn=Y((e,t)=>{const n=W("PopoverDropdown",null,e),{className:o,style:r,vars:i,children:s,onKeyDownCapture:l,variant:c,classNames:a,styles:f,...p}=n,d=Jo(),m=Dr({opened:d.opened,shouldReturnFocus:d.returnFocus}),h=d.withRoles?{"aria-labelledby":d.getTargetId(),id:d.getDropdownId(),role:"dialog",tabIndex:-1}:{},g=re(t,d.floating);return d.disabled?null:w.jsx(vn,{...d.portalProps,withinPortal:d.withinPortal,children:w.jsx(fo,{mounted:d.opened,...d.transitionProps,transition:d.transitionProps?.transition||"fade",duration:d.transitionProps?.duration??150,keepMounted:d.keepMounted,exitDuration:typeof d.transitionProps?.exitDuration=="number"?d.transitionProps.exitDuration:d.transitionProps?.duration,children:b=>w.jsx(wn,{active:d.trapFocus&&d.opened,innerRef:g,children:w.jsxs(Q,{...h,...p,variant:c,onKeyDownCapture:Tr(()=>{d.onClose?.(),d.onDismiss?.()},{active:d.closeOnEscape,onTrigger:m,onKeyDown:l}),"data-position":d.placement,"data-fixed":d.floatingStrategy==="fixed"||void 0,...d.getStyles("dropdown",{className:o,props:n,classNames:a,styles:f,style:[{...b,zIndex:d.zIndex,top:d.y??0,left:d.x??0,width:d.width==="target"?void 0:ze(d.width),...d.referenceHidden?{display:"none"}:null},d.resolvedStyles.dropdown,f?.dropdown,r]}),children:[s,w.jsx(qo,{ref:d.arrowRef,arrowX:d.arrowX,arrowY:d.arrowY,visible:d.withArrow,position:d.placement,arrowSize:d.arrowSize,arrowRadius:d.arrowRadius,arrowOffset:d.arrowOffset,arrowPosition:d.arrowPosition,...d.getStyles("arrow",{props:n,classNames:a,styles:f})})]})})})})});yn.classes=Qo;yn.displayName="@mantine/core/PopoverDropdown";const $i={refProp:"ref",popupType:"dialog"},tr=Y((e,t)=>{const{children:n,refProp:o,popupType:r,...i}=W("PopoverTarget",$i,e),s=Rt(n);if(!s)throw new Error("Popover.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const l=i,c=Jo(),a=re(c.reference,xo(s),t),f=c.withRoles?{"aria-haspopup":r,"aria-expanded":c.opened,"aria-controls":c.opened?c.getDropdownId():void 0,id:c.getTargetId()}:{},p=s.props;return u.cloneElement(s,{...l,...f,...c.targetProps,className:po(c.targetProps.className,l.className,p.className),[o]:a,...c.controlled?null:{onClick:()=>{c.onToggle(),p.onClick?.()}}})});tr.displayName="@mantine/core/PopoverTarget";function Hi(e){if(e===void 0)return{shift:!0,flip:!0};const t={...e};return e.shift===void 0&&(t.shift=!0),e.flip===void 0&&(t.flip=!0),t}function zi(e,t,n){const o=Hi(e.middlewares),r=[ni(e.offset),si()];return e.dropdownVisible&&n!=="test"&&e.preventPositionChangeWhenVisible&&(o.flip=!1),o.flip&&r.push(typeof o.flip=="boolean"?Gn():Gn(o.flip)),o.shift&&r.push(oi(typeof o.shift=="boolean"?{limiter:qn(),padding:5}:{limiter:qn(),padding:5,...o.shift})),o.inline&&r.push(typeof o.inline=="boolean"?Zn():Zn(o.inline)),r.push(ii({element:e.arrowRef,padding:e.arrowOffset})),(o.size||e.width==="target")&&r.push(ri({...typeof o.size=="boolean"?{}:o.size,apply({rects:i,availableWidth:s,availableHeight:l,...c}){const f=t().refs.floating.current?.style??{};o.size&&(typeof o.size=="object"&&o.size.apply?o.size.apply({rects:i,availableWidth:s,availableHeight:l,...c}):Object.assign(f,{maxWidth:`${s}px`,maxHeight:`${l}px`})),e.width==="target"&&Object.assign(f,{width:`${i.reference.width}px`})}})),r}function Vi(e){const t=tn(),[n,o]=mt({value:e.opened,defaultValue:e.defaultOpened,finalValue:!1,onChange:e.onChange}),r=u.useRef(n),i=()=>{n&&!e.disabled&&o(!1)},s=()=>{e.disabled||o(!n)},l=wi({strategy:e.strategy,placement:e.preventPositionChangeWhenVisible?e.positionRef.current:e.position,middleware:zi(e,()=>l,t),whileElementsMounted:e.keepMounted?void 0:Xn});return u.useEffect(()=>{if(!(!l.refs.reference.current||!l.refs.floating.current)&&n)return Xn(l.refs.reference.current,l.refs.floating.current,l.update)},[n,l.update]),Wt(()=>{e.onPositionChange?.(l.placement),e.positionRef.current=l.placement},[l.placement,e.preventPositionChangeWhenVisible]),Wt(()=>{n!==r.current&&(n?e.onOpen?.():e.onClose?.()),r.current=n},[n,e.onClose,e.onOpen]),en(()=>{let c=-1;return n&&(c=window.setTimeout(()=>e.setDropdownVisible(!0),4)),()=>{window.clearTimeout(c)}},[n,e.position]),{floating:l,controlled:typeof e.opened=="boolean",opened:n,onClose:i,onToggle:s}}const Wi={position:"bottom",offset:8,positionDependencies:[],transitionProps:{transition:"fade",duration:150},middlewares:{flip:!0,shift:!0,inline:!1},arrowSize:7,arrowOffset:5,arrowRadius:0,arrowPosition:"side",closeOnClickOutside:!0,withinPortal:!0,closeOnEscape:!0,trapFocus:!1,withRoles:!0,returnFocus:!1,withOverlay:!1,hideDetached:!0,clickOutsideEvents:["mousedown","touchstart"],zIndex:ao("popover"),__staticSelector:"Popover",width:"max-content"},Bi=tt((e,{radius:t,shadow:n})=>({dropdown:{"--popover-radius":t===void 0?void 0:uo(t),"--popover-shadow":Rr(n)}}));function Ee(e){const t=W("Popover",Wi,e),{children:n,position:o,offset:r,onPositionChange:i,positionDependencies:s,opened:l,transitionProps:c,onExitTransitionEnd:a,onEnterTransitionEnd:f,width:p,middlewares:d,withArrow:m,arrowSize:h,arrowOffset:g,arrowRadius:b,arrowPosition:v,unstyled:C,classNames:S,styles:x,closeOnClickOutside:T,withinPortal:R,portalProps:E,closeOnEscape:O,clickOutsideEvents:_,trapFocus:I,onClose:H,onDismiss:j,onOpen:M,onChange:A,zIndex:k,radius:D,shadow:P,id:y,defaultOpened:N,__staticSelector:L,withRoles:B,disabled:$,returnFocus:K,variant:Pe,keepMounted:X,vars:ee,floatingStrategy:de,withOverlay:Xe,overlayProps:Te,hideDetached:Ye,attributes:Ue,preventPositionChangeWhenVisible:Oe,...qe}=t,_e=We({name:L,props:t,classes:Qo,classNames:S,styles:x,unstyled:C,attributes:Ue,rootSelector:"dropdown",vars:ee,varsResolver:Bi}),{resolvedStyles:Nn}=mo({classNames:S,styles:x,props:t}),[Ln,Lt]=u.useState(l??N??!1),ot=u.useRef(o),Ge=u.useRef(null),[Mt,rt]=u.useState(null),[Fe,Ze]=u.useState(null),{dir:je}=nn(),U=tn(),Je=yt(y),F=Vi({middlewares:d,width:p,position:Mi(je,o),offset:typeof r=="number"?r+(m?h/2:0):r,arrowRef:Ge,arrowOffset:g,onPositionChange:i,positionDependencies:s,opened:l,defaultOpened:N,onChange:A,onOpen:M,onClose:H,onDismiss:j,strategy:de,dropdownVisible:Ln,setDropdownVisible:Lt,positionRef:ot,disabled:$,preventPositionChangeWhenVisible:Oe,keepMounted:X});Ar(()=>{T&&(F.onClose(),j?.())},_,[Mt,Fe]);const st=u.useCallback(te=>{rt(te),F.floating.refs.setReference(te)},[F.floating.refs.setReference]),it=u.useCallback(te=>{Ze(te),F.floating.refs.setFloating(te)},[F.floating.refs.setFloating]),le=u.useCallback(()=>{c?.onExited?.(),a?.(),Lt(!1),Oe||(ot.current=o)},[c?.onExited,a,Oe,o]),lt=u.useCallback(()=>{c?.onEntered?.(),f?.()},[c?.onEntered,f]);return w.jsxs(ji,{value:{returnFocus:K,disabled:$,controlled:F.controlled,reference:st,floating:it,x:F.floating.x,y:F.floating.y,arrowX:F.floating?.middlewareData?.arrow?.x,arrowY:F.floating?.middlewareData?.arrow?.y,opened:F.opened,arrowRef:Ge,transitionProps:{...c,onExited:le,onEntered:lt},width:p,withArrow:m,arrowSize:h,arrowOffset:g,arrowRadius:b,arrowPosition:v,placement:F.floating.placement,trapFocus:I,withinPortal:R,portalProps:E,zIndex:k,radius:D,shadow:P,closeOnEscape:O,onDismiss:j,onClose:F.onClose,onToggle:F.onToggle,getTargetId:()=>`${Je}-target`,getDropdownId:()=>`${Je}-dropdown`,withRoles:B,targetProps:qe,__staticSelector:L,classNames:S,styles:x,unstyled:C,variant:Pe,keepMounted:X,getStyles:_e,resolvedStyles:Nn,floatingStrategy:de,referenceHidden:Ye&&U!=="test"?F.floating.middlewareData.hide?.referenceHidden:!1},children:[n,Xe&&w.jsx(fo,{transition:"fade",mounted:F.opened,duration:c?.duration||250,exitDuration:c?.exitDuration||250,children:te=>w.jsx(vn,{withinPortal:R,children:w.jsx(bn,{...Te,..._e("overlay",{className:Te?.className,style:[te,Te?.style]})})})})]})}Ee.Target=tr;Ee.Dropdown=yn;Ee.displayName="@mantine/core/Popover";Ee.extend=e=>e;function nr(e){return typeof e=="string"?{value:e,label:e}:"value"in e&&!("label"in e)?{value:e.value,label:e.value,disabled:e.disabled}:typeof e=="number"?{value:e.toString(),label:e.toString()}:"group"in e?{group:e.group,items:e.items.map(t=>nr(t))}:e}function Ki(e){return e?e.map(t=>nr(t)):[]}function or(e){return e.reduce((t,n)=>"group"in n?{...t,...or(n.items)}:(t[n.value]=n,t),{})}var G={dropdown:"m_88b62a41",search:"m_985517d8",options:"m_b2821a6e",option:"m_92253aa5",empty:"m_2530cd1d",header:"m_858f94bd",footer:"m_82b967cb",group:"m_254f3e4f",groupLabel:"m_2bb2e9e5",chevron:"m_2943220b",optionsDropdownOption:"m_390b5f4",optionsDropdownCheckIcon:"m_8ee53fc2",optionsDropdownCheckPlaceholder:"m_a530ee0a"};const Xi={error:null},Yi=tt((e,{size:t,color:n})=>({chevron:{"--combobox-chevron-size":Bt(t,"combobox-chevron-size"),"--combobox-chevron-color":n?Sr(n,e):void 0}})),xn=Y((e,t)=>{const n=W("ComboboxChevron",Xi,e),{size:o,error:r,style:i,className:s,classNames:l,styles:c,unstyled:a,vars:f,mod:p,...d}=n,m=We({name:"ComboboxChevron",classes:G,props:n,style:i,className:s,classNames:l,styles:c,unstyled:a,vars:f,varsResolver:Yi,rootSelector:"chevron"});return w.jsx(Q,{component:"svg",...d,...m("chevron"),size:o,viewBox:"0 0 15 15",fill:"none",xmlns:"http://www.w3.org/2000/svg",mod:["combobox-chevron",{error:r},p],ref:t,children:w.jsx("path",{d:"M4.93179 5.43179C4.75605 5.60753 4.75605 5.89245 4.93179 6.06819C5.10753 6.24392 5.39245 6.24392 5.56819 6.06819L7.49999 4.13638L9.43179 6.06819C9.60753 6.24392 9.89245 6.24392 10.0682 6.06819C10.2439 5.89245 10.2439 5.60753 10.0682 5.43179L7.81819 3.18179C7.73379 3.0974 7.61933 3.04999 7.49999 3.04999C7.38064 3.04999 7.26618 3.0974 7.18179 3.18179L4.93179 5.43179ZM10.0682 9.56819C10.2439 9.39245 10.2439 9.10753 10.0682 8.93179C9.89245 8.75606 9.60753 8.75606 9.43179 8.93179L7.49999 10.8636L5.56819 8.93179C5.39245 8.75606 5.10753 8.75606 4.93179 8.93179C4.75605 9.10753 4.75605 9.39245 4.93179 9.56819L7.18179 11.8182C7.35753 11.9939 7.64245 11.9939 7.81819 11.8182L10.0682 9.56819Z",fill:"currentColor",fillRule:"evenodd",clipRule:"evenodd"})})});xn.classes=G;xn.displayName="@mantine/core/ComboboxChevron";const[Ui,ie]=wt("Combobox component was not found in tree"),rr=u.forwardRef(({size:e,onMouseDown:t,onClick:n,onClear:o,...r},i)=>w.jsx(ho.ClearButton,{ref:i,tabIndex:-1,"aria-hidden":!0,...r,onMouseDown:s=>{s.preventDefault(),t?.(s)},onClick:s=>{o(),n?.(s)}}));rr.displayName="@mantine/core/ComboboxClearButton";const Cn=Y((e,t)=>{const{classNames:n,styles:o,className:r,style:i,hidden:s,...l}=W("ComboboxDropdown",null,e),c=ie();return w.jsx(Ee.Dropdown,{...l,ref:t,role:"presentation","data-hidden":s||void 0,...c.getStyles("dropdown",{className:r,style:i,classNames:n,styles:o})})});Cn.classes=G;Cn.displayName="@mantine/core/ComboboxDropdown";const qi={refProp:"ref"},sr=Y((e,t)=>{const{children:n,refProp:o}=W("ComboboxDropdownTarget",qi,e);if(ie(),!bo(n))throw new Error("Combobox.DropdownTarget component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");return w.jsx(Ee.Target,{ref:t,refProp:o,children:n})});sr.displayName="@mantine/core/ComboboxDropdownTarget";const Rn=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,...l}=W("ComboboxEmpty",null,e),c=ie();return w.jsx(Q,{ref:t,...c.getStyles("empty",{className:o,classNames:n,styles:i,style:r}),...l})});Rn.classes=G;Rn.displayName="@mantine/core/ComboboxEmpty";function Sn({onKeyDown:e,withKeyboardNavigation:t,withAriaAttributes:n,withExpandedAttribute:o,targetType:r,autoComplete:i}){const s=ie(),[l,c]=u.useState(null),a=p=>{if(e?.(p),!s.readOnly&&t){if(p.nativeEvent.isComposing)return;if(p.nativeEvent.code==="ArrowDown"&&(p.preventDefault(),s.store.dropdownOpened?c(s.store.selectNextOption()):(s.store.openDropdown("keyboard"),c(s.store.selectActiveOption()),s.store.updateSelectedOptionIndex("selected",{scrollIntoView:!0}))),p.nativeEvent.code==="ArrowUp"&&(p.preventDefault(),s.store.dropdownOpened?c(s.store.selectPreviousOption()):(s.store.openDropdown("keyboard"),c(s.store.selectActiveOption()),s.store.updateSelectedOptionIndex("selected",{scrollIntoView:!0}))),p.nativeEvent.code==="Enter"||p.nativeEvent.code==="NumpadEnter"){if(p.nativeEvent.keyCode===229)return;const d=s.store.getSelectedOptionIndex();s.store.dropdownOpened&&d!==-1?(p.preventDefault(),s.store.clickSelectedOption()):r==="button"&&(p.preventDefault(),s.store.openDropdown("keyboard"))}p.key==="Escape"&&s.store.closeDropdown("keyboard"),p.nativeEvent.code==="Space"&&r==="button"&&(p.preventDefault(),s.store.toggleDropdown("keyboard"))}};return{...n?{"aria-haspopup":"listbox","aria-expanded":o?!!(s.store.listId&&s.store.dropdownOpened):void 0,"aria-controls":s.store.dropdownOpened&&s.store.listId?s.store.listId:void 0,"aria-activedescendant":s.store.dropdownOpened&&l||void 0,autoComplete:i,"data-expanded":s.store.dropdownOpened||void 0,"data-mantine-stop-propagation":s.store.dropdownOpened||void 0}:{},onKeyDown:a}}const Gi={refProp:"ref",targetType:"input",withKeyboardNavigation:!0,withAriaAttributes:!0,withExpandedAttribute:!1,autoComplete:"off"},ir=Y((e,t)=>{const{children:n,refProp:o,withKeyboardNavigation:r,withAriaAttributes:i,withExpandedAttribute:s,targetType:l,autoComplete:c,...a}=W("ComboboxEventsTarget",Gi,e),f=Rt(n);if(!f)throw new Error("Combobox.EventsTarget component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const p=ie(),d=Sn({targetType:l,withAriaAttributes:i,withKeyboardNavigation:r,withExpandedAttribute:s,onKeyDown:f.props.onKeyDown,autoComplete:c});return u.cloneElement(f,{...d,...a,[o]:re(t,p.store.targetRef,xo(f))})});ir.displayName="@mantine/core/ComboboxEventsTarget";const En=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,...l}=W("ComboboxFooter",null,e),c=ie();return w.jsx(Q,{ref:t,...c.getStyles("footer",{className:o,classNames:n,style:r,styles:i}),...l,onMouseDown:a=>{a.preventDefault()}})});En.classes=G;En.displayName="@mantine/core/ComboboxFooter";const Pn=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,children:l,label:c,id:a,...f}=W("ComboboxGroup",null,e),p=ie(),d=yt(a);return w.jsxs(Q,{ref:t,role:"group","aria-labelledby":c?d:void 0,...p.getStyles("group",{className:o,classNames:n,style:r,styles:i}),...f,children:[c&&w.jsx("div",{id:d,...p.getStyles("groupLabel",{classNames:n,styles:i}),children:c}),l]})});Pn.classes=G;Pn.displayName="@mantine/core/ComboboxGroup";const Tn=Y((e,t)=>{const{classNames:n,className:o,style:r,styles:i,vars:s,...l}=W("ComboboxHeader",null,e),c=ie();return w.jsx(Q,{ref:t,...c.getStyles("header",{className:o,classNames:n,style:r,styles:i}),...l,onMouseDown:a=>{a.preventDefault()}})});Tn.classes=G;Tn.displayName="@mantine/core/ComboboxHeader";function lr({value:e,valuesDivider:t=",",...n}){return w.jsx("input",{type:"hidden",value:Array.isArray(e)?e.join(t):e||"",...n})}lr.displayName="@mantine/core/ComboboxHiddenInput";const On=Y((e,t)=>{const n=W("ComboboxOption",null,e),{classNames:o,className:r,style:i,styles:s,vars:l,onClick:c,id:a,active:f,onMouseDown:p,onMouseOver:d,disabled:m,selected:h,mod:g,...b}=n,v=ie(),C=u.useId(),S=a||C;return w.jsx(Q,{...v.getStyles("option",{className:r,classNames:o,styles:s,style:i}),...b,ref:t,id:S,mod:["combobox-option",{"combobox-active":f,"combobox-disabled":m,"combobox-selected":h},g],role:"option",onClick:x=>{m?x.preventDefault():(v.onOptionSubmit?.(n.value,n),c?.(x))},onMouseDown:x=>{x.preventDefault(),p?.(x)},onMouseOver:x=>{v.resetSelectionOnOptionHover&&v.store.resetSelectedOption(),d?.(x)}})});On.classes=G;On.displayName="@mantine/core/ComboboxOption";const An=Y((e,t)=>{const n=W("ComboboxOptions",null,e),{classNames:o,className:r,style:i,styles:s,id:l,onMouseDown:c,labelledBy:a,...f}=n,p=ie(),d=yt(l);return u.useEffect(()=>{p.store.setListId(d)},[d]),w.jsx(Q,{ref:t,...p.getStyles("options",{className:r,style:i,classNames:o,styles:s}),...f,id:d,role:"listbox","aria-labelledby":a,onMouseDown:m=>{m.preventDefault(),c?.(m)}})});An.classes=G;An.displayName="@mantine/core/ComboboxOptions";const Zi={withAriaAttributes:!0,withKeyboardNavigation:!0},Dn=Y((e,t)=>{const n=W("ComboboxSearch",Zi,e),{classNames:o,styles:r,unstyled:i,vars:s,withAriaAttributes:l,onKeyDown:c,withKeyboardNavigation:a,size:f,...p}=n,d=ie(),m=d.getStyles("search"),h=Sn({targetType:"input",withAriaAttributes:l,withKeyboardNavigation:a,withExpandedAttribute:!1,onKeyDown:c,autoComplete:"off"});return w.jsx(ho,{ref:re(t,d.store.searchRef),classNames:[{input:m.className},o],styles:[{input:m.style},r],size:f||d.size,...h,...p,__staticSelector:"Combobox"})});Dn.classes=G;Dn.displayName="@mantine/core/ComboboxSearch";const Ji={refProp:"ref",targetType:"input",withKeyboardNavigation:!0,withAriaAttributes:!0,withExpandedAttribute:!1,autoComplete:"off"},cr=Y((e,t)=>{const{children:n,refProp:o,withKeyboardNavigation:r,withAriaAttributes:i,withExpandedAttribute:s,targetType:l,autoComplete:c,...a}=W("ComboboxTarget",Ji,e),f=Rt(n);if(!f)throw new Error("Combobox.Target component children should be an element or a component that accepts ref. Fragments, strings, numbers and other primitive values are not supported");const p=ie(),d=Sn({targetType:l,withAriaAttributes:i,withKeyboardNavigation:r,withExpandedAttribute:s,onKeyDown:f.props.onKeyDown,autoComplete:c}),m=u.cloneElement(f,{...d,...a});return w.jsx(Ee.Target,{ref:re(t,p.store.targetRef),children:m})});cr.displayName="@mantine/core/ComboboxTarget";function Qi(e,t,n){for(let o=e-1;o>=0;o-=1)if(!t[o].hasAttribute("data-combobox-disabled"))return o;if(n){for(let o=t.length-1;o>-1;o-=1)if(!t[o].hasAttribute("data-combobox-disabled"))return o}return e}function el(e,t,n){for(let o=e+1;o{l||(c(!0),r?.(D))},[c,r,l]),v=u.useCallback((D="unknown")=>{l&&(c(!1),o?.(D))},[c,o,l]),C=u.useCallback((D="unknown")=>{l?v(D):b(D)},[v,b,l]),S=u.useCallback(()=>{const D=we(d.current),P=ut(`#${a.current} [data-combobox-selected]`,D);P?.removeAttribute("data-combobox-selected"),P?.removeAttribute("aria-selected")},[]),x=u.useCallback(D=>{const P=we(d.current),y=ut(`#${a.current}`,P),N=y?ye("[data-combobox-option]",y):null;if(!N)return null;const L=D>=N.length?0:D<0?N.length-1:D;return f.current=L,N?.[L]&&!N[L].hasAttribute("data-combobox-disabled")?(S(),N[L].setAttribute("data-combobox-selected","true"),N[L].setAttribute("aria-selected","true"),N[L].scrollIntoView({block:"nearest",behavior:s}),N[L].id):null},[s,S]),T=u.useCallback(()=>{const D=we(d.current),P=ut(`#${a.current} [data-combobox-active]`,D);if(P){const N=ye(`#${a.current} [data-combobox-option]`,D).findIndex(L=>L===P);return x(N)}return x(0)},[x]),R=u.useCallback(()=>{const D=we(d.current),P=ye(`#${a.current} [data-combobox-option]`,D);return x(el(f.current,P,i))},[x,i]),E=u.useCallback(()=>{const D=we(d.current),P=ye(`#${a.current} [data-combobox-option]`,D);return x(Qi(f.current,P,i))},[x,i]),O=u.useCallback(()=>{const D=we(d.current),P=ye(`#${a.current} [data-combobox-option]`,D);return x(tl(P))},[x]),_=u.useCallback((D="selected",P)=>{g.current=window.setTimeout(()=>{const y=we(d.current),N=ye(`#${a.current} [data-combobox-option]`,y),L=N.findIndex(B=>B.hasAttribute(`data-combobox-${D}`));f.current=L,P?.scrollIntoView&&N[L]?.scrollIntoView({block:"nearest",behavior:s})},0)},[]),I=u.useCallback(()=>{f.current=-1,S()},[S]),H=u.useCallback(()=>{const D=we(d.current);ye(`#${a.current} [data-combobox-option]`,D)?.[f.current]?.click()},[]),j=u.useCallback(D=>{a.current=D},[]),M=u.useCallback(()=>{m.current=window.setTimeout(()=>p.current?.focus(),0)},[]),A=u.useCallback(()=>{h.current=window.setTimeout(()=>d.current?.focus(),0)},[]),k=u.useCallback(()=>f.current,[]);return u.useEffect(()=>()=>{window.clearTimeout(m.current),window.clearTimeout(h.current),window.clearTimeout(g.current)},[]),{dropdownOpened:l,openDropdown:b,closeDropdown:v,toggleDropdown:C,selectedOptionIndex:f.current,getSelectedOptionIndex:k,selectOption:x,selectFirstOption:O,selectActiveOption:T,selectNextOption:R,selectPreviousOption:E,resetSelectedOption:I,updateSelectedOptionIndex:_,listId:a.current,setListId:j,clickSelectedOption:H,searchRef:p,focusSearchInput:M,targetRef:d,focusTarget:A}}const nl={keepMounted:!0,withinPortal:!0,resetSelectionOnOptionHover:!1,width:"target",transitionProps:{transition:"fade",duration:0},size:"sm"},ol=tt((e,{size:t,dropdownPadding:n})=>({options:{"--combobox-option-fz":_n(t),"--combobox-option-padding":Bt(t,"combobox-option-padding")},dropdown:{"--combobox-padding":n===void 0?void 0:ze(n),"--combobox-option-fz":_n(t),"--combobox-option-padding":Bt(t,"combobox-option-padding")}}));function z(e){const t=W("Combobox",nl,e),{classNames:n,styles:o,unstyled:r,children:i,store:s,vars:l,onOptionSubmit:c,onClose:a,size:f,dropdownPadding:p,resetSelectionOnOptionHover:d,__staticSelector:m,readOnly:h,attributes:g,...b}=t,v=ar(),C=s||v,S=We({name:m||"Combobox",classes:G,props:t,classNames:n,styles:o,unstyled:r,attributes:g,vars:l,varsResolver:ol}),x=()=>{a?.(),C.closeDropdown()};return w.jsx(Ui,{value:{getStyles:S,store:C,onOptionSubmit:c,size:f,resetSelectionOnOptionHover:d,readOnly:h},children:w.jsx(Ee,{opened:C.dropdownOpened,preventPositionChangeWhenVisible:!1,...b,onChange:T=>!T&&x(),withRoles:!1,unstyled:r,children:i})})}const rl=e=>e;z.extend=rl;z.classes=G;z.displayName="@mantine/core/Combobox";z.Target=cr;z.Dropdown=Cn;z.Options=An;z.Option=On;z.Search=Dn;z.Empty=Rn;z.Chevron=xn;z.Footer=En;z.Header=Tn;z.EventsTarget=ir;z.DropdownTarget=sr;z.Group=Pn;z.ClearButton=rr;z.HiddenInput=lr;function ur({size:e,style:t,...n}){const o=e!==void 0?{width:ze(e),height:ze(e),...t}:t;return w.jsx("svg",{viewBox:"0 0 10 7",fill:"none",xmlns:"http://www.w3.org/2000/svg",style:o,"aria-hidden":!0,...n,children:w.jsx("path",{d:"M4 4.586L1.707 2.293A1 1 0 1 0 .293 3.707l3 3a.997.997 0 0 0 1.414 0l5-5A1 1 0 1 0 8.293.293L4 4.586z",fill:"currentColor",fillRule:"evenodd",clipRule:"evenodd"})})}function xl({indeterminate:e,...t}){return e?w.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 32 6","aria-hidden":!0,...t,children:w.jsx("rect",{width:"32",height:"6",fill:"currentColor",rx:"3"})}):w.jsx(ur,{...t})}function et(e){return"group"in e}function fr({options:e,search:t,limit:n}){const o=t.trim().toLowerCase(),r=[];for(let i=0;i0)return!1;return!0}function dr(e,t=new Set){if(Array.isArray(e))for(const n of e)if(et(n))dr(n.items,t);else{if(typeof n.value>"u")throw new Error("[@mantine/core] Each option must have value property");if(typeof n.value!="string")throw new Error(`[@mantine/core] Option value must be a string, other data formats are not supported, got ${typeof n.value}`);if(t.has(n.value))throw new Error(`[@mantine/core] Duplicate options are not supported. Option with value "${n.value}" was provided more than once`);t.add(n.value)}}function il(e,t){return Array.isArray(e)?e.includes(t):e===t}function pr({data:e,withCheckIcon:t,withAlignedLabels:n,value:o,checkIconPosition:r,unstyled:i,renderOption:s}){if(!et(e)){const c=il(o,e.value),a=t&&(c?w.jsx(ur,{className:G.optionsDropdownCheckIcon}):n?w.jsx("div",{className:G.optionsDropdownCheckPlaceholder}):null),f=w.jsxs(w.Fragment,{children:[r==="left"&&a,w.jsx("span",{children:e.label}),r==="right"&&a]});return w.jsx(z.Option,{value:e.value,disabled:e.disabled,className:po({[G.optionsDropdownOption]:!i}),"data-reverse":r==="right"||void 0,"data-checked":c||void 0,"aria-selected":c,active:c,children:typeof s=="function"?s({option:e,checked:c}):f})}const l=e.items.map(c=>w.jsx(pr,{data:c,value:o,unstyled:i,withCheckIcon:t,withAlignedLabels:n,checkIconPosition:r,renderOption:s},c.value));return w.jsx(z.Group,{label:e.group,children:l})}function ll({data:e,hidden:t,hiddenWhenEmpty:n,filter:o,search:r,limit:i,maxDropdownHeight:s,withScrollArea:l=!0,filterOptions:c=!0,withCheckIcon:a=!1,withAlignedLabels:f=!1,value:p,checkIconPosition:d,nothingFoundMessage:m,unstyled:h,labelId:g,renderOption:b,scrollAreaProps:v,"aria-label":C}){dr(e);const x=typeof r=="string"?(o||fr)({options:e,search:c?r:"",limit:i??1/0}):e,T=sl(x),R=x.map(E=>w.jsx(pr,{data:E,withCheckIcon:a,withAlignedLabels:f,value:p,checkIconPosition:d,unstyled:h,renderOption:b},et(E)?E.group:E.value));return w.jsx(z.Dropdown,{hidden:t||n&&T,"data-composed":!0,children:w.jsxs(z.Options,{labelledBy:g,"aria-label":C,children:[l?w.jsx(nt.Autosize,{mah:s??220,type:"scroll",scrollbarSize:"var(--combobox-padding)",offsetScrollbars:"y",...v,children:R}):R,T&&m&&w.jsx(z.Empty,{children:m})]})})}const cl={withCheckIcon:!0,allowDeselect:!0,checkIconPosition:"left",openOnFocus:!0},mr=Y((e,t)=>{const n=W("Select",cl,e),{classNames:o,styles:r,unstyled:i,vars:s,dropdownOpened:l,defaultDropdownOpened:c,onDropdownClose:a,onDropdownOpen:f,onFocus:p,onBlur:d,onClick:m,onChange:h,data:g,value:b,defaultValue:v,selectFirstOptionOnChange:C,selectFirstOptionOnDropdownOpen:S,onOptionSubmit:x,comboboxProps:T,readOnly:R,disabled:E,filter:O,limit:_,withScrollArea:I,maxDropdownHeight:H,size:j,searchable:M,rightSection:A,checkIconPosition:k,withCheckIcon:D,withAlignedLabels:P,nothingFoundMessage:y,name:N,form:L,searchValue:B,defaultSearchValue:$,onSearchChange:K,allowDeselect:Pe,error:X,rightSectionPointerEvents:ee,id:de,clearable:Xe,clearButtonProps:Te,hiddenInputProps:Ye,renderOption:Ue,onClear:Oe,autoComplete:qe,scrollAreaProps:_e,__defaultRightSection:Nn,__clearSection:Ln,__clearable:Lt,chevronColor:ot,autoSelectOnBlur:Ge,openOnFocus:Mt,attributes:rt,...Fe}=n,Ze=u.useMemo(()=>Ki(g),[g]),je=u.useRef({}),U=u.useMemo(()=>or(Ze),[Ze]),Je=yt(de),[F,st,it]=mt({value:b,defaultValue:v,finalValue:null,onChange:h}),le=typeof F=="string"?F in U?U[F]:je.current[F]:void 0,lt=jr(le),[te,br,vr]=mt({value:B,defaultValue:$,finalValue:le?le.label:"",onChange:K}),Z=ar({opened:l,defaultOpened:c,onDropdownOpen:()=>{f?.(),S?Z.selectFirstOption():Z.updateSelectedOptionIndex("active",{scrollIntoView:!0})},onDropdownClose:()=>{a?.(),setTimeout(Z.resetSelectedOption,0)}}),Ae=J=>{br(J),Z.resetSelectedOption()},{resolvedClassNames:Mn,resolvedStyles:In}=mo({props:n,styles:r,classNames:o});u.useEffect(()=>{C&&Z.selectFirstOption()},[C,te]),u.useEffect(()=>{b===null&&Ae(""),typeof b=="string"&&le&&(lt?.value!==le.value||lt?.label!==le.label)&&Ae(le.label)},[b,le]),u.useEffect(()=>{!it&&!vr&&Ae(typeof F=="string"?F in U?U[F]?.label:je.current[F]?.label||"":"")},[U,F]),u.useEffect(()=>{F&&F in U&&(je.current[F]=U[F])},[U,F]);const wr=w.jsx(z.ClearButton,{...Te,onClear:()=>{st(null,null),Ae(""),Oe?.()}}),yr=Xe&&!!F&&!E&&!R;return w.jsxs(w.Fragment,{children:[w.jsxs(z,{store:Z,__staticSelector:"Select",classNames:Mn,styles:In,unstyled:i,readOnly:R,size:j,attributes:rt,keepMounted:Ge,onOptionSubmit:J=>{x?.(J);const De=Pe&&U[J].value===F?null:U[J],It=De?De.value:null;It!==F&&st(It,De),!it&&Ae(typeof It=="string"&&De?.label||""),Z.closeDropdown()},...T,children:[w.jsx(z.Target,{targetType:M?"input":"button",autoComplete:qe,children:w.jsx(xt,{id:Je,ref:t,__defaultRightSection:w.jsx(z.Chevron,{size:j,error:X,unstyled:i,color:ot}),__clearSection:wr,__clearable:yr,rightSection:A,rightSectionPointerEvents:ee||"none",...Fe,size:j,__staticSelector:"Select",disabled:E,readOnly:R||!M,value:te,onChange:J=>{Ae(J.currentTarget.value),Z.openDropdown(),C&&Z.selectFirstOption()},onFocus:J=>{Mt&&M&&Z.openDropdown(),p?.(J)},onBlur:J=>{Ge&&Z.clickSelectedOption(),M&&Z.closeDropdown();const De=typeof F=="string"&&(F in U?U[F]:je.current[F]);Ae(De&&De.label||""),d?.(J)},onClick:J=>{M?Z.openDropdown():Z.toggleDropdown(),m?.(J)},classNames:Mn,styles:In,unstyled:i,pointer:!M,error:X,attributes:rt})}),w.jsx(ll,{data:Ze,hidden:R||E,filter:O,search:te,limit:_,hiddenWhenEmpty:!y,withScrollArea:I,maxDropdownHeight:H,filterOptions:!!M&&le?.label!==te,value:F,checkIconPosition:k,withCheckIcon:D,withAlignedLabels:P,nothingFoundMessage:y,unstyled:i,labelId:Fe.label?`${Je}-label`:void 0,"aria-label":Fe.label?void 0:Fe["aria-label"],renderOption:Ue,scrollAreaProps:_e})]}),w.jsx(z.HiddenInput,{value:F,name:N,form:L,disabled:E,...Ye})]})});mr.classes={...xt.classes,...z.classes};mr.displayName="@mantine/core/Select";const hr=Y((e,t)=>{const n=W("TextInput",null,e);return w.jsx(xt,{component:"input",ref:t,...n,__staticSelector:"TextInput"})});hr.classes=xt.classes;hr.displayName="@mantine/core/TextInput";const al=[["path",{d:"M12 9v4",key:"svg-0"}],["path",{d:"M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0",key:"svg-1"}],["path",{d:"M12 16h.01",key:"svg-2"}]],ul=go("outline","alert-triangle","AlertTriangle",al);const fl=[["path",{d:"M12.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74",key:"svg-0"}],["path",{d:"M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6",key:"svg-1"}],["path",{d:"M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4",key:"svg-2"}],["path",{d:"M3 3l18 18",key:"svg-3"}]],dl=go("outline","database-off","DatabaseOff",fl);function Cl({title:e,description:t,action:n,tone:o="empty"}){const r=o==="error"?ul:dl;return w.jsxs("div",{className:`nf-state-view nf-state-view--${o}`,role:o==="error"?"alert":"status",children:[w.jsx(r,{size:28,stroke:1.5,"aria-hidden":"true"}),w.jsxs("div",{children:[w.jsx("strong",{children:e}),w.jsx("span",{children:t})]}),n]})}function Rl({onClick:e}){return w.jsx(Er,{variant:"light",color:"nodeflow",onClick:e,children:"Повторить"})}function Sl({title:e,description:t,actions:n,children:o,className:r="",as:i="section",...s}){return w.jsxs(i,{className:`nf-surface ${r}`,...s,children:[(e||t||n)&&w.jsxs("header",{className:"nf-surface__header",children:[w.jsxs("div",{children:[e&&w.jsx("h2",{children:e}),t&&w.jsx("p",{children:t})]}),n&&w.jsx("div",{className:"nf-surface__actions",children:n})]}),o]})}const gr=(e,t=0)=>Number.isFinite(e)?new Intl.NumberFormat("ru-RU",{maximumFractionDigits:t}).format(Number(e)):"—";function El(e){if(!Number.isFinite(e))return"—";const t=["Б","КиБ","МиБ","ГиБ","ТиБ","ПиБ"];let n=Math.max(0,Number(e)),o=0;for(;n>=1024&&o=100?0:n>=10?1:2)} ${t[o]}`}function Pl(e){if(typeof e!="number"||!Number.isFinite(e))return"—";const t=["бит/с","Кбит/с","Мбит/с","Гбит/с","Тбит/с"];let n=Math.max(0,Number(e)),o=0;for(;n>=1e3&&o=100||o===0?0:n>=10?1:2)} ${t[o]}`}function Tl(e){return String(e??"").match(/(?:HAProxy\s+version\s+)?(\d+\.\d+\.\d+)(?:[-+\s]|$)/i)?.[1]??e??"—"}function Ol(e){if(!e)return"никогда";const t=Math.max(0,(Date.now()-Date.parse(e))/1e3);return t<60?`${Math.floor(t)} сек назад`:t<3600?`${Math.floor(t/60)} мин назад`:t<86400?`${Math.floor(t/3600)} ч назад`:`${Math.floor(t/86400)} д назад`}function Al(e){if(!Number.isFinite(e))return"—";let t=Math.max(0,Math.floor(Number(e)));const n=Math.floor(t/86400);t%=86400;const o=Math.floor(t/3600);t%=3600;const r=Math.floor(t/60);return n?`${n} д. ${o} ч. ${r} м.`:o?`${o} ч. ${r} м.`:`${r} мин.`}function Dl(e){return!e||!Number.isFinite(Date.parse(e))?"—":new Intl.DateTimeFormat("ru-RU",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}).format(new Date(e))}export{wi as A,oi as B,xl as C,Ce as D,xo as E,wn as F,hl as G,Xn as H,ul as I,gl as J,wl as K,ml as L,vl as M,yl as N,ll as O,Ee as P,bl as Q,Rl as R,Cl as S,hr as T,ni as U,Gn as V,ii as W,Zn as X,Mi as Y,qo as Z,vt as _,El as a,gr as b,Sl as c,mr as d,Al as e,Pl as f,Dl as g,Ki as h,et as i,or as j,ar as k,z as l,Fr as m,ur as n,Xt as o,bn as p,Dr as q,vn as r,Tl as s,Ol as t,re as u,nn as v,bo as w,Rt as x,nt as y,Pr as z}; diff --git a/internal/panel/web_dist/assets/index-Dy6W__Vz.js b/internal/panel/web_dist/assets/index-fgrXogF6.js similarity index 99% rename from internal/panel/web_dist/assets/index-Dy6W__Vz.js rename to internal/panel/web_dist/assets/index-fgrXogF6.js index 2e09c8b..c301897 100644 --- a/internal/panel/web_dist/assets/index-Dy6W__Vz.js +++ b/internal/panel/web_dist/assets/index-fgrXogF6.js @@ -1,4 +1,4 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/NodesOverviewPage-esI7wwJs.js","assets/PageHeader-C4N9uitv.js","assets/format-D6_ab21F.js","assets/model-BX4frb_O.js","assets/IconKey-D6H2eVar.js","assets/IconServer-BpOSndTX.js","assets/IconArrowUp-Cj3lrfzR.js","assets/IconPlus-N6bDt4BE.js","assets/TrafficChart-BU3flakD.js","assets/chart-react-C4b8adjg.js","assets/chart-engine-Dbh3Q7E_.js","assets/chart-renderer-CWmX7Ukt.js","assets/useTrafficOverview-7XLu6zlh.js","assets/RouteEditorPage-PVwzgvr8.js","assets/uuid-CHFAcSZK.js","assets/IconDots-B4BXVaDG.js","assets/IconTrash-CZzjtN_Z.js","assets/RouteEditorPage-CKuDBsYn.css","assets/NodeDetailPage-qxCia4WP.js","assets/platform-C19YEZOH.js","assets/haproxy-BnB0NJ0D.js","assets/interaction-BrakVCuN.js","assets/TrafficPage-BPEXjV3K.js","assets/TrafficPage-DV4UxU_q.css","assets/SettingsPage-Cn7Tfg_U.js","assets/SettingsPage-CTYLL-Sl.css"])))=>i.map(i=>d[i]); +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/NodesOverviewPage-B2WqQpz1.js","assets/PageHeader-Fvu-o_Iq.js","assets/format-DGDz36zr.js","assets/model-Dv87zZ-k.js","assets/IconKey-DrhZ0AMo.js","assets/IconServer-DmZ16e5j.js","assets/IconArrowUp-DwKi77Ll.js","assets/IconPlus-D0GthIF3.js","assets/TrafficChart-84ShhOyf.js","assets/chart-react-C4b8adjg.js","assets/chart-engine-Dbh3Q7E_.js","assets/chart-renderer-CWmX7Ukt.js","assets/useTrafficOverview-CPWkIFeU.js","assets/RouteEditorPage-BOKhQYM4.js","assets/uuid-CMwH_1Ko.js","assets/IconDots-BNcckjtc.js","assets/IconTrash-Bdw5EaPs.js","assets/RouteEditorPage-CKuDBsYn.css","assets/NodeDetailPage-J8oehTrg.js","assets/platform-DnnQQ6bP.js","assets/haproxy-BnB0NJ0D.js","assets/interaction-BrakVCuN.js","assets/TrafficPage-BghnUjc1.js","assets/TrafficPage-DV4UxU_q.css","assets/SettingsPage-B9rk-cjR.js","assets/SettingsPage-CTYLL-Sl.css"])))=>i.map(i=>d[i]); import{r as fd,g as t0,a as rl,b as a0,c as Z1}from"./chart-react-C4b8adjg.js";function F1(a,l){for(var i=0;io[c]})}}}return Object.freeze(Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}))}(function(){const l=document.createElement("link").relList;if(l&&l.supports&&l.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))o(c);new MutationObserver(c=>{for(const f of c)if(f.type==="childList")for(const d of f.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&o(d)}).observe(document,{childList:!0,subtree:!0});function i(c){const f={};return c.integrity&&(f.integrity=c.integrity),c.referrerPolicy&&(f.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?f.credentials="include":c.crossOrigin==="anonymous"?f.credentials="omit":f.credentials="same-origin",f}function o(c){if(c.ep)return;c.ep=!0;const f=i(c);fetch(c.href,f)}})();var gf={exports:{}},Mi={};var qv;function K1(){if(qv)return Mi;qv=1;var a=Symbol.for("react.transitional.element"),l=Symbol.for("react.fragment");function i(o,c,f){var d=null;if(f!==void 0&&(d=""+f),c.key!==void 0&&(d=""+c.key),"key"in c){f={};for(var h in c)h!=="key"&&(f[h]=c[h])}else f=c;return c=f.ref,{$$typeof:a,type:o,key:d,ref:c!==void 0?c:null,props:f}}return Mi.Fragment=l,Mi.jsx=i,Mi.jsxs=i,Mi}var Yv;function J1(){return Yv||(Yv=1,gf.exports=K1()),gf.exports}var O=J1(),S=fd();const n0=t0(S),P1=F1({__proto__:null,default:n0},[S]);var Du="right-scroll-bar-position",Nu="width-before-scroll-bar",W1="with-scroll-bars-hidden",I1="--removed-body-scroll-bar-size";function bf(a,l){return typeof a=="function"?a(l):a&&(a.current=l),a}function eS(a,l){var i=S.useState(function(){return{value:a,callback:l,facade:{get current(){return i.value},set current(o){var c=i.value;c!==o&&(i.value=o,i.callback(o,c))}}}})[0];return i.callback=l,i.facade}var tS=typeof window<"u"?S.useLayoutEffect:S.useEffect,Vv=new WeakMap;function aS(a,l){var i=eS(null,function(o){return a.forEach(function(c){return bf(c,o)})});return tS(function(){var o=Vv.get(i);if(o){var c=new Set(o),f=new Set(a),d=i.current;c.forEach(function(h){f.has(h)||bf(h,null)}),f.forEach(function(h){c.has(h)||bf(h,d)})}Vv.set(i,a)},[a]),i}function nS(a){return a}function lS(a,l){l===void 0&&(l=nS);var i=[],o=!1,c={read:function(){if(o)throw new Error("Sidecar: could not `read` from an `assigned` medium. `read` could be used only with `useMedium`.");return i.length?i[i.length-1]:a},useMedium:function(f){var d=l(f,o);return i.push(d),function(){i=i.filter(function(h){return h!==d})}},assignSyncMedium:function(f){for(o=!0;i.length;){var d=i;i=[],d.forEach(f)}i={push:function(h){return f(h)},filter:function(){return i}}},assignMedium:function(f){o=!0;var d=[];if(i.length){var h=i;i=[],h.forEach(f),d=i}var v=function(){var y=d;d=[],y.forEach(f)},m=function(){return Promise.resolve().then(v)};m(),i={push:function(y){d.push(y),m()},filter:function(y){return d=d.filter(y),i}}}};return c}function rS(a){a===void 0&&(a={});var l=lS(null);return l.options=rl({async:!0,ssr:!1},a),l}var l0=function(a){var l=a.sideCar,i=a0(a,["sideCar"]);if(!l)throw new Error("Sidecar: please provide `sideCar` property to import the right car");var o=l.read();if(!o)throw new Error("Sidecar medium not found");return S.createElement(o,rl({},i))};l0.isSideCarExport=!0;function iS(a,l){return a.useMedium(l),l0}var r0=rS(),Sf=function(){},Xu=S.forwardRef(function(a,l){var i=S.useRef(null),o=S.useState({onScrollCapture:Sf,onWheelCapture:Sf,onTouchMoveCapture:Sf}),c=o[0],f=o[1],d=a.forwardProps,h=a.children,v=a.className,m=a.removeScrollBar,y=a.enabled,b=a.shards,E=a.sideCar,R=a.noRelative,C=a.noIsolation,T=a.inert,A=a.allowPinchZoom,q=a.as,$=q===void 0?"div":q,X=a.gapMode,J=a0(a,["forwardProps","children","className","removeScrollBar","enabled","shards","sideCar","noRelative","noIsolation","inert","allowPinchZoom","as","gapMode"]),K=E,W=aS([i,l]),P=rl(rl({},J),c);return S.createElement(S.Fragment,null,y&&S.createElement(K,{sideCar:r0,removeScrollBar:m,shards:b,noRelative:R,noIsolation:C,inert:T,setCallbacks:f,allowPinchZoom:!!A,lockRef:i,gapMode:X}),d?S.cloneElement(S.Children.only(h),rl(rl({},P),{ref:W})):S.createElement($,rl({},P,{className:v,ref:W}),h))});Xu.defaultProps={enabled:!0,removeScrollBar:!0,inert:!1};Xu.classNames={fullWidth:Nu,zeroRight:Du};var oS=function(){if(typeof __webpack_nonce__<"u")return __webpack_nonce__};function uS(){if(!document)return null;var a=document.createElement("style");a.type="text/css";var l=oS();return l&&a.setAttribute("nonce",l),a}function sS(a,l){a.styleSheet?a.styleSheet.cssText=l:a.appendChild(document.createTextNode(l))}function cS(a){var l=document.head||document.getElementsByTagName("head")[0];l.appendChild(a)}var fS=function(){var a=0,l=null;return{add:function(i){a==0&&(l=uS())&&(sS(l,i),cS(l)),a++},remove:function(){a--,!a&&l&&(l.parentNode&&l.parentNode.removeChild(l),l=null)}}},dS=function(){var a=fS();return function(l,i){S.useEffect(function(){return a.add(l),function(){a.remove()}},[l&&i])}},i0=function(){var a=dS(),l=function(i){var o=i.styles,c=i.dynamic;return a(o,c),null};return l},hS={left:0,top:0,right:0,gap:0},Ef=function(a){return parseInt(a||"",10)||0},mS=function(a){var l=window.getComputedStyle(document.body),i=l[a==="padding"?"paddingLeft":"marginLeft"],o=l[a==="padding"?"paddingTop":"marginTop"],c=l[a==="padding"?"paddingRight":"marginRight"];return[Ef(i),Ef(o),Ef(c)]},pS=function(a){if(a===void 0&&(a="margin"),typeof window>"u")return hS;var l=mS(a),i=document.documentElement.clientWidth,o=window.innerWidth;return{left:l[0],top:l[1],right:l[2],gap:Math.max(0,o-i+l[2]-l[0])}},vS=i0(),Ar="data-scroll-locked",yS=function(a,l,i,o){var c=a.left,f=a.top,d=a.right,h=a.gap;return i===void 0&&(i="margin"),` .`.concat(W1,` { overflow: hidden `).concat(o,`; @@ -54,4 +54,4 @@ Error generating stack: `+r.message+` `).replace(p1,"")}function ov(e,t){return t=iv(t),iv(e)===t}function We(e,t,n,r,u,s){switch(n){case"children":typeof r=="string"?t==="body"||t==="textarea"&&r===""||ql(e,r):(typeof r=="number"||typeof r=="bigint")&&t!=="body"&&ql(e,""+r);break;case"className":on(e,"class",r);break;case"tabIndex":on(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":on(e,n,r);break;case"style":oh(e,r,s);break;case"data":if(t!=="object"){on(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||n!=="href")){e.removeAttribute(n);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(n);break}r=fo(""+r),e.setAttribute(n,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(n,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof s=="function"&&(n==="formAction"?(t!=="input"&&We(e,t,"name",u.name,u,null),We(e,t,"formEncType",u.formEncType,u,null),We(e,t,"formMethod",u.formMethod,u,null),We(e,t,"formTarget",u.formTarget,u,null)):(We(e,t,"encType",u.encType,u,null),We(e,t,"method",u.method,u,null),We(e,t,"target",u.target,u,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(n);break}r=fo(""+r),e.setAttribute(n,r);break;case"onClick":r!=null&&(e.onclick=sn);break;case"onScroll":r!=null&&Oe("scroll",e);break;case"onScrollEnd":r!=null&&Oe("scrollend",e);break;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(o(61));if(n=r.__html,n!=null){if(u.children!=null)throw Error(o(60));e.innerHTML=n}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}n=fo(""+r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",n);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(n,""+r):e.removeAttribute(n);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(n,""):e.removeAttribute(n);break;case"capture":case"download":r===!0?e.setAttribute(n,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(n,r):e.removeAttribute(n);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(n,r):e.removeAttribute(n);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(n):e.setAttribute(n,r);break;case"popover":Oe("beforetoggle",e),Oe("toggle",e),rn(e,"popover",r);break;case"xlinkActuate":Se(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":Se(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":Se(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":Se(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":Se(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":Se(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":Se(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":Se(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":Se(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":rn(e,"is",r);break;case"innerText":case"textContent":break;default:(!(2g)break;var Y=w.transferSize,G=w.initiatorType;Y&&uv(G)&&(w=w.responseEnd,p+=Y*(w"u"?null:document;function Sv(e,t,n){var r=mr;if(r&&typeof t=="string"&&t){var u=Ht(t);u='link[rel="'+e+'"][href="'+u+'"]',typeof n=="string"&&(u+='[crossorigin="'+n+'"]'),bv.has(u)||(bv.add(u),e={rel:e,crossOrigin:n,href:t},r.querySelector(u)===null&&(t=r.createElement("link"),_t(t,"link",e),He(t),r.head.appendChild(t)))}}function z1(e){Tn.D(e),Sv("dns-prefetch",e,null)}function A1(e,t){Tn.C(e,t),Sv("preconnect",e,t)}function M1(e,t,n){Tn.L(e,t,n);var r=mr;if(r&&e&&t){var u='link[rel="preload"][as="'+Ht(t)+'"]';t==="image"&&n&&n.imageSrcSet?(u+='[imagesrcset="'+Ht(n.imageSrcSet)+'"]',typeof n.imageSizes=="string"&&(u+='[imagesizes="'+Ht(n.imageSizes)+'"]')):u+='[href="'+Ht(e)+'"]';var s=u;switch(t){case"style":s=pr(e);break;case"script":s=vr(e)}Ea.has(s)||(e=b({rel:"preload",href:t==="image"&&n&&n.imageSrcSet?void 0:e,as:t},n),Ea.set(s,e),r.querySelector(u)!==null||t==="style"&&r.querySelector(wi(s))||t==="script"&&r.querySelector(xi(s))||(t=r.createElement("link"),_t(t,"link",e),He(t),r.head.appendChild(t)))}}function _1(e,t){Tn.m(e,t);var n=mr;if(n&&e){var r=t&&typeof t.as=="string"?t.as:"script",u='link[rel="modulepreload"][as="'+Ht(r)+'"][href="'+Ht(e)+'"]',s=u;switch(r){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":s=vr(e)}if(!Ea.has(s)&&(e=b({rel:"modulepreload",href:e},t),Ea.set(s,e),n.querySelector(u)===null)){switch(r){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(n.querySelector(xi(s)))return}r=n.createElement("link"),_t(r,"link",e),He(r),n.head.appendChild(r)}}}function O1(e,t,n){Tn.S(e,t,n);var r=mr;if(r&&e){var u=ft(r).hoistableStyles,s=pr(e);t=t||"default";var p=u.get(s);if(!p){var g={loading:0,preload:null};if(p=r.querySelector(wi(s)))g.loading=5;else{e=b({rel:"stylesheet",href:e,"data-precedence":t},n),(n=Ea.get(s))&&sf(e,n);var w=p=r.createElement("link");He(w),_t(w,"link",e),w._p=new Promise(function(j,Y){w.onload=j,w.onerror=Y}),w.addEventListener("load",function(){g.loading|=1}),w.addEventListener("error",function(){g.loading|=2}),g.loading|=4,su(p,t,r)}p={type:"stylesheet",instance:p,count:1,state:g},u.set(s,p)}}}function D1(e,t){Tn.X(e,t);var n=mr;if(n&&e){var r=ft(n).hoistableScripts,u=vr(e),s=r.get(u);s||(s=n.querySelector(xi(u)),s||(e=b({src:e,async:!0},t),(t=Ea.get(u))&&cf(e,t),s=n.createElement("script"),He(s),_t(s,"link",e),n.head.appendChild(s)),s={type:"script",instance:s,count:1,state:null},r.set(u,s))}}function N1(e,t){Tn.M(e,t);var n=mr;if(n&&e){var r=ft(n).hoistableScripts,u=vr(e),s=r.get(u);s||(s=n.querySelector(xi(u)),s||(e=b({src:e,async:!0,type:"module"},t),(t=Ea.get(u))&&cf(e,t),s=n.createElement("script"),He(s),_t(s,"link",e),n.head.appendChild(s)),s={type:"script",instance:s,count:1,state:null},r.set(u,s))}}function Ev(e,t,n,r){var u=(u=Me.current)?uu(u):null;if(!u)throw Error(o(446));switch(e){case"meta":case"title":return null;case"style":return typeof n.precedence=="string"&&typeof n.href=="string"?(t=pr(n.href),n=ft(u).hoistableStyles,r=n.get(t),r||(r={type:"style",instance:null,count:0,state:null},n.set(t,r)),r):{type:"void",instance:null,count:0,state:null};case"link":if(n.rel==="stylesheet"&&typeof n.href=="string"&&typeof n.precedence=="string"){e=pr(n.href);var s=ft(u).hoistableStyles,p=s.get(e);if(p||(u=u.ownerDocument||u,p={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},s.set(e,p),(s=u.querySelector(wi(e)))&&!s._p&&(p.instance=s,p.state.loading=5),Ea.has(e)||(n={rel:"preload",as:"style",href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},Ea.set(e,n),s||j1(u,e,n,p.state))),t&&r===null)throw Error(o(528,""));return p}if(t&&r!==null)throw Error(o(529,""));return null;case"script":return t=n.async,n=n.src,typeof n=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=vr(n),n=ft(u).hoistableScripts,r=n.get(t),r||(r={type:"script",instance:null,count:0,state:null},n.set(t,r)),r):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,e))}}function pr(e){return'href="'+Ht(e)+'"'}function wi(e){return'link[rel="stylesheet"]['+e+"]"}function Rv(e){return b({},e,{"data-precedence":e.precedence,precedence:null})}function j1(e,t,n,r){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?r.loading=1:(t=e.createElement("link"),r.preload=t,t.addEventListener("load",function(){return r.loading|=1}),t.addEventListener("error",function(){return r.loading|=2}),_t(t,"link",n),He(t),e.head.appendChild(t))}function vr(e){return'[src="'+Ht(e)+'"]'}function xi(e){return"script[async]"+e}function wv(e,t,n){if(t.count++,t.instance===null)switch(t.type){case"style":var r=e.querySelector('style[data-href~="'+Ht(n.href)+'"]');if(r)return t.instance=r,He(r),r;var u=b({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement("style"),He(r),_t(r,"style",u),su(r,n.precedence,e),t.instance=r;case"stylesheet":u=pr(n.href);var s=e.querySelector(wi(u));if(s)return t.state.loading|=4,t.instance=s,He(s),s;r=Rv(n),(u=Ea.get(u))&&sf(r,u),s=(e.ownerDocument||e).createElement("link"),He(s);var p=s;return p._p=new Promise(function(g,w){p.onload=g,p.onerror=w}),_t(s,"link",r),t.state.loading|=4,su(s,n.precedence,e),t.instance=s;case"script":return s=vr(n.src),(u=e.querySelector(xi(s)))?(t.instance=u,He(u),u):(r=n,(u=Ea.get(s))&&(r=b({},n),cf(r,u)),e=e.ownerDocument||e,u=e.createElement("script"),He(u),_t(u,"link",r),e.head.appendChild(u),t.instance=u);case"void":return null;default:throw Error(o(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(r=t.instance,t.state.loading|=4,su(r,n.precedence,e));return t.instance}function su(e,t,n){for(var r=n.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),u=r.length?r[r.length-1]:null,s=u,p=0;p title"):null)}function L1(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Cv(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function U1(e,t,n,r){if(n.type==="stylesheet"&&(typeof r.media!="string"||matchMedia(r.media).matches!==!1)&&(n.state.loading&4)===0){if(n.instance===null){var u=pr(r.href),s=t.querySelector(wi(u));if(s){t=s._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fu.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=s,He(s);return}s=t.ownerDocument||t,r=Rv(r),(u=Ea.get(u))&&sf(r,u),s=s.createElement("link"),He(s);var p=s;p._p=new Promise(function(g,w){p.onload=g,p.onerror=w}),_t(s,"link",r),n.instance=s}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&(n.state.loading&3)===0&&(e.count++,n=fu.bind(e),t.addEventListener("load",n),t.addEventListener("error",n))}}var ff=0;function B1(e,t){return e.stylesheets&&e.count===0&&hu(e,e.stylesheets),0ff?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(u)}}:null}function fu(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hu(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var du=null;function hu(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,du=new Map,t.forEach(H1,e),du=null,fu.call(e))}function H1(e,t){if(!(t.state.loading&4)){var n=du.get(e);if(n)var r=n.get(null);else{n=new Map,du.set(e,n);for(var u=e.querySelectorAll("link[data-precedence],style[data-precedence]"),s=0;s"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(a)}catch(l){console.error(l)}}return a(),Of.exports=B3(),Of.exports}var $3=H3();var F0=a=>{throw TypeError(a)},K0=(a,l,i)=>l.has(a)||F0("Cannot "+i),Ra=(a,l,i)=>(K0(a,l,"read from private field"),i?i.call(a):l.get(a)),Li=(a,l,i)=>l.has(a)?F0("Cannot add the same private member more than once"):l instanceof WeakSet?l.add(a):l.set(a,i),Wa=(a,l,i,o)=>(K0(a,l,"write to private field"),l.set(a,i),i),ns=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,Yd=/^[\\/]{2}/;function J0(a,l){return l+a.replace(/\\/g,"/")}var Sy="popstate";function Ey(a){return typeof a=="object"&&a!=null&&"pathname"in a&&"search"in a&&"hash"in a&&"state"in a&&"key"in a}function q3(a={}){function l(o,c){let f=c.state?.masked,{pathname:d,search:h,hash:v}=f||o.location;return Gi("",{pathname:d,search:h,hash:v},c.state&&c.state.usr||null,c.state&&c.state.key||"default",f?{pathname:o.location.pathname,search:o.location.search,hash:o.location.hash}:void 0)}function i(o,c){return typeof c=="string"?c:tn(c)}return V3(l,i,null,a)}function Ee(a,l){if(a===!1||a===null||typeof a>"u")throw new Error(l)}function ct(a,l){if(!a){typeof console<"u"&&console.warn(l);try{throw new Error(l)}catch{}}}function Y3(){return Math.random().toString(36).substring(2,10)}function Ry(a,l){return{usr:a.state,key:a.key,idx:l,masked:a.mask?{pathname:a.pathname,search:a.search,hash:a.hash}:void 0}}function Gi(a,l,i=null,o,c){return{pathname:typeof a=="string"?a:a.pathname,search:"",hash:"",...typeof l=="string"?Va(l):l,state:i,key:l&&l.key||o||Y3(),mask:c}}function tn({pathname:a="/",search:l="",hash:i=""}){return l&&l!=="?"&&(a+=l.charAt(0)==="?"?l:"?"+l),i&&i!=="#"&&(a+=i.charAt(0)==="#"?i:"#"+i),a}function Va(a){let l={};if(a){let i=a.indexOf("#");i>=0&&(l.hash=a.substring(i),a=a.substring(0,i));let o=a.indexOf("?");o>=0&&(l.search=a.substring(o),a=a.substring(0,o)),a&&(l.pathname=a)}return l}function V3(a,l,i,o={}){let{window:c=document.defaultView,v5Compat:f=!1}=o,d=c.history,h="POP",v=null,m=y();m==null&&(m=0,d.replaceState({...d.state,idx:m},""));function y(){return(d.state||{idx:null}).idx}function b(){h="POP";let A=y(),q=A==null?null:A-m;m=A,v&&v({action:h,location:T.location,delta:q})}function E(A,q){h="PUSH";let $=Ey(A)?A:Gi(T.location,A,q);m=y()+1;let X=Ry($,m),J=T.createHref($.mask||$);try{d.pushState(X,"",J)}catch(K){if(K instanceof DOMException&&K.name==="DataCloneError")throw K;c.location.assign(J)}f&&v&&v({action:h,location:T.location,delta:1})}function R(A,q){h="REPLACE";let $=Ey(A)?A:Gi(T.location,A,q);m=y();let X=Ry($,m),J=T.createHref($.mask||$);d.replaceState(X,"",J),f&&v&&v({action:h,location:T.location,delta:0})}function C(A){return P0(c,A)}let T={get action(){return h},get location(){return a(c,d)},listen(A){if(v)throw new Error("A history only accepts one active listener");return c.addEventListener(Sy,b),v=A,()=>{c.removeEventListener(Sy,b),v=null}},createHref(A){return l(c,A)},createURL:C,encodeLocation(A){let q=C(A);return{pathname:q.pathname,search:q.search,hash:q.hash}},push:E,replace:R,go(A){return d.go(A)}};return T}function P0(a,l,i=!1){let o="http://localhost";a&&(o=a.location.origin!=="null"?a.location.origin:a.location.href),Ee(o,"No window.location.(origin|href) available to create URL");let c=typeof l=="string"?l:tn(l);return c=c.replace(/ $/,"%20"),!i&&Yd.test(c)&&(c=o+c),new URL(c,o)}var Ui,wy=class{constructor(a){if(Li(this,Ui,new Map),a)for(let[l,i]of a)this.set(l,i)}get(a){if(Ra(this,Ui).has(a))return Ra(this,Ui).get(a);if(a.defaultValue!==void 0)return a.defaultValue;throw new Error("No value found for context")}set(a,l){Ra(this,Ui).set(a,l)}};Ui=new WeakMap;var Q3=new Set(["lazy","caseSensitive","path","id","index","children"]);function G3(a){return Q3.has(a)}var X3=new Set(["lazy","caseSensitive","path","id","index","middleware","children"]);function k3(a){return X3.has(a)}function Z3(a){return a.index===!0}function Xi(a,l,i=[],o={},c=!1){return a.map((f,d)=>{let h=[...i,String(d)],v=typeof f.id=="string"?f.id:h.join("-");if(Ee(f.index!==!0||!f.children,"Cannot specify children on an index route"),Ee(c||!o[v],`Found a route id collision on id "${v}". Route id's must be globally unique within Data Router usages`),Z3(f)){let m={...f,id:v};return o[v]=xy(m,l(m)),m}else{let m={...f,id:v,children:void 0};return o[v]=xy(m,l(m)),f.children&&(m.children=Xi(f.children,l,h,o,c)),m}})}function xy(a,l){return Object.assign(a,{...l,...typeof l.lazy=="object"&&l.lazy!=null?{lazy:{...a.lazy,...l.lazy}}:{}})}function W0(a,l,i="/"){return Ha(a,l,i,!1)}function Ha(a,l,i,o,c){let f=typeof l=="string"?Va(l):l,d=Kt(f.pathname||"/",i);if(d==null)return null;let h=c??ju(a),v=null,m=r4(d);for(let y=0;v==null&&y{let y={relativePath:m===void 0?d.path||"":m,caseSensitive:d.caseSensitive===!0,childrenIndex:h,route:d};if(y.relativePath.startsWith("/")){if(!y.relativePath.startsWith(o)&&v)return;Ee(y.relativePath.startsWith(o),`Absolute route path "${y.relativePath}" nested under path "${o}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),y.relativePath=y.relativePath.slice(o.length)}let b=Ta([o,y.relativePath]),E=i.concat(y);d.children&&d.children.length>0&&(Ee(d.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${b}".`),I0(d.children,l,E,b,v)),!(d.path==null&&!d.index)&&l.push({path:b,score:a4(b,d.index),routesMeta:E.map((R,C)=>{let[T,A]=ag(R.relativePath,R.caseSensitive,C===E.length-1);return{...R,matcher:T,compiledParams:A}})})};return a.forEach((d,h)=>{if(d.path===""||!d.path?.includes("?"))f(d,h);else for(let v of eg(d.path))f(d,h,!0,v)}),l}function eg(a){let l=a.split("/");if(l.length===0)return[];let[i,...o]=l,c=i.endsWith("?"),f=i.replace(/\?$/,"");if(o.length===0)return c?[f,""]:[f];let d=eg(o.join("/")),h=[];return h.push(...d.map(v=>v===""?f:[f,v].join("/"))),c&&h.push(...d),h.map(v=>a.startsWith("/")&&v===""?"/":v)}function K3(a){a.sort((l,i)=>l.score!==i.score?i.score-l.score:n4(l.routesMeta.map(o=>o.childrenIndex),i.routesMeta.map(o=>o.childrenIndex)))}var J3=/^:[\w-]+$/,P3=3,W3=2,I3=1,e4=10,t4=-2,Ty=a=>a==="*";function a4(a,l){let i=a.split("/"),o=i.length;return i.some(Ty)&&(o+=t4),l&&(o+=W3),i.filter(c=>!Ty(c)).reduce((c,f)=>c+(J3.test(f)?P3:f===""?I3:e4),o)}function n4(a,l){return a.length===l.length&&a.slice(0,-1).every((o,c)=>o===l[c])?a[a.length-1]-l[l.length-1]:0}function l4(a,l,i=!1){let{routesMeta:o}=a,c={},f="/",d=[];for(let h=0;h{if(y==="*"){let C=h[E]||"";d=f.slice(0,f.length-C.length).replace(/(.)\/+$/,"$1")}const R=h[E];return b&&!R?m[y]=void 0:m[y]=(R||"").replace(/%2F/g,"/"),m},{}),pathname:f,pathnameBase:d,pattern:a}}function ag(a,l=!1,i=!0){ct(a==="*"||!a.endsWith("*")||a.endsWith("/*"),`Route path "${a}" will be treated as if it were "${a.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${a.replace(/\*$/,"/*")}".`);let o=[],c="^"+a.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(d,h,v,m,y)=>{if(o.push({paramName:h,isOptional:v!=null}),v){let b=y.charAt(m+d.length);return b&&b!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return a.endsWith("*")?(o.push({paramName:"*"}),c+=a==="*"||a==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):i?c+="\\/*$":a!==""&&a!=="/"&&(c+="(?:(?=\\/|$))"),[new RegExp(c,l?void 0:"i"),o]}function r4(a){try{return a.split("/").map(l=>decodeURIComponent(l).replace(/\//g,"%2F")).join("/")}catch(l){return ct(!1,`The URL path "${a}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${l}).`),a}}function Kt(a,l){if(l==="/")return a;if(!a.toLowerCase().startsWith(l.toLowerCase()))return null;let i=l.endsWith("/")?l.length-1:l.length,o=a.charAt(i);return o&&o!=="/"?null:a.slice(i)||"/"}function i4({basename:a,pathname:l}){return l==="/"?a:Ta([a,l])}var Vd=a=>ns.test(a);function o4(a,l="/"){let{pathname:i,search:o="",hash:c=""}=typeof a=="string"?Va(a):a,f;return i?(i=Qd(i),i.startsWith("/")?f=Cy(i.substring(1),"/"):f=Cy(i,l)):f=l,{pathname:f,search:s4(o),hash:c4(c)}}function Cy(a,l){let i=Qu(l).split("/");return a.split("/").forEach(c=>{c===".."?i.length>1&&i.pop():c!=="."&&i.push(c)}),i.length>1?i.join("/"):"/"}function jf(a,l,i,o){return`Cannot include a '${a}' character in a manually specified \`to.${l}\` field [${JSON.stringify(o)}]. Please separate it out to the \`to.${i}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ng(a){return a.filter((l,i)=>i===0||l.route.path&&l.route.path.length>0)}function ls(a){let l=ng(a);return l.map((i,o)=>o===l.length-1?i.pathname:i.pathnameBase)}function eo(a,l,i,o=!1){let c;typeof a=="string"?c=Va(a):(c={...a},Ee(!c.pathname||!c.pathname.includes("?"),jf("?","pathname","search",c)),Ee(!c.pathname||!c.pathname.includes("#"),jf("#","pathname","hash",c)),Ee(!c.search||!c.search.includes("#"),jf("#","search","hash",c)));let f=a===""||c.pathname==="",d=f?"/":c.pathname,h;if(d==null)h=i;else{let b=l.length-1;if(!o&&d.startsWith("..")){let E=d.split("/");for(;E[0]==="..";)E.shift(),b-=1;c.pathname=E.join("/")}h=b>=0?l[b]:"/"}let v=o4(c,h),m=d&&d!=="/"&&d.endsWith("/"),y=(f||d===".")&&i.endsWith("/");return!v.pathname.endsWith("/")&&(m||y)&&(v.pathname+="/"),v}var Qd=a=>a.replace(/[\\/]{2,}/g,"/"),Ta=a=>Qd(a.join("/")),Qu=a=>a.replace(/\/+$/,""),u4=a=>Qu(a).replace(/^\/*/,"/"),s4=a=>!a||a==="?"?"":a.startsWith("?")?a:"?"+a,c4=a=>!a||a==="#"?"":a.startsWith("#")?a:"#"+a,f4=["EvalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],to=class{constructor(a,l,i,o=!1){this.status=a,this.statusText=l||"",this.internal=o,i instanceof Error?(this.data=i.toString(),this.error=i):this.data=i}};function ki(a){return a!=null&&typeof a.status=="number"&&typeof a.statusText=="string"&&typeof a.internal=="boolean"&&"data"in a}function ao(a){let l=a.map(i=>i.route.path).filter(Boolean);return Ta(l)||"/"}var lg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function rg(a,l){let i=a;if(typeof i!="string"||!ns.test(i))return{absoluteURL:void 0,isExternal:!1,to:i};let o=i,c=!1;if(lg)try{let f=new URL(window.location.href),d=Yd.test(i)?new URL(J0(i,f.protocol)):new URL(i),h=Kt(d.pathname,l);d.origin===f.origin&&h!=null?i=h+d.search+d.hash:c=!0}catch{ct(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:o,isExternal:c,to:i}}var ol=Symbol("Uninstrumented");function d4(a,l){let i={lazy:[],"lazy.loader":[],"lazy.action":[],"lazy.middleware":[],middleware:[],loader:[],action:[]};a.forEach(c=>c({id:l.id,index:l.index,path:l.path,instrument(f){let d=Object.keys(i);for(let h of d)f[h]&&i[h].push(f[h])}}));let o={};if(typeof l.lazy=="function"&&i.lazy.length>0){let c=zr(i.lazy,l.lazy,()=>{});c&&(o.lazy=c)}if(typeof l.lazy=="object"){let c=l.lazy;["middleware","loader","action"].forEach(f=>{let d=c[f],h=i[`lazy.${f}`];if(typeof d=="function"&&h.length>0){let v=zr(h,d,()=>{});v&&(o.lazy=Object.assign(o.lazy||{},{[f]:v}))}})}return["loader","action"].forEach(c=>{let f=l[c];if(typeof f=="function"&&i[c].length>0){let d=f[ol]??f,h=zr(i[c],d,(...v)=>zy(v[0]));h&&(c==="loader"&&d.hydrate===!0&&(h.hydrate=!0),h[ol]=d,o[c]=h)}}),l.middleware&&l.middleware.length>0&&i.middleware.length>0&&(o.middleware=l.middleware.map(c=>{let f=c[ol]??c,d=zr(i.middleware,f,(...h)=>zy(h[0]));return d?(d[ol]=f,d):c})),o}function h4(a,l){let i={navigate:[],fetch:[]};if(l.forEach(o=>o({instrument(c){let f=Object.keys(c);for(let d of f)c[d]&&i[d].push(c[d])}})),i.navigate.length>0){let o=a.navigate[ol]??a.navigate,c=zr(i.navigate,o,(...f)=>{let[d,h]=f;return{to:typeof d=="number"||typeof d=="string"?d:d?tn(d):".",...Ay(a,h??{})}});c&&(c[ol]=o,a.navigate=c)}if(i.fetch.length>0){let o=a.fetch[ol]??a.fetch,c=zr(i.fetch,o,(...f)=>{let[d,,h,v]=f;return{href:h??".",fetcherKey:d,...Ay(a,v??{})}});c&&(c[ol]=o,a.fetch=c)}return a}function zr(a,l,i){return a.length===0?null:async(...o)=>{let c=await ig(a,i(...o),()=>l(...o),a.length-1);if(c.type==="error")throw c.value;return c.value}}async function ig(a,l,i,o){let c=a[o],f;if(c){let d,h=async()=>(d?console.error("You cannot call instrumented handlers more than once"):d=ig(a,l,i,o-1),f=await d,Ee(f,"Expected a result"),f.type==="error"&&f.value instanceof Error?{status:"error",error:f.value}:{status:"success",error:void 0});try{await c(h,l)}catch(v){console.error("An instrumentation function threw an error:",v)}d||await h(),await d}else try{f={type:"success",value:await i()}}catch(d){f={type:"error",value:d}}return f||{type:"error",value:new Error("No result assigned in instrumentation chain.")}}function zy(a){let{request:l,context:i,params:o,pattern:c}=a;return{request:m4(l),params:{...o},pattern:c,context:p4(i)}}function Ay(a,l){return{currentUrl:tn(a.state.location),..."formMethod"in l?{formMethod:l.formMethod}:{},..."formEncType"in l?{formEncType:l.formEncType}:{},..."formData"in l?{formData:l.formData}:{},..."body"in l?{body:l.body}:{}}}function m4(a){return{method:a.method,url:a.url,headers:{get:(...l)=>a.headers.get(...l)}}}function p4(a){if(y4(a)){let l={...a};return Object.freeze(l),l}else return{get:l=>a.get(l)}}var v4=Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function y4(a){if(a===null||typeof a!="object")return!1;const l=Object.getPrototypeOf(a);return l===Object.prototype||l===null||Object.getOwnPropertyNames(l).sort().join("\0")===v4}var og=["POST","PUT","PATCH","DELETE"],g4=new Set(og),b4=["GET",...og],S4=new Set(b4),ug=new Set([301,302,303,307,308]),E4=new Set([307,308]),Lf={state:"idle",location:void 0,matches:void 0,historyAction:void 0,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0},R4={state:"idle",data:void 0,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0},wr={state:"unblocked",proceed:void 0,reset:void 0,location:void 0},w4=a=>({hasErrorBoundary:!!a.hasErrorBoundary}),sg="remix-router-transitions",cg=Symbol("ResetLoaderData"),Ml,xr,ll,Tr,x4=class{constructor(a){Li(this,Ml),Li(this,xr),Li(this,ll),Li(this,Tr),Wa(this,Ml,a),Wa(this,xr,ju(a))}get stableRoutes(){return Ra(this,Ml)}get activeRoutes(){return Ra(this,ll)??Ra(this,Ml)}get branches(){return Ra(this,Tr)??Ra(this,xr)}get hasHMRRoutes(){return Ra(this,ll)!=null}setRoutes(a){Wa(this,Ml,a),Wa(this,xr,ju(a))}setHmrRoutes(a){Wa(this,ll,a),Wa(this,Tr,ju(a))}commitHmrRoutes(){Ra(this,ll)&&(Wa(this,Ml,Ra(this,ll)),Wa(this,xr,Ra(this,Tr)),Wa(this,ll,void 0),Wa(this,Tr,void 0))}};Ml=new WeakMap;xr=new WeakMap;ll=new WeakMap;Tr=new WeakMap;function T4(a){const l=a.window?a.window:typeof window<"u"?window:void 0,i=typeof l<"u"&&typeof l.document<"u"&&typeof l.document.createElement<"u";Ee(a.routes.length>0,"You must provide a non-empty routes array to createRouter");let o=a.hydrationRouteProperties||[],c=a.mapRouteProperties||w4,f=c;if(a.instrumentations){let x=a.instrumentations;f=M=>({...c(M),...d4(x.map(L=>L.route).filter(Boolean),M)})}let d={},h=new x4(Xi(a.routes,f,void 0,d)),v=a.basename||"/";v.startsWith("/")||(v=`/${v}`);let m=a.dataStrategy||_4,y={...a.future},b=null,E=new Set,R=null,C=null,T=null,A=null,q=a.hydrationData!=null,$=Ha(h.activeRoutes,a.history.location,v,!1,h.branches),X=!1,J=null,K,W;if($==null&&!a.patchRoutesOnNavigation){let x=wa(404,{pathname:a.history.location.pathname}),{matches:M,route:L}=zu(h.activeRoutes);K=!0,W=!K,$=M,J={[L.id]:x}}else if($&&!a.hydrationData&&Nn($,h.activeRoutes,a.history.location.pathname).active&&($=null),$)if($.some(x=>x.route.lazy))K=!1,W=!K;else if(!$.some(x=>Gd(x.route)))K=!0,W=!K;else{let x=a.hydrationData?a.hydrationData.loaderData:null,M=a.hydrationData?a.hydrationData.errors:null,L=$;if(M){let k=$.findIndex(Z=>M[Z.route.id]!==void 0);L=L.slice(0,k+1)}W=!1,K=!0,L.forEach(k=>{let Z=fg(k.route,x,M);W=W||Z.renderFallback,K=K&&!Z.shouldLoad})}else{K=!1,W=!K,$=[];let x=Nn(null,h.activeRoutes,a.history.location.pathname);x.active&&x.matches&&(X=!0,$=x.matches)}let P,_={historyAction:a.history.action,location:a.history.location,matches:$,initialized:K,renderFallback:W,navigation:Lf,restoreScrollPosition:a.hydrationData!=null?!1:null,preventScrollReset:!1,revalidation:"idle",loaderData:a.hydrationData&&a.hydrationData.loaderData||{},actionData:a.hydrationData&&a.hydrationData.actionData||null,errors:a.hydrationData&&a.hydrationData.errors||J,fetchers:new Map,blockers:new Map},ne="POP",se=null,Re=!1,oe,Qe=!1,ge=new Map,Te=null,U=!1,F=!1,ee=new Set,ie=new Map,de=0,ze=-1,be=new Map,ce=new Set,ye=new Map,Ge=new Map,Me=new Set,it=new Map,Et,vt=null;function Pt(){if(b=a.history.listen(({action:x,location:M,delta:L})=>{if(Et){Et(),Et=void 0;return}ct(it.size===0||L!=null,"You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL.");let k=dl({currentLocation:_.location,nextLocation:M,historyAction:x});if(k&&L!=null){let Z=new Promise(le=>{Et=le});a.history.go(L*-1),ln(k,{state:"blocked",location:M,proceed(){ln(k,{state:"proceeding",proceed:void 0,reset:void 0,location:M}),Z.then(()=>a.history.go(L))},reset(){let le=new Map(_.blockers);le.set(k,wr),ot({blockers:le})}}),se?.resolve(),se=null;return}return fa(x,M)}),i){K4(l,ge);let x=()=>J4(l,ge);l.addEventListener("pagehide",x),Te=()=>l.removeEventListener("pagehide",x)}return _.initialized||fa("POP",_.location,{initialHydration:!0}),P}function ca(){b&&b(),Te&&Te(),E.clear(),oe&&oe.abort(),_.fetchers.forEach((x,M)=>nn(_.fetchers,M)),_.blockers.forEach((x,M)=>fl(M))}function Qa(x){if(E.add(x),R){let{newErrors:M}=R;R=null,x(_,{deletedFetchers:[],newErrors:M,viewTransitionOpts:void 0,flushSync:!1})}return()=>E.delete(x)}function ot(x,M={}){x.matches&&(x.matches=x.matches.map(Z=>{let le=d[Z.route.id],I=Z.route;return I.element!==le.element||I.errorElement!==le.errorElement||I.hydrateFallbackElement!==le.hydrateFallbackElement?{...Z,route:le}:Z})),_={..._,...x};let L=[],k=[];_.fetchers.forEach((Z,le)=>{Z.state==="idle"&&(Me.has(le)?L.push(le):k.push(le))}),Me.forEach(Z=>{!_.fetchers.has(Z)&&!ie.has(Z)&&L.push(Z)}),E.size===0&&(R={newErrors:x.errors??null}),[...E].forEach(Z=>Z(_,{deletedFetchers:L,newErrors:x.errors??null,viewTransitionOpts:M.viewTransitionOpts,flushSync:M.flushSync===!0})),L.forEach(Z=>nn(_.fetchers,Z)),k.forEach(Z=>_.fetchers.delete(Z))}function Rt(x,M,{flushSync:L}={}){let k=_.actionData!=null&&_.navigation.formMethod!=null&&jt(_.navigation.formMethod)&&_.navigation.state==="loading"&&x.state?._isRedirect!==!0,Z;M.actionData?Object.keys(M.actionData).length>0?Z=M.actionData:Z=null:k?Z=_.actionData:Z=null;let le=M.loaderData?Hy(_.loaderData,M.loaderData,M.matches||[],M.errors):_.loaderData,I=_.blockers;I.size>0&&(I=new Map(I),I.forEach((me,we)=>I.set(we,wr)));let ae=U?!1:qr(x,M.matches||_.matches),te=Re===!0||_.navigation.formMethod!=null&&jt(_.navigation.formMethod)&&x.state?._isRedirect!==!0;h.commitHmrRoutes(),U||ne==="POP"||(ne==="PUSH"?a.history.push(x,x.state):ne==="REPLACE"&&a.history.replace(x,x.state));let he;if(ne==="POP"){let me=ge.get(_.location.pathname);me&&me.has(x.pathname)?he={currentLocation:_.location,nextLocation:x}:ge.has(x.pathname)&&(he={currentLocation:x,nextLocation:_.location})}else if(Qe){let me=ge.get(_.location.pathname);me?me.add(x.pathname):(me=new Set([x.pathname]),ge.set(_.location.pathname,me)),he={currentLocation:_.location,nextLocation:x}}ot({...M,actionData:Z,loaderData:le,historyAction:ne,location:x,initialized:!0,renderFallback:!1,navigation:Lf,revalidation:"idle",restoreScrollPosition:ae,preventScrollReset:te,blockers:I},{viewTransitionOpts:he,flushSync:L===!0}),ne="POP",Re=!1,Qe=!1,U=!1,F=!1,se?.resolve(),se=null,vt?.resolve(),vt=null}async function Aa(x,M){if(se?.resolve(),se=null,typeof x=="number"){se||(se=Vy());let qe=se.promise;return a.history.go(x),qe}let L=If(_.location,_.matches,v,x,M?.fromRouteId,M?.relative),{path:k,submission:Z,error:le}=My(!1,L,M),I;M?.mask&&(I={pathname:"",search:"",hash:"",...typeof M.mask=="string"?Va(M.mask):{..._.location.mask,...M.mask}});let ae=_.location,te=Gi(ae,k,M&&M.state,void 0,I);te={...te,...a.history.encodeLocation(te)};let he=M&&M.replace!=null?M.replace:void 0,me="PUSH";he===!0?me="REPLACE":he===!1||Z!=null&&jt(Z.formMethod)&&Z.formAction===_.location.pathname+_.location.search&&(me="REPLACE");let we=M&&"preventScrollReset"in M?M.preventScrollReset===!0:void 0,ve=(M&&M.flushSync)===!0,Ae=dl({currentLocation:ae,nextLocation:te,historyAction:me});if(Ae){ln(Ae,{state:"blocked",location:te,proceed(){ln(Ae,{state:"proceeding",proceed:void 0,reset:void 0,location:te}),Aa(x,M)},reset(){let qe=new Map(_.blockers);qe.set(Ae,wr),ot({blockers:qe})}});return}await fa(me,te,{submission:Z,pendingError:le,preventScrollReset:we,replace:M&&M.replace,enableViewTransition:M&&M.viewTransition,flushSync:ve,callSiteDefaultShouldRevalidate:M&&M.defaultShouldRevalidate})}function Ga(){vt||(vt=Vy()),On(),ot({revalidation:"loading"});let x=vt.promise;return _.navigation.state==="submitting"?x:_.navigation.state==="idle"?(fa(_.historyAction,_.location,{startUninterruptedRevalidation:!0}),x):(fa(ne||_.historyAction,_.navigation.location,{overrideNavigation:_.navigation,enableViewTransition:Qe===!0}),x)}async function fa(x,M,L){oe&&oe.abort(),oe=null,ne=x,U=(L&&L.startUninterruptedRevalidation)===!0,fs(_.location,_.matches),Re=(L&&L.preventScrollReset)===!0,Qe=(L&&L.enableViewTransition)===!0;let k=h.activeRoutes,Z=L?.initialHydration&&_.matches&&_.matches.length>0&&!X?_.matches:Ha(k,M,v,!1,h.branches),le=(L&&L.flushSync)===!0;if(Z&&_.initialized&&!F&&$4(_.location,M)&&!(L&&L.submission&&jt(L.submission.formMethod))){Rt(M,{matches:Z},{flushSync:le});return}let I=Nn(Z,k,M.pathname);if(I.active&&I.matches&&(Z=I.matches),!Z){let{error:Ze,notFoundMatches:Be,route:ft}=_a(M.pathname);Rt(M,{matches:Be,loaderData:{},errors:{[ft.id]:Ze}},{flushSync:le});return}let ae=L&&L.overrideNavigation?{...L.overrideNavigation,matches:Z,historyAction:x}:void 0;oe=new AbortController;let te=Cr(a.history,M,oe.signal,L&&L.submission),he=a.getContext?await a.getContext():new wy,me;if(L&&L.pendingError)me=[il(Z).route.id,{type:"error",error:L.pendingError}];else if(L&&L.submission&&jt(L.submission.formMethod)){let Ze=await cl(te,M,L.submission,Z,x,he,I.active,L&&L.initialHydration===!0,{replace:L.replace,flushSync:le});if(Ze.shortCircuited)return;if(Ze.pendingActionResult){let[Be,ft]=Ze.pendingActionResult;if(oa(ft)&&ki(ft.error)&&ft.error.status===404){oe=null,Rt(M,{matches:Ze.matches,loaderData:{},errors:{[Be]:ft.error}});return}}Z=Ze.matches||Z,me=Ze.pendingActionResult,ae=Uf(M,Z,x,L.submission),le=!1,I.active=!1,te=Cr(a.history,te.url,te.signal)}let{shortCircuited:we,matches:ve,loaderData:Ae,errors:qe,workingFetchers:at}=await Xa(te,M,Z,x,he,I.active,ae,L&&L.submission,L&&L.fetcherSubmission,L&&L.replace,L&&L.initialHydration===!0,le,me,L&&L.callSiteDefaultShouldRevalidate);we||(oe=null,Rt(M,{matches:ve||Z,...$y(me),loaderData:Ae,errors:qe,...at?{fetchers:at}:{}}))}async function cl(x,M,L,k,Z,le,I,ae,te={}){On();let he=Z4(M,k,Z,L);if(ot({navigation:he},{flushSync:te.flushSync===!0}),I){let ve=await Za(k,M.pathname,x.signal);if(ve.type==="aborted")return{shortCircuited:!0};if(ve.type==="error"){if(ve.partialMatches.length===0){let{matches:qe,route:at}=zu(h.activeRoutes);return{matches:qe,pendingActionResult:[at.id,{type:"error",error:ve.error}]}}let Ae=il(ve.partialMatches).route.id;return{matches:ve.partialMatches,pendingActionResult:[Ae,{type:"error",error:ve.error}]}}else if(ve.matches)k=ve.matches;else{let{notFoundMatches:Ae,error:qe,route:at}=_a(M.pathname);return{matches:Ae,pendingActionResult:[at.id,{type:"error",error:qe}]}}}let me,we=Lu(k,M);if(!we.route.action&&!we.route.lazy)me={type:"error",error:wa(405,{method:x.method,pathname:M.pathname,routeId:we.route.id})};else{let ve=Mr(f,d,x,M,k,we,ae?[]:o,le),Ae=await _n(x,M,ve,le,null);if(me=Ae[we.route.id],!me){for(let qe of k)if(Ae[qe.route.id]){me=Ae[qe.route.id];break}}if(x.signal.aborted)return{shortCircuited:!0}}if(_l(me)){let ve;return te&&te.replace!=null?ve=te.replace:ve=Ly(me.response.headers.get("Location"),new URL(x.url),v,a.history)===_.location.pathname+_.location.search,await an(x,me,!0,{submission:L,replace:ve}),{shortCircuited:!0}}if(oa(me)){let ve=il(k,we.route.id);return(te&&te.replace)!==!0&&(ne="PUSH"),{matches:k,pendingActionResult:[ve.route.id,me,we.route.id]}}return{matches:k,pendingActionResult:[we.route.id,me]}}async function Xa(x,M,L,k,Z,le,I,ae,te,he,me,we,ve,Ae){let qe=I||Uf(M,L,k,ae),at=ae||te||Yy(qe),Ze=!U&&!me;if(le){if(Ze){let et=ka(ve);ot({navigation:qe,...et!==void 0?{actionData:et}:{}},{flushSync:we})}let Se=await Za(L,M.pathname,x.signal);if(Se.type==="aborted")return{shortCircuited:!0};if(Se.type==="error"){if(Se.partialMatches.length===0){let{matches:It,route:Na}=zu(h.activeRoutes);return{matches:It,loaderData:{},errors:{[Na.id]:Se.error}}}let et=il(Se.partialMatches).route.id;return{matches:Se.partialMatches,loaderData:{},errors:{[et]:Se.error}}}else if(Se.matches)L=Se.matches;else{let{error:et,notFoundMatches:It,route:Na}=_a(M.pathname);return{matches:It,loaderData:{},errors:{[Na.id]:et}}}}let Be=h.activeRoutes,{dsMatches:ft,revalidatingFetchers:He}=_y(x,Z,f,d,a.history,_,L,at,M,me?[]:o,me===!0,F,ee,Me,ye,ce,Be,v,a.patchRoutesOnNavigation!=null,h.branches,ve,Ae);if(ze=++de,!a.dataStrategy&&!ft.some(Se=>Se.shouldLoad)&&!ft.some(Se=>Se.route.middleware&&Se.route.middleware.length>0)&&He.length===0){let Se=new Map(_.fetchers),et=io(Se);return Rt(M,{matches:L,loaderData:{},errors:ve&&oa(ve[1])?{[ve[0]]:ve[1].error}:null,...$y(ve),...et?{fetchers:Se}:{}},{flushSync:we}),{shortCircuited:!0}}if(Ze){let Se={};if(!le){Se.navigation=qe;let et=ka(ve);et!==void 0&&(Se.actionData=et)}He.length>0&&(Se.fetchers=Mn(He)),ot(Se,{flushSync:we})}He.forEach(Se=>{Tt(Se.key),Se.controller&&ie.set(Se.key,Se.controller)});let jn=()=>He.forEach(Se=>Tt(Se.key));oe&&oe.signal.addEventListener("abort",jn);let{loaderResults:Oa,fetcherResults:Yt}=await $r(ft,He,x,M,Z);if(x.signal.aborted)return{shortCircuited:!0};oe&&oe.signal.removeEventListener("abort",jn),He.forEach(Se=>ie.delete(Se.key));let Bt=Au(Oa);if(Bt)return await an(x,Bt.result,!0,{replace:he}),{shortCircuited:!0};if(Bt=Au(Yt),Bt)return ce.add(Bt.key),await an(x,Bt.result,!0,{replace:he}),{shortCircuited:!0};let ha=new Map(_.fetchers),{loaderData:Ll,errors:Da}=By(_,L,Oa,ve,He,Yt,ha);me&&_.errors&&(Da={..._.errors,...Da});let Ul=io(ha),rn=oo(ze,ha),on=Ul||rn||He.length>0;return{matches:L,loaderData:Ll,errors:Da,...on?{workingFetchers:ha}:{}}}function ka(x){if(x&&!oa(x[1]))return{[x[0]]:x[1].data};if(_.actionData)return Object.keys(_.actionData).length===0?null:_.actionData}function Mn(x){let M=new Map(_.fetchers);return x.forEach(L=>{let k=M.get(L.key),Z=Ni(void 0,k?k.data:void 0);M.set(L.key,Z)}),M}async function Wt(x,M,L,k){Tt(x);let Z=(k&&k.flushSync)===!0,le=h.activeRoutes,I=If(_.location,_.matches,v,L,M,k?.relative),ae=Ha(le,I,v,!1,h.branches),te=Nn(ae,le,I);if(te.active&&te.matches&&(ae=te.matches),!ae){da(x,M,wa(404,{pathname:I}),{flushSync:Z});return}let{path:he,submission:me,error:we}=My(!0,I,k);if(we){da(x,M,we,{flushSync:Z});return}let ve=a.getContext?await a.getContext():new wy,Ae=(k&&k.preventScrollReset)===!0;if(me&&jt(me.formMethod)){await os(x,M,he,ae,ve,te.active,Z,Ae,me,k&&k.defaultShouldRevalidate);return}ye.set(x,{routeId:M,path:he}),await Lt(x,M,he,ae,ve,te.active,Z,Ae,me)}async function os(x,M,L,k,Z,le,I,ae,te,he){On(),ye.delete(x);let me=_.fetchers.get(x);Ma(x,F4(te,me),{flushSync:I});let we=new AbortController,ve=Cr(a.history,L,we.signal,te);if(le){let Fe=await Za(k,new URL(ve.url).pathname,ve.signal,x);if(Fe.type==="aborted")return;if(Fe.type==="error"){da(x,M,Fe.error,{flushSync:I});return}else if(Fe.matches)k=Fe.matches;else{da(x,M,wa(404,{pathname:L}),{flushSync:I});return}}let Ae=Lu(k,L);if(!Ae.route.action&&!Ae.route.lazy){let Fe=wa(405,{method:te.formMethod,pathname:L,routeId:M});da(x,M,Fe,{flushSync:I});return}ie.set(x,we);let qe=de,at=Mr(f,d,ve,L,k,Ae,o,Z),Ze=await _n(ve,L,at,Z,x),Be=Ze[Ae.route.id];if(!Be){for(let Fe of at)if(Ze[Fe.route.id]){Be=Ze[Fe.route.id];break}}if(ve.signal.aborted){ie.get(x)===we&&ie.delete(x);return}if(Me.has(x)){if(_l(Be)||oa(Be)){Ma(x,Ia(void 0));return}}else{if(_l(Be))if(ie.delete(x),ze>qe){Ma(x,Ia(void 0));return}else return ce.add(x),Ma(x,Ni(te)),an(ve,Be,!1,{fetcherSubmission:te,preventScrollReset:ae});if(oa(Be)){da(x,M,Be.error);return}}let ft=_.navigation.location||_.location,He=Cr(a.history,ft,we.signal),jn=h.activeRoutes,Oa=_.navigation.state!=="idle"?Ha(jn,_.navigation.location,v,!1,h.branches):_.matches;Ee(Oa,"Didn't find any matches after fetcher action");let Yt=++de;be.set(x,Yt);let{dsMatches:Bt,revalidatingFetchers:ha}=_y(He,Z,f,d,a.history,_,Oa,te,ft,o,!1,F,ee,Me,ye,ce,jn,v,a.patchRoutesOnNavigation!=null,h.branches,[Ae.route.id,Be],he),Ll=Ni(te,Be.data),Da=new Map(_.fetchers);Da.set(x,Ll),ha.filter(Fe=>Fe.key!==x).forEach(Fe=>{let un=Fe.key,Ht=Da.get(un),Yr=Ni(void 0,Ht?Ht.data:void 0);Da.set(un,Yr),Tt(un),Fe.controller&&ie.set(un,Fe.controller)}),ot({fetchers:Da});let Ul=()=>ha.forEach(Fe=>Tt(Fe.key));we.signal.addEventListener("abort",Ul);let{loaderResults:rn,fetcherResults:on}=await $r(Bt,ha,He,ft,Z);if(we.signal.aborted)return;we.signal.removeEventListener("abort",Ul),be.delete(x),ie.delete(x),ha.forEach(Fe=>ie.delete(Fe.key));let Se=_.fetchers.has(x),et=Fe=>{if(!Se)return Fe;let un=new Map(Fe.fetchers);return un.set(x,Ia(Be.data)),{...Fe,fetchers:un}},It=Au(rn);if(It)return _=et(_),an(He,It.result,!1,{preventScrollReset:ae});if(It=Au(on),It)return ce.add(It.key),_=et(_),an(He,It.result,!1,{preventScrollReset:ae});let Na=new Map(_.fetchers);Se&&Na.set(x,Ia(Be.data));let{loaderData:Bl,errors:Hl}=By(_,Oa,rn,void 0,ha,on,Na);oo(Yt,Na),_.navigation.state==="loading"&&Yt>ze?(Ee(ne,"Expected pending action"),oe&&oe.abort(),Rt(_.navigation.location,{matches:Oa,loaderData:Bl,errors:Hl,fetchers:Na})):(ot({errors:Hl,loaderData:Hy(_.loaderData,Bl,Oa,Hl),fetchers:Na}),F=!1)}async function Lt(x,M,L,k,Z,le,I,ae,te){let he=_.fetchers.get(x);Ma(x,Ni(te,he?he.data:void 0),{flushSync:I});let me=new AbortController,we=Cr(a.history,L,me.signal);if(le){let Be=await Za(k,new URL(we.url).pathname,we.signal,x);if(Be.type==="aborted")return;if(Be.type==="error"){da(x,M,Be.error,{flushSync:I});return}else if(Be.matches)k=Be.matches;else{da(x,M,wa(404,{pathname:L}),{flushSync:I});return}}let ve=Lu(k,L);ie.set(x,me);let Ae=de,qe=Mr(f,d,we,L,k,ve,o,Z),at=await _n(we,L,qe,Z,x),Ze=at[ve.route.id];if(!Ze){for(let Be of k)if(at[Be.route.id]){Ze=at[Be.route.id];break}}if(ie.get(x)===me&&ie.delete(x),!we.signal.aborted){if(Me.has(x)){Ma(x,Ia(void 0));return}if(_l(Ze))if(ze>Ae){Ma(x,Ia(void 0));return}else{ce.add(x),await an(we,Ze,!1,{preventScrollReset:ae});return}if(oa(Ze)){da(x,M,Ze.error);return}Ma(x,Ia(Ze.data))}}async function an(x,M,L,{submission:k,fetcherSubmission:Z,preventScrollReset:le,replace:I}={}){L||(se?.resolve(),se=null),M.response.headers.has("X-Remix-Revalidate")&&(F=!0);let ae=M.response.headers.get("Location");Ee(ae,"Expected a Location header on the redirect Response"),ae=Ly(ae,new URL(x.url),v,a.history);let te=Gi(_.location,ae,{_isRedirect:!0});if(i){let qe=!1;if(M.response.headers.has("X-Remix-Reload-Document"))qe=!0;else if(Vd(ae)){const at=P0(l,ae,!0);qe=at.origin!==l.location.origin||Kt(at.pathname,v)==null}if(qe){I?l.location.replace(ae):l.location.assign(ae);return}}oe=null;let he=I===!0||M.response.headers.has("X-Remix-Replace")?"REPLACE":"PUSH",{formMethod:me,formAction:we,formEncType:ve}=_.navigation;!k&&!Z&&me&&we&&ve&&(k=Yy(_.navigation));let Ae=k||Z;if(E4.has(M.response.status)&&Ae&&jt(Ae.formMethod))await fa(he,te,{submission:{...Ae,formAction:ae},preventScrollReset:le||Re,enableViewTransition:L?Qe:void 0});else{let qe=Uf(te,[],he,k);await fa(he,te,{overrideNavigation:qe,fetcherSubmission:Z,preventScrollReset:le||Re,enableViewTransition:L?Qe:void 0})}}async function _n(x,M,L,k,Z){let le,I={};try{le=await D4(m,x,M,L,Z,k,!1)}catch(ae){return L.filter(te=>te.shouldLoad).forEach(te=>{I[te.route.id]={type:"error",error:ae}}),I}if(x.signal.aborted)return I;if(!jt(x.method))for(let ae of L){if(le[ae.route.id]?.type==="error")break;!le.hasOwnProperty(ae.route.id)&&!_.loaderData.hasOwnProperty(ae.route.id)&&(!_.errors||!_.errors.hasOwnProperty(ae.route.id))&&ae.shouldCallHandler()&&(le[ae.route.id]={type:"error",result:new Error(`No result returned from dataStrategy for route ${ae.route.id}`)})}for(let[ae,te]of Object.entries(le))if(Q4(te)){let he=te.result;I[ae]={type:"redirect",response:U4(he,x,ae,L,v)}}else I[ae]=await L4(te);return I}async function $r(x,M,L,k,Z){let le=_n(L,k,x,Z,null),I=Promise.all(M.map(async he=>{if(he.matches&&he.match&&he.request&&he.controller){let we=(await _n(he.request,he.path,he.matches,Z,he.key))[he.match.route.id];return{[he.key]:we}}else return Promise.resolve({[he.key]:{type:"error",error:wa(404,{pathname:he.path})}})})),ae=await le,te=(await I).reduce((he,me)=>Object.assign(he,me),{});return{loaderResults:ae,fetcherResults:te}}function On(){F=!0,ye.forEach((x,M)=>{ie.has(M)&&ee.add(M),Tt(M)})}function Ma(x,M,L={}){let k=new Map(_.fetchers);k.set(x,M),ot({fetchers:k},{flushSync:(L&&L.flushSync)===!0})}function da(x,M,L,k={}){let Z=il(_.matches,M),le=new Map(_.fetchers);nn(le,x),ot({errors:{[Z.route.id]:L},fetchers:le},{flushSync:(k&&k.flushSync)===!0})}function us(x){return Ge.set(x,(Ge.get(x)||0)+1),Me.has(x)&&Me.delete(x),_.fetchers.get(x)||R4}function ss(x,M){Tt(x,M?.reason),Ma(x,Ia(null))}function nn(x,M){let L=_.fetchers.get(M);ie.has(M)&&!(L&&L.state==="loading"&&be.has(M))&&Tt(M),ye.delete(M),be.delete(M),ce.delete(M),Me.delete(M),ee.delete(M),x.delete(M)}function Ut(x){let M=(Ge.get(x)||0)-1;M<=0?(Ge.delete(x),Me.add(x)):Ge.set(x,M),ot({fetchers:new Map(_.fetchers)})}function Tt(x,M){let L=ie.get(x);L&&(L.abort(M),ie.delete(x))}function Dt(x,M){for(let L of x){let k=M.get(L);Ee(k,`Expected fetcher: ${L}`);let Z=Ia(k.data);M.set(L,Z)}}function io(x){let M=[],L=!1;for(let k of ce){let Z=x.get(k);Ee(Z,`Expected fetcher: ${k}`),Z.state==="loading"&&(ce.delete(k),M.push(k),L=!0)}return Dt(M,x),L}function oo(x,M){let L=[];for(let[k,Z]of be)if(Z0}function cs(x,M){let L=_.blockers.get(x)||wr;return it.get(x)!==M&&it.set(x,M),L}function fl(x){_.blockers.delete(x),it.delete(x)}function ln(x,M){let L=_.blockers.get(x)||wr;Ee(L.state==="unblocked"&&M.state==="blocked"||L.state==="blocked"&&M.state==="blocked"||L.state==="blocked"&&M.state==="proceeding"||L.state==="blocked"&&M.state==="unblocked"||L.state==="proceeding"&&M.state==="unblocked",`Invalid blocker state transition: ${L.state} -> ${M.state}`);let k=new Map(_.blockers);k.set(x,M),ot({blockers:k})}function dl({currentLocation:x,nextLocation:M,historyAction:L}){if(it.size===0)return;it.size>1&&ct(!1,"A router only supports one blocker at a time");let k=Array.from(it.entries()),[Z,le]=k[k.length-1],I=_.blockers.get(Z);if(!(I&&I.state==="proceeding")&&le({currentLocation:x,nextLocation:M,historyAction:L}))return Z}function _a(x){let M=wa(404,{pathname:x}),L=h.activeRoutes,{matches:k,route:Z}=zu(L);return{notFoundMatches:k,route:Z,error:M}}function jl(x,M,L){if(C=x,A=M,T=L||null,!q&&_.navigation===Lf){q=!0;let k=qr(_.location,_.matches);k!=null&&ot({restoreScrollPosition:k})}return()=>{C=null,A=null,T=null}}function Dn(x,M){return T&&T(x,M.map(k=>F3(k,_.loaderData)))||x.key}function fs(x,M){if(C&&A){let L=Dn(x,M);C[L]=A()}}function qr(x,M){if(C){let L=Dn(x,M),k=C[L];if(typeof k=="number")return k}return null}function Nn(x,M,L){if(a.patchRoutesOnNavigation){let k=h.branches;if(x){if(Object.keys(x[0].params).length>0)return{active:!0,matches:Ha(M,L,v,!0,k)}}else return{active:!0,matches:Ha(M,L,v,!0,k)||[]}}return{active:!1,matches:null}}async function Za(x,M,L,k){if(!a.patchRoutesOnNavigation)return{type:"success",matches:x};let Z=x;for(;;){let le=d;try{await a.patchRoutesOnNavigation({signal:L,path:M,matches:Z,fetcherKey:k,patch:(he,me)=>{L.aborted||Oy(he,me,h,le,f,!1)}})}catch(he){return{type:"error",error:he,partialMatches:Z}}if(L.aborted)return{type:"aborted"};let I=h.branches,ae=Ha(h.activeRoutes,M,v,!1,I),te=null;if(ae){if(Object.keys(ae[0].params).length===0)return{type:"success",matches:ae};if(te=Ha(h.activeRoutes,M,v,!0,I),!(te&&Z.lengthL.route.id===M[k].route.id)}function so(x){d={},h.setHmrRoutes(Xi(x,f,void 0,d))}function co(x,M,L=!1){Oy(x,M,h,d,f,L),h.hasHMRRoutes||ot({})}return P={get basename(){return v},get future(){return y},get state(){return _},get routes(){return h.stableRoutes},get branches(){return h.branches},get manifest(){return d},get window(){return l},initialize:Pt,subscribe:Qa,enableScrollRestoration:jl,navigate:Aa,fetch:Wt,revalidate:Ga,createHref:x=>a.history.createHref(x),encodeLocation:x=>a.history.encodeLocation(x),getFetcher:us,resetFetcher:ss,deleteFetcher:Ut,dispose:ca,getBlocker:cs,deleteBlocker:fl,patchRoutes:co,_internalFetchControllers:ie,_internalSetRoutes:so,_internalSetStateDoNotUseOrYouWillBreakYourApp(x){ot(x)}},a.instrumentations&&(P=h4(P,a.instrumentations.map(x=>x.router).filter(Boolean))),P}function C4(a){return a!=null&&("formData"in a&&a.formData!=null||"body"in a&&a.body!==void 0)}function If(a,l,i,o,c,f){let d,h;if(c){d=[];for(let m of l)if(d.push(m),m.route.id===c){h=m;break}}else d=l,h=l[l.length-1];let v=eo(o||".",ls(d),Kt(a.pathname,i)||a.pathname,f==="path");if(o==null&&(v.search=a.search,v.hash=a.hash),(o==null||o===""||o===".")&&h){let m=kd(v.search);if(h.route.index&&!m)v.search=v.search?v.search.replace(/^\?/,"?index&"):"?index";else if(!h.route.index&&m){let y=new URLSearchParams(v.search),b=y.getAll("index");y.delete("index"),b.filter(R=>R).forEach(R=>y.append("index",R));let E=y.toString();v.search=E?`?${E}`:""}}return i!=="/"&&(v.pathname=i4({basename:i,pathname:v.pathname})),tn(v)}function My(a,l,i){if(!i||!C4(i))return{path:l};if(i.formMethod&&!k4(i.formMethod))return{path:l,error:wa(405,{method:i.formMethod})};let o=()=>({path:l,error:wa(400,{type:"invalid-body"})}),f=(i.formMethod||"get").toUpperCase(),d=gg(l);if(i.body!==void 0){if(i.formEncType==="text/plain"){if(!jt(f))return o();let b=typeof i.body=="string"?i.body:i.body instanceof FormData||i.body instanceof URLSearchParams?Array.from(i.body.entries()).reduce((E,[R,C])=>`${E}${R}=${C} `,""):String(i.body);return{path:l,submission:{formMethod:f,formAction:d,formEncType:i.formEncType,formData:void 0,json:void 0,text:b}}}else if(i.formEncType==="application/json"){if(!jt(f))return o();try{let b=typeof i.body=="string"?JSON.parse(i.body):i.body;return{path:l,submission:{formMethod:f,formAction:d,formEncType:i.formEncType,formData:void 0,json:b,text:void 0}}}catch{return o()}}}Ee(typeof FormData=="function","FormData is not available in this environment");let h,v;if(i.formData)h=ad(i.formData),v=i.formData;else if(i.body instanceof FormData)h=ad(i.body),v=i.body;else if(i.body instanceof URLSearchParams)h=i.body,v=Uy(h);else if(i.body==null)h=new URLSearchParams,v=new FormData;else try{h=new URLSearchParams(i.body),v=Uy(h)}catch{return o()}let m={formMethod:f,formAction:d,formEncType:i&&i.formEncType||"application/x-www-form-urlencoded",formData:v,json:void 0,text:void 0};if(jt(m.formMethod))return{path:l,submission:m};let y=Va(l);return a&&y.search&&kd(y.search)&&h.append("index",""),y.search=`?${h}`,{path:tn(y),submission:m}}function _y(a,l,i,o,c,f,d,h,v,m,y,b,E,R,C,T,A,q,$,X,J,K){let W=J?oa(J[1])?J[1].error:J[1].data:void 0,P=c.createURL(f.location),_=c.createURL(v),ne;if(y&&f.errors){let U=Object.keys(f.errors)[0];ne=d.findIndex(F=>F.route.id===U)}else if(J&&oa(J[1])){let U=J[0];ne=d.findIndex(F=>F.route.id===U)-1}let se=J?J[1].statusCode:void 0,Re=se&&se>=400,oe={currentUrl:P,currentParams:f.matches[0]?.params||{},nextUrl:_,nextParams:d[0].params,...h,actionResult:W,actionStatus:se},Qe=ao(d),ge=d.map((U,F)=>{let{route:ee}=U,ie=null;if(ne!=null&&F>ne)ie=!1;else if(ee.lazy)ie=!0;else if(!Gd(ee))ie=!1;else if(y){let{shouldLoad:ce}=fg(ee,f.loaderData,f.errors);ie=ce}else z4(f.loaderData,f.matches[F],U)&&(ie=!0);if(ie!==null)return ed(i,o,a,v,Qe,U,m,l,ie);let de=!1;typeof K=="boolean"?de=K:Re?de=!1:(b||P.pathname+P.search===_.pathname+_.search||P.search!==_.search||A4(f.matches[F],U))&&(de=!0);let ze={...oe,defaultShouldRevalidate:de},be=Hi(U,ze);return ed(i,o,a,v,Qe,U,m,l,be,ze,K)}),Te=[];return C.forEach((U,F)=>{if(y||!d.some(Ge=>Ge.route.id===U.routeId)||R.has(F))return;let ee=f.fetchers.get(F),ie=ee&&ee.state!=="idle"&&ee.data===void 0,de=Ha(A,U.path,q??"/",!1,X);if(!de){if($&&ie)return;Te.push({key:F,routeId:U.routeId,path:U.path,matches:null,match:null,request:null,controller:null});return}if(T.has(F))return;let ze=Lu(de,U.path),be=new AbortController,ce=Cr(c,U.path,be.signal),ye=null;if(E.has(F))E.delete(F),ye=Mr(i,o,ce,U.path,de,ze,m,l);else if(ie)b&&(ye=Mr(i,o,ce,U.path,de,ze,m,l));else{let Ge;typeof K=="boolean"?Ge=K:Re?Ge=!1:Ge=b;let Me={...oe,defaultShouldRevalidate:Ge};Hi(ze,Me)&&(ye=Mr(i,o,ce,U.path,de,ze,m,l,Me))}ye&&Te.push({key:F,routeId:U.routeId,path:U.path,matches:ye,match:ze,request:ce,controller:be})}),{dsMatches:ge,revalidatingFetchers:Te}}function Gd(a){return a.loader!=null||a.middleware!=null&&a.middleware.length>0}function fg(a,l,i){if(a.lazy)return{shouldLoad:!0,renderFallback:!0};if(!Gd(a))return{shouldLoad:!1,renderFallback:!1};let o=l!=null&&a.id in l,c=i!=null&&i[a.id]!==void 0;if(!o&&c)return{shouldLoad:!1,renderFallback:!1};if(typeof a.loader=="function"&&a.loader.hydrate===!0)return{shouldLoad:!0,renderFallback:!o};let f=!o&&!c;return{shouldLoad:f,renderFallback:f}}function z4(a,l,i){let o=!l||i.route.id!==l.route.id,c=!a.hasOwnProperty(i.route.id);return o||c}function A4(a,l){let i=a.route.path;return a.pathname!==l.pathname||i!=null&&i.endsWith("*")&&a.params["*"]!==l.params["*"]}function Hi(a,l){if(a.route.shouldRevalidate){let i=a.route.shouldRevalidate(l);if(typeof i=="boolean")return i}return l.defaultShouldRevalidate}function Oy(a,l,i,o,c,f){let d;if(a){let m=o[a];Ee(m,`No route found to patch children into: routeId = ${a}`),m.children||(m.children=[]),d=m.children}else d=i.activeRoutes;let h=[],v=[];if(l.forEach(m=>{let y=d.find(b=>dg(m,b));y?v.push({existingRoute:y,newRoute:m}):h.push(m)}),h.length>0){let m=Xi(h,c,[a||"_","patch",String(d?.length||"0")],o);d.push(...m)}if(f&&v.length>0)for(let m=0;ml.children?.some(c=>dg(i,c)))??!1:!1}var Dy=new WeakMap,hg=({key:a,route:l,manifest:i,mapRouteProperties:o})=>{let c=i[l.id];if(Ee(c,"No route found in manifest"),!c.lazy||typeof c.lazy!="object")return;let f=c.lazy[a];if(!f)return;let d=Dy.get(c);d||(d={},Dy.set(c,d));let h=d[a];if(h)return h;let v=(async()=>{let m=G3(a),b=c[a]!==void 0&&a!=="hasErrorBoundary";if(m)ct(!m,"Route property "+a+" is not a supported lazy route property. This property will be ignored."),d[a]=Promise.resolve();else if(b)ct(!1,`Route "${c.id}" has a static property "${a}" defined. The lazy property will be ignored.`);else{let E=await f();E!=null&&(Object.assign(c,{[a]:E}),Object.assign(c,o(c)))}typeof c.lazy=="object"&&(c.lazy[a]=void 0,Object.values(c.lazy).every(E=>E===void 0)&&(c.lazy=void 0))})();return d[a]=v,v},Ny=new WeakMap;function M4(a,l,i,o,c){let f=i[a.id];if(Ee(f,"No route found in manifest"),!a.lazy)return{lazyRoutePromise:void 0,lazyHandlerPromise:void 0};if(typeof a.lazy=="function"){let y=Ny.get(f);if(y)return{lazyRoutePromise:y,lazyHandlerPromise:y};let b=(async()=>{Ee(typeof a.lazy=="function","No lazy route function found");let E=await a.lazy(),R={};for(let C in E){let T=E[C];if(T===void 0)continue;let A=k3(C),$=f[C]!==void 0&&C!=="hasErrorBoundary";A?ct(!A,"Route property "+C+" is not a supported property to be returned from a lazy route function. This property will be ignored."):$?ct(!$,`Route "${f.id}" has a static property "${C}" defined but its lazy function is also returning a value for this property. The lazy route property "${C}" will be ignored.`):R[C]=T}Object.assign(f,R),Object.assign(f,{...o(f),lazy:void 0})})();return Ny.set(f,b),b.catch(()=>{}),{lazyRoutePromise:b,lazyHandlerPromise:b}}let d=Object.keys(a.lazy),h=[],v;for(let y of d){if(c&&c.includes(y))continue;let b=hg({key:y,route:a,manifest:i,mapRouteProperties:o});b&&(h.push(b),y===l&&(v=b))}let m=h.length>0?Promise.all(h).then(()=>{}):void 0;return m?.catch(()=>{}),v?.catch(()=>{}),{lazyRoutePromise:m,lazyHandlerPromise:v}}async function jy(a){let l=a.matches.filter(c=>c.shouldLoad),i={};return(await Promise.all(l.map(c=>c.resolve()))).forEach((c,f)=>{i[l[f].route.id]=c}),i}async function _4(a){return a.matches.some(l=>l.route.middleware)?mg(a,()=>jy(a)):jy(a)}function mg(a,l){return O4(a,l,o=>{if(X4(o))throw o;return o},Y4,i);function i(o,c,f){if(f)return Promise.resolve(Object.assign(f.value,{[c]:{type:"error",result:o}}));{let{matches:d}=a,h=Math.min(Math.max(d.findIndex(m=>m.route.id===c),0),Math.max(d.findIndex(m=>m.shouldCallHandler()),0)),v=il(d,d[h].route.id).route.id;return Promise.resolve({[v]:{type:"error",result:o}})}}}async function O4(a,l,i,o,c){let{matches:f,...d}=a,h=f.flatMap(m=>m.route.middleware?m.route.middleware.map(y=>[m.route.id,y]):[]);return await pg(d,h,l,i,o,c)}async function pg(a,l,i,o,c,f,d=0){let{request:h}=a;if(h.signal.aborted)throw h.signal.reason??new Error(`Request aborted: ${h.method} ${h.url}`);let v=l[d];if(!v)return await i();let[m,y]=v,b,E=async()=>{if(b)throw new Error("You may only call `next()` once per middleware");try{return b={value:await pg(a,l,i,o,c,f,d+1)},b.value}catch(R){return b={value:await f(R,m,b)},b.value}};try{let R=await y(a,E),C=R!=null?o(R):void 0;return c(C)?C:b?C??b.value:(b={value:await E()},b.value)}catch(R){return await f(R,m,b)}}function vg(a,l,i,o,c){let f=hg({key:"middleware",route:o.route,manifest:l,mapRouteProperties:a}),d=M4(o.route,jt(i.method)?"action":"loader",l,a,c);return{middleware:f,route:d.lazyRoutePromise,handler:d.lazyHandlerPromise}}function ed(a,l,i,o,c,f,d,h,v,m=null,y){let b=!1,E=vg(a,l,i,f,d);return{...f,_lazyPromises:E,shouldLoad:v,shouldRevalidateArgs:m,shouldCallHandler(R){return b=!0,m?typeof y=="boolean"?Hi(f,{...m,defaultShouldRevalidate:y}):typeof R=="boolean"?Hi(f,{...m,defaultShouldRevalidate:R}):Hi(f,m):v},resolve(R){let{lazy:C,loader:T,middleware:A}=f.route,q=b||v||R&&!jt(i.method)&&(C||T),$=A&&A.length>0&&!T&&!C;return q&&(jt(i.method)||!$)?N4({request:i,path:o,pattern:c,match:f,lazyHandlerPromise:E?.handler,lazyRoutePromise:E?.route,handlerOverride:R,scopedContext:h}):Promise.resolve({type:"data",result:void 0})}}}function Mr(a,l,i,o,c,f,d,h,v=null){return c.map(m=>m.route.id!==f.route.id?{...m,shouldLoad:!1,shouldRevalidateArgs:v,shouldCallHandler:()=>!1,_lazyPromises:vg(a,l,i,m,d),resolve:()=>Promise.resolve({type:"data",result:void 0})}:ed(a,l,i,o,ao(c),m,d,h,!0,v))}async function D4(a,l,i,o,c,f,d){o.some(y=>y._lazyPromises?.middleware)&&await Promise.all(o.map(y=>y._lazyPromises?.middleware));let h={request:l,url:yg(l,i),pattern:ao(o),params:o[0].params,context:f,matches:o},m=await a({...h,fetcherKey:c,runClientMiddleware:y=>{let b=h;return mg(b,()=>y({...b,fetcherKey:c,runClientMiddleware:()=>{throw new Error("Cannot call `runClientMiddleware()` from within an `runClientMiddleware` handler")}}))}});try{await Promise.all(o.flatMap(y=>[y._lazyPromises?.handler,y._lazyPromises?.route]))}catch{}return m}async function N4({request:a,path:l,pattern:i,match:o,lazyHandlerPromise:c,lazyRoutePromise:f,handlerOverride:d,scopedContext:h}){let v,m,y=jt(a.method),b=y?"action":"loader",E=R=>{let C,T=new Promise(($,X)=>C=X);m=()=>C(),a.signal.addEventListener("abort",m);let A=$=>typeof R!="function"?Promise.reject(new Error(`You cannot call the handler for a route which defines a boolean "${b}" [routeId: ${o.route.id}]`)):R({request:a,url:yg(a,l),pattern:i,params:o.params,context:h},...$!==void 0?[$]:[]),q=(async()=>{try{return{type:"data",result:await(d?d(X=>A(X)):A())}}catch($){return{type:"error",result:$}}})();return Promise.race([q,T])};try{let R=y?o.route.action:o.route.loader;if(c||f)if(R){let C,[T]=await Promise.all([E(R).catch(A=>{C=A}),c,f]);if(C!==void 0)throw C;v=T}else{await c;let C=y?o.route.action:o.route.loader;if(C)[v]=await Promise.all([E(C),f]);else if(b==="action"){let T=new URL(a.url),A=T.pathname+T.search;throw wa(405,{method:a.method,pathname:A,routeId:o.route.id})}else return{type:"data",result:void 0}}else if(R)v=await E(R);else{let C=new URL(a.url),T=C.pathname+C.search;throw wa(404,{pathname:T})}}catch(R){return{type:"error",result:R}}finally{m&&a.signal.removeEventListener("abort",m)}return v}async function j4(a){let l=a.headers.get("Content-Type");return l&&/\bapplication\/json\b/.test(l)?a.body==null?null:a.json():a.text()}async function L4(a){let{result:l,type:i}=a;if(Xd(l)){let o;try{o=await j4(l)}catch(c){return{type:"error",error:c}}return i==="error"?{type:"error",error:new to(l.status,l.statusText,o),statusCode:l.status,headers:l.headers}:{type:"data",data:o,statusCode:l.status,headers:l.headers}}return i==="error"?qy(l)?l.data instanceof Error?{type:"error",error:l.data,statusCode:l.init?.status,headers:l.init?.headers?new Headers(l.init.headers):void 0}:{type:"error",error:q4(l),statusCode:ki(l)?l.status:void 0,headers:l.init?.headers?new Headers(l.init.headers):void 0}:{type:"error",error:l,statusCode:ki(l)?l.status:void 0}:qy(l)?{type:"data",data:l.data,statusCode:l.init?.status,headers:l.init?.headers?new Headers(l.init.headers):void 0}:{type:"data",data:l}}function U4(a,l,i,o,c){let f=a.headers.get("Location");if(Ee(f,"Redirects returned/thrown from loaders/actions must have a Location header"),!Vd(f)){let d=o.slice(0,o.findIndex(h=>h.route.id===i)+1);f=If(new URL(l.url),d,c,f),a.headers.set("Location",f)}return a}var B4=["about:","blob:","chrome:","chrome-untrusted:","content:","data:","devtools:","file:","filesystem:","javascript:"];function td(a){try{return B4.includes(new URL(a).protocol)}catch{return!1}}function Ly(a,l,i,o){if(Vd(a)){let c=a,f=Yd.test(c)?new URL(J0(c,l.protocol)):new URL(c);if(td(f.toString()))throw new Error("Invalid redirect location");let d=Kt(f.pathname,i)!=null;if(f.origin===l.origin&&d)return Qd(f.pathname)+f.search+f.hash}try{let c=o.createURL(a);if(td(c.toString()))throw new Error("Invalid redirect location")}catch{}return a}function Cr(a,l,i,o){let c=a.createURL(gg(l)).toString(),f={signal:i};if(o&&jt(o.formMethod)){let{formMethod:d,formEncType:h}=o;f.method=d.toUpperCase(),h==="application/json"?(f.headers=new Headers({"Content-Type":h}),f.body=JSON.stringify(o.json)):h==="text/plain"?f.body=o.text:h==="application/x-www-form-urlencoded"&&o.formData?f.body=ad(o.formData):f.body=o.formData}return new Request(c,f)}function yg(a,l){let i=new URL(a.url),o=typeof l=="string"?Va(l):l;if(i.pathname=o.pathname||"/",o.search){let c=new URLSearchParams(o.search),f=c.getAll("index");c.delete("index");for(let d of f.filter(Boolean))c.append("index",d);i.search=c.size?`?${c.toString()}`:""}else i.search="";return i.hash=o.hash||"",i}function ad(a){let l=new URLSearchParams;for(let[i,o]of a.entries())l.append(i,typeof o=="string"?o:o.name);return l}function Uy(a){let l=new FormData;for(let[i,o]of a.entries())l.append(i,o);return l}function H4(a,l,i,o=!1,c=!1){let f={},d=null,h,v=!1,m={},y=i&&oa(i[1])?i[1].error:void 0;return a.forEach(b=>{if(!(b.route.id in l))return;let E=b.route.id,R=l[E];if(Ee(!_l(R),"Cannot handle redirect results in processLoaderData"),oa(R)){let C=R.error;if(y!==void 0&&(C=y,y=void 0),d=d||{},c)d[E]=C;else{let T=il(a,E);d[T.route.id]==null&&(d[T.route.id]=C)}o||(f[E]=cg),v||(v=!0,h=ki(R.error)?R.error.status:500),R.headers&&(m[E]=R.headers)}else f[E]=R.data,R.statusCode&&R.statusCode!==200&&!v&&(h=R.statusCode),R.headers&&(m[E]=R.headers)}),y!==void 0&&i&&(d={[i[0]]:y},i[2]&&(f[i[2]]=void 0)),{loaderData:f,errors:d,statusCode:h||200,loaderHeaders:m}}function By(a,l,i,o,c,f,d){let{loaderData:h,errors:v}=H4(l,i,o);return c.filter(m=>!m.matches||m.matches.some(y=>y.shouldLoad)).forEach(m=>{let{key:y,match:b,controller:E}=m;if(E&&E.signal.aborted)return;let R=f[y];if(Ee(R,"Did not find corresponding fetcher result"),oa(R)){let C=il(a.matches,b?.route.id);v&&v[C.route.id]||(v={...v,[C.route.id]:R.error}),d.delete(y)}else if(_l(R))Ee(!1,"Unhandled fetcher revalidation redirect");else{let C=Ia(R.data);d.set(y,C)}}),{loaderData:h,errors:v}}function Hy(a,l,i,o){let c=Object.entries(l).filter(([,f])=>f!==cg).reduce((f,[d,h])=>(f[d]=h,f),{});for(let f of i){let d=f.route.id;if(!l.hasOwnProperty(d)&&a.hasOwnProperty(d)&&f.route.loader&&(c[d]=a[d]),o&&o.hasOwnProperty(d))break}return c}function $y(a){return a?oa(a[1])?{actionData:{}}:{actionData:{[a[0]]:a[1].data}}:{}}function il(a,l){return(l?a.slice(0,a.findIndex(o=>o.route.id===l)+1):[...a]).reverse().find(o=>o.route.hasErrorBoundary===!0)||a[0]}function zu(a){let l=a.length===1?a[0]:a.find(i=>i.index||!i.path||i.path==="/")||{id:"__shim-error-route__"};return{matches:[{params:{},pathname:"",pathnameBase:"",route:l}],route:l}}function wa(a,{pathname:l,routeId:i,method:o,type:c,message:f}={}){let d="Unknown Server Error",h="Unknown @remix-run/router error";return a===400?(d="Bad Request",o&&l&&i?h=`You made a ${o} request to "${l}" but did not provide a \`loader\` for route "${i}", so there is no way to handle the request.`:c==="invalid-body"&&(h="Unable to encode submission body")):a===403?(d="Forbidden",h=`Route "${i}" does not match URL "${l}"`):a===404?(d="Not Found",h=`No route matches URL "${l}"`):a===405&&(d="Method Not Allowed",o&&l&&i?h=`You made a ${o.toUpperCase()} request to "${l}" but did not provide an \`action\` for route "${i}", so there is no way to handle the request.`:o&&(h=`Invalid request method "${o.toUpperCase()}"`)),new to(a||500,d,new Error(h),!0)}function Au(a){let l=Object.entries(a);for(let i=l.length-1;i>=0;i--){let[o,c]=l[i];if(_l(c))return{key:o,result:c}}}function gg(a){let l=typeof a=="string"?Va(a):a;return tn({...l,hash:""})}function $4(a,l){return a.pathname!==l.pathname||a.search!==l.search?!1:a.hash===""?l.hash!=="":a.hash===l.hash?!0:l.hash!==""}function q4(a){return new to(a.init?.status??500,a.init?.statusText??"Internal Server Error",a.data)}function Y4(a){return a!=null&&typeof a=="object"&&Object.entries(a).every(([l,i])=>typeof l=="string"&&V4(i))}function V4(a){return a!=null&&typeof a=="object"&&"type"in a&&"result"in a&&(a.type==="data"||a.type==="error")}function Q4(a){return Xd(a.result)&&ug.has(a.result.status)}function oa(a){return a.type==="error"}function _l(a){return(a&&a.type)==="redirect"}function qy(a){return typeof a=="object"&&a!=null&&"type"in a&&"data"in a&&"init"in a&&a.type==="DataWithResponseInit"}function Xd(a){return a!=null&&typeof a.status=="number"&&typeof a.statusText=="string"&&typeof a.headers=="object"&&typeof a.body<"u"}function G4(a){return ug.has(a)}function X4(a){return Xd(a)&&G4(a.status)&&a.headers.has("Location")}function k4(a){return S4.has(a.toUpperCase())}function jt(a){return g4.has(a.toUpperCase())}function kd(a){return new URLSearchParams(a).getAll("index").some(l=>l==="")}function Lu(a,l){let i=typeof l=="string"?Va(l).search:l.search;if(a[a.length-1].route.index&&kd(i||""))return a[a.length-1];let o=ng(a);return o[o.length-1]}function Yy(a){let{formMethod:l,formAction:i,formEncType:o,text:c,formData:f,json:d}=a;if(!(!l||!i||!o)){if(c!=null)return{formMethod:l,formAction:i,formEncType:o,formData:void 0,json:void 0,text:c};if(f!=null)return{formMethod:l,formAction:i,formEncType:o,formData:f,json:void 0,text:void 0};if(d!==void 0)return{formMethod:l,formAction:i,formEncType:o,formData:void 0,json:d,text:void 0}}}function Uf(a,l,i,o){return o?{state:"loading",location:a,matches:l,historyAction:i,formMethod:o.formMethod,formAction:o.formAction,formEncType:o.formEncType,formData:o.formData,json:o.json,text:o.text}:{state:"loading",location:a,matches:l,historyAction:i,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0}}function Z4(a,l,i,o){return{state:"submitting",location:a,matches:l,historyAction:i,formMethod:o.formMethod,formAction:o.formAction,formEncType:o.formEncType,formData:o.formData,json:o.json,text:o.text}}function Ni(a,l){return a?{state:"loading",formMethod:a.formMethod,formAction:a.formAction,formEncType:a.formEncType,formData:a.formData,json:a.json,text:a.text,data:l}:{state:"loading",formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0,data:l}}function F4(a,l){return{state:"submitting",formMethod:a.formMethod,formAction:a.formAction,formEncType:a.formEncType,formData:a.formData,json:a.json,text:a.text,data:l?l.data:void 0}}function Ia(a){return{state:"idle",formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0,data:a}}function K4(a,l){try{let i=a.sessionStorage.getItem(sg);if(i){let o=JSON.parse(i);for(let[c,f]of Object.entries(o||{}))f&&Array.isArray(f)&&l.set(c,new Set(f||[]))}}catch{}}function J4(a,l){if(l.size>0){let i={};for(let[o,c]of l)i[o]=[...c];try{a.sessionStorage.setItem(sg,JSON.stringify(i))}catch(o){ct(!1,`Failed to save applied view transitions in sessionStorage (${o}).`)}}}function Vy(){let a,l,i=new Promise((o,c)=>{a=async f=>{o(f);try{await i}catch{}},l=async f=>{c(f);try{await i}catch{}}});return{promise:i,resolve:a,reject:l}}var Dl=S.createContext(null);Dl.displayName="DataRouter";var no=S.createContext(null);no.displayName="DataRouterState";var bg=S.createContext(!1);function Sg(){return S.useContext(bg)}var Zd=S.createContext({isTransitioning:!1});Zd.displayName="ViewTransition";var Eg=S.createContext(new Map);Eg.displayName="Fetchers";var P4=S.createContext(null);P4.displayName="Await";var sa=S.createContext(null);sa.displayName="Navigation";var lo=S.createContext(null);lo.displayName="Location";var za=S.createContext({outlet:null,matches:[],isDataRoute:!1});za.displayName="Route";var Fd=S.createContext(null);Fd.displayName="RouteError";var Rg="REACT_ROUTER_ERROR",W4="REDIRECT",I4="ROUTE_ERROR_RESPONSE";function eR(a){if(a.startsWith(`${Rg}:${W4}:{`))try{let l=JSON.parse(a.slice(28));if(typeof l=="object"&&l&&typeof l.status=="number"&&typeof l.statusText=="string"&&typeof l.location=="string"&&typeof l.reloadDocument=="boolean"&&typeof l.replace=="boolean")return l}catch{}}function tR(a){if(a.startsWith(`${Rg}:${I4}:{`))try{let l=JSON.parse(a.slice(40));if(typeof l=="object"&&l&&typeof l.status=="number"&&typeof l.statusText=="string")return new to(l.status,l.statusText,l.data)}catch{}}function aR(a,{relative:l}={}){Ee(Hr(),"useHref() may be used only in the context of a component.");let{basename:i,navigator:o}=S.useContext(sa),{hash:c,pathname:f,search:d}=ro(a,{relative:l}),h=f;return i!=="/"&&(h=f==="/"?i:Ta([i,f])),o.createHref({pathname:h,search:d,hash:c})}function Hr(){return S.useContext(lo)!=null}function Jt(){return Ee(Hr(),"useLocation() may be used only in the context of a component."),S.useContext(lo).location}var wg="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function xg(a){S.useContext(sa).static||S.useLayoutEffect(a)}function Kd(){let{isDataRoute:a}=S.useContext(za);return a?vR():nR()}function nR(){Ee(Hr(),"useNavigate() may be used only in the context of a component.");let a=S.useContext(Dl),{basename:l,navigator:i}=S.useContext(sa),{matches:o}=S.useContext(za),{pathname:c}=Jt(),f=JSON.stringify(ls(o)),d=S.useRef(!1);return xg(()=>{d.current=!0}),S.useCallback((v,m={})=>{if(ct(d.current,wg),!d.current)return;if(typeof v=="number"){i.go(v);return}let y=eo(v,JSON.parse(f),c,m.relative==="path");a==null&&l!=="/"&&(y.pathname=y.pathname==="/"?l:Ta([l,y.pathname])),(m.replace?i.replace:i.push)(y,m.state,m)},[l,i,f,c,a])}var lR=S.createContext(null);function rR(a){let l=S.useContext(za).outlet;return S.useMemo(()=>l&&S.createElement(lR.Provider,{value:a},l),[l,a])}function tw(){let{matches:a}=S.useContext(za);return a[a.length-1]?.params??{}}function ro(a,{relative:l}={}){let{matches:i}=S.useContext(za),{pathname:o}=Jt(),c=JSON.stringify(ls(i));return S.useMemo(()=>eo(a,JSON.parse(c),o,l==="path"),[a,c,o,l])}function iR(a,l){return Tg(a,l)}function Tg(a,l,i){Ee(Hr(),"useRoutes() may be used only in the context of a component.");let{navigator:o}=S.useContext(sa),{matches:c}=S.useContext(za),f=c[c.length-1],d=f?f.params:{},h=f?f.pathname:"/",v=f?f.pathnameBase:"/",m=f&&f.route;{let A=m&&m.path||"";Mg(h,!m||A.endsWith("*")||A.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${h}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. -Please change the parent to .`)}let y=Jt(),b;if(l){let A=typeof l=="string"?Va(l):l;Ee(v==="/"||A.pathname?.startsWith(v),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${v}" but pathname "${A.pathname}" was given in the \`location\` prop.`),b=A}else b=y;let E=b.pathname||"/",R=E;if(v!=="/"){let A=v.replace(/^\//,"").split("/");R="/"+E.replace(/^\//,"").split("/").slice(A.length).join("/")}let C=i&&i.state.matches.length?i.state.matches.map(A=>Object.assign(A,{route:i.manifest[A.route.id]||A.route})):W0(a,{pathname:R});ct(m||C!=null,`No routes matched location "${b.pathname}${b.search}${b.hash}" `),ct(C==null||C[C.length-1].route.element!==void 0||C[C.length-1].route.Component!==void 0||C[C.length-1].route.lazy!==void 0,`Matched leaf route at location "${b.pathname}${b.search}${b.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let T=fR(C&&C.map(A=>Object.assign({},A,{params:Object.assign({},d,A.params),pathname:Ta([v,o.encodeLocation?o.encodeLocation(A.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:A.pathname]),pathnameBase:A.pathnameBase==="/"?v:Ta([v,o.encodeLocation?o.encodeLocation(A.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:A.pathnameBase])})),c,i);return l&&T?S.createElement(lo.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...b},navigationType:"POP"}},T):T}function oR(){let a=mR(),l=ki(a)?`${a.status} ${a.statusText}`:a instanceof Error?a.message:JSON.stringify(a),i=a instanceof Error?a.stack:null,o="rgba(200,200,200, 0.5)",c={padding:"0.5rem",backgroundColor:o},f={padding:"2px 4px",backgroundColor:o},d=null;return console.error("Error handled by React Router default ErrorBoundary:",a),d=S.createElement(S.Fragment,null,S.createElement("p",null,"💿 Hey developer 👋"),S.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",S.createElement("code",{style:f},"ErrorBoundary")," or"," ",S.createElement("code",{style:f},"errorElement")," prop on your route.")),S.createElement(S.Fragment,null,S.createElement("h2",null,"Unexpected Application Error!"),S.createElement("h3",{style:{fontStyle:"italic"}},l),i?S.createElement("pre",{style:c},i):null,d)}var uR=S.createElement(oR,null),Cg=class extends S.Component{constructor(a){super(a),this.state={location:a.location,revalidation:a.revalidation,error:a.error}}static getDerivedStateFromError(a){return{error:a}}static getDerivedStateFromProps(a,l){return l.location!==a.location||l.revalidation!=="idle"&&a.revalidation==="idle"?{error:a.error,location:a.location,revalidation:a.revalidation}:{error:a.error!==void 0?a.error:l.error,location:l.location,revalidation:a.revalidation||l.revalidation}}componentDidCatch(a,l){this.props.onError?this.props.onError(a,l):console.error("React Router caught the following error during render",a)}render(){let a=this.state.error;if(this.context&&typeof a=="object"&&a&&"digest"in a&&typeof a.digest=="string"){const i=tR(a.digest);i&&(a=i)}let l=a!==void 0?S.createElement(za.Provider,{value:this.props.routeContext},S.createElement(Fd.Provider,{value:a,children:this.props.component})):this.props.children;return this.context?S.createElement(sR,{error:a},l):l}};Cg.contextType=bg;var Bf=new WeakMap;function sR({children:a,error:l}){let{basename:i}=S.useContext(sa);if(typeof l=="object"&&l&&"digest"in l&&typeof l.digest=="string"){let o=eR(l.digest);if(o){let c=Bf.get(l);if(c)throw c;let f=rg(o.location,i),d=f.absoluteURL||f.to;if(td(d))throw new Error("Invalid redirect location");if(lg&&!Bf.get(l))if(f.isExternal||o.reloadDocument)window.location.href=d;else{const h=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(f.to,{replace:o.replace}));throw Bf.set(l,h),h}return S.createElement("meta",{httpEquiv:"refresh",content:`0;url=${d}`})}}return a}function cR({routeContext:a,match:l,children:i}){let o=S.useContext(Dl);return o&&o.static&&o.staticContext&&(l.route.errorElement||l.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=l.route.id),S.createElement(za.Provider,{value:a},i)}function fR(a,l=[],i){let o=i?.state;if(a==null){if(!o)return null;if(o.errors)a=o.matches;else if(l.length===0&&!o.initialized&&o.matches.length>0)a=o.matches;else return null}let c=a,f=o?.errors;if(f!=null){let y=c.findIndex(b=>b.route.id&&f?.[b.route.id]!==void 0);Ee(y>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(f).join(",")}`),c=c.slice(0,Math.min(c.length,y+1))}let d=!1,h=-1;if(i&&o){d=o.renderFallback;for(let y=0;y=0?c=c.slice(0,h+1):c=[c[0]];break}}}}let v=i?.onError,m=o&&v?(y,b)=>{v(y,{location:o.location,params:o.matches?.[0]?.params??{},pattern:ao(o.matches),errorInfo:b})}:void 0;return c.reduceRight((y,b,E)=>{let R,C=!1,T=null,A=null;o&&(R=f&&b.route.id?f[b.route.id]:void 0,T=b.route.errorElement||uR,d&&(h<0&&E===0?(Mg("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),C=!0,A=null):h===E&&(C=!0,A=b.route.hydrateFallbackElement||null)));let q=l.concat(c.slice(0,E+1)),$=()=>{let X;return R?X=T:C?X=A:b.route.Component?X=S.createElement(b.route.Component,null):b.route.element?X=b.route.element:X=y,S.createElement(cR,{match:b,routeContext:{outlet:y,matches:q,isDataRoute:o!=null},children:X})};return o&&(b.route.ErrorBoundary||b.route.errorElement||E===0)?S.createElement(Cg,{location:o.location,revalidation:o.revalidation,component:T,error:R,children:$(),routeContext:{outlet:null,matches:q,isDataRoute:!0},onError:m}):$()},null)}function Jd(a){return`${a} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function zg(a){let l=S.useContext(Dl);return Ee(l,Jd(a)),l}function Ag(a){let l=S.useContext(no);return Ee(l,Jd(a)),l}function dR(a){let l=S.useContext(za);return Ee(l,Jd(a)),l}function Pd(a){let l=dR(a),i=l.matches[l.matches.length-1];return Ee(i.route.id,`${a} can only be used on routes that contain a unique "id"`),i.route.id}function hR(){return Pd("useRouteId")}function mR(){let a=S.useContext(Fd),l=Ag("useRouteError"),i=Pd("useRouteError");return a!==void 0?a:l.errors?.[i]}var pR=0;function aw(a){let{router:l,basename:i}=zg("useBlocker"),o=Ag("useBlocker"),[c,f]=S.useState(""),d=S.useCallback(h=>{if(typeof a!="function")return!!a;if(i==="/")return a(h);let{currentLocation:v,nextLocation:m,historyAction:y}=h;return a({currentLocation:{...v,pathname:Kt(v.pathname,i)||v.pathname},nextLocation:{...m,pathname:Kt(m.pathname,i)||m.pathname},historyAction:y})},[i,a]);return S.useEffect(()=>{let h=String(++pR);return f(h),()=>l.deleteBlocker(h)},[l]),S.useEffect(()=>{c!==""&&l.getBlocker(c,d)},[l,c,d]),c&&o.blockers.has(c)?o.blockers.get(c):wr}function vR(){let{router:a}=zg("useNavigate"),l=Pd("useNavigate"),i=S.useRef(!1);return xg(()=>{i.current=!0}),S.useCallback(async(c,f={})=>{ct(i.current,wg),i.current&&(typeof c=="number"?await a.navigate(c):await a.navigate(c,{fromRouteId:l,...f}))},[a,l])}var Qy={};function Mg(a,l,i){!l&&!Qy[a]&&(Qy[a]=!0,ct(!1,i))}var Gy={};function Xy(a,l){!a&&!Gy[l]&&(Gy[l]=!0,console.warn(l))}var yR="useOptimistic",ky=P1[yR],gR=()=>{};function bR(a){return ky?ky(a):[a,gR]}function SR(a){let l={hasErrorBoundary:a.hasErrorBoundary||a.ErrorBoundary!=null||a.errorElement!=null};return a.Component&&(a.element&&ct(!1,"You should not include both `Component` and `element` on your route - `Component` will be used."),Object.assign(l,{element:S.createElement(a.Component),Component:void 0})),a.HydrateFallback&&(a.hydrateFallbackElement&&ct(!1,"You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - `HydrateFallback` will be used."),Object.assign(l,{hydrateFallbackElement:S.createElement(a.HydrateFallback),HydrateFallback:void 0})),a.ErrorBoundary&&(a.errorElement&&ct(!1,"You should not include both `ErrorBoundary` and `errorElement` on your route - `ErrorBoundary` will be used."),Object.assign(l,{errorElement:S.createElement(a.ErrorBoundary),ErrorBoundary:void 0})),l}var ER=["HydrateFallback","hydrateFallbackElement"],RR=class{constructor(){this.status="pending",this.promise=new Promise((a,l)=>{this.resolve=i=>{this.status==="pending"&&(this.status="resolved",a(i))},this.reject=i=>{this.status==="pending"&&(this.status="rejected",l(i))}})}};function wR({router:a,flushSync:l,onError:i,useTransitions:o}){o=Sg()||o;let[f,d]=S.useState(a.state),[h,v]=bR(f),[m,y]=S.useState(),[b,E]=S.useState({isTransitioning:!1}),[R,C]=S.useState(),[T,A]=S.useState(),[q,$]=S.useState(),X=S.useRef(new Map),J=S.useCallback((_,{deletedFetchers:ne,newErrors:se,flushSync:Re,viewTransitionOpts:oe})=>{se&&i&&Object.values(se).forEach(ge=>i(ge,{location:_.location,params:_.matches[0]?.params??{},pattern:ao(_.matches)})),_.fetchers.forEach((ge,Te)=>{ge.data!==void 0&&X.current.set(Te,ge.data)}),ne.forEach(ge=>X.current.delete(ge)),Xy(Re===!1||l!=null,'You provided the `flushSync` option to a router update, but you are not using the `` from `react-router/dom` so `ReactDOM.flushSync()` is unavailable. Please update your app to `import { RouterProvider } from "react-router/dom"` and ensure you have `react-dom` installed as a dependency to use the `flushSync` option.');let Qe=a.window!=null&&a.window.document!=null&&typeof a.window.document.startViewTransition=="function";if(Xy(oe==null||Qe,"You provided the `viewTransition` option to a router update, but you do not appear to be running in a DOM environment as `window.startViewTransition` is not available."),!oe||!Qe){l&&Re?l(()=>d(_)):o===!1?d(_):S.startTransition(()=>{o===!0&&v(ge=>Zy(ge,_)),d(_)});return}if(l&&Re){l(()=>{T&&(R?.resolve(),T.skipTransition()),E({isTransitioning:!0,flushSync:!0,currentLocation:oe.currentLocation,nextLocation:oe.nextLocation})});let ge=a.window.document.startViewTransition(()=>{l(()=>d(_))});ge.finished.finally(()=>{l(()=>{C(void 0),A(void 0),y(void 0),E({isTransitioning:!1})})}),l(()=>A(ge));return}T?(R?.resolve(),T.skipTransition(),$({state:_,currentLocation:oe.currentLocation,nextLocation:oe.nextLocation})):(y(_),E({isTransitioning:!0,flushSync:!1,currentLocation:oe.currentLocation,nextLocation:oe.nextLocation}))},[a.window,l,T,R,o,v,i]);S.useLayoutEffect(()=>a.subscribe(J),[a,J]),S.useEffect(()=>{b.isTransitioning&&!b.flushSync&&C(new RR)},[b]),S.useEffect(()=>{if(R&&m&&a.window){let _=m,ne=R.promise,se=a.window.document.startViewTransition(async()=>{o===!1?d(_):S.startTransition(()=>{o===!0&&v(Re=>Zy(Re,_)),d(_)}),await ne});se.finished.finally(()=>{C(void 0),A(void 0),y(void 0),E({isTransitioning:!1})}),A(se)}},[m,R,a.window,o,v]),S.useEffect(()=>{R&&m&&h.location.key===m.location.key&&R.resolve()},[R,T,h.location,m]),S.useEffect(()=>{!b.isTransitioning&&q&&(y(q.state),E({isTransitioning:!0,flushSync:!1,currentLocation:q.currentLocation,nextLocation:q.nextLocation}),$(void 0))},[b.isTransitioning,q]);let K=S.useMemo(()=>({createHref:a.createHref,encodeLocation:a.encodeLocation,go:_=>a.navigate(_),push:(_,ne,se)=>a.navigate(_,{state:ne,preventScrollReset:se?.preventScrollReset}),replace:(_,ne,se)=>a.navigate(_,{replace:!0,state:ne,preventScrollReset:se?.preventScrollReset})}),[a]),W=a.basename||"/",P=S.useMemo(()=>({router:a,navigator:K,static:!1,basename:W,onError:i}),[a,K,W,i]);return S.createElement(S.Fragment,null,S.createElement(Dl.Provider,{value:P},S.createElement(no.Provider,{value:h},S.createElement(Eg.Provider,{value:X.current},S.createElement(Zd.Provider,{value:b},S.createElement(zR,{basename:W,location:h.location,navigationType:h.historyAction,navigator:K,useTransitions:o},S.createElement(xR,{routes:a.routes,manifest:a.manifest,future:a.future,state:h,isStatic:!1,onError:i})))))),null)}function Zy(a,l){return{...a,navigation:l.navigation.state!=="idle"?l.navigation:a.navigation,revalidation:l.revalidation!=="idle"?l.revalidation:a.revalidation,actionData:l.navigation.state!=="submitting"?l.actionData:a.actionData,fetchers:l.fetchers}}var xR=S.memo(TR);function TR({routes:a,manifest:l,future:i,state:o,isStatic:c,onError:f}){return Tg(a,void 0,{manifest:l,state:o,isStatic:c,onError:f})}function Fy({to:a,replace:l,state:i,relative:o}){Ee(Hr()," may be used only in the context of a component.");let{static:c}=S.useContext(sa);ct(!c," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:f}=S.useContext(za),{pathname:d}=Jt(),h=Kd(),v=eo(a,ls(f),d,o==="path"),m=JSON.stringify(v);return S.useEffect(()=>{h(JSON.parse(m),{replace:l,state:i,relative:o})},[h,m,o,l,i]),null}function CR(a){return rR(a.context)}function Ba(a){Ee(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function zR({basename:a="/",children:l=null,location:i,navigationType:o="POP",navigator:c,static:f=!1,useTransitions:d}){Ee(!Hr(),"You cannot render a inside another . You should never have more than one in your app.");let h=a.replace(/^\/*/,"/"),v=S.useMemo(()=>({basename:h,navigator:c,static:f,useTransitions:d,future:{}}),[h,c,f,d]);typeof i=="string"&&(i=Va(i));let{pathname:m="/",search:y="",hash:b="",state:E=null,key:R="default",mask:C}=i,T=S.useMemo(()=>{let A=Kt(m,h);return A==null?null:{location:{pathname:A,search:y,hash:b,state:E,key:R,mask:C},navigationType:o}},[h,m,y,b,E,R,o,C]);return ct(T!=null,` is not able to match the URL "${m}${y}${b}" because it does not start with the basename, so the won't render anything.`),T==null?null:S.createElement(sa.Provider,{value:v},S.createElement(lo.Provider,{children:l,value:T}))}function AR({children:a,location:l}){return iR(nd(a),l)}function nd(a,l=[]){let i=[];return S.Children.forEach(a,(o,c)=>{if(!S.isValidElement(o))return;let f=[...l,c];if(o.type===S.Fragment){i.push.apply(i,nd(o.props.children,f));return}Ee(o.type===Ba,`[${typeof o.type=="string"?o.type:o.type.name}] is not a component. All component children of must be a or `),Ee(!o.props.index||!o.props.children,"An index route cannot have child routes.");let d={id:o.props.id||f.join("-"),caseSensitive:o.props.caseSensitive,element:o.props.element,Component:o.props.Component,index:o.props.index,path:o.props.path,middleware:o.props.middleware,loader:o.props.loader,action:o.props.action,hydrateFallbackElement:o.props.hydrateFallbackElement,HydrateFallback:o.props.HydrateFallback,errorElement:o.props.errorElement,ErrorBoundary:o.props.ErrorBoundary,hasErrorBoundary:o.props.hasErrorBoundary===!0||o.props.ErrorBoundary!=null||o.props.errorElement!=null,shouldRevalidate:o.props.shouldRevalidate,handle:o.props.handle,lazy:o.props.lazy};o.props.children&&(d.children=nd(o.props.children,f)),i.push(d)}),i}var Uu="get",Bu="application/x-www-form-urlencoded";function rs(a){return typeof HTMLElement<"u"&&a instanceof HTMLElement}function MR(a){return rs(a)&&a.tagName.toLowerCase()==="button"}function _R(a){return rs(a)&&a.tagName.toLowerCase()==="form"}function OR(a){return rs(a)&&a.tagName.toLowerCase()==="input"}function DR(a){return!!(a.metaKey||a.altKey||a.ctrlKey||a.shiftKey)}function NR(a,l){return a.button===0&&(!l||l==="_self")&&!DR(a)}function ld(a=""){return new URLSearchParams(typeof a=="string"||Array.isArray(a)||a instanceof URLSearchParams?a:Object.keys(a).reduce((l,i)=>{let o=a[i];return l.concat(Array.isArray(o)?o.map(c=>[i,c]):[[i,o]])},[]))}function jR(a,l){let i=ld(a);return l&&l.forEach((o,c)=>{i.has(c)||l.getAll(c).forEach(f=>{i.append(c,f)})}),i}var Mu=null;function LR(){if(Mu===null)try{new FormData(document.createElement("form"),0),Mu=!1}catch{Mu=!0}return Mu}var UR=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Hf(a){return a!=null&&!UR.has(a)?(ct(!1,`"${a}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Bu}"`),null):a}function BR(a,l){let i,o,c,f,d;if(_R(a)){let h=a.getAttribute("action");o=h?Kt(h,l):null,i=a.getAttribute("method")||Uu,c=Hf(a.getAttribute("enctype"))||Bu,f=new FormData(a)}else if(MR(a)||OR(a)&&(a.type==="submit"||a.type==="image")){let h=a.form;if(h==null)throw new Error('Cannot submit a